Spaces:
Runtime error
Runtime error
Update main.py
Browse files
main.py
CHANGED
|
@@ -11,8 +11,8 @@ from collections import defaultdict
|
|
| 11 |
import uvicorn
|
| 12 |
|
| 13 |
# 檢查環境變數
|
| 14 |
-
if not all(k in os.environ for k in ["CHANNEL_ACCESS_TOKEN", "CHANNEL_SECRET", "GOOGLE_API_KEY"]):
|
| 15 |
-
raise ValueError("Missing environment variables. Please set CHANNEL_ACCESS_TOKEN, CHANNEL_SECRET, and
|
| 16 |
|
| 17 |
# Line Bot API 設定
|
| 18 |
line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"])
|
|
@@ -32,6 +32,7 @@ user_states = defaultdict(lambda: {
|
|
| 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 |
|
| 36 |
app = FastAPI()
|
| 37 |
|
|
@@ -65,6 +66,20 @@ def get_base64_image(message_id: str):
|
|
| 65 |
image_bytes = message_content.content
|
| 66 |
return base64.b64encode(image_bytes).decode('utf-8')
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
def get_gemini_response(prompt: str, images: list):
|
| 69 |
payload = {
|
| 70 |
"contents": [
|
|
@@ -180,7 +195,9 @@ def handle_image_message(event):
|
|
| 180 |
try:
|
| 181 |
image_id = event.message.id
|
| 182 |
base64_img = get_base64_image(image_id)
|
| 183 |
-
|
|
|
|
|
|
|
| 184 |
user_states[user_id]["is_ready_for_photo"] = True
|
| 185 |
|
| 186 |
line_bot_api.reply_message(
|
|
@@ -192,6 +209,7 @@ def handle_image_message(event):
|
|
| 192 |
user_info = user_states[user_id]["user_info"]
|
| 193 |
occasion = user_info["occasion"]
|
| 194 |
|
|
|
|
| 195 |
prompt = (
|
| 196 |
f"我提供了三件上衣圖片和三件下半身圖片,以及使用者的一張個人照片。使用者資訊:身高 {user_info['height']}cm,三圍 {user_info['bust']}-{user_info['waist']}-{user_info['hip']},場合是「{occasion}」。"
|
| 197 |
"請根據這些衣物,為我推薦一套最適合的穿搭,並詳細說明為何這套搭配適合這個場合。請以繁體中文回答。"
|
|
@@ -211,7 +229,7 @@ def handle_image_message(event):
|
|
| 211 |
best_lower_body_image = user_states[user_id]["lower_body_images"][best_lower_index]
|
| 212 |
|
| 213 |
# 呼叫虛擬試穿 API,並取得結果圖片 URL
|
| 214 |
-
|
| 215 |
|
| 216 |
# 發送 Gemini 的文字建議
|
| 217 |
line_bot_api.push_message(
|
|
@@ -222,7 +240,7 @@ def handle_image_message(event):
|
|
| 222 |
# 發送虛擬試穿照片
|
| 223 |
line_bot_api.push_message(
|
| 224 |
user_id,
|
| 225 |
-
ImageSendMessage(original_content_url=
|
| 226 |
)
|
| 227 |
|
| 228 |
# 重置狀態以便下一次使用
|
|
@@ -248,10 +266,18 @@ def handle_image_message(event):
|
|
| 248 |
try:
|
| 249 |
image_id = event.message.id
|
| 250 |
base64_img = get_base64_image(image_id)
|
| 251 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
if mode == "upper":
|
| 253 |
if len(user_states[user_id]["upper_body_images"]) < MAX_IMAGES_PER_TYPE:
|
| 254 |
-
user_states[user_id]["upper_body_images"].append(
|
| 255 |
else:
|
| 256 |
line_bot_api.reply_message(
|
| 257 |
reply_token,
|
|
@@ -260,7 +286,7 @@ def handle_image_message(event):
|
|
| 260 |
return
|
| 261 |
else: # mode == "lower"
|
| 262 |
if len(user_states[user_id]["lower_body_images"]) < MAX_IMAGES_PER_TYPE:
|
| 263 |
-
user_states[user_id]["lower_body_images"].append(
|
| 264 |
else:
|
| 265 |
line_bot_api.reply_message(
|
| 266 |
reply_token,
|
|
|
|
| 11 |
import uvicorn
|
| 12 |
|
| 13 |
# 檢查環境變數
|
| 14 |
+
if not all(k in os.environ for k in ["CHANNEL_ACCESS_TOKEN", "CHANNEL_SECRET", "GOOGLE_API_KEY", "IMGUR_CLIENT_ID"]):
|
| 15 |
+
raise ValueError("Missing environment variables. Please set CHANNEL_ACCESS_TOKEN, CHANNEL_SECRET, GOOGLE_API_KEY, and IMGUR_CLIENT_ID.")
|
| 16 |
|
| 17 |
# Line Bot API 設定
|
| 18 |
line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"])
|
|
|
|
| 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 |
+
IMGUR_CLIENT_ID = os.environ["IMGUR_CLIENT_ID"]
|
| 36 |
|
| 37 |
app = FastAPI()
|
| 38 |
|
|
|
|
| 66 |
image_bytes = message_content.content
|
| 67 |
return base64.b64encode(image_bytes).decode('utf-8')
|
| 68 |
|
| 69 |
+
def upload_to_imgur(image_base64: str):
|
| 70 |
+
"""
|
| 71 |
+
將 Base64 編碼的圖片上傳到 Imgur。
|
| 72 |
+
"""
|
| 73 |
+
headers = {"Authorization": f"Client-ID {IMGUR_CLIENT_ID}"}
|
| 74 |
+
payload = {"image": image_base64}
|
| 75 |
+
try:
|
| 76 |
+
response = requests.post("https://api.imgur.com/3/image", headers=headers, data=payload)
|
| 77 |
+
response.raise_for_status()
|
| 78 |
+
return response.json()["data"]["link"]
|
| 79 |
+
except requests.exceptions.RequestException as e:
|
| 80 |
+
print(f"Error uploading to Imgur: {e}")
|
| 81 |
+
return None
|
| 82 |
+
|
| 83 |
def get_gemini_response(prompt: str, images: list):
|
| 84 |
payload = {
|
| 85 |
"contents": [
|
|
|
|
| 195 |
try:
|
| 196 |
image_id = event.message.id
|
| 197 |
base64_img = get_base64_image(image_id)
|
| 198 |
+
# 將個人照片上傳到 Imgur,並儲存 URL
|
| 199 |
+
photo_url = upload_to_imgur(base64_img)
|
| 200 |
+
user_states[user_id]["personal_photo"] = photo_url
|
| 201 |
user_states[user_id]["is_ready_for_photo"] = True
|
| 202 |
|
| 203 |
line_bot_api.reply_message(
|
|
|
|
| 209 |
user_info = user_states[user_id]["user_info"]
|
| 210 |
occasion = user_info["occasion"]
|
| 211 |
|
| 212 |
+
# Gemini 提示詞現在使用圖片 URL,而不是 Base64 編碼
|
| 213 |
prompt = (
|
| 214 |
f"我提供了三件上衣圖片和三件下半身圖片,以及使用者的一張個人照片。使用者資訊:身高 {user_info['height']}cm,三圍 {user_info['bust']}-{user_info['waist']}-{user_info['hip']},場合是「{occasion}」。"
|
| 215 |
"請根據這些衣物,為我推薦一套最適合的穿搭,並詳細說明為何這套搭配適合這個場合。請以繁體中文回答。"
|
|
|
|
| 229 |
best_lower_body_image = user_states[user_id]["lower_body_images"][best_lower_index]
|
| 230 |
|
| 231 |
# 呼叫虛擬試穿 API,並取得結果圖片 URL
|
| 232 |
+
virtual_tryon_url = get_virtual_tryon_image(user_states[user_id]["personal_photo"], best_upper_body_image, best_lower_body_image)
|
| 233 |
|
| 234 |
# 發送 Gemini 的文字建議
|
| 235 |
line_bot_api.push_message(
|
|
|
|
| 240 |
# 發送虛擬試穿照片
|
| 241 |
line_bot_api.push_message(
|
| 242 |
user_id,
|
| 243 |
+
ImageSendMessage(original_content_url=virtual_tryon_url, preview_image_url=virtual_tryon_url)
|
| 244 |
)
|
| 245 |
|
| 246 |
# 重置狀態以便下一次使用
|
|
|
|
| 266 |
try:
|
| 267 |
image_id = event.message.id
|
| 268 |
base64_img = get_base64_image(image_id)
|
| 269 |
+
# 上傳圖片到 Imgur,並儲存 URL
|
| 270 |
+
image_url = upload_to_imgur(base64_img)
|
| 271 |
+
if not image_url:
|
| 272 |
+
line_bot_api.reply_message(
|
| 273 |
+
reply_token,
|
| 274 |
+
TextSendMessage(text="圖片上傳 Imgur 失敗,請稍後再試。")
|
| 275 |
+
)
|
| 276 |
+
return
|
| 277 |
+
|
| 278 |
if mode == "upper":
|
| 279 |
if len(user_states[user_id]["upper_body_images"]) < MAX_IMAGES_PER_TYPE:
|
| 280 |
+
user_states[user_id]["upper_body_images"].append(image_url)
|
| 281 |
else:
|
| 282 |
line_bot_api.reply_message(
|
| 283 |
reply_token,
|
|
|
|
| 286 |
return
|
| 287 |
else: # mode == "lower"
|
| 288 |
if len(user_states[user_id]["lower_body_images"]) < MAX_IMAGES_PER_TYPE:
|
| 289 |
+
user_states[user_id]["lower_body_images"].append(image_url)
|
| 290 |
else:
|
| 291 |
line_bot_api.reply_message(
|
| 292 |
reply_token,
|