hazelhh commited on
Commit
74c58ba
·
verified ·
1 Parent(s): e76fd12

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +127 -94
main.py CHANGED
@@ -23,11 +23,13 @@ user_states = defaultdict(lambda: {
23
  "upper_body_images": [],
24
  "lower_body_images": [],
25
  "current_mode": None, # "upper" or "lower"
26
- "is_ready": False # 新增狀態,標記圖片是否收集完畢
 
 
 
27
  })
28
 
29
  MAX_IMAGES_PER_TYPE = 3
30
- MAX_TOTAL_IMAGES = MAX_IMAGES_PER_TYPE * 2
31
  GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent"
32
  GOOGLE_API_KEY = os.environ["GOOGLE_API_KEY"]
33
 
@@ -88,103 +90,136 @@ def handle_text_message(event):
88
  text = event.message.text.lower()
89
  reply_token = event.reply_token
90
 
91
- # 檢查是否已準備好處理場合選擇
92
- if user_states[user_id]["is_ready"]:
93
- prompt = (
94
- f"我提供了三件上衣圖片和三件下半身圖片。請根據這些衣服,為我推薦一個適合「{text}」的穿搭建議,並詳細描述你推薦的上衣與下衣組合。請以繁體中文回答。"
95
- "請在描述中以圖片連結的形式(例如:'https://example.com/outfit1.jpg')顯示你搭配好的衣物組合。"
96
- "請將圖片連結放在一個新行,並使用 markdown 語法。"
97
- )
98
-
99
- all_images = user_states[user_id]["upper_body_images"] + user_states[user_id]["lower_body_images"]
100
-
101
- # 準備要回覆的訊息列表
102
- messages_to_send = [
103
- TextSendMessage(text="已收到場合資訊,正在為您生成穿搭建議... 請稍候。")
104
- ]
105
-
106
- # 在這裡顯示使用者上傳的原始圖片
107
- messages_to_send.append(
108
- TextSendMessage(text="這是您上傳的所有衣物:")
109
- )
110
-
111
- # 使用一個佔位符來顯示所有上傳的圖片
112
- upper_placeholders = [
113
- f"https://placehold.co/1024x1024?text=Upper_Body_{i+1}" for i in range(MAX_IMAGES_PER_TYPE)
114
- ]
115
- lower_placeholders = [
116
- f"https://placehold.co/1024x1024?text=Lower_Body_{i+1}" for i in range(MAX_IMAGES_PER_TYPE)
117
- ]
118
-
119
- for url in upper_placeholders:
120
- messages_to_send.append(ImageSendMessage(original_content_url=url, preview_image_url=url))
121
-
122
- for url in lower_placeholders:
123
- messages_to_send.append(ImageSendMessage(original_content_url=url, preview_image_url=url))
124
-
125
- line_bot_api.push_message(
126
- user_id,
127
- messages_to_send
128
- )
129
-
130
- response_text = get_gemini_response(prompt, all_images)
131
-
132
- # 解析 Gemini 的回應,將圖片 URL 和文字分開
133
- lines = response_text.split('\n')
134
- gemini_messages = []
135
- for line in lines:
136
- if line.startswith('http'):
137
- # 這是圖片 URL,將其轉為 ImageSendMessage
138
- gemini_messages.append(ImageSendMessage(original_content_url=line, preview_image_url=line))
139
- else:
140
- # 這是文字,將其轉為 TextSendMessage
141
- gemini_messages.append(TextSendMessage(text=line))
142
-
143
- line_bot_api.push_message(
144
- user_id,
145
- TextSendMessage(text="這是為您推薦的搭配:")
146
- )
147
 
148
- line_bot_api.push_message(
149
- user_id,
150
- gemini_messages
151
- )
152
-
153
- # 重置狀態以便下一次使用
154
- user_states[user_id] = defaultdict(lambda: {"upper_body_images": [], "lower_body_images": [], "current_mode": None, "is_ready": False})[user_id]
155
- return
156
-
157
- if text == "上衣":
158
- user_states[user_id]["current_mode"] = "upper"
159
- line_bot_api.reply_message(
160
- reply_token,
161
- TextSendMessage(text=f"請上傳三件上衣圖片,您已上傳 {len(user_states[user_id]['upper_body_images'])}/{MAX_IMAGES_PER_TYPE} 張。")
162
- )
163
- elif text == "褲子":
164
- user_states[user_id]["current_mode"] = "lower"
165
- line_bot_api.reply_message(
166
- reply_token,
167
- TextSendMessage(text=f"請上傳三件褲子/裙子圖片,您已上傳 {len(user_states[user_id]['lower_body_images'])}/{MAX_IMAGES_PER_TYPE} 張。")
168
- )
169
- elif text == "重置":
170
- user_states[user_id] = defaultdict(lambda: {"upper_body_images": [], "lower_body_images": [], "current_mode": None, "is_ready": False})[user_id]
171
- line_bot_api.reply_message(
172
- reply_token,
173
- TextSendMessage(text="狀態已重置。請傳送「上衣」或「褲子」來開始上傳。")
174
- )
175
- else:
176
- line_bot_api.reply_message(
177
- reply_token,
178
- TextSendMessage(text="請先傳送「上衣」或「褲子」來選擇要上傳的衣服類型。")
179
- )
180
 
