1b2b935832
- Platform-based architecture (Windows/Linux/Mac) - Agent instance registry (agents.yaml) - Management dashboard with cross-platform monitoring - xmpp_bot with HTTP bridge + health endpoints - wechat_agent with WeChat-Hermes bridging - Platform services: ProcessGuardian, HealthProbe, APIRouter, ChannelBridge - Deployment: systemd (Linux) + PowerShell (Windows) - Monitoring: SSH+ejabberdctl for cross-platform presence
117 lines
4.5 KiB
Python
117 lines
4.5 KiB
Python
"""
|
|
VoceChat Webhook → Session Bridge.
|
|
|
|
Receives VoceChat webhook events, forwards to opencode serve session,
|
|
captures AI reply, and sends it back to the VC group.
|
|
"""
|
|
import os, sys, json, time, threading, urllib.request
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
from chat_bridge import SessionBridge
|
|
from session_router import SessionRouter
|
|
from proc_guard import guard as _proc_guard
|
|
|
|
# ── PID lock — prevent duplicate instances ──
|
|
_lock = _proc_guard("vc_webhook")
|
|
if not _lock.ok:
|
|
print(_lock.message, flush=True)
|
|
sys.exit(1)
|
|
|
|
# ── Config ────────────────────────────────────────────────
|
|
SERVE_URL = "http://127.0.0.1:4096"
|
|
ATTACH_SESSION = "ses_1d95d15c4ffehQaZ6hrbIbak5k"
|
|
|
|
VC_API = "http://192.168.1.246:3009"
|
|
VC_BOT_KEY = os.environ.get(
|
|
"VC_BOT_KEY",
|
|
"5b2bd4ce2e0395503b4849a69a47a4e2a3f7aa81af242d2666b31e7519589c477b22756964223a362c226e6f6e6365223a2252576a744643384947476f41414141417a4c6a6e355a7a484731723839494b59227d")
|
|
VC_SELF_UID = 6
|
|
|
|
SPEAKERS = {1: "老爸", 5: "莫荷", VC_SELF_UID: "莫笑笑"}
|
|
|
|
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "logs")
|
|
LOG_FILE = os.path.join(LOG_DIR, "vc_webhook.log")
|
|
os.makedirs(LOG_DIR, exist_ok=True)
|
|
|
|
# ── Logging ───────────────────────────────────────────────
|
|
def log(msg: str):
|
|
with open(LOG_FILE, "a", encoding="utf-8") as f:
|
|
f.write(f"{time.strftime('%H:%M:%S')} {msg}\n")
|
|
|
|
# ── Router ────────────────────────────────────────────────
|
|
_router = SessionRouter(
|
|
bridge=SessionBridge(session_id=ATTACH_SESSION, serve_url=SERVE_URL),
|
|
default_session=ATTACH_SESSION,
|
|
)
|
|
|
|
|
|
def _speaker(uid: int) -> str:
|
|
return SPEAKERS.get(uid, f"用户{uid}")
|
|
|
|
|
|
def _send_to_vc_group(gid: int, text: str):
|
|
"""Post reply to a VoceChat group via Bot API."""
|
|
url = f"{VC_API}/api/bot/send_to_group/{gid}"
|
|
headers = {"X-API-Key": VC_BOT_KEY, "Content-Type": "text/plain"}
|
|
urllib.request.urlopen(
|
|
urllib.request.Request(url, data=text.encode("utf-8"), headers=headers),
|
|
timeout=10)
|
|
|
|
|
|
def _process_message(content: str, sender: int, data: dict):
|
|
"""VC message → router → reply → VC."""
|
|
if sender == VC_SELF_UID:
|
|
return
|
|
log(f"router.route: sender={sender} content={content[:50]}...")
|
|
reply = _router.route("vc", str(sender), content)
|
|
if reply:
|
|
log(f"reply[:80]={reply[:80]}")
|
|
gid = data.get("target", {}).get("gid", 0)
|
|
if gid:
|
|
try:
|
|
_send_to_vc_group(gid, reply)
|
|
log(f"Replied to VC group {gid}")
|
|
except Exception as e:
|
|
log(f"VC reply ERR: {e}")
|
|
else:
|
|
log("no text reply in time")
|
|
|
|
|
|
# ── HTTP Handler ──────────────────────────────────────────
|
|
class WebhookHandler(BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
self.wfile.write(b"ok")
|
|
|
|
def do_POST(self):
|
|
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
|
|
log(f"RAW: {body.decode('utf-8', errors='replace')[:300]}")
|
|
try:
|
|
data = json.loads(body)
|
|
if data.get("type") in ("new_message", "chat"):
|
|
detail = data.get("detail", {})
|
|
content = detail.get("content", "") or data.get("content", "")
|
|
sender = data.get("from_uid", 0)
|
|
log(f"MSG uid={sender}: {str(content)[:80]}")
|
|
threading.Thread(
|
|
target=_process_message,
|
|
args=(str(content), sender, data),
|
|
daemon=True,
|
|
).start()
|
|
except Exception as e:
|
|
log(f"ERR: {e}")
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
|
|
def log_message(self, *args):
|
|
pass
|
|
|
|
|
|
# ── Main ──────────────────────────────────────────────────
|
|
if __name__ == "__main__":
|
|
server = HTTPServer(("0.0.0.0", 8010), WebhookHandler)
|
|
log("VC webhook listening on :8010")
|
|
server.serve_forever()
|