asemxin commited on
Commit
19bb594
·
1 Parent(s): 4dca48a

fix: image_daemon 接管飞书交互,禁用 OpenClaw 飞书插件

Browse files
Files changed (4) hide show
  1. Dockerfile +3 -2
  2. entrypoint.sh +1 -1
  3. image_daemon.py +75 -16
  4. test_api.py +21 -0
Dockerfile CHANGED
@@ -15,8 +15,9 @@ RUN npm install -g openclaw@latest
15
  RUN mkdir -p /root/.openclaw/workspace /root/.openclaw/extensions /root/.openclaw/credentials /root/.openclaw/skills
16
 
17
  # 安装飞书插件
18
- RUN openclaw plugins install feishu-openclaw 2>/dev/null || true
19
- RUN cd /root/.openclaw/extensions/feishu-openclaw && npm install @sinclair/typebox 2>/dev/null || true
 
20
 
21
  # 复制文件
22
  COPY SOUL.md /root/.openclaw/workspace/SOUL.md
 
15
  RUN mkdir -p /root/.openclaw/workspace /root/.openclaw/extensions /root/.openclaw/credentials /root/.openclaw/skills
16
 
17
  # 安装飞书插件
18
+ # 安装飞书插件 (禁用以避免 WebSocket 竞争)
19
+ # RUN openclaw plugins install feishu-openclaw 2>/dev/null || true
20
+ # RUN cd /root/.openclaw/extensions/feishu-openclaw && npm install @sinclair/typebox 2>/dev/null || true
21
 
22
  # 复制文件
23
  COPY SOUL.md /root/.openclaw/workspace/SOUL.md
entrypoint.sh CHANGED
@@ -42,7 +42,7 @@ cat > "$OPENCLAW_DIR/openclaw.json" << JSONEOF
42
  },
43
  "channels": {
44
  "feishu": {
45
- "enabled": true,
46
  "appId": "${FEISHU_APP_ID}",
47
  "appSecret": "${FEISHU_APP_SECRET}"
48
  }
 
42
  },