181
  @line_handler.add(MessageEvent, message=ImageMessage)
182
  def handle_image_message(event):
183
  user_id = event.source.user_id
184
  reply_token = event.reply_token
185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  mode = user_states[user_id]["current_mode"]
187
-
188
  if not mode:
189
  line_bot_api.reply_message(
190
  reply_token,
@@ -224,11 +259,9 @@ def handle_image_message(event):
224
  TextSendMessage(text=f"已接收。上衣: {upper_count}/{MAX_IMAGES_PER_TYPE},褲子/裙子: {lower_count}/{MAX_IMAGES_PER_TYPE}。")
225
  )
226
  else:
227
- # 所有圖片已收集完畢,改變狀態並提示使用者選擇場合
228
- user_states[user_id]["is_ready"] = True
229
  line_bot_api.reply_message(
230
  reply_token,
231
- TextSendMessage(text="已收到所有圖片!請告訴我您想參加什麼樣的場合?例如:約會、工作、結婚典禮。")
232
  )
233
 
234
  except Exception as e:
 
23
  "upper_body_images": [],
24
  "lower_body_images": [],
25
  "current_mode": None, # "upper" or "lower"
26
+ "is_ready_for_outfit": False, # 標記衣物是否收集完畢
27
+ "is_ready_for_photo": False, # 標記個人照片是否上傳
28
+ "user_info": {}, # 儲存身高、三圍、場合
29
+ "personal_photo": None # 儲存個人照片
30
  })
31
 
32
  MAX_IMAGES_PER_TYPE = 3
 
33
  GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent"
34
  GOOGLE_API_KEY = os.environ["GOOGLE_API_KEY"]
35
 
 
90
  text = event.message.text.lower()
91
  reply_token = event.reply_token
92
 
93
+ # 處理個人資訊輸入
94
+ if not user_states[user_id]["is_ready_for_photo"] and not user_states[user_id]["is_ready_for_outfit"]:
95
+ try:
96
+ parts = text.split(',')
97
+ if len(parts) == 5:
98
+ height = float(parts[0])
99
+ bust = float(parts[1])
100
+ waist = float(parts[2])
101
+ hip = float(parts[3])
102
+ occasion = parts[4].strip()
103
+
104
+ user_states[user_id]["user_info"] = {
105
+ "height": height,
106
+ "bust": bust,
107
+ "waist": waist,
108
+ "hip": hip,
109
+ "occasion": occasion
110
+ }
111
+ user_states[user_id]["is_ready_for_outfit"] = True
112
+
113
+ line_bot_api.reply_message(
114
+ reply_token,
115
+ TextSendMessage(text=f"已收到您的資訊!接下來請上傳三件上衣和三件褲子的圖片。請先輸入「上衣」或「褲子」來開始。")
116
+ )
117
+ return
118
+ except ValueError:
119
+ line_bot_api.reply_message(
120
+ reply_token,
121
+ TextSendMessage(text="請依照格式輸入:身高,三圍胸圍,腰圍,臀圍,場合。例如:165,85,65,90,約會")
122
+ )
123
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
+ # 處理衣物上傳模式
126
+ if user_states[user_id]["is_ready_for_outfit"]:
127
+ if text == "上衣":
128
+ user_states[user_id]["current_mode"] = "upper"
129
+ line_bot_api.reply_message(
130
+ reply_token,
131
+ TextSendMessage(text=f"請上傳三件上衣圖片,您已上傳 {len(user_states[user_id]['upper_body_images'])}/{MAX_IMAGES_PER_TYPE} 張。")
132
+ )
133
+ return
134
+ elif text == "褲子":
135
+ user_states[user_id]["current_mode"] = "lower"
136
+ line_bot_api.reply_message(
137
+ reply_token,
138
+ TextSendMessage(text=f"請上傳三件褲子/裙子圖片,您已上傳 {len(user_states[user_id]['lower_body_images'])}/{MAX_IMAGES_PER_TYPE} 張。")
139
+ )
140
+ return
141
+ elif text == "重置":
142
+ user_states[user_id] = defaultdict(lambda: {"upper_body_images": [], "lower_body_images": [], "current_mode": None, "is_ready_for_outfit": False, "is_ready_for_photo": False, "user_info": {}, "personal_photo": None})[user_id]
143
+ line_bot_api.reply_message(
144
+ reply_token,
145
+ TextSendMessage(text="狀態已重置。請重新輸入個人資訊,格式為:身高,胸圍,腰圍,臀圍,場合")
146
+ )
147
+ return
148
+
149
+ # 如果沒有進入任何模式,給予提示
150
+ line_bot_api.reply_message(
151
+ reply_token,
152
+ TextSendMessage(text="請先依照格式輸入個人資訊,格式為:身高,胸圍,腰圍,臀圍,場合。")
153
+ )
 
 
 
