-
Notifications
You must be signed in to change notification settings - Fork 113
Expand file tree
/
Copy pathwecomapp.py
More file actions
108 lines (92 loc) · 4.45 KB
/
wecomapp.py
File metadata and controls
108 lines (92 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import asyncio, os, sys, threading
from collections import deque
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from agentmain import GeneraticAgent
from chatapp_common import AgentChatMixin, ensure_single_instance, public_access, redirect_log, require_runtime, split_text
from llmcore import mykeys
try:
from wecom_aibot_sdk import WSClient, generate_req_id
except Exception:
print("Please install wecom_aibot_sdk to use WeCom: pip install wecom_aibot_sdk")
sys.exit(1)
agent = GeneraticAgent(); agent.verbose = False
BOT_ID = str(mykeys.get("wecom_bot_id", "") or "").strip()
SECRET = str(mykeys.get("wecom_secret", "") or "").strip()
WELCOME = str(mykeys.get("wecom_welcome_message", "") or "").strip()
ALLOWED = {str(x).strip() for x in mykeys.get("wecom_allowed_users", []) if str(x).strip()}
PROCESSED_IDS, USER_TASKS = deque(maxlen=1000), {}
class WeComApp(AgentChatMixin):
label, source, split_limit = "WeCom", "wecom", 1200
def __init__(self):
super().__init__(agent, USER_TASKS)
self.client, self.chat_frames = None, {}
async def send_text(self, chat_id, content):
if not self.client or chat_id not in self.chat_frames:
if chat_id not in self.chat_frames:
print(f"[WeCom] no frame found for chat: {chat_id}")
return
frame = self.chat_frames[chat_id]
for part in split_text(content, self.split_limit):
await self.client.reply_stream(frame, generate_req_id("stream"), part, finish=True)
async def on_text(self, frame):
try:
body = frame.body if hasattr(frame, "body") else frame.get("body", frame) if isinstance(frame, dict) else {}
if not isinstance(body, dict):
return
msg_id = body.get("msgid") or f"{body.get('chatid', '')}_{body.get('sendertime', '')}"
if msg_id in PROCESSED_IDS:
return
PROCESSED_IDS.append(msg_id)
from_info = body.get("from", {}) if isinstance(body.get("from", {}), dict) else {}
sender_id = str(from_info.get("userid", "") or "unknown")
chat_id = str(body.get("chatid", "") or sender_id)
content = str((body.get("text", {}) or {}).get("content", "") or "").strip()
if not content:
return
if not public_access(ALLOWED) and sender_id not in ALLOWED:
print(f"[WeCom] unauthorized user: {sender_id}")
return
self.chat_frames[chat_id] = frame
print(f"[WeCom] message from {sender_id}: {content}")
if content.startswith("/"):
return await self.handle_command(chat_id, content)
asyncio.create_task(self.run_agent(chat_id, content))
except Exception:
import traceback
print("[WeCom] handle_message error")
traceback.print_exc()
async def on_enter_chat(self, frame):
if WELCOME and self.client:
try:
await self.client.reply_welcome(frame, {"msgtype": "text", "text": {"content": WELCOME}})
except Exception as e:
print(f"[WeCom] welcome error: {e}")
async def on_connected(self, frame):
print("[WeCom] connected")
async def on_authenticated(self, frame):
print("[WeCom] authenticated")
async def on_disconnected(self, frame):
print("[WeCom] disconnected")
async def on_error(self, frame):
print(f"[WeCom] error: {frame}")
async def start(self):
self.client = WSClient({"bot_id": BOT_ID, "secret": SECRET, "reconnect_interval": 1000, "max_reconnect_attempts": -1, "heartbeat_interval": 30000})
for event, handler in {
"connected": self.on_connected,
"authenticated": self.on_authenticated,
"disconnected": self.on_disconnected,
"error": self.on_error,
"message.text": self.on_text,
"event.enter_chat": self.on_enter_chat,
}.items():
self.client.on(event, handler)
print("[WeCom] bot starting...")
await self.client.connect_async()
while True:
await asyncio.sleep(1)
if __name__ == "__main__":
_LOCK_SOCK = ensure_single_instance(19529, "WeCom")
require_runtime(agent, "WeCom", wecom_bot_id=BOT_ID, wecom_secret=SECRET)
redirect_log(__file__, "wecomapp.log", "WeCom", ALLOWED)
threading.Thread(target=agent.run, daemon=True).start()
asyncio.run(WeComApp().start())