PhilipL commited on
Commit
e0b41e1
·
verified ·
1 Parent(s): 6abbb4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -39
app.py CHANGED
@@ -77,36 +77,31 @@ custom_css = """
77
  .vertical-radio label { width: 100% !important; margin: 0 !important; display: flex !important; }
78
  """
79
 
80
- # 設定圖片路徑 (包含新增的 Q3, Q4, Q5)
81
  img_path_1 = "images/image_0.png"
82
  img_path_2 = "images/image_1.png"
83
  img_path_3 = "images/image_2.png" # Q3
84
- img_path_4 = "images/image_3.png" # Q4
85
- img_path_5 = "images/image_4.png" # Q5
86
 
87
  if not os.path.exists("images"): os.makedirs("images")
88
- # 建立預設圖片以防報錯
89
- for p in [img_path_1, img_path_2, img_path_3, img_path_4, img_path_5]:
90
  if not os.path.exists(p):
91
  Image.new('RGB', (400, 300), color='lightgray').save(p)
92
 
93
- # --- Q1 選項 ---
94
  q1_options_map = {
95
  "不​要​再​問白癡​問題​了​我​只​想​吃飯​": "現實主義者 (只想吃飯)",
96
  "去​過隱​居​生活": "隱士 (嚮往平靜)",
97
  "加入​禁衛軍,​保衛​這個​世界": "守護者 (充滿正義感)",
98
  "神​羅​天​征,毀滅這個​世界​": "破壞神 (心情可能很差或很中二)"
99
  }
100
-
101
- # --- Q2 選項 ---
102
  q2_options_map = {
103
  "不​要​再​問白癡​問題​了​我​只​想​吃飯​": "無魔法 (飢餓度MAX)",
104
  "麵​包形狀​的​魔法​炸彈": "爆炸魔法 (喜歡刺激/重口味)",
105
  "毒氣​的​生化​魔法": "毒氣魔法 (可能想吃臭豆腐或特殊風味)",
106
  "領域​展開:​無量​空處​": "領域展開 (思緒混亂或想放空)"
107
  }
108
-
109
- # --- [新增] Q3 選項 ---
110
  q3_options_map = {
111
  "不​要​在​問白癡​問題​了​我​只​想​吃飯​": "現實主義者 (只想吃飯)",
112
  "歐洲": "嚮往歐洲 (浪漫/西式)",
@@ -114,16 +109,12 @@ q3_options_map = {
114
  "泰國": "嚮往泰國 (熱情/酸辣)",
115
  "轉身搭機捷回家": "戀家 (只想回家)"
116
  }
117
-
118
- # --- [新增] Q4 選項 ---
119
  q4_options_map = {
120
  "轉頭​回家​睡覺​": "獨行俠 (想睡覺)",
121
  "看​起來​很​會玩​的​帥潮​": "外向 (找帥潮)",
122
  "感覺​是​動漫宅​的​同好​": "御宅族 (找同好)",
123
  "有​興趣​的​異性​": "大膽 (找異性)"
124
  }
125
-
126
- # --- [新增] Q5 選項 ---
127
  q5_options_map = {
128
  "甚麼​都​不​想​​": "放空 (什麼都不想)",
129
  "來​自​星星​的​你​": "韓劇迷 (浪漫愛情)",
@@ -173,14 +164,14 @@ def get_restaurant_data(mood_score_str, food_choice):
173
 
174
  return result, is_random, rec_categories, mood_reason
175
 
176
- def generate_content_with_groq(restaurant_name, restaurant_detail, user_diary, mood_score, quiz_result, mood_guide_reason):
 
177
  if not GROQ_API_KEY: return "⚠️ 請設定 GROQ_API_KEY"
178
 
179
  client = OpenAI(api_key=GROQ_API_KEY, base_url="https://api.groq.com/openai/v1")
180
 
181
  system_prompt = "你是一個幽默、懂吃且善解人意的 AI 朋友。請根據使用者的日記、心情以及「心情美食指南」來推薦餐廳。"
182
 
183
- # [修改] 將新增的測驗結果加入 Prompt
184
  user_msg = f"""
185
  【狀態】心情分數:{mood_score},日記:{user_diary}
186
 
@@ -200,16 +191,29 @@ def generate_content_with_groq(restaurant_name, restaurant_detail, user_diary, m
200
 
201
  任務:
202
  請用繁體中文寫一段溫暖有趣的回覆:
203
- 1. 綜合回應他的日記與上述 5 個測驗結果(例如如果他選日本,可以提到這家店有沒有日式氛圍;如果選動漫宅,可以用一點動漫梗)。
204
  2. 引用「心情美食指南」的原因。
205
  3. 介紹這家餐廳的特色。
206
  (只需要回覆文字內容)
207
  """
 
208
  try:
209
  response = client.chat.completions.create(
210
  model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_msg}]
211
  )
