Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
| 2 |
import io
|
| 3 |
import PIL.Image
|
| 4 |
import uvicorn
|
|
|
|
| 5 |
from collections import defaultdict
|
| 6 |
from fastapi import FastAPI, Request, Header, BackgroundTasks, HTTPException
|
| 7 |
from fastapi.middleware.cors import CORSMiddleware
|
|
@@ -18,11 +19,16 @@ from linebot.models import (
|
|
| 18 |
ImageMessage,
|
| 19 |
)
|
| 20 |
|
| 21 |
-
# --- 修正
|
| 22 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
| 23 |
from langchain_core.tools import tool
|
| 24 |
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# ==========================
|
| 28 |
# 環境設定與工具函式
|
|
@@ -34,10 +40,8 @@ line_bot_api = LineBotApi(os.environ.get("CHANNEL_ACCESS_TOKEN"))
|
|
| 34 |
line_handler = WebhookHandler(os.environ.get("CHANNEL_SECRET"))
|
| 35 |
|
| 36 |
user_message_history = defaultdict(list)
|
| 37 |
-
|
| 38 |
app = FastAPI()
|
| 39 |
|
| 40 |
-
# 確保 static 資料夾存在
|
| 41 |
if not os.path.exists("static"):
|
| 42 |
os.makedirs("static")
|
| 43 |
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
@@ -53,7 +57,7 @@ app.add_middleware(
|
|
| 53 |
def get_image_url_from_line(message_id):
|
| 54 |
try:
|
| 55 |
message_content = line_bot_api.get_message_content(message_id)
|
| 56 |
-
file_path = f"static/{message_id}.png"
|
| 57 |
with open(file_path, "wb") as f:
|
| 58 |
for chunk in message_content.iter_content():
|
| 59 |
f.write(chunk)
|
|
@@ -78,7 +82,6 @@ def get_previous_message(user_id):
|
|
| 78 |
def generate_and_upload_image(prompt: str) -> str:
|
| 79 |
"""根據文字提示生成圖片。"""
|
| 80 |
try:
|
| 81 |
-
# 修正模型名稱:目前最新穩定版為 imagen-3
|
| 82 |
response = genai_client.models.generate_content(
|
| 83 |
model="imagen-3.0-generate-001",
|
| 84 |
contents=prompt,
|
|
@@ -96,10 +99,9 @@ def generate_and_upload_image(prompt: str) -> str:
|
|
| 96 |
file_name = f"static/{os.urandom(8).hex()}.png"
|
| 97 |
image.save(file_name, format="PNG")
|
| 98 |
|
| 99 |
-
# 修正 URL 拼接邏輯
|
| 100 |
base_url = os.getenv("HF_SPACE", "http://localhost:7860").rstrip("/")
|
| 101 |
-
|
| 102 |
-
return
|
| 103 |
return "圖片生成失敗:模型未回傳數據。"
|
| 104 |
except Exception as e:
|
| 105 |
return f"圖片生成失敗: {e}"
|
|
@@ -110,11 +112,10 @@ def analyze_image_with_text(image_path: str, user_text: str) -> str:
|
|
| 110 |
try:
|
| 111 |
if not os.path.exists(image_path):
|
| 112 |
return "錯誤:找不到該圖片檔案。"
|
| 113 |
-
|
| 114 |
img_user = PIL.Image.open(image_path)
|
| 115 |
-
# 修正
|
| 116 |
response = genai_client.models.generate_content(
|
| 117 |
-
model="gemini-
|
| 118 |
contents=[img_user, user_text]
|
| 119 |
)
|
| 120 |
return response.text if response.text else "Gemini 沒答案!"
|
|
@@ -125,8 +126,7 @@ def analyze_image_with_text(image_path: str, user_text: str) -> str:
|
|
| 125 |
# LangChain 代理人設定
|
| 126 |
# ==========================
|
| 127 |
tools = [generate_and_upload_image, analyze_image_with_text]
|
| 128 |
-
|
| 129 |
-
llm = ChatGoogleGenerativeAI(model="gemini-3-flash-preview", temperature=0.2)
|
| 130 |
|
| 131 |
prompt_template = ChatPromptTemplate.from_messages([
|
| 132 |
("system", "你是一個強大的助理。如果生成了圖片,請直接給出 URL。"),
|
|
@@ -158,20 +158,22 @@ async def webhook(request: Request, background_tasks: BackgroundTasks, x_line_si
|
|
| 158 |
def handle_message(event):
|
| 159 |
user_id = event.source.user_id
|
| 160 |
|
| 161 |
-
|
|
|
|
| 162 |
image_path = get_image_url_from_line(event.message.id)
|
| 163 |
if image_path:
|
| 164 |
store_user_message(user_id, "image", image_path)
|
| 165 |
-
line_bot_api.reply_message(event.reply_token, TextSendMessage(text="收到圖片了!請問你想
|
| 166 |
|
| 167 |
-
|
|
|
|
| 168 |
user_text = event.message.text
|
| 169 |
previous_message = get_previous_message(user_id)
|
| 170 |
|
| 171 |
if previous_message["type"] == "image":
|
| 172 |
image_path = previous_message["content"]
|
| 173 |
-
agent_input = {"input": f"請分析
|
| 174 |
-
user_message_history[user_id].pop()
|
| 175 |
else:
|
| 176 |
agent_input = {"input": user_text}
|
| 177 |
|
|
@@ -179,25 +181,23 @@ def handle_message(event):
|
|
| 179 |
response = agent_executor.invoke(agent_input)
|
| 180 |
out = response["output"]
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', out)
|
| 186 |
-
if urls:
|
| 187 |
-
image_url = urls[0]
|
| 188 |
-
line_bot_api.reply_message(
|
| 189 |
-
event.reply_token,
|
| 190 |
-
[
|
| 191 |
-
TextSendMessage(text="這是為你生成的圖片:"),
|
| 192 |
-
ImageSendMessage(original_content_url=image_url, preview_image_url=image_url)
|
| 193 |
-
]
|
| 194 |
-
)
|
| 195 |
-
return
|
| 196 |
-
|
| 197 |
-
line_bot_api.reply_message(event.reply_token, TextSendMessage(text=out))
|
| 198 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
except Exception as e:
|
| 200 |
-
|
|
|
|
| 201 |
|
| 202 |
if __name__ == "__main__":
|
| 203 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 2 |
import io
|
| 3 |
import PIL.Image
|
| 4 |
import uvicorn
|
| 5 |
+
import re
|
| 6 |
from collections import defaultdict
|
| 7 |
from fastapi import FastAPI, Request, Header, BackgroundTasks, HTTPException
|
| 8 |
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
| 19 |
ImageMessage,
|
| 20 |
)
|
| 21 |
|
| 22 |
+
# --- 核心修正:改用絕對路徑匯入 AgentExecutor ---
|
| 23 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
| 24 |
from langchain_core.tools import tool
|
| 25 |
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 26 |
+
# 如果 langchain.agents 匯入失敗,這裡改從 .agent 模組直接抓取
|
| 27 |
+
try:
|
| 28 |
+
from langchain.agents import create_tool_calling_agent, AgentExecutor
|
| 29 |
+
except ImportError:
|
| 30 |
+
from langchain.agents.agent import AgentExecutor
|
| 31 |
+
from langchain.agents import create_tool_calling_agent
|
| 32 |
|
| 33 |
# ==========================
|
| 34 |
# 環境設定與工具函式
|
|
|
|
| 40 |
line_handler = WebhookHandler(os.environ.get("CHANNEL_SECRET"))
|
| 41 |
|
| 42 |
user_message_history = defaultdict(list)
|
|
|
|
| 43 |
app = FastAPI()
|
| 44 |
|
|
|
|
| 45 |
if not os.path.exists("static"):
|
| 46 |
os.makedirs("static")
|
| 47 |
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
|
|
| 57 |
def get_image_url_from_line(message_id):
|
| 58 |
try:
|
| 59 |
message_content = line_bot_api.get_message_content(message_id)
|
| 60 |
+
file_path = f"static/{message_id}.png"
|
| 61 |
with open(file_path, "wb") as f:
|
| 62 |
for chunk in message_content.iter_content():
|
| 63 |
f.write(chunk)
|
|
|
|
| 82 |
def generate_and_upload_image(prompt: str) -> str:
|
| 83 |
"""根據文字提示生成圖片。"""
|
| 84 |
try:
|
|
|
|
| 85 |
response = genai_client.models.generate_content(
|
| 86 |
model="imagen-3.0-generate-001",
|
| 87 |
contents=prompt,
|
|
|
|
| 99 |
file_name = f"static/{os.urandom(8).hex()}.png"
|
| 100 |
image.save(file_name, format="PNG")
|
| 101 |
|
|
|
|
| 102 |
base_url = os.getenv("HF_SPACE", "http://localhost:7860").rstrip("/")
|
| 103 |
+
# 如果在本地執行,請確保 URL 格式正確
|
| 104 |
+
return f"{base_url}/{file_name}"
|
| 105 |
return "圖片生成失敗:模型未回傳數據。"
|
| 106 |
except Exception as e:
|
| 107 |
return f"圖片生成失敗: {e}"
|
|
|
|
| 112 |
try:
|
| 113 |
if not os.path.exists(image_path):
|
| 114 |
return "錯誤:找不到該圖片檔案。"
|
|
|
|
| 115 |
img_user = PIL.Image.open(image_path)
|
| 116 |
+
# 修正:目前最新為 gemini-2.0-flash 或 1.5-flash
|
| 117 |
response = genai_client.models.generate_content(
|
| 118 |
+
model="gemini-1.5-flash",
|
| 119 |
contents=[img_user, user_text]
|
| 120 |
)
|
| 121 |
return response.text if response.text else "Gemini 沒答案!"
|
|
|
|
| 126 |
# LangChain 代理人設定
|
| 127 |
# ==========================
|
| 128 |
tools = [generate_and_upload_image, analyze_image_with_text]
|
| 129 |
+
llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.2)
|
|
|
|
| 130 |
|
| 131 |
prompt_template = ChatPromptTemplate.from_messages([
|
| 132 |
("system", "你是一個強大的助理。如果生成了圖片,請直接給出 URL。"),
|
|
|
|
| 158 |
def handle_message(event):
|
| 159 |
user_id = event.source.user_id
|
| 160 |
|
| 161 |
+
# 處理圖片訊息
|
| 162 |
+
if isinstance(event.message, ImageMessage):
|
| 163 |
image_path = get_image_url_from_line(event.message.id)
|
| 164 |
if image_path:
|
| 165 |
store_user_message(user_id, "image", image_path)
|
| 166 |
+
line_bot_api.reply_message(event.reply_token, TextSendMessage(text="收到圖片了!請問你想分析什麼?"))
|
| 167 |
|
| 168 |
+
# 處理文字訊息
|
| 169 |
+
elif isinstance(event.message, TextMessage):
|
| 170 |
user_text = event.message.text
|
| 171 |
previous_message = get_previous_message(user_id)
|
| 172 |
|
| 173 |
if previous_message["type"] == "image":
|
| 174 |
image_path = previous_message["content"]
|
| 175 |
+
agent_input = {"input": f"請分析圖片 {image_path},問題:{user_text}"}
|
| 176 |
+
user_message_history[user_id].pop()
|
| 177 |
else:
|
| 178 |
agent_input = {"input": user_text}
|
| 179 |
|
|
|
|
| 181 |
response = agent_executor.invoke(agent_input)
|
| 182 |
out = response["output"]
|
| 183 |
|
| 184 |
+
# URL 偵測邏輯
|
| 185 |
+
urls = re.findall(r'https?://[^\s<>"]+|www\.[^\s<>"]+', out)
|
| 186 |
+
image_url = next((u for u in urls if any(ext in u.lower() for ext in ['.png', '.jpg', '.jpeg'])), None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
| 188 |
+
if image_url:
|
| 189 |
+
line_bot_api.reply_message(
|
| 190 |
+
event.reply_token,
|
| 191 |
+
[
|
| 192 |
+
TextSendMessage(text="這是生成的圖片:"),
|
| 193 |
+
ImageSendMessage(original_content_url=image_url, preview_image_url=image_url)
|
| 194 |
+
]
|
| 195 |
+
)
|
| 196 |
+
else:
|
| 197 |
+
line_bot_api.reply_message(event.reply_token, TextSendMessage(text=out))
|
| 198 |
except Exception as e:
|
| 199 |
+
print(f"Agent Error: {e}")
|
| 200 |
+
line_bot_api.reply_message(event.reply_token, TextSendMessage(text="處理訊息時發生錯誤。"))
|
| 201 |
|
| 202 |
if __name__ == "__main__":
|
| 203 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|