yuna456789/Linebot
0
1from fastapi.middleware.cors import CORSMiddleware2from fastapi import FastAPI, Request, Header, BackgroundTasks, HTTPException, status3from fastapi.staticfiles import StaticFiles4from google import genai5from linebot import LineBotApi, WebhookHandler6from linebot.exceptions import InvalidSignatureError7from linebot.models import MessageEvent, TextMessage, TextSendMessage, ImageSendMessage, AudioMessage, ImageMessage8import json, os9import io10import PIL.Image11from Image_text_generation import Image_text_Generator12from Uploading_images_file import get_image_url, store_user_message, analyze_with_gemini, get_previous_message13 14#==========================15# API 金鑰16#==========================17 18# 設定 Google AI API 金鑰19client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))20 21# 設定生成文字的參數22generation_config = genai.types.GenerateContentConfig(max_output_tokens=256, temperature=0.5, top_p=0.5, top_k=16)23 24# 設定 Line Bot 的 API 金鑰和秘密金鑰25line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"])26line_handler = WebhookHandler(os.environ["CHANNEL_SECRET"])27 28# 設定是否正在與使用者交談29working_status = os.getenv("DEFALUT_TALKING", default = "true").lower() == "true"30 31# 建立 FastAPI 應用程式32app = FastAPI()33app.mount("/static", StaticFiles(directory="static"), name="static")34 35# 設定 CORS,允許跨域請求36app.add_middleware(37 CORSMiddleware,38 allow_origins=["*"],39 allow_credentials=True,40 allow_methods=["*"],41 allow_headers=["*"],42)43 44# 處理根路徑請求45@app.get("/")46def root():47 return {"title": "Line Bot"}48 49# 處理 Line Webhook 請求50@app.post("/webhook")51async def webhook(52 request: Request,53 background_tasks: BackgroundTasks,54 x_line_signature=Header(None),55):56 # 取得請求內容57 body = await request.body()58 try:59 # 將處理 Line 事件的任務加入背景工作60 background_tasks.add_task(61 line_handler.handle, body.decode("utf-8"), x_line_signature62 )63 except InvalidSignatureError:64 # 處理無效的簽章錯誤65 raise HTTPException(status_code=400, detail="Invalid signature")66 return "ok"67 68 69#==========================70# 主程式(圖片與文字)71#==========================72# 建立 chat_sessions 字典73chat_sessions = {}74@line_handler.add(MessageEvent, message=(ImageMessage, TextMessage))75def handle_image_message(event):76 user_id = event.source.user_id77 user_text = event.message.text if event.message.type == "text" else None78 previous_message = get_previous_message(user_id)79 80 if event.message.type != "text" and event.message.type != "image":81 line_bot_api.reply_message(event.reply_token, TextSendMessage(text="請輸入文字或圖片~"))82 return83 elif user_text == "再見":84 line_bot_api.reply_message(event.reply_token, TextSendMessage(text="Bye!"))85 return86 87 # ========88 # 生成圖片89 # ========90 elif user_text and user_text.startswith("生成圖片"):91 prompt = user_text.replace("生成圖片", "").strip()92 93 # 先立即回覆避免token過期94 line_bot_api.reply_message(event.reply_token, TextSendMessage(text="圖片生成中~ 請稍候.....✨"))95 image_generator = Image_text_Generator(user_id)96 # 生成圖片97 image_binary = image_generator.generate_image_with_gemini(prompt)98 99 if image_binary:100 image_url = os.path.join(os.getenv("HF_SPACE"),image_generator.upload_image_to_tmp(image_binary)) ### os.getenv("HF_SPACE") => https://xxxxx.hf.space101 102 if image_url:103 # 使用 push message 發送圖片,避免 reply token 超時104 line_bot_api.push_message(105 event.source.user_id,106 [107 TextSendMessage(text="✨ 這是我為你生成的圖片喔~"),108 ImageSendMessage(original_content_url=image_url, preview_image_url=image_url)109 ]110 )111 else:112 line_bot_api.push_message(113 event.source.user_id,114 TextSendMessage(text="⚠️ 圖片上傳失敗,請稍後再試~")115 )116 else:117 line_bot_api.push_message(118 event.source.user_id,119 TextSendMessage(text="⚠️ 圖片生成失敗,請稍後再試~")120 )121 return122 123 # ========124 # 純文字125 # ========126 elif event.message.type == "text" and previous_message["type"] != "image":127 try: 128 user_id = event.source.user_id129 chat = chat_sessions.get(user_id) or client.chats.create(model="gemini-2.0-flash", config=generation_config)130 chat_sessions[user_id] = chat131 # 取得使用者輸入的文字132 user_input = event.message.text133 response = chat.send_message(user_input)134 if (response.text != None):135 out = response.text136 else:137 out = "Gemini沒答案!請換個說法!"138 except:139 # 處理錯誤140 out = "Gemini執行出錯!請換個說法!" 141 142 elif previous_message and previous_message["type"] == "image" and event.message.type == "text":143 image_path = previous_message["content"]144 user_text = event.message.text145 store_user_message(user_id, "text", user_text)146 try:147 if not os.path.exists(image_path):148 raise FileNotFoundError(f"圖片路徑無效:{image_path}")149 previous_img = PIL.Image.open(image_path)150 user_id = event.source.user_id151 chat = chat_sessions.get(user_id) or client.chats.create(model="gemini-2.0-flash", config=generation_config)152 chat_sessions[user_id] = chat153 # 取得使用者輸入的文字154 user_input = event.message.text155 response = chat.send_message([previous_img, user_input])156 if (response.text != None):157 out = response.text158 else:159 out = "Gemini沒答案!請換個說法!"160 except:161 # 處理錯誤162 out = "Gemini執行出錯!請換個說法!" 163 164 # ========165 # 上傳圖片166 # ========167 elif event.message.type == "image":168 image_path = get_image_url(event.message.id)169 if image_path:170 store_user_message(user_id, "image", image_path)171 line_bot_api.reply_message(event.reply_token, TextSendMessage(text="圖片已接收成功囉,幫我輸入你想詢問的問題喔~"))172 else:173 line_bot_api.reply_message(event.reply_token, TextSendMessage(text="沒有接收到圖片~"))174 return175 176 line_bot_api.reply_message(event.reply_token, TextSendMessage(text=out))177 178 179if __name__ == "__main__":180 # 啟動 FastAPI 應用程式181 uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)