ForcePilot/backend/package/yuxi/channel/extensions/zalo/monitor.py
Kris 5946478772 feat(channel): 添加小红书、XMPP、元宝和 Zalo 渠道扩展
新增小红书、XMPP、元宝、Zalo 四个渠道扩展。

小红书渠道扩展主要模块:config, gateway, webhook, outbound, streaming, pairing, security, dedupe, media, status, window

XMPP 渠道扩展主要模块:plugin, config, gateway, outbound, streaming, pairing, security, dedupe, accounts, commands, muc, rate_limiter, stanza_utils, status, monitor

元宝渠道扩展主要模块:plugin, client, config_schema, gateway, outbound(chunk/queue/transport), inbound(dispatcher), streaming, pairing, security, accounts, actions, commands, codec(biz/conn), session, shared, utils

Zalo 渠道扩展主要模块:api, config, gateway, webhook, outbound, pairing, security, session, polling, monitor, status
2026-05-21 12:04:05 +08:00

107 lines
3.4 KiB
Python

from __future__ import annotations
import logging
from datetime import datetime, UTC
from yuxi.channel.extensions.zalo.types import ZaloAccount, ZaloMessage
logger = logging.getLogger(__name__)
def parse_update_to_unified(update: dict, account: ZaloAccount | dict) -> dict | None:
event_name = update.get("event_name", "")
message = update.get("message", {})
if not message:
logger.debug("Zalo update without message field, skipping")
return None
sender = message.get("from", {})
if sender.get("is_bot"):
logger.debug("Zalo skipping bot message from %s", sender.get("id"))
return None
chat = message.get("chat", {})
zm = ZaloMessage(
event_name=event_name,
message_id=message.get("message_id", ""),
from_id=sender.get("id", ""),
from_name=sender.get("name", ""),
from_display_name=sender.get("display_name", sender.get("name", "")),
from_avatar=sender.get("avatar", ""),
chat_id=chat.get("id", ""),
chat_type=chat.get("chat_type", "PRIVATE"),
date=message.get("date", 0),
text=message.get("text", ""),
photo_url=message.get("photo", ""),
caption=message.get("caption", ""),
)
return _build_unified_message(zm, account, message)
def parse_updates_to_unified(updates: list[dict], account: ZaloAccount | dict) -> list[dict]:
results = []
for update in updates:
unified = parse_update_to_unified(update, account)
if unified:
results.append(unified)
return results
def _build_unified_message(zm: ZaloMessage, account: ZaloAccount | dict, message: dict) -> dict | None:
account_id = account.get("account_id", "default") if isinstance(account, dict) else account.account_id
event_name = zm.event_name
if event_name == "message.text.received":
message_type = "TEXT"
content = zm.text
elif event_name == "message.image.received":
message_type = "IMAGE"
content = zm.caption or "[图片]"
elif event_name == "message.sticker.received":
message_type = "STICKER"
sticker_id = message.get("sticker", "")
content = f"[贴纸 {sticker_id}]"
elif event_name == "message.unsupported.received":
logger.debug("Zalo unsupported message received, skipping")
return None
else:
logger.debug("Zalo unknown event: %s, skipping", event_name)
return None
is_group = zm.chat_type == "GROUP"
timestamp = None
if zm.date:
timestamp = datetime.fromtimestamp(zm.date, tz=UTC)
media_urls = [zm.photo_url] if zm.photo_url else []
if message_type == "STICKER":
sticker_url = message.get("url", "")
if sticker_url:
media_urls.append(sticker_url)
return {
"msg_id": zm.message_id,
"channel_type": "zalo",
"account_id": account_id,
"content": content,
"message_type": message_type,
"media_urls": media_urls,
"sender": {
"id": zm.from_id,
"display_name": zm.from_display_name or zm.from_name,
"kind": "GROUP" if is_group else "DIRECT",
},
"group": {"id": zm.chat_id} if is_group else None,
"timestamp": timestamp,
"mentioned_ids": [],
"reply_to_id": None,
"raw_payload": {
"event_name": event_name,
"text": zm.text,
"photo_url": zm.photo_url,
"caption": zm.caption,
},
}