from fastapi.middleware.cors import CORSMiddleware from fastapi import FastAPI, Request, Header, BackgroundTasks, HTTPException, status, staticfiles from gradio_client import Client import json import os from linebot import ( LineBotApi, WebhookHandler ) from linebot.exceptions import ( InvalidSignatureError ) from linebot.models import ( MessageEvent, TextMessage, TextSendMessage, ImageSendMessage, AudioMessage ) # 設定 GeminiRAG 的HF網址 client = Client(os.environ["GeminiRAGapi"]) # 設定 Line Bot 的 API 金鑰和秘密金鑰 line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"]) line_handler = WebhookHandler(os.environ["CHANNEL_SECRET"]) # 設定是否正在與使用者交談 working_status = os.getenv("DEFALUT_TALKING", default = "true").lower() == "true" # 建立 FastAPI 應用程式 app = FastAPI() app.mount("/static", staticfiles.StaticFiles(directory="static"), name="static") # 設定 CORS,允許跨域請求 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 處理根路徑請求 @app.get("/") def root(): return {"title": "Line Bot"} # 處理 Line Webhook 請求 @app.post("/webhook") async def webhook( request: Request, background_tasks: BackgroundTasks, x_line_signature=Header(None), ): # 取得請求內容 body = await request.body() try: # 將處理 Line 事件的任務加入背景工作 background_tasks.add_task( line_handler.handle, body.decode("utf-8"), x_line_signature ) except InvalidSignatureError: # 處理無效的簽章錯誤 raise HTTPException(status_code=400, detail="Invalid signature") return "ok" # 處理文字訊息事件 @line_handler.add(MessageEvent, message=TextMessage) def handle_message(event): global working_status # 檢查事件類型和訊息類型 if event.type != "message" or event.message.type != "text": # 回覆錯誤訊息 line_bot_api.reply_message( event.reply_token, TextSendMessage(text="Event type error:[No message or the message does not contain text]") ) # 檢查使用者是否輸入 "再見" elif event.message.text == "再見": # 回覆 "Bye!" line_bot_api.reply_message( event.reply_token, TextSendMessage(text="Bye!") ) return # 檢查是否正在與使用者交談 elif working_status: try: # 取得使用者輸入的文字 prompt = event.message.text # 使用 GeminiRAGapi completion = client.predict(question=prompt, api_name="/predict") # 檢查生成結果是否為空 if (completion != None): # 取得生成結果 out = completion else: # 回覆 "Gemini沒答案!請換個說法!" out = "Gemini沒答案!請換個說法!" except: # 處理錯誤 out = "Gemini執行出錯!請換個說法!" # 回覆生成結果 line_bot_api.reply_message( event.reply_token, TextSendMessage(text=out)) if __name__ == "__main__": # 啟動 FastAPI 應用程式 uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True) # 註解說明: # import 導入必要的套件 # line_bot_api 和 line_handler 設定 Line Bot API 和 webhook 處理器 # working_status 設定是否正在與使用者交談 # app 建立 FastAPI 應用程式 # app.add_middleware 設定 CORS # @app.get("/") 處理根路徑請求 # @app.post("/webhook") 處理 Line Webhook 請求 # @line_handler.add(MessageEvent, message=TextMessage) 處理文字訊息事件 # if __name__ == "__main__": 啟動 FastAPI 應用程式 # 程式碼功能說明: # 接著會建立 FastAPI 應用程式,並設定 CORS。 # 程式碼會定義兩個函數: # root() 處理根路徑請求,返回一個簡單的 JSON 訊息。 # webhook() 處理 Line Webhook 請求,將處理 Line 事件的任務加入背景工作,並處理無效的簽章錯誤。 # 程式碼還定義一個函數 handle_message() 來處理文字訊息事件,它會檢查事件類型和訊息類型,並根據使用者輸入執行不同的動作: # 如果使用者輸入 "再見",回覆 "Bye!"。 # 如果正在與使用者交談,則會使用 Gemini 模型生成文字,並將結果回覆給使用者。 # 最後,程式碼會啟動 FastAPI 應用程式,開始監聽 HTTP 請求。 # 程式碼運行方式: # 將程式碼存為 main.py 文件。 # 在環境變數中設定 GeminiRAGapi, CHANNEL_ACCESS_TOKEN 和 CHANNEL_SECRET。 # 執行 uvicorn main:app --host 0.0.0.0 --port 7860 --reload 命令啟動 FastAPI 應用程式。 # 使用 Line 帳戶與 Line Bot 進行對話。 # 注意: # 程式碼中使用os.environ["GeminiRAGapi"], os.environ["CHANNEL_ACCESS_TOKEN"] 和 os.environ["CHANNEL_SECRET"] 來存取環境變數,需要先在環境變數中設定這些值。 # 程式碼中使用 uvicorn 執行 FastAPI 應用程式,需要先安裝 uvicorn 套件。 # 程式碼中使用 linebot 套件,需要先安裝 linebot 套件。