Nai-Yun commited on
Commit
436f0e6
·
verified ·
1 Parent(s): 7e64585

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -9
app.py CHANGED
@@ -16,6 +16,20 @@ handler = WebhookHandler(os.environ.get('LINE_CHANNEL_SECRET'))
16
  genai.configure(api_key=os.environ.get('GEMINI_API_KEY'))
17
  model = genai.GenerativeModel('gemini-2.5-flash')
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  # ================= 2. 建立狀態儲存區(暫存每個用戶的進度) =================
20
  user_states = {}
21
 
@@ -51,12 +65,16 @@ def handle_image(event):
51
 
52
  # 2. 設定 Prompt,要求 Gemini 直接分析這張圖片
53
  vision_prompt = """
 
 
 
 
54
  你現在是一位專業的台灣藥妝購物精靈。請看這張圖片中的產品:
55
  1. 辨識它是什麼真實的品牌與品名。
56
  2. 估算它在台灣藥妝店(如屈臣氏、康是美)的合理售價。
57
  3. 指出哪個商家買得到。
58
 
59
- 請直接輸出以下格式的純文字(不需要包含其他廢話):
60
  品名:[產品完整名稱]
61
  售價:$[估計價格]
62
  商家:[推薦藥妝店名稱]
@@ -64,21 +82,133 @@ def handle_image(event):
64
 
65
  # 3. 把圖片和 Prompt 一起丟給 Gemini (支援多模態)
66
  response = model.generate_content([vision_prompt, pil_image])
67
- ai_reply = response.text
68
 
69
- # 4. 將結果推播給使用者(目前先用文字,後續可升級成圖卡)
70
- line_bot_api.push_message(
71
- user_id,
72
- TextSendMessage(text=f"🧚‍♀️ 辨識成功!\n\n{ai_reply}")
73
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
- # 任務完成,清除狀態
76
  del user_states[user_id]
77
 
78
  except Exception as e:
79
  line_bot_api.push_message(
80
  user_id,
81
- TextSendMessage(text=f"❌ 哎呀!精靈的眼睛剛剛眨了一下,沒看清楚照片。錯誤原因:\n{e}")
82
  )
83
 
84
  # ================= 3. 多輪對話核心邏輯 =================
 
16
  genai.configure(api_key=os.environ.get('GEMINI_API_KEY'))
17
  model = genai.GenerativeModel('gemini-2.5-flash')
18
 
19
+ # 建立我們的虛擬藥妝資料庫 (Mock Database)
20
+ fake_database = {
21
+ "CeraVe適樂膚 長效潤澤修護霜 340g": [
22
+ {"store": "屈臣氏", "name": "CeraVe適樂膚 長效潤澤修護霜 340g", "price": "619","link": "https://www.watsons.com.tw/cerave-cerave%E9%81%A9%E6%A8%82%E8%86%9A%E9%95%B7%E6%95%88%E6%BD%A4%E6%BE%A4%E4%BF%AE%E8%AD%B7%E9%9C%9C-340g/p/BP_153671"},
23
+ {"store": "康是美", "name": "CeraVe適樂膚 長效潤澤修護霜 340g", "price": "619", "link": "https://shop.cosmed.com.tw/SalePage/Index/6414249"},
24
+ {"store": "寶雅", "name": "CeraVe適樂膚 長效潤澤修護霜 340g", "price": "619","link": "https://www.poyabuy.com.tw/SalePage/Index/10104261"}
25
+ ],
26
+ "Avene 雅漾舒護活泉水150ml": [
27
+ {"store": "屈臣氏", "name": "Avene 雅漾舒護活泉水150ml", "price": "299","discount": "🔥限時67折", "link": "https://www.watsons.com.tw/avene-%E9%9B%85%E6%BC%BE-%E9%9B%85%E6%BC%BE%E8%88%92%E8%AD%B7%E6%B4%BB%E6%B3%89%E6%B0%B4150ml/p/BP_291419"},
28
+ {"store": "康是美", "name": "Avene 雅漾舒護活泉水150ml", "price": "299","discount": "🔥限時67折", "link": "https://shop.cosmed.com.tw/SalePage/Index/5767522"},
29
+ {"store": "寶雅", "name": "Avene 雅漾舒護活泉水150ml", "price": "450", "link": "https://www.poyabuy.com.tw/SalePage/Index/9929185"}
30
+ ]
31
+ }
32
+
33
  # ================= 2. 建立狀態儲存區(暫存每個用戶的進度) =================
34
  user_states = {}
35
 
 
65
 
66
  # 2. 設定 Prompt,要求 Gemini 直接分析這張圖片
67
  vision_prompt = """
68
+ 請辨識這張圖片中的保養品。
69
+ 如果是 CeraVe 的 PM 乳液,請直接回答:CeraVe長效清爽保濕乳PM
70
+ 如果是 理膚寶水 B5,請直接回答:理膚寶水B5全面修復霜
71
+ 如果都不是
72
  你現在是一位專業的台灣藥妝購物精靈。請看這張圖片中的產品:
73
  1. 辨識它是什麼真實的品牌與品名。
74
  2. 估算它在台灣藥妝店(如屈臣氏、康是美)的合理售價。
75
  3. 指出哪個商家買得到。
76
 
77
+ 請直接輸出以下格式的純文字(不需要包含其他廢話):
78
  品名:[產品完整名稱]
79
  售價:$[估計價格]
80
  商家:[推薦藥妝店名稱]
 
82
 
83
  # 3. 把圖片和 Prompt 一起丟給 Gemini (支援多模態)
84
  response = model.generate_content([vision_prompt, pil_image])
