Update app.py
Browse files
app.py
CHANGED
|
@@ -46,7 +46,7 @@ def init_rag_system():
|
|
| 46 |
rag_initialized = True
|
| 47 |
|
| 48 |
# ==========================================
|
| 49 |
-
# 2. 核心功能 (
|
| 50 |
# ==========================================
|
| 51 |
def get_restaurant_data(mood_score_str, food_choice):
|
| 52 |
init_rag_system()
|
|
@@ -74,12 +74,22 @@ def get_restaurant_data(mood_score_str, food_choice):
|
|
| 74 |
|
| 75 |
def generate_content_with_groq(restaurant_name, restaurant_detail, user_diary, mood_score, mood_guide_reason, debug_mode=False):
|
| 76 |
if not GROQ_API_KEY: return "⚠️ 請設定 GROQ_API_KEY"
|
|
|
|
| 77 |
client = OpenAI(api_key=GROQ_API_KEY, base_url="https://api.groq.com/openai/v1")
|
|
|
|
| 78 |
system_prompt = "你是一個幽默、懂吃且善解人意的 AI 朋友..."
|
| 79 |
user_msg = f"【狀態】心情分數:{mood_score}\n【日記】{user_diary}\n【建議原因】{mood_guide_reason}\n【餐廳】{restaurant_name}\n資料:{restaurant_detail}"
|
|
|
|
| 80 |
try:
|
| 81 |
response = client.chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_msg}])
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
except Exception as e: return f"Groq Error: {str(e)}"
|
| 84 |
|
| 85 |
def generate_image_huggingface(prompt):
|
|
@@ -97,26 +107,30 @@ def mood_agent_logic(score_input, food_input, diary_input, debug_mode):
|
|
| 97 |
if global_retriever:
|
| 98 |
docs = global_retriever.invoke(name)
|
| 99 |
if docs: rag_info = "\n".join([d.page_content for d in docs])
|
|
|
|
| 100 |
ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, mood_reason, debug_mode)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
final_response = f"### 🍽️ 推薦:{name}\n\n{ai_text}"
|
| 102 |
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>'
|
|
|
|
| 103 |
yield final_response, None, map_html
|
| 104 |
image_output = generate_image_huggingface(img_prompt)
|
| 105 |
yield final_response, image_output, map_html
|
| 106 |
|
| 107 |
|
| 108 |
# ==========================================
|
| 109 |
-
# 3.
|
| 110 |
# ==========================================
|
| 111 |
|
| 112 |
-
# 這是 app.py 自己的格式 (注意:這裡是半形括號)
|
| 113 |
def _score_to_radio_value(score):
|
| 114 |
mapping = {1: "1 (心情差)", 2: "2 (不太好)", 3: "3 (普通)", 4: "4 (不錯)", 5: "5 (超棒)"}
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
score = int(score)
|
| 118 |
-
except:
|
| 119 |
-
score = 3
|
| 120 |
return mapping.get(score, "3 (普通)")
|
| 121 |
|
| 122 |
# 橋接 1:開始
|
|
@@ -129,33 +143,21 @@ def bridge_stop_click(st):
|
|
| 129 |
res = emotion.on_stop(st)
|
| 130 |
return res[1], res[0], gr.update(visible=False), res[5], res[4]
|
| 131 |
|
| 132 |
-
# 橋接 3:Webcam 串流
|
| 133 |
def bridge_predict_frame(frame, st):
|
| 134 |
res = emotion.on_stream(frame, st)
|
|
|
|
| 135 |
|
| 136 |
-
|
| 137 |
-
out_result = res[1]
|
| 138 |
-
# out_mood = res[2] # ❌ 我們不使用隊友回傳的 UI 更新,因為括號格式不同
|
| 139 |
-
out_st = res[4]
|
| 140 |
-
out_btn_start = res[5]
|
| 141 |
-
|
| 142 |
-
score_update = gr.update()
|
| 143 |
-
tabs_update = gr.update()
|
| 144 |
-
out_btn_stop = gr.update()
|
| 145 |
|
| 146 |
-
# 如果辨識完成,我們自己產生一個符合 app.py 格式的 UI 更新
|
| 147 |
if out_st.finished and hasattr(out_st, 'final_score'):
|
| 148 |
-
# ✅ 使用 _score_to_radio_value 將整數轉換為半形括號字串
|
| 149 |
new_val = _score_to_radio_value(out_st.final_score)
|
| 150 |
score_update = gr.update(value=new_val)
|
| 151 |
-
|
| 152 |
tabs_update = gr.Tabs(selected=1)
|
| 153 |
out_btn_stop = gr.update(visible=False)
|
| 154 |
|
| 155 |
return out_cam, out_result, out_st, out_btn_stop, out_btn_start, score_update, tabs_update
|
| 156 |
|
| 157 |
-
# (已移除) 橋接 4:圖片上傳 - 功能已移除
|
| 158 |
-
|
| 159 |
|
| 160 |
# ==========================================
|
| 161 |
# 4. Gradio 介面建構
|
|
@@ -180,8 +182,6 @@ with gr.Blocks(title="AI 心情食堂", css=combined_css) as demo:
|
|
| 180 |
|
| 181 |
cam = gr.Image(sources=["webcam"], streaming=True, type="numpy", label="攝影機畫面", visible=False)
|
| 182 |
result_markdown = gr.Markdown(emotion._hint_html("請按「開啟攝影機辨識」並允許瀏覽器使用��機。"))
|
| 183 |
-
|
| 184 |
-
# (已移除) 上傳照片區塊
|
| 185 |
|
| 186 |
# Tab 2: 主功能區
|
| 187 |
with gr.TabItem("🍽️ AI 心情食堂 (Step 2)", id=1):
|
|
@@ -189,7 +189,6 @@ with gr.Blocks(title="AI 心情食堂", css=combined_css) as demo:
|
|
| 189 |
gr.Markdown(f"## 🍱 今天想吃點什麼?")
|
| 190 |
with gr.Row():
|
| 191 |
with gr.Column(scale=1):
|
| 192 |
-
# 这里的 Radio 选项使用的是半形括号
|
| 193 |
score_input = gr.Radio(
|
| 194 |
["1 (心情差)", "2 (不太好)", "3 (普通)", "4 (不錯)", "5 (超棒)"],
|
| 195 |
label="1. 心情分數 (由 Tab 1 自動填入)",
|
|
@@ -230,8 +229,6 @@ with gr.Blocks(title="AI 心情食堂", css=combined_css) as demo:
|
|
| 230 |
show_progress="minimal"
|
| 231 |
)
|
| 232 |
|
| 233 |
-
# (已移除) 上傳圖片事件
|
| 234 |
-
|
| 235 |
submit_btn.click(
|
| 236 |
fn=mood_agent_logic,
|
| 237 |
inputs=[score_input, food_input, diary_input, debug_mode_btn],
|
|
|
|
| 46 |
rag_initialized = True
|
| 47 |
|
| 48 |
# ==========================================
|
| 49 |
+
# 2. 核心功能 (已修復除錯模式)
|
| 50 |
# ==========================================
|
| 51 |
def get_restaurant_data(mood_score_str, food_choice):
|
| 52 |
init_rag_system()
|
|
|
|
| 74 |
|
| 75 |
def generate_content_with_groq(restaurant_name, restaurant_detail, user_diary, mood_score, mood_guide_reason, debug_mode=False):
|
| 76 |
if not GROQ_API_KEY: return "⚠️ 請設定 GROQ_API_KEY"
|
| 77 |
+
|
| 78 |
client = OpenAI(api_key=GROQ_API_KEY, base_url="https://api.groq.com/openai/v1")
|
| 79 |
+
|
| 80 |
system_prompt = "你是一個幽默、懂吃且善解人意的 AI 朋友..."
|
| 81 |
user_msg = f"【狀態】心情分數:{mood_score}\n【日記】{user_diary}\n【建議原因】{mood_guide_reason}\n【餐廳】{restaurant_name}\n資料:{restaurant_detail}"
|
| 82 |
+
|
| 83 |
try:
|
| 84 |
response = client.chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_msg}])
|
| 85 |
+
content = response.choices[0].message.content
|
| 86 |
+
|
| 87 |
+
# ### [修復] 除錯模式邏輯 ###
|
| 88 |
+
if debug_mode:
|
| 89 |
+
content += f"\n\n--- 🔧 DEBUG: Groq Prompt ---\n**System:** {system_prompt}\n\n**User:** {user_msg}\n-----------------------"
|
| 90 |
+
# ########################
|
| 91 |
+
|
| 92 |
+
return content
|
| 93 |
except Exception as e: return f"Groq Error: {str(e)}"
|
| 94 |
|
| 95 |
def generate_image_huggingface(prompt):
|
|
|
|
| 107 |
if global_retriever:
|
| 108 |
docs = global_retriever.invoke(name)
|
| 109 |
if docs: rag_info = "\n".join([d.page_content for d in docs])
|
| 110 |
+
|
| 111 |
ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, mood_reason, debug_mode)
|
| 112 |
+
|
| 113 |
+
# ### [修復] 除錯模式邏輯 (圖片 Prompt) ###
|
| 114 |
+
if debug_mode:
|
| 115 |
+
ai_text += f"\n\n--- 🔧 DEBUG: Image Prompt ---\n{img_prompt}\n-----------------------"
|
| 116 |
+
# ######################################
|
| 117 |
+
|
| 118 |
final_response = f"### 🍽️ 推薦:{name}\n\n{ai_text}"
|
| 119 |
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>'
|
| 120 |
+
|
| 121 |
yield final_response, None, map_html
|
| 122 |
image_output = generate_image_huggingface(img_prompt)
|
| 123 |
yield final_response, image_output, map_html
|
| 124 |
|
| 125 |
|
| 126 |
# ==========================================
|
| 127 |
+
# 3. 橋接邏輯 (Bridge Functions)
|
| 128 |
# ==========================================
|
| 129 |
|
|
|
|
| 130 |
def _score_to_radio_value(score):
|
| 131 |
mapping = {1: "1 (心情差)", 2: "2 (不太好)", 3: "3 (普通)", 4: "4 (不錯)", 5: "5 (超棒)"}
|
| 132 |
+
try: score = int(score)
|
| 133 |
+
except: score = 3
|
|
|
|
|
|
|
|
|
|
| 134 |
return mapping.get(score, "3 (普通)")
|
| 135 |
|
| 136 |
# 橋接 1:開始
|
|
|
|
| 143 |
res = emotion.on_stop(st)
|
| 144 |
return res[1], res[0], gr.update(visible=False), res[5], res[4]
|
| 145 |
|
| 146 |
+
# 橋接 3:Webcam 串流
|
| 147 |
def bridge_predict_frame(frame, st):
|
| 148 |
res = emotion.on_stream(frame, st)
|
| 149 |
+
out_cam = res[0]; out_result = res[1]; out_st = res[4]; out_btn_start = res[5]
|
| 150 |
|
| 151 |
+
score_update = gr.update(); tabs_update = gr.update(); out_btn_stop = gr.update()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
|
|
|
| 153 |
if out_st.finished and hasattr(out_st, 'final_score'):
|
|
|
|
| 154 |
new_val = _score_to_radio_value(out_st.final_score)
|
| 155 |
score_update = gr.update(value=new_val)
|
|
|
|
| 156 |
tabs_update = gr.Tabs(selected=1)
|
| 157 |
out_btn_stop = gr.update(visible=False)
|
| 158 |
|
| 159 |
return out_cam, out_result, out_st, out_btn_stop, out_btn_start, score_update, tabs_update
|
| 160 |
|
|
|
|
|
|
|
| 161 |
|
| 162 |
# ==========================================
|
| 163 |
# 4. Gradio 介面建構
|
|
|
|
| 182 |
|
| 183 |
cam = gr.Image(sources=["webcam"], streaming=True, type="numpy", label="攝影機畫面", visible=False)
|
| 184 |
result_markdown = gr.Markdown(emotion._hint_html("請按「開啟攝影機辨識」並允許瀏覽器使用��機。"))
|
|
|
|
|
|
|
| 185 |
|
| 186 |
# Tab 2: 主功能區
|
| 187 |
with gr.TabItem("🍽️ AI 心情食堂 (Step 2)", id=1):
|
|
|
|
| 189 |
gr.Markdown(f"## 🍱 今天想吃點什麼?")
|
| 190 |
with gr.Row():
|
| 191 |
with gr.Column(scale=1):
|
|
|
|
| 192 |
score_input = gr.Radio(
|
| 193 |
["1 (心情差)", "2 (不太好)", "3 (普通)", "4 (不錯)", "5 (超棒)"],
|
| 194 |
label="1. 心情分數 (由 Tab 1 自動填入)",
|
|
|
|
| 229 |
show_progress="minimal"
|
| 230 |
)
|
| 231 |
|
|
|
|
|
|
|
| 232 |
submit_btn.click(
|
| 233 |
fn=mood_agent_logic,
|
| 234 |
inputs=[score_input, food_input, diary_input, debug_mode_btn],
|