Files
workphone-sdk/sdk/scripts/gen_integration_manifest.py
Manus AI 9c30320826 feat(接口): 四端可直调·模块化接口能力清单(自动生成)
实时拉 skill-registry(9平台/49模块/211动作)生成清单,按平台×模块×动作组织+四端入口矩阵+连接方案切换;真机只读复验 group20/tag323/contacts50。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 12:55:58 +08:00

172 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
四端可直调·模块化接口能力清单 生成器
从运行中的 SDK 实时拉取 skill-registry211 动作 / 49 模块 / 9 平台),
生成模块化、可直读的接口能力清单 Markdown供存客宝 / 触客宝 / AI数智员工 /
SuperAdmin 直接对接判断「哪些能力可直调、走什么通道、经哪个 BFF/SDK 路径」。
- 不改任何兄弟仓库代码;只输出工作手机侧文档。
- 真源GET /api/v3/ai/brain/skill-registrylive
- 用法python3 sdk/scripts/gen_integration_manifest.py [--base http://127.0.0.1:8899]
输出:开发文档/5、接口/01-规范与统一层/四端可直调接口能力清单.md
"""
from __future__ import annotations
import argparse
import datetime
import json
import os
import sys
import urllib.request
ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
OUT = os.path.join(ROOT, "开发文档", "5、接口", "01-规范与统一层", "四端可直调接口能力清单.md")
# 平台 → 默认执行通道 + 四端推荐入口(不改对方代码,全部 HTTP
PLATFORM_CHANNEL = {
"wechat": ("Frida Hook / u2兜底", "/api/v3/message/* friend/* group/* tag/* moments/* + hook/execute"),
"douyin": ("execute-scriptAI Brain", "/api/v3/ai/brain/execute-script (script=douyin)"),
"xhs": ("execute-scriptAI Brain", "/api/v3/ai/brain/execute-script (script=xhs)"),
"xianyu": ("execute-scriptAI Brain", "/api/v3/ai/brain/execute-script (script=xianyu)"),
"soul": ("execute-scriptAI Brain", "/api/v3/ai/brain/execute-script (script=soul)"),
"system": ("Agent 系统能力", "/api/v3/devices/{id}/* "),
"hook": ("Hook 统一执行", "/api/v3/hook/execute"),
"ai_brain":("AI 中台编排", "/api/v3/ai/brain/* · /api/v3/devices/{id}/ai/*"),
"anti_ban":("防封守护", "/api/v3/anti-ban/*"),
}
# 四端可直调矩阵(来自需求 §3.8 真源;纯文档约定,不改对方代码)
FOUR_END = [
("存客宝 H5 (:3100)", "经存客宝 BFF /v1/workphone/* 或联调直连 :8899", "发消息/群发/加好友/朋友圈/标签/线索/状态/中台 Skill"),
("触客宝 (:3101)", "必经存客宝 BFF同域 JWT", "message/send · messages/list · moments/post · agent/execute"),
("AI数智员工 (:3104)", "经存客宝 OpenPlatform / proxy不直连 :8899", "设备状态/截图/终端绑定 + proxy→execute-script 多平台控机"),
("SuperAdmin (:3103)", "只读聚合 + 连接方案切换主控台", "GET /devices · status · connection/provider/switch"),
]
def fetch_registry(base: str) -> dict:
url = base.rstrip("/") + "/api/v3/ai/brain/skill-registry"
try:
with urllib.request.urlopen(url, timeout=10) as r:
return json.loads(r.read().decode())
except Exception as e: # 离线回退到缓存
cache = os.path.join(ROOT, "sdk", "tmp", "manifest_20260530", "skill_registry.json")
if os.path.exists(cache):
sys.stderr.write(f"[warn] live 拉取失败({e}),用缓存 {cache}\n")
return json.load(open(cache, encoding="utf-8"))
raise
def render(reg: dict, base: str) -> str:
data = reg["data"]
summary = data.get("summary", {})
skills = data.get("skills", {})
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
L = []
L.append("---")
L.append("tags: [工作手机, 接口, 四端对接, 能力清单, 自动生成]")
L.append("doc-type: 索引")
L.append("layer: 5、接口/01-规范与统一层")
L.append('parent: "[[5、接口/README|5、接口]]"')
L.append("obsidian-color: \"#0277BD\"")
L.append("---\n")
L.append("# 四端可直调 · 模块化接口能力清单")
L.append("")
L.append(f"> **自动生成**(勿手改):`python3 sdk/scripts/gen_integration_manifest.py` ")
L.append(f"> **真源**`GET {base}/api/v3/ai/brain/skill-registry`live · **生成时间**{now} ")
L.append("> **铁律**:四端**只调 HTTP**;工作手机**不改**存客宝/触客宝/AI数智员工/SuperAdmin 代码;缺口走 COORD 或 `sdk/proxy` 透传。")
L.append("")
L.append("## 〇、总览")
L.append("")
L.append("| 维度 | 数量 |")
L.append("|:---|:---:|")
L.append(f"| 平台skill | {summary.get('total_skills', len(skills))} |")
L.append(f"| 功能模块 | {summary.get('total_modules', '')} |")
L.append(f"| 动作action总计 | {summary.get('total_actions', '')} |")
L.append(f"| 平台业务动作 | {summary.get('platform_actions', '')} |")
L.append("")
L.append("**通道图例**`Frida Hook`=设备本机 Frida RPC微信主通道· `execute-script`=AI Brain 多平台脚本 · `u2`=UI 自动化兜底 · `companion`=设备端无障碍/广播模块(资料/红包等需 APK 模块或测试号)。")
L.append("")
# 四端入口矩阵
L.append("## 一、四端入口矩阵(不改对方代码)")
L.append("")
L.append("| 端 | 调用方式 | 典型可直调能力 |")
L.append("|:---|:---|:---|")
for end, how, caps in FOUR_END:
L.append(f"| **{end}** | {how} | {caps} |")
L.append("")
L.append("> 连接方案切换(超管主控台):`POST /api/v3/connection/provider/switch`jiqing/aochuang/legacy/custom_*)· 列表 `GET /api/v3/connection/providers`。")
L.append("")
# 平台 → 模块 → 动作
L.append("## 二、平台 × 模块 × 动作(实时)")
L.append("")
for plat, sk in skills.items():
ch, entry = PLATFORM_CHANNEL.get(plat, ("", ""))
name = sk.get("name", plat) if isinstance(sk, dict) else plat
pkg = sk.get("package", "") if isinstance(sk, dict) else ""
mods = sk.get("modules", {}) if isinstance(sk, dict) else {}
total = sum(len(v) if isinstance(v, (list, dict)) else 0 for v in mods.values()) if isinstance(mods, dict) else 0
L.append(f"### {name} `{plat}`")
L.append("")
L.append(f"- **包名**`{pkg or ''}` · **动作数**{total} · **默认通道**{ch}")
L.append(f"- **统一入口**`{entry}`")
L.append("")
if isinstance(mods, dict) and mods:
L.append("| 模块 | 动作数 | 动作action |")
L.append("|:---|:---:|:---|")
for mk, acts in mods.items():
names = acts if isinstance(acts, list) else (acts.get("actions", []) if isinstance(acts, dict) else [])
disp = " · ".join(f"`{a}`" for a in names) if names else ""
L.append(f"| {mk} | {len(names)} | {disp} |")
L.append("")
# 统一调用范式
L.append("## 三、统一调用范式(可直接联调)")
L.append("")
L.append("```http")
L.append("# 微信Frida 主通道)")
L.append("POST /api/v3/hook/execute")
L.append('{"device_id":"<serial>","platform":"wechat","action":"send_message",')
L.append(' "params":{"to_id":"文件传输助手","content":"hi"},"hook_only":1}')
L.append("")
L.append("# 多平台精确控机(抖音/小红书/闲鱼/Soul")
L.append("POST /api/v3/ai/brain/execute-script")
L.append('{"device_id":"<serial>","script":"douyin","action":"send_message","params":{...}}')
L.append("")
L.append("# 未注册 BFF 的能力 → 经存客宝 BFF 透传(不新造接口)")
L.append("POST /v1/workphone/sdk/proxy")
L.append('{"method":"POST","path":"/api/v3/ai/brain/execute-script","body":{...}}')
L.append("```")
L.append("")
L.append("## 四、关联文档")
L.append("")
L.append("- 四端开放接口与对接铁律:`5、接口/02-业务对接/四端开放接口汇总与对接铁律.md`")
L.append("- 存客宝 BFF↔SDK 映射:`5、接口/02-业务对接/存客宝BFF与工作手机SDK映射表.md`")
L.append("- 全量接口目录:`5、接口/01-规范与统一层/工作手机API全量接口目录.md`")
L.append("- 需求真源:`1、需求/修改/工作手机_存客宝四端对接_20260529.md` §3.8 / §十")
L.append("- 静态对齐校验:`python3 sdk/scripts/wechat_interface_audit.py`0 缺失)")
L.append("")
return "\n".join(L)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--base", default="http://127.0.0.1:8899")
args = ap.parse_args()
reg = fetch_registry(args.base)
md = render(reg, args.base)
os.makedirs(os.path.dirname(OUT), exist_ok=True)
with open(OUT, "w", encoding="utf-8") as f:
f.write(md)
print(f"[ok] 写入 {OUT}{len(md)} 字)")
if __name__ == "__main__":
main()