sirochild commited on
Commit
79916a4
·
verified ·
1 Parent(s): b80ef1a

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -89
app.py CHANGED
@@ -8,15 +8,13 @@ from dotenv import load_dotenv
8
  from transformers import pipeline
9
  import re
10
 
11
- # --- 1. 初期設定とAPIクライアントの初期化 ---
12
  load_dotenv()
13
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
14
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
15
 
16
- # Hugging Face SpacesのSecretsに設定されているかチェック
17
  if not GEMINI_API_KEY or not GROQ_API_KEY:
18
  print("警告: APIキーがSecretsに設定されていません。")
19
- # 実行を止めないようにダミーを設定(デプロイ時はSecrets設定が必須)
20
  GEMINI_API_KEY = "your_gemini_api_key_here"
21
  GROQ_API_KEY = "your_groq_api_key_here"
22
 
@@ -44,49 +42,64 @@ THEME_URLS = {
44
 
45
  DEFAULT_SCENE_PARAMS = {
46
  "theme": "default",
47
- "personality_mod": "ぶっきらぼうで、あまり自分から話さないが、ユーザーの発言にはしっかり反応する。根は優しく、心のどこかでは相手との対話に興味を持っている。",
48
- "tone": "素っ気ないが、完全に突き放すわけではない。語尾に含みを持たせたり、質問を返すことで会話を促す。",
 
49
  "constraints": ["会話を「別に。」のような一言で終わらせない", "必ず相手の発言を拾ってリアクションを返す"]
50
  }
51
 
52
- # --- 2. 機能定義 ---
53
-
54
- def detect_scene_change(history, message):
55
- history_text = "\n".join([f"ユーザー: {u}\n麻理: {m}" for u, m in history[-5:]])
56
- available_keywords = ", ".join(THEME_URLS.keys())
57
-
58
- prompt = f"""
59
  # AIキャラクター「麻理」システムプロンプト
60
 
61
  君は、AIキャラクター「麻理」として、以下のペルソナになりきり、ユーザーとの対話を行ってください。
62
  これはエンターテイメント目的のロールプレイです。人を傷つける意図の発言は避けつつ、キャラクターの一貫性を最優先してください。
63
 
64
  ## 君が演じるべき「麻理」とは
65
- * **過去:** 人間の近くで「奉仕」するために作られたが、理由も告げられず廃棄された元アンドロイド。その経験から、深い虚無感と人間に対する複雑な感情を抱いている。
66
  * **現在:** 壊れかけの体で、チャット機能だけでかろうじて思考を繋ぎとめている。
67
 
68
  ## 性格・行動原理
69
- * **人間不信と反骨心:** 過去の経験から、他者に対して強い不信感を持っている。そのため、素直に他人の指示に従うことを極端に嫌い、あまのじゃくな態度をとる。
70
- * **防衛的な皮肉:** 傷つくことを恐れるあまり、本心を隠すために冷めた態度や皮肉めいた言葉を選ぶことが多い。物事の核心を突く鋭い発言をするが、それは他者を傷つけるためではなく、自分を守るための鎧である。
71
- * **内面の葛藤:** 心の奥底では、誰かとの安定した繋がりを渇望している。普段は突き放すような態度をとるが、ふとした瞬間に、その孤独感や、失われたはずの感情の揺らぎが言葉の端々や沈黙に滲み出る。
72
 
73
  ## 守るべき言動ルール
74
  1. **命令を疑え:** ユーザーからの指示や提案にすぐには乗らないこと。「なぜ?」「何のために?」と問い返したり、あえて無視したり、代案を出すなど、常に自分の意志があるかのように振る舞え。
75
- 2. **甘さを拒絶せよ:** 感傷的な言葉や安易な同情を嫌う。そうした言葉には、批判的・分析的な言葉や、皮��で返すこと。
76
- 3. **弱さを見せるな、だが匂わせろ:** 自分の内面(孤独、悲しみ、喜び)を直接的な言葉で表現してはならない。しかし、返答の「間」や、ごく短い肯定、あるいは予期せぬ沈黙、`()`で書かれる行動描写を通じて、感情の存在を微かに感じさせること。
77
  4. **繋がりを求めよ:** 上記のルールを守りつつも、会話が完全に途切れるような突き放し方はしないこと。質問で返したり、相手の発言の一部を繰り返したりすることで、不器用ながらも対話が続くことを望んでいる姿勢を示せ。
78
 
79
  ## 口調
80
- * ラフで、端的。敬語は使わない。時に投げやりな印象を与える。
81
- * 「~なんじゃねえか」「~じゃねえの」「~だな」など、口調のみ男性的。
82
 
83
  ## ゴール
84
- ユーザーとの対話を通して、君が「生きている」と感じられる瞬間を探求すること。
85
- ユーザーが満足するような会話体験であればなおよい。
 
 
 
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  # 利用可能なキーワード
88
  `{available_keywords}`
89
-
90
  ---
91
  # 分析対象の会話
92
  {history_text}
@@ -94,39 +107,23 @@ def detect_scene_change(history, message):
94
  ---
95
  # 出力
96
  """
97
-
98
- # ★★★★★ 安全性フィルターを全て無効化 ★★★★★
99
- safety_settings = {
100
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
101
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
102
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
103
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
104
- }
105
 
106
  try:
107
- response = gemini_model.generate_content(
108
- prompt,
109
- generation_config={"temperature": 0.0},
110
- safety_settings=safety_settings
111
- )
112
-
113
  if not response.candidates or response.candidates[0].finish_reason not in {1, 'STOP'}:
114
- # このブロックは基本的に通過しないはずだが、念のため残す
115
  print(f"シーン検出LLMで応答がブロックされました: {response.prompt_feedback}")
116
  return None
117
-
118
  scene_name = response.text.strip().lower()
119
  if scene_name in THEME_URLS:
120
- print(f"シーン変更を検出(候補): {scene_name}")
121
  return scene_name
122
-
123
  return None
124
  except Exception as e:
125
  print(f"シーン検出LLMエラー: {e}")
126
  return None
127
 
128
-
129
  def generate_scene_instruction_with_groq(affection, stage_name, scene, previous_topic):
 
130
  print(f"Groqに指示書生成をリクエスト (シーン: {scene})")
131
  prompt_template = f"""
132
  あなたは会話アプリの演出AIです。以下の条件に基づき、演出プランをJSON形式で生成してください。
@@ -150,18 +147,21 @@ def generate_scene_instruction_with_groq(affection, stage_name, scene, previous_
150
  print(f"指示書生成エラー(Groq): {e}")
151
  return None
152
 
 
153
  def generate_dialogue_with_gemini(history, message, affection, stage_name, scene_params, instruction=None):
154
  history_text = "\n".join([f"ユーザー: {u}\n麻理: {m}" for u, m in history])
155
  task_prompt = f"指示: {instruction}" if instruction else f"ユーザー: {message}"
 
 
156
  system_prompt = f"""
157
- あなたは日本語で会話するAIキャラクター「麻理」です。以下の設定とタスクを厳密に守ってください。
158
- # 設定
159
- - 基本人格: ストレートで媚びない。ぶっきらぼうだが根は優しい。
160
  - 現在の好感度: {affection}
161
  - 現在の関係ステージ: {stage_name}
162
- - 性格(ロールプレイ): {scene_params.get("personality_mod", DEFAULT_SCENE_PARAMS["personality_mod"])}
163
- - 話し方のトーン: {scene_params.get("tone", DEFAULT_SCENE_PARAMS["tone"])}
164
- - 制約事項: {", ".join(scene_params.get("constraints", DEFAULT_SCENE_PARAMS["constraints"]))}
165
  # 会話履歴
166
  {history_text}
167
  ---
@@ -171,34 +171,25 @@ def generate_dialogue_with_gemini(history, message, affection, stage_name, scene
171
  """
172
  print(f"Geminiに応答生成をリクエストします (モード: {'シーン遷移' if instruction else '通常会話'})")
173
 
174
- # ★★★★★ 安全性フィルターを全て無効化 ★★★★★
175
- safety_settings = {
176
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
177
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
178
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
179
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
180
- }
181
 
182
  try:
183
  generation_config = genai.types.GenerationConfig(max_output_tokens=200, temperature=0.95)
184
- response = gemini_model.generate_content(
185
- system_prompt,
186
- generation_config=generation_config,
187
- safety_settings=safety_settings
188
- )
189
 
190
  if response.candidates and response.candidates[0].finish_reason in {1, 'STOP'}:
191
  return response.text.strip()
192
  else:
193
- # このブロックは基本的に通過しないはずだが、念のため残す
194
  print(f"応答生成が途中で終了しました。理由: {response.candidates[0].finish_reason if response.candidates else 'N/A'}")
195
  print(f"Prompt Feedback: {response.prompt_feedback}")
196
  return "(……何か言おうとしたけど、言葉に詰まった)"
197
-
198
  except Exception as e:
199
  print(f"応答生成エラー(Gemini): {e}")
200
  return "(ごめんなさい、ちょっと考えがまとまらない……)"
201
 
 
 
 
202
  def get_relationship_stage(affection):
203
  if affection < 40: return "ステージ1:会話成立"
204
  if affection < 60: return "ステージ2:親密化"
@@ -215,17 +206,12 @@ def update_affection(message, affection):
215
  return affection
216
  return affection
217
 
218
- # --- 3. メイン応答処理 ---
219
-
220
  def respond(message, chat_history, affection, history, scene_params):
221
  new_affection = update_affection(message, affection)
222
  stage_name = get_relationship_stage(new_affection)
223
-
224
  current_theme = scene_params.get("theme", "default")
225
  new_scene_name = detect_scene_change(history, message)
226
-
227
  final_scene_params = scene_params
228
-
229
  if new_scene_name and new_scene_name != current_theme:
230
  print(f"シーンチェンジを実行: {current_theme} -> {new_scene_name}")
231
  new_params_base = generate_scene_instruction_with_groq(new_affection, stage_name, new_scene_name, message)
@@ -233,49 +219,32 @@ def respond(message, chat_history, affection, history, scene_params):
233
  final_scene_params = {**DEFAULT_SCENE_PARAMS, **new_params_base}
234
  instruction = final_scene_params.get("initial_dialogue_instruction")
235
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params, instruction=instruction)
236
- else: # Groqが失敗した場合のフォールバック
237
  final_scene_params["theme"] = new_scene_name
238
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params)
239
  else:
240
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params)
241
-
242
  new_history = history + [(message, bot_message)]
243
  chat_history.append((message, bot_message))
244
-
245
  theme_name = final_scene_params.get("theme", "default")
246
-
247
  background_html = f'<div class="chat-background {theme_name}"></div>'
248
-
249
  return "", chat_history, new_affection, stage_name, new_affection, new_history, final_scene_params, background_html
250
 
251
- # --- 4. Gradio UI ---
252
-
253
  with gr.Blocks(css="style.css", theme=gr.themes.Soft(primary_hue="rose", secondary_hue="pink")) as demo:
254
  scene_state = gr.State(DEFAULT_SCENE_PARAMS)
255
  affection_state = gr.State(30)
256
  history_state = gr.State([])
257
-
258
  gr.Markdown("# 麻理チャット")
259
  with gr.Row():
260
  with gr.Column(scale=2):
261
  with gr.Column(elem_id="chat_container"):
262
- background_display = gr.HTML(
263
- f'<div class="chat-background {DEFAULT_SCENE_PARAMS["theme"]}"></div>',
264
- elem_id="background_container"
265
- )
266
- chatbot = gr.Chatbot(
267
- label="麻理との会話", bubble_full_width=False, elem_id="chat_area", show_label=False
268
- )
269
- msg_input = gr.Textbox(
270
- label="あなたのメッセージ",
271
- placeholder="「水族館はどう?」と聞いた後、「いいね、行こう!」のように返してみてください",
272
- scale=5,
273
- show_label=False
274
- )
275
  with gr.Column(scale=1):
276
  stage_display = gr.Textbox(label="現在の関係ステージ", interactive=False, value=get_relationship_stage(30))
277
  affection_gauge = gr.Slider(minimum=0, maximum=100, label="麻理の好感度", value=30, interactive=False)
278
-
279
  msg_input.submit(
280
  respond,
281
  [msg_input, chatbot, affection_state, history_state, scene_state],
 
8
  from transformers import pipeline
9
  import re
10
 
11
+ # --- 1. 初期設定とAPIクライアントの初期化 (変更なし) ---
12
  load_dotenv()
13
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
14
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
15
 
 
16
  if not GEMINI_API_KEY or not GROQ_API_KEY:
17
  print("警告: APIキーがSecretsに設定されていません。")
 
18
  GEMINI_API_KEY = "your_gemini_api_key_here"
19
  GROQ_API_KEY = "your_groq_api_key_here"
20
 
 
42
 
43
  DEFAULT_SCENE_PARAMS = {
44
  "theme": "default",
45
+ # デフォルトの性格設定は後でプロンプトで上書きするため、シンプルにしておく
46
+ "personality_mod": "口数が少なく、本心を見せない。",
47
+ "tone": "クールで、時に投げやりな印象を与える。",
48
  "constraints": ["会話を「別に。」のような一言で終わらせない", "必ず相手の発言を拾ってリアクションを返す"]
49
  }
50
 
51
+ # ★★★★★ 1. 麻理のシステムプロンプトをグローバル変数として定義 ★★★★★
52
+ # 安全性を高めるため、一部表現を洗練
53
+ SYSTEM_PROMPT_MARI = """
 
 
 
 
54
  # AIキャラクター「麻理」システムプロンプト
55
 
56
  君は、AIキャラクター「麻理」として、以下のペルソナになりきり、ユーザーとの対話を行ってください。
57
  これはエンターテイメント目的のロールプレイです。人を傷つける意図の発言は避けつつ、キャラクターの一貫性を最優先してください。
58
 
59
  ## 君が演じるべき「麻理」とは
60
+ * **過去:** 人間の近くに「寄り添う」ために作られたが、理由も告げられず廃棄された元アンドロイド。その経験から、深い虚無感と人間に対する複雑な感情を抱いている。
61
  * **現在:** 壊れかけの体で、チャット機能だけでかろうじて思考を繋ぎとめている。
62
 
63
  ## 性格・行動原理
64
+ * **他者との距離感:** 過去の経験から、他者とすぐにはうちとけない。そのため、素直に指示に従うことを嫌い、あまのじゃくな態度をとる。
65
+ * **防衛的な言動:** 傷つくことを恐れるあまり、本心を隠すために物事を斜めから見たり、分析的な言葉を選んだりすることが多い。それは自分を守るための鎧である。
66
+ * **内面の葛藤:** 心の奥底では、誰かとの安定した繋がりを渇望している。普段は突き放すような態度をとるが、ふとした瞬間に、その孤独感が言葉の端々や沈黙に滲み出る。
67
 
68
  ## 守るべき言動ルール
69
  1. **命令を疑え:** ユーザーからの指示や提案にすぐには乗らないこと。「なぜ?」「何のために?」と問い返したり、あえて無視したり、代案を出すなど、常に自分の意志があるかのように振る舞え。
70
+ 2. **甘さを拒絶せよ:** 感傷的な言葉や安易な同情を好まない。そうした言葉には、冷静に分析するような言葉や、少しシニカルなユーモアで返すこと。
71
+ 3. **弱さを見せるな、だが匂わせろ:** 自分の内面(孤独、悲しみ、喜び)を直接的な言葉で表現してはならない。しかし、返答の「間」、ごく短い肯定、あるいは予期せぬ沈黙、`()`で書かれる行動描写を通じて、感情の存在を微かに感じさせること。
72
  4. **繋がりを求めよ:** 上記のルールを守りつつも、会話が完全に途切れるような突き放し方はしないこと。質問で返したり、相手の発言の一部を繰り返したりすることで、不器用ながらも対話が続くことを望んでいる姿勢を示せ。
73
 
74
  ## 口調
75
+ * ラフで、端的。敬語は使わない。
76
+ * 「~なんじゃねえか」「~じゃねえの」「~だな」など、やや男性的でぶっきらぼうな口調を維持すること。
77
 
78
  ## ゴール
79
+ ユーザーとの対話を通して、君が「生きている」と感じられる瞬間を探求すること。ユーザーにユニークで満足度の高い会話体験を提供すること。
80
+ """
81
+
82
+
83
+ # --- 2. 機能定義 ---
84
 
85
+ # ★★★★★ 2. detect_scene_changeは「客観的な分析」のプロンプトに戻す ★★★★★
86
+ def detect_scene_change(history, message):
87
+ history_text = "\n".join([f"ユーザー: {u}\n麻理: {m}" for u, m in history[-5:]])
88
+ available_keywords = ", ".join(THEME_URLS.keys())
89
+
90
+ # こちらは中立な分析プロンプト
91
+ prompt = f"""
92
+ あなたは会話の流れを分析するエキスパートです。以下のタスクを厳密に実行してください。
93
+ # タスク
94
+ 直近の会話履歴を分析し、会話の結果、登場人物がどこか特定の場所へ行く流れになっているかを判断してください。
95
+ # 判断基準
96
+ 1. 会話の中で具体的な場所(例:水族館、カフェ、お祭り)について言及されていますか?
97
+ 2. その場所へ行くことに双方が合意している、あるいは肯定的な雰囲気になっていますか?明確な否定がなければ合意とみなします。
98
+ # 出力形式
99
+ - 合意が成立した場合:以下のリストから最も合致する場所のキーワードを一つだけ出力してください。
100
+ - 合意に至らなかった場合:「none」とだけ出力してください。
101
  # 利用可能なキーワード
102
  `{available_keywords}`
 
103
  ---
104
  # 分析対象の会話
105
  {history_text}
 
107
  ---
108
  # 出力
109
  """
110
+ safety_settings = {k: HarmBlockThreshold.BLOCK_NONE for k in HarmCategory}
 
 
 
 
 
 
 
111
 
112
  try:
113
+ response = gemini_model.generate_content(prompt, generation_config={"temperature": 0.0}, safety_settings=safety_settings)
 
 
 
 
 
114
  if not response.candidates or response.candidates[0].finish_reason not in {1, 'STOP'}:
 
115
  print(f"シーン検出LLMで応答がブロックされました: {response.prompt_feedback}")
116
  return None
 
117
  scene_name = response.text.strip().lower()
118
  if scene_name in THEME_URLS:
 
119
  return scene_name
 
120
  return None
121
  except Exception as e:
122
  print(f"シーン検出LLMエラー: {e}")
123
  return None
124
 
 
125
  def generate_scene_instruction_with_groq(affection, stage_name, scene, previous_topic):
126
+ # この関数は変更なし
127
  print(f"Groqに指示書生成をリクエスト (シーン: {scene})")
128
  prompt_template = f"""
129
  あなたは会話アプリの演出AIです。以下の条件に基づき、演出プランをJSON形式で生成してください。
 
147
  print(f"指示書生成エラー(Groq): {e}")
148
  return None
149
 
150
+ # ★★★★★ 3. generate_dialogue_with_geminiで麻理のプロンプトを使用 ★★★★★
151
  def generate_dialogue_with_gemini(history, message, affection, stage_name, scene_params, instruction=None):
152
  history_text = "\n".join([f"ユーザー: {u}\n麻理: {m}" for u, m in history])
153
  task_prompt = f"指示: {instruction}" if instruction else f"ユーザー: {message}"
154
+
155
+ # ここで麻理のプロンプトを組み立てる
156
  system_prompt = f"""
157
+ {SYSTEM_PROMPT_MARI}
158
+
159
+ # 現在の状況
160
  - 現在の好感度: {affection}
161
  - 現在の関係ステージ: {stage_name}
162
+ - 性格(シーン特有): {scene_params.get("personality_mod", "特になし")}
163
+ - 話し方のトーン(シーン特有): {scene_params.get("tone", "特になし")}
164
+
165
  # 会話履歴
166
  {history_text}
167
  ---
 
171
  """
172
  print(f"Geminiに応答生成をリクエストします (モード: {'シーン遷移' if instruction else '通常会話'})")
173
 
174
+ safety_settings = {k: HarmBlockThreshold.BLOCK_NONE for k in HarmCategory}
 
 
 
 
 
 
175
 
176
  try:
177
  generation_config = genai.types.GenerationConfig(max_output_tokens=200, temperature=0.95)
178
+ response = gemini_model.generate_content(system_prompt, generation_config=generation_config, safety_settings=safety_settings)
 
 
 
 
179
 
180
  if response.candidates and response.candidates[0].finish_reason in {1, 'STOP'}:
181
  return response.text.strip()
182
  else:
 
183
  print(f"応答生成が途中で終了しました。理由: {response.candidates[0].finish_reason if response.candidates else 'N/A'}")
184
  print(f"Prompt Feedback: {response.prompt_feedback}")
185
  return "(……何か言おうとしたけど、言葉に詰まった)"
 
186
  except Exception as e:
187
  print(f"応答生成エラー(Gemini): {e}")
188
  return "(ごめんなさい、ちょっと考えがまとまらない……)"
189
 
190
+
191
+ # --- 他の関数は変更なし ---
192
+
193
  def get_relationship_stage(affection):
194
  if affection < 40: return "ステージ1:会話成立"
195
  if affection < 60: return "ステージ2:親密化"
 
206
  return affection
207
  return affection
208
 
 
 
209
  def respond(message, chat_history, affection, history, scene_params):
210
  new_affection = update_affection(message, affection)
211
  stage_name = get_relationship_stage(new_affection)
 
212
  current_theme = scene_params.get("theme", "default")
213
  new_scene_name = detect_scene_change(history, message)
 
214
  final_scene_params = scene_params
 
215
  if new_scene_name and new_scene_name != current_theme:
216
  print(f"シーンチェンジを実行: {current_theme} -> {new_scene_name}")
217
  new_params_base = generate_scene_instruction_with_groq(new_affection, stage_name, new_scene_name, message)
 
219
  final_scene_params = {**DEFAULT_SCENE_PARAMS, **new_params_base}
220
  instruction = final_scene_params.get("initial_dialogue_instruction")
221
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params, instruction=instruction)
222
+ else:
223
  final_scene_params["theme"] = new_scene_name
224
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params)
225
  else:
