asemxin commited on
Commit ·
957c1e7
1
Parent(s): bfc462f
feat: Vision API 图片识别,大师看图说法
Browse files- image_daemon.py +63 -7
image_daemon.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
通过 lark-oapi SDK 的 WebSocket 长连接实时接收消息事件,
|
| 5 |
检测图片消息后下载、上传到图床、回复 URL。
|
| 6 |
"""
|
| 7 |
-
import os, sys, json, time, requests, threading
|
| 8 |
|
| 9 |
FEISHU_BASE = "https://open.feishu.cn/open-apis"
|
| 10 |
APP_ID = os.environ.get("FEISHU_APP_ID", "")
|
|
@@ -155,9 +155,47 @@ def send_text(token, chat_id, text):
|
|
| 155 |
log(f"❌ 发送消息失败 (code={code}): {data.get('msg', '')}")
|
| 156 |
return data
|
| 157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
# ---------- 处理图片消息 ----------
|
| 159 |
def handle_image_message(message_id, chat_id, image_key):
|
| 160 |
-
"""下载 → 上传 → 发送"""
|
| 161 |
token = get_token()
|
| 162 |
if not token:
|
| 163 |
log("❌ 无法获取 token,跳过")
|
|
@@ -170,14 +208,32 @@ def handle_image_message(message_id, chat_id, image_key):
|
|
| 170 |
if not img_data:
|
| 171 |
return
|
| 172 |
|
| 173 |
-
log(f"📥 {len(img_data)} bytes, 上传中...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
-
# 上传
|
| 176 |
-
url = upload_image(img_data)
|
| 177 |
if url:
|
| 178 |
log(f"✅ {url}")
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
| 181 |
result = send_text(token, chat_id, reply)
|
| 182 |
log(f"📤 已发送 (code={result.get('code', '?')})")
|
| 183 |
else:
|
|
|
|
| 4 |
通过 lark-oapi SDK 的 WebSocket 长连接实时接收消息事件,
|
| 5 |
检测图片消息后下载、上传到图床、回复 URL。
|
| 6 |
"""
|
| 7 |
+
import os, sys, json, time, requests, threading, base64
|
| 8 |
|
| 9 |
FEISHU_BASE = "https://open.feishu.cn/open-apis"
|
| 10 |
APP_ID = os.environ.get("FEISHU_APP_ID", "")
|
|
|
|
| 155 |
log(f"❌ 发送消息失败 (code={code}): {data.get('msg', '')}")
|
| 156 |
return data
|
| 157 |
|
| 158 |
+
# ---------- Vision 图片分析 ----------
|
| 159 |
+
def analyze_image_with_vision(img_data):
|
| 160 |
+
"""将图片 base64 传给 LLM,由大师以人行佛教视角描述"""
|
| 161 |
+
if not API_KEY:
|
| 162 |
+
return None
|
| 163 |
+
try:
|
| 164 |
+
b64 = base64.b64encode(img_data).decode("utf-8")
|
| 165 |
+
soul = _soul_prompt or "You are a helpful assistant."
|
| 166 |
+
prompt = (
|
| 167 |
+
"这位信徒发来了一张图片,请以你的风格阅览这张图片,它占据了你的视野。"
|
| 168 |
+
"简要阐述你的感悟,200字以内,不必报平就班。"
|
| 169 |
+
)
|
| 170 |
+
payload = {
|
| 171 |
+
"model": MODEL_NAME,
|
| 172 |
+
"messages": [{
|
| 173 |
+
"role": "user",
|
| 174 |
+
"content": [
|
| 175 |
+
{"type": "text", "text": soul + "\n\n---\n\n" + prompt},
|
| 176 |
+
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}}
|
| 177 |
+
]
|
| 178 |
+
}],
|
| 179 |
+
"max_tokens": 300,
|
| 180 |
+
"stream": False
|
| 181 |
+
}
|
| 182 |
+
resp = requests.post(
|
| 183 |
+
f"{API_BASE_URL}/chat/completions",
|
| 184 |
+
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
|
| 185 |
+
json=payload, timeout=30
|
| 186 |
+
)
|
| 187 |
+
if resp.status_code == 200:
|
| 188 |
+
reply = resp.json()["choices"][0]["message"]["content"]
|
| 189 |
+
log(f"📸 Vision 分析完成: {reply[:60]}...")
|
| 190 |
+
return reply
|
| 191 |
+
log(f"⚠️ Vision API 失败 ({resp.status_code}),跳过描述")
|
| 192 |
+
except Exception as e:
|
| 193 |
+
log(f"⚠️ Vision 异常: {e}")
|
| 194 |
+
return None
|
| 195 |
+
|
| 196 |
# ---------- 处理图片消息 ----------
|
| 197 |
def handle_image_message(message_id, chat_id, image_key):
|
| 198 |
+
"""下载 → Vision分析 → 上传 → 发送"""
|
| 199 |
token = get_token()
|
| 200 |
if not token:
|
| 201 |
log("❌ 无法获取 token,跳过")
|
|
|
|
| 208 |
if not img_data:
|
| 209 |
return
|
| 210 |
|
| 211 |
+
log(f"📥 {len(img_data)} bytes, 上传+分析中...")
|
| 212 |
+
|
| 213 |
+
# 并行:Vision分析 + 上传图床
|
| 214 |
+
vision_result = [None]
|
| 215 |
+
url_result = [None]
|
| 216 |
+
|
| 217 |
+
def do_vision():
|
| 218 |
+
vision_result[0] = analyze_image_with_vision(img_data)
|
| 219 |
+
|
| 220 |
+
def do_upload():
|
| 221 |
+
url_result[0] = upload_image(img_data)
|
| 222 |
+
|
| 223 |
+
t1 = threading.Thread(target=do_vision)
|
| 224 |
+
t2 = threading.Thread(target=do_upload)
|
| 225 |
+
t1.start(); t2.start()
|
| 226 |
+
t1.join(); t2.join()
|
| 227 |
+
|
| 228 |
+
url = url_result[0]
|
| 229 |
+
vision = vision_result[0]
|
| 230 |
|
|
|
|
|
|
|
| 231 |
if url:
|
| 232 |
log(f"✅ {url}")
|
| 233 |
+
if vision:
|
| 234 |
+
reply = f"✅ 图片已转存:\n{url}\n\n{vision}"
|
| 235 |
+
else:
|
| 236 |
+
reply = f"✅ 图片已转存:\n{url}"
|
| 237 |
result = send_text(token, chat_id, reply)
|
| 238 |
log(f"📤 已发送 (code={result.get('code', '?')})")
|
| 239 |
else:
|