85
+ product_name = response.text.strip()
86
 
87
+ # --- 第 3 步:雙軌制 (假資料庫 vs AI估價) ---
88
+ if product_name in fake_database:
89
+ # 🌟 路線 A:命中資料庫,使用妳設定的真實數據!
90
+ data_list = fake_database[product_name]
91
+ price_tag = "資料庫真實價" # 讓圖卡顯示這是真實數據
92
+ else:
93
+ # 🤖 路線 B:資料庫沒有,呼叫 AI 進行現場估價!
94
+ line_bot_api.push_message(user_id, TextSendMessage(text=f"🔍 辨識出「{product_name}」,資料庫無建檔,啟動 AI 現場估價..."))
95
+
96
+ estimate_prompt = f"""
97
+ 請估算「{product_name}」這款產品在台灣屈臣氏、康是美、寶雅的合理售價。
98
+ 請務必「只回傳」一個標準的 JSON 陣列,不要有任何額外的說明文字。格式嚴格如下:
99
+ [
100
+ {{"store": "屈臣氏", "name": "{product_name}", "price": "估計數字"}},
101
+ {{"store": "康是美", "name": "{product_name}", "price": "估計數字"}},
102
+ {{"store": "寶雅", "name": "{product_name}", "price": "估計數字"}}
103
+ ]
104
+ """
105
+ est_response = model.generate_content(estimate_prompt)
106
+ clean_text = est_response.text.replace("```json", "").replace("```", "").strip()
107
+ data_list = json.loads(clean_text)
108
+ price_tag = "AI 估計價" # 讓圖卡顯示這是 AI 猜的
109
+
110
+ # --- 第 4 步:將資料塞進橫向圖卡 (不管哪條路線,最後都會來到這裡) ---
111
+ # --- 第 4 步:將資料塞進橫向圖卡 ---
112
+ bubbles = []
113
+ for item in data_list:
114
+
115
+ # --- 這裡用來判斷要不要顯示折扣標籤 ---
116
+ discount_box = []
117
+ # 只有當資料庫裡的 discount 不是空字串時,才生出這塊紅色的標籤
118
+ if item.get("discount"):
119
+ discount_box = [
120
+ {
121
+ "type": "box",
122
+ "layout": "baseline",
123
+ "spacing": "sm",
124
+ "contents": [
125
+ {
126
+ "type": "text",
127
+ "text": item["discount"],
128
+ "color": "#ffffff",
129
+ "size": "xs",
130
+ "weight": "bold",
131
+ "margin": "sm"
132
+ }
133
+ ],
134
+ "backgroundColor": "#ff3b30", # 紅色底
135
+ "cornerRadius": "md",
136
+ "paddingAll": "2px",
137
+ "paddingStart": "8px",
138
+ "paddingEnd": "8px",
139
+ "margin": "sm"
140
+ }
141
+ ]
142
+
143
+ # 這是原本卡片的身體內容,我們把剛剛可能生出來的折扣標籤塞進去
144
+ card_contents = [
145
+ {"type": "text", "text": item["store"], "weight": "bold", "color": "#1DB446", "size": "md"},
146
+ {"type": "text", "text": item["name"], "weight": "bold", "size": "lg", "margin": "md", "wrap": True},
147
+ ]
148
+
149
+ # 把折扣標籤接在商品名稱後面
150
+ card_contents.extend(discount_box)
151
+
152
+ # 補上最後的價格線
153
+ card_contents.extend([
154
+ {"type": "separator", "margin": "lg"},
155
+ {
156
+ "type": "box",
157
+ "layout": "horizontal",
158
+ "margin": "md",
159
+ "contents": [
160
+ {"type": "text", "text": price_tag, "size": "sm", "color": "#555555"},
161
+ {"type": "text", "text": f"${item['price']}", "size": "lg", "color": "#111111", "align": "end", "weight": "bold"}
162
+ ]
163
+ }
164
+ ])
165
+
166
+ # 組裝最終的卡片
167
+ card = {
168
+ "type": "bubble",
169
+ "body": {
170
+ "type": "box",
171
+ "layout": "vertical",
172
+ "contents": card_contents
173
+ },
174
+ "footer": {
175
+ "type": "box",
176
+ "layout": "vertical",
177
+ "contents": [
178
+ {
179
+ "type": "button",
180
+ "style": "primary",
181
+ "color": "#1DB446",
182
+ "height": "sm",
183
+ "action": {
184
+ "type": "uri",
185
+ "label": "前往商家購買",
186
+ # 這裡改用資料庫裡設定的專屬網址!(如果沒設定,就預設用 Google 搜尋)
187
+ "uri": item.get("link", f"https://www.google.com/search?q={item['store']}+{item['name']}")
188
+ }
189
+ }
190
+ ]
191
+ }
192
+ }
193
+ bubbles.append(card)
194
+
195
+ # --- 第 5 步:打包發送圖卡 ---
196
+ flex_message = FlexSendMessage.new_from_json_dict({
197
+ "type": "flex",
198
+ "alt_text": "🔍 藥妝精靈比價報告來囉!",
199
+ "contents": {
200
+ "type": "carousel",
201
+ "contents": bubbles
202
+ }
203
+ })
204
 
205
+ line_bot_api.push_message(user_id, flex_message)
206
  del user_states[user_id]
207
 
208
  except Exception as e:
209
  line_bot_api.push_message(
210
  user_id,
211
+ TextSendMessage(text=f"❌ 哎呀!精靈遇到了一點問題。錯誤原因:\n{e}")
212
  )
213
 
214
  # ================= 3. 多輪對話核心邏輯 =================