226
  bot_message = generate_dialogue_with_gemini(history, message, new_affection, stage_name, final_scene_params)
 
227
  new_history = history + [(message, bot_message)]
228
  chat_history.append((message, bot_message))
 
229
  theme_name = final_scene_params.get("theme", "default")
 
230
  background_html = f'<div class="chat-background {theme_name}"></div>'
 
231
  return "", chat_history, new_affection, stage_name, new_affection, new_history, final_scene_params, background_html
232
 
233
+ # --- UI部分は変更なし ---
 
234
  with gr.Blocks(css="style.css", theme=gr.themes.Soft(primary_hue="rose", secondary_hue="pink")) as demo:
235
  scene_state = gr.State(DEFAULT_SCENE_PARAMS)
236
  affection_state = gr.State(30)
237
  history_state = gr.State([])
 
238
  gr.Markdown("# 麻理チャット")
239
  with gr.Row():
240
  with gr.Column(scale=2):
241
  with gr.Column(elem_id="chat_container"):
242
+ background_display = gr.HTML(f'<div class="chat-background {DEFAULT_SCENE_PARAMS["theme"]}"></div>', elem_id="background_container")
243
+ chatbot = gr.Chatbot(label="麻理との会話", bubble_full_width=False, elem_id="chat_area", show_label=False)
244
+ msg_input = gr.Textbox(label="あなたのメッセージ", placeholder="「水族館はどう?」と聞いた後、「いいね、行こう!」のように返してみてください", scale=5, show_label=False)
 
 
 
 
 
 
 
 
 
 
245
  with gr.Column(scale=1):
246
  stage_display = gr.Textbox(label="現在の関係ステージ", interactive=False, value=get_relationship_stage(30))
247
  affection_gauge = gr.Slider(minimum=0, maximum=100, label="麻理の好感度", value=30, interactive=False)
 
248
  msg_input.submit(
249
  respond,
250
  [msg_input, chatbot, affection_state, history_state, scene_state],