qwen_agent/skills/developing/mineru/scripts/sinks/wecom.py
2026-06-05 14:35:17 +08:00

61 lines
2.4 KiB
Python

"""WeCom (企业微信 / WeChat Work) sink — send parsed Markdown as an app message.
WeCom apps deliver content via the message-send API. The native ingestion path
is a ``markdown`` message from a self-built app: first an access token is fetched
with the corp id + secret, then the message is posted. WeCom's markdown is a
limited subset with a 2048-byte content cap and no inline images, so the body is
truncated to fit.
Docs: https://developer.work.weixin.qq.com/document/path/90236 (message/send),
https://developer.work.weixin.qq.com/document/path/91039 (gettoken).
"""
from __future__ import annotations
from . import _http
from .base import ParsedDoc, Sink, SinkError, SinkResult, register
TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
SEND_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
@register
class WeComSink(Sink):
name = "wecom"
aliases = ("企业微信", "wechatwork")
requires = ("WECOM_CORPID", "WECOM_CORPSECRET", "WECOM_AGENTID")
label = "WeCom app markdown (企业微信)"
def deliver(self, doc: ParsedDoc) -> SinkResult:
corpid = self.env("WECOM_CORPID")
secret = self.env("WECOM_CORPSECRET")
agentid = self.env("WECOM_AGENTID")
touser = self.env("WECOM_TOUSER", "@all")
# Step 1: fetch an access token.
token_url = f"{TOKEN_URL}?corpid={corpid}&corpsecret={secret}"
status, parsed = _http.request_json("GET", token_url)
if parsed.get("errcode") not in (0, None) or not parsed.get("access_token"):
raise SinkError(parsed.get("errmsg") or f"WeCom token fetch failed: {parsed}")
token = parsed["access_token"]
# Step 2: send the markdown message.
send_url = f"{SEND_URL}?access_token={token}"
payload = {
"touser": touser,
"msgtype": "markdown",
"agentid": int(agentid),
"markdown": {"content": doc.markdown[:2048]},
}
status, parsed = _http.request_json("POST", send_url, payload=payload)
if parsed.get("errcode") not in (0, None):
raise SinkError(parsed.get("errmsg") or f"WeCom send failed: {parsed}")
return SinkResult(
sink=self.name,
ok=True,
url=None,
detail="markdown notification (WeCom markdown is a limited subset, "
"2048-byte cap, no inline images)",
)