212
- return response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
213
  except Exception as e:
214
  return f"Groq Error: {str(e)}"
215
 
@@ -224,7 +228,8 @@ def generate_image_huggingface(prompt):
224
  print(f"❌ 生圖失敗: {e}")
225
  return None
226
 
227
- def mood_agent_logic(score_input, food_input, diary_input, quiz_state):
 
228
  restaurant, is_random, rec_categories, mood_reason = get_restaurant_data(score_input, food_input)
229
 
230
  if restaurant is None:
@@ -244,8 +249,19 @@ def mood_agent_logic(score_input, food_input, diary_input, quiz_state):
244
  if docs:
245
  rag_info = "\n".join([d.page_content for d in docs])
246
 
247
- ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, quiz_state, mood_reason)
 
248
 
 
 
 
 
 
 
 
 
 
 
249
  final_response = f"### 🍽️ 推薦:{name} {note}\n\n{ai_text}"
250
  map_html = f'<div style="text-align:center"><a href="{url}" target="_blank" style="background:#4CAF50;color:white;padding:8px 16px;border-radius:20px;text-decoration:none">🗺️ Google Map 導航</a></div>'
251
 
@@ -264,21 +280,18 @@ def handle_q1_change(selected_label, current_state):
264
  def handle_q2_change(selected_label, current_state):
265
  if not selected_label: return current_state, gr.Button(interactive=False)
266
  current_state["q2"] = q2_options_map[selected_label]
267
- return current_state, gr.Button(interactive=True, variant="primary") # 修改:這裡不再是完成,而是下一頁
268
 
269
- # [新增] Q3 Handler
270
  def handle_q3_change(selected_label, current_state):
271
  if not selected_label: return current_state, gr.Button(interactive=False)
272
  current_state["q3"] = q3_options_map[selected_label]
273
  return current_state, gr.Button(interactive=True, variant="primary")
274
 
275
- # [新增] Q4 Handler
276
  def handle_q4_change(selected_label, current_state):
277
  if not selected_label: return current_state, gr.Button(interactive=False)
278
  current_state["q4"] = q4_options_map[selected_label]
279
  return current_state, gr.Button(interactive=True, variant="primary")
280
 
281
- # [新增] Q5 Handler (最後一題)
282
  def handle_q5_change(selected_label, current_state):
283
  if not selected_label: return current_state, gr.Button(interactive=False)
284
  current_state["q5"] = q5_options_map[selected_label]
@@ -308,9 +321,9 @@ with gr.Blocks(title="AI 心情食堂") as demo:
308
  gr.Image(value=img_path_2, type="filepath", label="請觀察圖片", height=300)
309
  gr.Markdown("**問題:身為魔導士的你,會選擇哪一個法術?**")