154
 
155
  @line_handler.add(MessageEvent, message=ImageMessage)
156
  def handle_image_message(event):
157
  user_id = event.source.user_id
158
  reply_token = event.reply_token
159
 
160
+ # 檢查是否已準備好處理圖片
161
+ if not user_states[user_id]["is_ready_for_outfit"]:
162
+ line_bot_api.reply_message(
163
+ reply_token,
164
+ TextSendMessage(text="請先輸入個人資訊,格式為:身高,胸圍,腰圍,臀圍,場合。")
165
+ )
166
+ return
167
+
168
+ # 如果個人照片還沒上傳
169
+ if not user_states[user_id]["personal_photo"]:
170
+ try:
171
+ image_id = event.message.id
172
+ base64_img = get_base64_image(image_id)
173
+ user_states[user_id]["personal_photo"] = base64_img
174
+ user_states[user_id]["is_ready_for_photo"] = True
175
+
176
+ line_bot_api.reply_message(
177
+ reply_token,
178
+ TextSendMessage(text="已收到您的個人照片,正在為您準備穿搭... 請稍候。")
179
+ )
180
+
181
+ # 開始生成搭配建議和試穿照片
182
+ user_info = user_states[user_id]["user_info"]
183
+ occasion = user_info["occasion"]
184
+
185
+ prompt = (
186
+ f"我提供了三件上衣圖片和三件下半身圖片,以及使用者的一張個人照片。使用者的身高為 {user_info['height']},三圍為 {user_info['bust']}-{user_info['waist']}-{user_info['hip']},想要參加的場合是「{occasion}」。"
187
+ "請根據這些衣物,為我推薦一套最適合的穿搭,並詳細說明為何這套搭配適合這個場合。請以繁體中文回答。"
188
+ "接著,請生成一張虛擬試穿的照片,將推薦的上衣和下衣搭配到使用者提供的照片上。由於模型限制,我會使用佔位符圖片來模擬試穿效果。"
189
+ )
190
+
191
+ all_images = user_states[user_id]["upper_body_images"] + user_states[user_id]["lower_body_images"] + [user_states[user_id]["personal_photo"]]
192
+
193
+ response_text = get_gemini_response(prompt, all_images)
194
+
195
+ # 虛擬試穿照片佔位符
196
+ virtual_try_on_url = "https://placehold.co/1024x1024?text=Virtual+Try-On+Outfit"
197
+
198
+ # 發送 Gemini 的文字建議
199
+ line_bot_api.push_message(
200
+ user_id,
201
+ TextSendMessage(text=f"這是為您推薦的搭配:\n\n{response_text}")
202
+ )
203
+
204
+ # 發送虛擬試穿照片
205
+ line_bot_api.push_message(
206
+ user_id,
207
+ ImageSendMessage(original_content_url=virtual_try_on_url, preview_image_url=virtual_try_on_url)
208
+ )
209
+
210
+ # 重置狀態以便下一次使用
211
+ user_states[user_id] = defaultdict(lambda: {"upper_body_images": [], "lower_body_images": [], "current_mode": None, "is_ready_for_outfit": False, "is_ready_for_photo": False, "user_info": {}, "personal_photo": None})[user_id]
212
+ return
213
+
214
+ except Exception as e:
215
+ line_bot_api.reply_message(
216
+ reply_token,
217
+ TextSendMessage(text=f"圖片處理失敗,請稍後再試。錯誤:{e}")
218
+ )
219
+ return
220
+
221
+ # 處理衣物圖片上傳
222
  mode = user_states[user_id]["current_mode"]
 
223
  if not mode:
224
  line_bot_api.reply_message(
225
  reply_token,
 
259
  TextSendMessage(text=f"已接收。上衣: {upper_count}/{MAX_IMAGES_PER_TYPE},褲子/裙子: {lower_count}/{MAX_IMAGES_PER_TYPE}。")
260
  )
261
  else:
 
 
262
  line_bot_api.reply_message(
263
  reply_token,
264
+ TextSendMessage(text="已收到所有衣物圖片!接下來,請上傳一張您個人的全身照片,以便進行虛擬試穿。")
265
  )
266
 
267
  except Exception as e: