PhilipL commited on
Commit
180c45d
·
verified ·
1 Parent(s): 40e5154

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -47
app.py CHANGED
@@ -80,63 +80,41 @@ def sync_google_maps(url):
80
  return
81
 
82
  try:
83
- yield "🚀 [1/4] 啟動瀏覽器並準備抓取實景圖..."
84
  with sync_playwright() as p:
85
  browser = p.chromium.launch(headless=True)
86
  page = browser.new_page()
 
87
  page.goto(clean_url, wait_until="domcontentloaded", timeout=60000)
88
- time.sleep(10) # 等待圖片加載
89
-
90
- yield "📄 [2/4] 正在解析餐廳資訊與圖片..."
91
-
92
- # 定位所有的餐廳卡片
93
- items = page.locator('div[role="article"]').all()
94
 
95
  restaurant_list = []
96
- for item in items:
97
- try:
98
- # 抓取店名
99
- name_el = item.locator('div.fontHeadlineSmall')
100
- if name_el.count() == 0: continue
101
- name = name_el.inner_text().strip()
102
-
103
- # 抓取地址/描述
104
- detail_el = item.locator('div.fontBodyMedium').first
105
- addr = detail_el.inner_text().strip() if detail_el.count() > 0 else "位置詳見地圖"
106
-
107
- # ✅ 抓取圖片網址 (Google Maps 的縮圖通常在 img 標籤中)
108
- img_el = item.locator('img').first
109
- img_url = None
110
- if img_el.count() > 0:
111
- img_url = img_el.get_attribute('src')
112
-
113
- # 如果圖片是 Data URL (base64) 或太小,通常代表沒載入成功,可以設個預設圖
114
- if not img_url or img_url.startswith('data:'):
115
- img_url = "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?q=80&w=400" # 預設餐廳美圖
116
-
117
  restaurant_list.append({
118
  "Name": name,
119
  "Address": addr,
120
- "Image_URL": img_url, # ✅ 新增欄位
121
- "RAG_Content": f"餐廳:{name},資訊:{addr}",
122
  "URL": f"https://www.google.com/search?q={urllib.parse.quote(name)}"
123
  })
124
- except:
125
- continue
126
-
127
  browser.close()
128
 
129
  if not restaurant_list:
130
- yield "⚠️ 找不到餐廳資訊,請確認連結格式。"
131
  return
132
 
133
- # 更新向量資料庫
134
  global_df = pd.DataFrame(restaurant_list)
135
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
136
  vectorstore = FAISS.from_texts(global_df['RAG_Content'].tolist(), embeddings, metadatas=global_df.to_dict('records'))
137
  global_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
138
  rag_initialized = True
139
- yield f"✅ 同步成功!已載入 {len(restaurant_list)} 間包含實景圖的餐廳。"
140
  except Exception as e:
141
  yield f"❌ 系統錯誤:{str(e)}"
142
 
@@ -197,27 +175,24 @@ def mood_agent_logic(score_input, food_input, diary_input, debug_mode):
197
  yield "⚠️ 請先同步地圖清單!", None, ""
198
  return
199
 
200
- # 取得推薦資料
201
  restaurant, is_match, rec_categories, mood_reason, all_names = get_restaurant_data(score_input, food_input)
202
 
 
203
  prefix = ""
 
204
  if not is_match and food_input != "隨便":
205
- prefix = f"> 💡 **溫馨提示**:名單中沒找到『{food_input}』,目前清單有:**{all_names}**。為您挑選了這一間:\n\n"
 
206
 
207
- name = restaurant['Name']
208
- url = restaurant.get('URL', '#')
209
- real_img_url = restaurant.get('Image_URL') # ✅ 取得抓到的真實圖片
210
- rag_info = str(restaurant.get('RAG_Content', ''))
211
 
212
- # 產生 AI 回應
213
  ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, mood_reason)
214
 
215
  final_response = f"{prefix}### 🍽️ 推薦:{name}\n\n{ai_text}"
216
- 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>'
217
 
218
- # ✅ 直接回傳圖片網址給 Gradio 的 image_output
219
- # 注意:Gradio 的 gr.Image 可以直接接收 URL 字串
220
- yield final_response, real_img_url, map_html
221
 
222
  # ==========================================
223
  # 3. 橋接邏輯 (保留原本情緒辨識部分)
 
80
  return
81
 
82
  try:
83
+ yield "🚀 [1/4] 啟動瀏覽器..."
84
  with sync_playwright() as p:
85
  browser = p.chromium.launch(headless=True)
86
  page = browser.new_page()
87
+ yield "🌐 [2/4] 連線中..."
88
  page.goto(clean_url, wait_until="domcontentloaded", timeout=60000)
89
+ yield "⏳ [3/4] 等待加載 (10秒)..."
90
+ time.sleep(10)
91
+ yield "📄 [4/4] 解析中..."
92
+ titles = page.locator('div.fontHeadlineSmall').all_inner_texts()
93
+ details = page.locator('div.fontBodyMedium').all_inner_texts()
 
94
 
95
  restaurant_list = []
96
+ for i, name in enumerate(titles):
97
+ name = name.strip()
98
+ if name:
99
+ addr = details[i].strip() if i < len(details) else "詳情見地圖"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  restaurant_list.append({
101
  "Name": name,
102
  "Address": addr,
103
+ "RAG_Content": f"餐廳:{name},地址:{addr}",
 
104
  "URL": f"https://www.google.com/search?q={urllib.parse.quote(name)}"
105
  })
 
 
 
106
  browser.close()
107
 
108
  if not restaurant_list:
109
+ yield "⚠️ 找不到餐廳。請確認連結已設為「共用」。"
110
  return
111
 
 
112
  global_df = pd.DataFrame(restaurant_list)
113
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
114
  vectorstore = FAISS.from_texts(global_df['RAG_Content'].tolist(), embeddings, metadatas=global_df.to_dict('records'))
115
  global_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
116
  rag_initialized = True
117
+ yield f"✅ 同步成功!共有 {len(restaurant_list)} 間餐廳。"
118
  except Exception as e:
119
  yield f"❌ 系統錯誤:{str(e)}"
120
 
 
175
  yield "⚠️ 請先同步地圖清單!", None, ""
176
  return
177
 
 
178
  restaurant, is_match, rec_categories, mood_reason, all_names = get_restaurant_data(score_input, food_input)
179
 
180
+ # 增加告知訊息
181
  prefix = ""
182
+ status_hint = ""
183
  if not is_match and food_input != "隨便":
184
+ prefix = f"> 💡 **溫馨提示**:您的清單目前只有:**{all_names}**,沒找到符合『{food_input}』的店。我先幫您從現有名單挑一間最讚的!\n\n"
185
+ status_hint = f"\n(注意:清單中無 '{food_input}',請幽默解釋為何先推薦這間。)"
186
 
187
+ name = restaurant['Name']; url = restaurant.get('URL', '#')
188
+ rag_info = str(restaurant.get('RAG_Content', '')) + status_hint
 
 
189
 
 
190
  ai_text = generate_content_with_groq(name, rag_info, diary_input, score_input, mood_reason)
191
 
192
  final_response = f"{prefix}### 🍽️ 推薦:{name}\n\n{ai_text}"
193
+ 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">🗺️ 導航</a></div>'
194
 
195
+ yield final_response, None, map_html
 
 
196
 
197
  # ==========================================
198
  # 3. 橋接邏輯 (保留原本情緒辨識部分)