310
  radio_q2 = gr.Radio(choices=list(q2_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
311
- btn_q2_next = gr.Button("下一頁 ➔", interactive=False) # 修改按鈕名稱
312
 
313
- # [新增] Tab 2: Q3
314
  with gr.TabItem("Q3", id=2):
315
  with gr.Column():
316
  gr.Markdown("### 🔮 第三題:旅遊直覺")
@@ -319,7 +332,7 @@ with gr.Blocks(title="AI 心情食堂") as demo:
319
  radio_q3 = gr.Radio(choices=list(q3_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
320
  btn_q3_next = gr.Button("下一頁 ➔", interactive=False)
321
 
322
- # [新增] Tab 3: Q4
323
  with gr.TabItem("Q4", id=3):
324
  with gr.Column():
325
  gr.Markdown("### 🔮 第四題:社交場合")
@@ -328,7 +341,7 @@ with gr.Blocks(title="AI 心情食堂") as demo:
328
  radio_q4 = gr.Radio(choices=list(q4_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
329
  btn_q4_next = gr.Button("下一頁 ➔", interactive=False)
330
 
331
- # [新增] Tab 4: Q5
332
  with gr.TabItem("Q5", id=4):
333
  with gr.Column():
334
  gr.Markdown("### 🔮 第五題:追劇時光")
@@ -346,6 +359,10 @@ with gr.Blocks(title="AI 心情食堂") as demo:
346
  score_input = gr.Radio(["1 (心情差)", "2 (不太好)", "3 (普通)", "4 (不錯)", "5 (超棒)"], label="1. 心情分數", value="3 (普通)")
347
  food_input = gr.Radio(["吃飯", "吃麵", "隨便"], label="2. 想吃什麼", value="隨便")
348
  diary_input = gr.Textbox(lines=4, label="3. 心情日記", placeholder="寫下今天發生的事...")
 
 
 
 
349
  submit_btn = gr.Button("送出給 Agent", variant="primary")
350
  with gr.Column(scale=1):
351
  agent_output = gr.Markdown(label="AI 回應")
@@ -353,29 +370,25 @@ with gr.Blocks(title="AI 心情食堂") as demo:
353
  map_output = gr.HTML(label="地圖導航")
354
 
355
  # 事件綁定 (Events)
356
- # Q1
357
  radio_q1.change(fn=handle_q1_change, inputs=[radio_q1, quiz_state], outputs=[quiz_state, btn_q1_next])
358
- btn_q1_next.click(fn=lambda: gr.Tabs(selected=1), outputs=tabs) # 跳到 Q2
359
 
360
- # Q2
361
  radio_q2.change(fn=handle_q2_change, inputs=[radio_q2, quiz_state], outputs=[quiz_state, btn_q2_next])
362
- btn_q2_next.click(fn=lambda: gr.Tabs(selected=2), outputs=tabs) # 跳到 Q3
363
 
364
- # [新增] Q3
365
  radio_q3.change(fn=handle_q3_change, inputs=[radio_q3, quiz_state], outputs=[quiz_state, btn_q3_next])
366
- btn_q3_next.click(fn=lambda: gr.Tabs(selected=3), outputs=tabs) # 跳到 Q4
367
 
368
- # [新增] Q4
369
  radio_q4.change(fn=handle_q4_change, inputs=[radio_q4, quiz_state], outputs=[quiz_state, btn_q4_next])
370
- btn_q4_next.click(fn=lambda: gr.Tabs(selected=4), outputs=tabs) # 跳到 Q5
371
 
372
- # [新增] Q5
373
  radio_q5.change(fn=handle_q5_change, inputs=[radio_q5, quiz_state], outputs=[quiz_state, btn_q5_finish])
374
- btn_q5_finish.click(fn=lambda: gr.Tabs(selected=5), outputs=tabs) # 跳到 Main
375
 
 
376
  submit_btn.click(
377
  fn=mood_agent_logic,
378
- inputs=[score_input, food_input, diary_input, quiz_state],
379
  outputs=[agent_output, image_output, map_output]
380
  )
381
 
 
77
  .vertical-radio label { width: 100% !important; margin: 0 !important; display: flex !important; }
78
  """
79
 
80
+ # 設定圖片路徑
81
  img_path_1 = "images/image_0.png"
82
  img_path_2 = "images/image_1.png"
83
  img_path_3 = "images/image_2.png" # Q3
84
+ img_path_4 = "images/image_4.png" # Q4
85
+ img_path_5 = "images/image_3.png" # Q5
86
 
87
  if not os.path.exists("images"): os.makedirs("images")
88
+ for p in [img_path_0, img_path_1, img_path_2, img_path_4, img_path_3]:
 
89
  if not os.path.exists(p):
90
  Image.new('RGB', (400, 300), color='lightgray').save(p)
91
 
92
+ # --- 選項設定 ---
93
  q1_options_map = {
94
  "不​要​再​問白癡​問題​了​我​只​想​吃飯​": "現實主義者 (只想吃飯)",
95
  "去​過隱​居​生活": "隱士 (嚮往平靜)",
96
  "加入​禁衛軍,​保衛​這個​世界": "守護者 (充滿正義感)",
97
  "神​羅​天​征,毀滅這個​世界​": "破壞神 (心情可能很差或很中二)"
98
  }
 
 
99
  q2_options_map = {
100
  "不​要​再​問白癡​問題​了​我​只​想​吃飯​": "無魔法 (飢餓度MAX)",
101
  "麵​包形狀​的​魔法​炸彈": "爆炸魔法 (喜歡刺激/重口味)",
102
  "毒氣​的​生化​魔法": "毒氣魔法 (可能想吃臭豆腐或特殊風味)",
103
  "領域​展開:​無量​空處​": "領域展開 (思緒混亂或想放空)"
104
  }
 
 
105
  q3_options_map = {
106
  "不​要​在​問白癡​問題​了​我​只​想​吃飯​": "現實主義者 (只想吃飯)",
107
  "歐洲": "嚮往歐洲 (浪漫/西式)",
 
109
  "泰國": "嚮往泰國 (熱情/酸辣)",
110
  "轉身搭機捷回家": "戀家 (只想回家)"
111
  }
 
 
112
  q4_options_map = {
113
  "轉頭​回家​睡覺​": "獨行俠 (想睡覺)",
114
  "看​起來​很​會玩​的​帥潮​": "外向 (找帥潮)",
115
  "感覺​是​動漫宅​的​同好​": "御宅族 (找同好)",
116
  "有​興趣​的​異性​": "大膽 (找異性)"
117
  }
 
 
118
  q5_options_map = {
119
  "甚麼​都​不​想​​": "放空 (什麼都不想)",
120
  "來​自​星星​的​你​": "韓劇迷 (浪漫愛情)",
 
164
 
165
  return result, is_random, rec_categories, mood_reason
166
 
167
+ # [修改] 增加 debug_mode 參數
168
+ def generate_content_with_groq(restaurant_name, restaurant_detail, user_diary, mood_score, quiz_result, mood_guide_reason, debug_mode=False):
169
  if not GROQ_API_KEY: return "⚠️ 請設定 GROQ_API_KEY"
170
 
171
  client = OpenAI(api_key=GROQ_API_KEY, base_url="https://api.groq.com/openai/v1")
172
 
173
  system_prompt = "你是一個幽默、懂吃且善解人意的 AI 朋友。請根據使用者的日記、心情以及「心情美食指南」來推薦餐廳。"
174
 
 
175
  user_msg = f"""
176
  【狀態】心情分數:{mood_score},日記:{user_diary}
177
 
 
191
 
192
  任務:
193
  請用繁體中文寫一段溫暖有趣的回覆:
194
+ 1. 綜合回應他的日記與上述 5 個測驗結果。
195
  2. 引用「心情美食指南」的原因。
196
  3. 介紹這家餐廳的特色。
197
  (只需要回覆文字內容)
198
  """
199
+
200
  try:
201
  response = client.chat.completions.create(
202
  model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_msg}]
203
  )
204
+ content = response.choices[0].message.content
205
+
206
+ # [修改] 如果開啟除錯模式,附加 Prompt 資訊
207
+ if debug_mode:
208
+ debug_info = f"""
209
+ \n\n--- 🛠️ [DEBUG] LLM Prompt 檢查 ---
210
+ \n**System Prompt:**\n{system_prompt}
211
+ \n**User Message:**\n{user_msg}
212
+ \n-----------------------------------
213
+ """
214
+ return content + debug_info
215
+
216
+ return content
217
  except Exception as e:
218
  return f"Groq Error: {str(e)}"
219
 
 
228
  print(f"❌ 生圖失敗: {e}")
229
  return None
230
 
231
+ # [修改] 增加 debug_mode 參數
232
+ def mood_agent_logic(score_input, food_input, diary_input, quiz_state, debug_mode):
233
  restaurant, is_random, rec_categories, mood_reason = get_restaurant_data(score_input, food_input)
234
 
235
  if restaurant is None:
 
249
  if docs:
250
  rag_info = "\n".join([d.page_content for d in docs])
251
 
252
+ # [修改] 傳入 debug_mode
253
+ ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, quiz_state, mood_reason, debug_mode)
254
 
255
+ # [修改] 如果開啟除錯模式,附加圖片 Prompt 資訊
256
+ if debug_mode:
257
+ img_debug_info = f"""
258
+ \n\n--- 🛠️ [DEBUG] 圖片生成檢查 ---
259
+ \n**使用的 Visual Prompt:**\n{img_prompt}
260
+ \n(如果上方圖片為空白,可能是 HF API 忙碌或 Prompt 無效)
261
+ \n-----------------------------------
262
+ """
263
+ ai_text += img_debug_info
264
+
265
  final_response = f"### 🍽️ 推薦:{name} {note}\n\n{ai_text}"
266
  map_html = f'<div style="text-align:center"><a href="{url}" target="_blank" style="background:#4CAF50;color:white;padding:8px 16px;border-radius:20px;text-decoration:none">🗺️ Google Map 導航</a></div>'
267
 
 
280
  def handle_q2_change(selected_label, current_state):
281
  if not selected_label: return current_state, gr.Button(interactive=False)
282
  current_state["q2"] = q2_options_map[selected_label]
283
+ return current_state, gr.Button(interactive=True, variant="primary")
284
 
 
285
  def handle_q3_change(selected_label, current_state):
286
  if not selected_label: return current_state, gr.Button(interactive=False)
287
  current_state["q3"] = q3_options_map[selected_label]
288
  return current_state, gr.Button(interactive=True, variant="primary")
289
 
 
290
  def handle_q4_change(selected_label, current_state):
291
  if not selected_label: return current_state, gr.Button(interactive=False)
292
  current_state["q4"] = q4_options_map[selected_label]
293
  return current_state, gr.Button(interactive=True, variant="primary")
294
 
 
295
  def handle_q5_change(selected_label, current_state):
296
  if not selected_label: return current_state, gr.Button(interactive=False)
297
  current_state["q5"] = q5_options_map[selected_label]
 
321
  gr.Image(value=img_path_2, type="filepath", label="請觀察圖片", height=300)
322
  gr.Markdown("**問題:身為魔導士的你,會選擇哪一個法術?**")
323
  radio_q2 = gr.Radio(choices=list(q2_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
324
+ btn_q2_next = gr.Button("下一頁 ➔", interactive=False)
325
 
326
+ # Tab 2: Q3
327
  with gr.TabItem("Q3", id=2):
328
  with gr.Column():
329
  gr.Markdown("### 🔮 第三題:旅遊直覺")
 
332
  radio_q3 = gr.Radio(choices=list(q3_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
333
  btn_q3_next = gr.Button("下一頁 ➔", interactive=False)
334
 
335
+ # Tab 3: Q4
336
  with gr.TabItem("Q4", id=3):
337
  with gr.Column():
338
  gr.Markdown("### 🔮 第四題:社交場合")
 
341
  radio_q4 = gr.Radio(choices=list(q4_options_map.keys()), label="請選擇", elem_classes="vertical-radio")
342
  btn_q4_next = gr.Button("下一頁 ➔", interactive=False)
343
 
344
+ # Tab 4: Q5
345
  with gr.TabItem("Q5", id=4):
346
  with gr.Column():
347
  gr.Markdown("### 🔮 第五題:追劇時光")
 
359
  score_input = gr.Radio(["1 (心情差)", "2 (不太好)", "3 (普通)", "4 (不錯)", "5 (超棒)"], label="1. 心情分數", value="3 (普通)")
360
  food_input = gr.Radio(["吃飯", "吃麵", "隨便"], label="2. 想吃什麼", value="隨便")
361
  diary_input = gr.Textbox(lines=4, label="3. 心情日記", placeholder="寫下今天發生的事...")
362
+
363
+ # [新增] 除錯模式開關
364
+ debug_mode_btn = gr.Checkbox(label="🔧 開啟除錯模式 (顯示 Prompt 與圖片資訊)", value=False)
365
+
366
  submit_btn = gr.Button("送出給 Agent", variant="primary")
367
  with gr.Column(scale=1):
368
  agent_output = gr.Markdown(label="AI 回應")
 
370
  map_output = gr.HTML(label="地圖導航")
371
 
372
  # 事件綁定 (Events)
 
373
  radio_q1.change(fn=handle_q1_change, inputs=[radio_q1, quiz_state], outputs=[quiz_state, btn_q1_next])
374
+ btn_q1_next.click(fn=lambda: gr.Tabs(selected=1), outputs=tabs)
375
 
 
376
  radio_q2.change(fn=handle_q2_change, inputs=[radio_q2, quiz_state], outputs=[quiz_state, btn_q2_next])
377
+ btn_q2_next.click(fn=lambda: gr.Tabs(selected=2), outputs=tabs)
378
 
 
379
  radio_q3.change(fn=handle_q3_change, inputs=[radio_q3, quiz_state], outputs=[quiz_state, btn_q3_next])
380
+ btn_q3_next.click(fn=lambda: gr.Tabs(selected=3), outputs=tabs)
381
 
 
382
  radio_q4.change(fn=handle_q4_change, inputs=[radio_q4, quiz_state], outputs=[quiz_state, btn_q4_next])
383
+ btn_q4_next.click(fn=lambda: gr.Tabs(selected=4), outputs=tabs)
384
 
 
385
  radio_q5.change(fn=handle_q5_change, inputs=[radio_q5, quiz_state], outputs=[quiz_state, btn_q5_finish])
386
+ btn_q5_finish.click(fn=lambda: gr.Tabs(selected=5), outputs=tabs)
387
 
388
+ # [修改] 加入 debug_mode_btn 到輸入
389
  submit_btn.click(
390
  fn=mood_agent_logic,
391
+ inputs=[score_input, food_input, diary_input, quiz_state, debug_mode_btn],
392
  outputs=[agent_output, image_output, map_output]
393
  )
394