43
  "channels": {
44
  "feishu": {
45
+ "enabled": false,
46
  "appId": "${FEISHU_APP_ID}",
47
  "appSecret": "${FEISHU_APP_SECRET}"
48
  }
image_daemon.py CHANGED
@@ -10,6 +10,11 @@ FEISHU_BASE = "https://open.feishu.cn/open-apis"
10
  APP_ID = os.environ.get("FEISHU_APP_ID", "")
11
  APP_SECRET = os.environ.get("FEISHU_APP_SECRET", "")
12
 
 
 
 
 
 
13
  # ---------- 日志 ----------
14
  def log(msg):
15
  ts = time.strftime("%H:%M:%S")
@@ -176,6 +181,55 @@ def handle_image_message(message_id, chat_id, image_key):
176
  f.write(img_data)
177
  log(f"⚠️ 图床全部失败,本地保存: {path}")
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  # ---------- 事件处理 ----------
180
  def on_message_receive(data):
181
  """im.message.receive_v1 事件回调"""
@@ -185,32 +239,37 @@ def on_message_receive(data):
185
  sender = event.sender
186
 
187
  msg_type = message.message_type
188
- # 调试:打印所有收到的消息类型
189
- log(f"📨 WebSocket 收到消息: type={msg_type}, msg_id={message.message_id}")
190
-
191
  msg_id = message.message_id
192
  chat_id = message.chat_id
193
  sender_type = getattr(sender, 'sender_type', '') if sender else ''
194
 
195
- # 只处理用户发的图片
196
  if sender_type == "app":
197
  return
198
- if msg_type != "image":
 
 
 
 
 
 
 
 
 
 
 
 
199
  return
200
 
201
- content = json.loads(message.content)
202
- image_key = content.get("image_key", "")
203
- if not image_key:
204
- log(f"⚠️ 图片消息但无 image_key: {message.content}")
 
 
 
205
  return
206
 
207
- log(f"📨 实时收到图片消息: msg_id={msg_id[:16]}..., image_key={image_key[:20]}...")
208
-
209
- # 在新线程中处理,避免阻塞事件循环
210
- t = threading.Thread(target=handle_image_message, args=(msg_id, chat_id, image_key))
211
- t.daemon = True
212
- t.start()
213
-
214
  except Exception as e:
215
  log(f"❌ on_message_receive 异常: {type(e).__name__}: {e}")
216
  import traceback
 
10
  APP_ID = os.environ.get("FEISHU_APP_ID", "")
11
  APP_SECRET = os.environ.get("FEISHU_APP_SECRET", "")
12
 
13
+ # LLM 配置
14
+ API_BASE_URL = os.environ.get("API_BASE_URL", "https://asem12345-cliproxyapi.hf.space/v1")
15
+ API_KEY = os.environ.get("API_KEY", "")
16
+ MODEL_NAME = os.environ.get("MODEL_NAME", "gemini-3-flash")
17
+
18
  # ---------- 日志 ----------
19
  def log(msg):
20
  ts = time.strftime("%H:%M:%S")
 
181
  f.write(img_data)
182
  log(f"⚠️ 图床全部失败,本地保存: {path}")
183
 
184
+ # ---------- LLM 对话 ----------
185
+ def chat_with_llm(user_text):
186
+ """调用 LLM API 获取回复"""
187
+ if not API_KEY:
188
+ log("❌ API_KEY 未设置,无法对话")
189
+ return "抱歉,我的大脑连接中断了 (API_KEY missing)"
190
+
191
+ try:
192
+ url = f"{API_BASE_URL}/chat/completions"
193
+ headers = {
194
+ "Authorization": f"Bearer {API_KEY}",
195
+ "Content-Type": "application/json"
196
+ }
197
+ payload = {
198
+ "model": MODEL_NAME,
199
+ "messages": [
200
+ {"role": "system", "content": "You are MoltBot, a helpful AI assistant."},
201
+ {"role": "user", "content": user_text}
202
+ ],
203
+ "stream": False
204
+ }
205
+ log(f"🤖 调用 LLM: {user_text[:50]}...")
206
+ resp = requests.post(url, headers=headers, json=payload, timeout=60)
207
+
208
+ if resp.status_code == 200:
209
+ data = resp.json()
210
+ reply = data["choices"][0]["message"]["content"]
211
+ log(f"🤖 LLM 回复: {reply[:50]}...")
212
+ return reply
213
+ else:
214
+ log(f"❌ LLM 错误 {resp.status_code}: {resp.text}")
215
+ return f"思考时遇到错误 ({resp.status_code})"
216
+ except Exception as e:
217
+ log(f"❌ LLM 异常: {e}")
218
+ return f"大脑短路了: {e}"
219
+
220
+ # ---------- 处理文本消息 ----------
221
+ def handle_text_message(message_id, chat_id, text):
222
+ """LLM -> 发送"""
223
+ token = get_token()
224
+ if not token:
225
+ return
226
+
227
+ # 简单防重:也许以后需要
228
+ # 这里直接调用 LLM
229
+ reply = chat_with_llm(text)
230
+ if reply:
231
+ send_text(token, chat_id, reply)
232
+
233
  # ---------- 事件处理 ----------
234
  def on_message_receive(data):
235
  """im.message.receive_v1 事件回调"""
 
239
  sender = event.sender
240
 
241
  msg_type = message.message_type
 
 
 
242
  msg_id = message.message_id
243
  chat_id = message.chat_id
244
  sender_type = getattr(sender, 'sender_type', '') if sender else ''
245
 
246
+ # 过滤
247
  if sender_type == "app":
248
  return
249
+
250
+ content_json = json.loads(message.content)
251
+
252
+ # 调试
253
+ log(f"📨 WebSocket 收到消息: type={msg_type}, msg_id={msg_id}")
254
+
255
+ # 图片消息
256
+ if msg_type == "image":
257
+ image_key = content_json.get("image_key", "")
258
+ if image_key:
259
+ t = threading.Thread(target=handle_image_message, args=(msg_id, chat_id, image_key))
260
+ t.daemon = True
261
+ t.start()
262
  return
263
 
264
+ # 文本消息
265
+ if msg_type == "text":
266
+ text = content_json.get("text", "")
267
+ if text:
268
+ t = threading.Thread(target=handle_text_message, args=(msg_id, chat_id, text))
269
+ t.daemon = True
270
+ t.start()
271
  return
272
 
 
 
 
 
 
 
 
273
  except Exception as e:
274
  log(f"❌ on_message_receive 异常: {type(e).__name__}: {e}")
275
  import traceback
test_api.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ try:
5
+ # 尝试 OpenAI 格式
6
+ resp = requests.post("http://127.0.0.1:18789/v1/chat/completions",
7
+ json={
8
+ "model": "default",
9
+ "messages": [{"role": "user", "content": "hello"}]
10
+ }, timeout=5)
11
+ print(f"POST /v1/chat/completions: {resp.status_code}")
12
+ print(resp.text[:200])
13
+ except Exception as e:
14
+ print(f"POST /v1/chat/completions error: {e}")
15
+
16
+ try:
17
+ # 尝试 OpenClaw 原生格式 (如果有)
18
+ resp = requests.get("http://127.0.0.1:18789/health", timeout=5)
19
+ print(f"GET /health: {resp.status_code}")
20
+ except Exception as e:
21
+ print(f"GET /health error: {e}")