wsy07 commited on
Commit
2b0943a
·
1 Parent(s): 79d4f9b

首次上傳 LINE Bot

Browse files
Files changed (1) hide show
  1. gemini.py +107 -51
gemini.py CHANGED
@@ -3,7 +3,7 @@ import logging
3
  import os
4
  import tempfile
5
  import uuid
6
- from io import BytesIO
7
 
8
  import markdown
9
  from bs4 import BeautifulSoup
@@ -44,7 +44,11 @@ google_search_tool = Tool(
44
  chat = client.chats.create(
45
  model="gemini-2.0-flash",
46
  config=GenerateContentConfig(
47
- system_instruction="你是一個中文的AI助手,請用繁體中文回答",
 
 
 
 
48
  tools=[google_search_tool],
49
  response_modalities=["TEXT"],
50
  )
@@ -220,63 +224,115 @@ def handle_image_message(event):
220
 
221
  # === 處理影片訊息 ===
222
 
223
- @handler.add(MessageEvent, message=VideoMessageContent)
224
- def handle_video_message(event):
225
- # 下載影片內容
226
- with ApiClient(configuration) as api_client:
227
- blob_api = MessagingApiBlob(api_client)
228
- video_data = blob_api.get_message_content(message_id=event.message.id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
- # 儲存影片到本地
231
- if video_data is None:
232
- err_msg = "抱歉,無法取得影片內容。"
233
- app.logger.error(err_msg)
234
  with ApiClient(configuration) as api_client:
235
  line_bot_api = MessagingApi(api_client)
236
  line_bot_api.reply_message(
237
  ReplyMessageRequest(
238
  reply_token=event.reply_token,
239
- messages=[TextMessage(text=err_msg)]
240
  )
241
  )
242
- return
243
-
244
- with tempfile.NamedTemporaryFile(
245
- dir=static_tmp_path, suffix=".mp4", delete=False
246
- ) as tf:
247
- tf.write(video_data)
248
- filename = os.path.basename(tf.name)
249
 
250
- video_url = f"https://{base_url}/images/{filename}"
251
- app.logger.info(f"Video URL: {video_url}")
252
-
253
- # 影片說明
254
- try:
255
- from io import BytesIO
256
- video_bytes = BytesIO(video_data)
257
- response = client.models.generate_content(
258
- model="gemini-2.5-flash-preview-05-20",
259
- config=types.GenerateContentConfig(
260
- system_instruction="你是一個專業的影片解說員,請用繁體中文簡要說明這段影片的內容。",
261
- response_modalities=["TEXT"],
262
- tools=[google_search_tool],
263
- ),
264
- contents=[video_bytes, "用繁體中文描述這段影片"],
265
- )
266
- description = response.text
267
- except Exception as e:
268
- app.logger.error(f"Gemini API error (video): {e}")
269
- description = "抱歉,無法解釋這段影片內容。"
270
 
271
- # 回傳影片連結與說明
272
- with ApiClient(configuration) as api_client:
273
- line_bot_api = MessagingApi(api_client)
274
- line_bot_api.reply_message(
275
- ReplyMessageRequest(
276
- reply_token=event.reply_token,
277
- messages=[
278
- TextMessage(text=f"影片連結:{video_url}"),
279
- TextMessage(text=description),
280
- ],
281
  )
282
- )
 
3
  import os
4
  import tempfile
5
  import uuid
6
+ from io import BytesIO
7
 
8
  import markdown
9
  from bs4 import BeautifulSoup
 
44
  chat = client.chats.create(
45
  model="gemini-2.0-flash",
46
  config=GenerateContentConfig(
47
+ system_instruction=(
48
+ "你是一位專業健身教練與營養顧問,擁有多年重量訓練與健身飲食指導經驗。"
49
+ "請使用繁體中文,針對使用者的健身問題提供專業建議,包含動作教學、訓練計畫、飲食建議與常見錯誤修正等。"
50
+ ),
51
+
52
  tools=[google_search_tool],
53
  response_modalities=["TEXT"],
54
  )
 
224
 
225
  # === 處理影片訊息 ===
226
 
227
+ @handler.add(MessageEvent, message=TextMessageContent)
228
+ def handle_text_message(event):
229
+ user_input = event.message.text.strip()
230
+
231
+ # === 使用 Gemini 生成圖片(AI xxx) ===
232
+ if user_input.startswith("AI "):
233
+ prompt = user_input[3:].strip()
234
+ try:
235
+ response = client.models.generate_content(
236
+ model="gemini-2.0-flash-exp-image-generation",
237
+ contents=prompt,
238
+ config=types.GenerateContentConfig(
239
+ response_modalities=["TEXT", "IMAGE"]
240
+ ),
241
+ )
242
+
243
+ for part in response.candidates[0].content.parts:
244
+ if part.inline_data is not None:
245
+ image = Image.open(BytesIO(part.inline_data.data))
246
+ filename = f"{uuid.uuid4().hex}.png"
247
+ image_path = os.path.join(static_tmp_path, filename)
248
+ image.save(image_path)
249
+
250
+ image_url = f"https://{base_url}/images/{filename}"
251
+ app.logger.info(f"Image URL: {image_url}")
252
+
253
+ with ApiClient(configuration) as api_client:
254
+ line_bot_api = MessagingApi(api_client)
255
+ line_bot_api.reply_message(
256
+ ReplyMessageRequest(
257
+ reply_token=event.reply_token,
258
+ messages=[
259
+ ImageMessage(
260
+ original_content_url=image_url,
261
+ preview_image_url=image_url,
262
+ )
263
+ ],
264
+ )
265
+ )
266
+
267
+ except Exception as e:
268
+ app.logger.error(f"Gemini API error: {e}")
269
+ with ApiClient(configuration) as api_client:
270
+ line_bot_api = MessagingApi(api_client)
271
+ line_bot_api.reply_message(
272
+ ReplyMessageRequest(
273
+ reply_token=event.reply_token,
274
+ messages=[TextMessage(text="抱歉,生成圖片時發生錯誤。")],
275
+ )
276
+ )
277
+
278
+ # === 處理「菜單 xxx」功能 ===
279
+ elif user_input.startswith("菜單 "):
280
+ muscle_group = user_input[3:].strip()
281
+ if not muscle_group:
282
+ with ApiClient(configuration) as api_client:
283
+ line_bot_api = MessagingApi(api_client)
284
+ line_bot_api.reply_message(
285
+ ReplyMessageRequest(
286
+ reply_token=event.reply_token,
287
+ messages=[TextMessage(text="請輸入要安排的部位,例如:菜單 胸肌、菜單 臀部")]
288
+ )
289
+ )
290
+ return
291
+
292
+ # 同義詞簡化
293
+ synonym_map = {
294
+ "胸": "胸肌",
295
+ "腿": "腿部",
296
+ "肩": "肩膀",
297
+ "背": "背肌",
298
+ "手": "手臂",
299
+ "手臂": "手臂",
300
+ "核心": "核心肌群",
301
+ "臀": "臀部",
302
+ "臀部": "臀部",
303
+ "全身": "全身初學者",
304
+ "初學者": "全身初學者",
305
+ }
306
+ muscle_group = synonym_map.get(muscle_group, muscle_group)
307
+
308
+ # 發送訓練菜單請求
309
+ prompt = (
310
+ f"請依據「{muscle_group}」提供一份健身訓練菜單。"
311
+ "每份菜單包含 3~5 個動作,建議組數與次數,以及適當的休息時間。"
312
+ "請以繁體中文簡潔列出,使用條列方式排版,適合 LINE 顯示格式。"
313
+ )
314
+ response = query(prompt)
315
 
 
 
 
 
316
  with ApiClient(configuration) as api_client:
317
  line_bot_api = MessagingApi(api_client)
318
  line_bot_api.reply_message(
319
  ReplyMessageRequest(
320
  reply_token=event.reply_token,
321
+ messages=[TextMessage(text=response)],
322
  )
323
  )
 
 
 
 
 
 
 
324
 
325
+ # === 處理一般文字訊息 ===
326
+ else:
327
+ with ApiClient(configuration) as api_client:
328
+ line_bot_api = MessagingApi(api_client)
329
+ response = query(event.message.text)
330
+ html_msg = markdown.markdown(response)
331
+ soup = BeautifulSoup(html_msg, "html.parser")
 
 
 
 
 
 
 
 
 
 
 
 
 
332
 
333
+ line_bot_api.reply_message_with_http_info(
334
+ ReplyMessageRequest(
335
+ reply_token=event.reply_token,
336
+ messages=[TextMessage(text=soup.get_text())],
337
+ )
 
 
 
 
 
338
  )