@tencent-rtc/trtc-agent-skills 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/CODEBUDDY.md +1 -1
  4. package/README.md +10 -7
  5. package/README.zh.md +10 -7
  6. package/bin/cli.js +196 -44
  7. package/knowledge-base/conference/web/index.yaml +6 -6
  8. package/knowledge-base/slices/conference/web/official-roomkit-api.md +119 -8
  9. package/package.json +1 -1
  10. package/skills/trtc/SKILL.md +45 -10
  11. package/skills/trtc-ai-oral-coach/README.ja.md +3 -3
  12. package/skills/trtc-ai-oral-coach/README.md +3 -3
  13. package/skills/trtc-ai-oral-coach/README.zh-CN.md +3 -3
  14. package/skills/trtc-ai-oral-coach/SKILL.md +7 -4
  15. package/skills/trtc-ai-realtime-interpreter/README.ja.md +197 -0
  16. package/skills/trtc-ai-realtime-interpreter/README.md +197 -0
  17. package/skills/trtc-ai-realtime-interpreter/README.zh-CN.md +197 -0
  18. package/skills/trtc-ai-realtime-interpreter/SKILL.md +748 -0
  19. package/skills/trtc-ai-realtime-interpreter/auto_adapters/integration_templates/generic-rest-api.md +85 -0
  20. package/skills/trtc-ai-realtime-interpreter/auto_adapters/integration_templates/room-owner-authz-note.md +53 -0
  21. package/skills/trtc-ai-realtime-interpreter/auto_adapters/manifest.yaml +49 -0
  22. package/skills/trtc-ai-realtime-interpreter/auto_adapters/python/README.md +11 -0
  23. package/skills/trtc-ai-realtime-interpreter/auto_adapters/python/fastapi_reverse_proxy.py.tpl +84 -0
  24. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/.env.example +17 -0
  25. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/frontend/silent-listener.ts +91 -0
  26. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/manifest.yaml +110 -0
  27. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/requirements.txt +5 -0
  28. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/__init__.py +0 -0
  29. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/_capability_loader.py +89 -0
  30. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/agent.py +153 -0
  31. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/credentials.py +112 -0
  32. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/health.py +218 -0
  33. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/log_filter.py +33 -0
  34. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/server.py +266 -0
  35. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/trtc_client.py +188 -0
  36. package/skills/trtc-ai-realtime-interpreter/capabilities/conversation-core/src/usersig.py +53 -0
  37. package/skills/trtc-ai-realtime-interpreter/capabilities/meeting-ops/README.md +46 -0
  38. package/skills/trtc-ai-realtime-interpreter/capabilities/meeting-ops/manifest.yaml +63 -0
  39. package/skills/trtc-ai-realtime-interpreter/capabilities/meeting-ops/src/__init__.py +0 -0
  40. package/skills/trtc-ai-realtime-interpreter/capabilities/meeting-ops/src/fanout.py +149 -0
  41. package/skills/trtc-ai-realtime-interpreter/capabilities/meeting-ops/src/router.py +83 -0
  42. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/frontend/subtitle-parser.ts +145 -0
  43. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/manifest.yaml +68 -0
  44. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/src/__init__.py +0 -0
  45. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/src/modes.py +73 -0
  46. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/src/router.py +83 -0
  47. package/skills/trtc-ai-realtime-interpreter/capabilities/realtime-translation/src/service.py +77 -0
  48. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/README.md +23 -0
  49. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/backend/app/__init__.py +0 -0
  50. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/backend/app/server.py +277 -0
  51. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/backend/requirements.txt +5 -0
  52. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/backend/start.sh +28 -0
  53. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/recipe.yaml +72 -0
  54. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/index.html +12 -0
  55. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/legacy/index.html +738 -0
  56. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/package-lock.json +4302 -0
  57. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/package.json +33 -0
  58. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/postcss.config.js +6 -0
  59. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/App.vue +18 -0
  60. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/api/backend.ts +82 -0
  61. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/SetupScreen.vue +362 -0
  62. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/SummaryScreen.vue +203 -0
  63. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/ChatPanel.vue +188 -0
  64. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/ConferenceRoom.vue +453 -0
  65. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/ParticipantViewUI.vue +170 -0
  66. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/PeoplePanel.vue +206 -0
  67. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/SidePanel.vue +77 -0
  68. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/Toolbar.vue +371 -0
  69. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/TopBar.vue +310 -0
  70. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/components/conference/TranscriptPanel.vue +225 -0
  71. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/composables/useAiInterpreter.ts +263 -0
  72. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/composables/useConference.ts +98 -0
  73. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/env.d.ts +7 -0
  74. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/main.ts +5 -0
  75. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/store.ts +103 -0
  76. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/src/style.css +19 -0
  77. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/tailwind.config.js +25 -0
  78. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/tsconfig.json +25 -0
  79. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/tsconfig.node.json +10 -0
  80. package/skills/trtc-ai-realtime-interpreter/scenarios/meeting-interpreter/ui/vite.config.ts +26 -0
  81. package/skills/trtc-ai-realtime-interpreter/scripts/add-capability.py +163 -0
  82. package/skills/trtc-ai-realtime-interpreter/scripts/deploy-demo.sh +64 -0
  83. package/skills/trtc-ai-realtime-interpreter/scripts/lib/__init__.py +0 -0
  84. package/skills/trtc-ai-realtime-interpreter/scripts/lib/credential_validators.py +143 -0
  85. package/skills/trtc-ai-realtime-interpreter/scripts/lib/manifest_resolver.py +60 -0
  86. package/skills/trtc-ai-realtime-interpreter/scripts/lib/stack_detector.py +50 -0
  87. package/skills/trtc-ai-realtime-interpreter/scripts/post-install-patch.py +79 -0
  88. package/skills/trtc-ai-realtime-interpreter/scripts/verify-credentials.py +76 -0
  89. package/skills/trtc-ai-realtime-interpreter/start.sh +85 -0
  90. package/skills/trtc-ai-realtime-interpreter/triggers.yaml +29 -0
  91. package/skills/trtc-ai-service/README.ja.md +3 -3
  92. package/skills/trtc-ai-service/README.md +3 -3
  93. package/skills/trtc-ai-service/README.zh-CN.md +3 -3
  94. package/skills/trtc-ai-service/SKILL.md +9 -7
  95. package/skills/trtc-ai-service/capabilities/conversation-core/src/credentials.py +1 -1
  96. package/skills/trtc-chat/SKILL.md +1 -1
  97. package/skills/trtc-chat/docs/SKILL.md +1 -1
  98. package/skills/trtc-conference/flows/onboarding.md +6 -0
  99. package/skills/trtc-conference/flows/topic.md +6 -2
  100. package/skills/trtc-conference/playbooks/official-roomkit.md +3 -1
  101. package/skills/trtc-conference/tests/test_conference_index_contract.py +16 -0
  102. package/skills/trtc-conference/tests/test_conference_onboarding_contract.py +9 -0
  103. package/skills/trtc-conference/tests/test_conference_topic_flow_contract.py +16 -0
  104. package/skills/trtc-push/SKILL.md +118 -0
  105. package/skills/trtc-push/issues/ROUTER.json +429 -0
  106. package/skills/trtc-push/issues/cards/android/fcm-gms-domestic.md +53 -0
  107. package/skills/trtc-push/issues/cards/android/vendor-huawei.md +72 -0
  108. package/skills/trtc-push/issues/cards/common/console-certificate-quota.md +46 -0
  109. package/skills/trtc-push/issues/cards/common/registration-binding.md +67 -0
  110. package/skills/trtc-push/issues/cards/ios/aps-environment-3000.md +55 -0
  111. package/skills/trtc-push/issues/cards/ios/certificate-businessid.md +56 -0
  112. package/skills/trtc-push/issues/cards/ios/xcodegen-cocoapods-module.md +54 -0
  113. package/skills/trtc-push/issues/flows/android/delivered-not-displayed.md +52 -0
  114. package/skills/trtc-push/issues/flows/android/vendor-not-received.md +57 -0
  115. package/skills/trtc-push/issues/flows/common/badge.md +49 -0
  116. package/skills/trtc-push/issues/flows/common/console-product-limits.md +48 -0
  117. package/skills/trtc-push/issues/flows/common/server-api.md +51 -0
  118. package/skills/trtc-push/issues/flows/cross-platform/harmonyos.md +51 -0
  119. package/skills/trtc-push/issues/flows/cross-platform/uniapp-integration.md +57 -0
  120. package/skills/trtc-push/issues/flows/ios/offline-not-received.md +57 -0
  121. package/skills/trtc-push/references/code-templates.md +386 -0
  122. package/skills/trtc-push/references/hard-rules.md +112 -0
  123. package/skills/trtc-push/references/timpush-sdk-api.md +72 -0
  124. package/skills/trtc-push/references/workflow-protocol.md +82 -0
  125. /package/.cursor/rules/{main.mdc → ui-mode.mdc} +0 -0
@@ -0,0 +1,85 @@
1
+ # 通用 REST API 集成指南(L3 兜底:识别不出技术栈时的手动接入方式)
2
+
3
+ 无论你的项目是什么技术栈,都可以直接调用 `conversation-core`(骨架必装)暴露的 REST API。是否再装 `realtime-translation` / `meeting-ops`,取决于你是「单目标」还是「多目标扇出」场景(见下方两条路径)。
4
+
5
+ ## 0. 启动骨架
6
+
7
+ ```bash
8
+ cd capabilities/conversation-core
9
+ cp .env.example .env # 填好三把钥匙
10
+ python3 -m venv .venv && source .venv/bin/activate
11
+ pip install -r requirements.txt
12
+ python -m src.server # 默认 0.0.0.0:8020
13
+ ```
14
+
15
+ ## 1. 骨架通用接口
16
+
17
+ | Method | Path | 说明 |
18
+ |---|---|---|
19
+ | GET | `/api/v1/health` | 三把钥匙实时自检 |
20
+ | POST | `/api/v1/usersig` | 给任意 user_id 签发 UserSig(供旁听客户端等场景使用) |
21
+ | POST | `/api/v1/agent/start` | 起一路会话(单目标,room_id 由你给定) |
22
+ | POST | `/api/v1/agent/stop` | 停一路会话 |
23
+ | POST | `/api/v1/agent/control` | 文本注入 / 打断 |
24
+
25
+ ## 2. 场景 A:单目标翻译(给一个人配一路 AI 翻译)
26
+
27
+ 装 `realtime-translation` 后新增:
28
+
29
+ | Method | Path | 说明 |
30
+ |---|---|---|
31
+ | GET | `/api/v1/translation/modes` | 列出可用语言对(zh-en / zh-yue / en-yue) |
32
+ | POST | `/api/v1/translation/start` | 给单一目标起一路翻译会话 |
33
+ | POST | `/api/v1/translation/stop` | 停止 |
34
+
35
+ ```bash
36
+ curl -X POST https://localhost:8020/api/v1/translation/start \
37
+ -H "Content-Type: application/json" \
38
+ -d '{
39
+ "room_id": "你的房间号",
40
+ "room_id_type": 0,
41
+ "target_user_id": "要被翻译的那个人的 userId",
42
+ "mode": "zh-en"
43
+ }'
44
+ ```
45
+
46
+ 返回 `session_id`,之后用它调用 `/api/v1/translation/stop` 结束。
47
+
48
+ ## 3. 场景 B:多目标扇出(多人房间,谁说话都翻译)
49
+
50
+ 装 `meeting-ops`(依赖 `realtime-translation`)后新增:
51
+
52
+ | Method | Path | 说明 |
53
+ |---|---|---|
54
+ | POST | `/api/v1/meeting/session/start` | 按参会人列表批量起翻译会话(特权操作) |
55
+ | POST | `/api/v1/meeting/session/stop` | 批量停止 |
56
+ | GET | `/api/v1/meeting/session/state` | 查询房间当前扇出状态(只读) |
57
+
58
+ ```bash
59
+ curl -X POST https://localhost:8020/api/v1/meeting/session/start \
60
+ -H "Content-Type: application/json" \
61
+ -d '{
62
+ "room_id": "你的房间号",
63
+ "room_id_type": 1,
64
+ "participants": ["user_a", "user_b"],
65
+ "capability": "realtime-translation",
66
+ "params": { "mode": "zh-en" }
67
+ }'
68
+ ```
69
+
70
+ **⚠️ 安全要求(务必阅读)**:`meeting-ops` 的这两个端点是特权操作(会产生真实云服务调用费用),本能力包**不做任何调用者权限校验**。你必须在自己的后端加一层校验(比如"调用者是不是这个房间的管理员"),校验通过才转发到这里,绝不能让未经身份校验的客户端直接打到这些端点。详见 `room-owner-authz-note.md`。
71
+
72
+ ## 4. 前端:如何收到 AI 的字幕/状态
73
+
74
+ 如果你已有的会议/直播 SDK 没有把底层 TRTC engine 暴露出来供你监听自定义消息,参考 `../frontend_assets` 里的两个框架无关片段:
75
+
76
+ - `silent-listener.ts`:独立起一个静默旁听 TRTC 客户端,只收自定义消息不推流
77
+ - `subtitle-parser.ts`:解析 cmd 10000/10001,产出双语气泡 + 转写记录
78
+
79
+ 拷进你的项目后按你的技术栈(Vue/React/纯 JS)简单包一层调用即可,两个文件都不依赖任何 UI 框架。
80
+
81
+ ## 5. 安全合规
82
+
83
+ - **HTTPS**:生产环境务必启用(TRTC Web SDK 采集麦克风也要求安全上下文)
84
+ - **SecretKey 不下发到客户端**:骨架只把 `user_sig`(带 TTL)发给客户端,绝不暴露 `SDKSecretKey`
85
+ - **日志脱敏**:骨架内置 `RedactingFilter`;反向代理层也应避免记录 Authorization 头
@@ -0,0 +1,53 @@
1
+ # 权限校验说明:meeting-ops 为什么不内置房主/管理员判断
2
+
3
+ ## 结论
4
+
5
+ `meeting-ops` 的 `/api/v1/meeting/session/start` 和 `/session/stop` 是特权操作端点(会触发真实的云服务调用,产生费用),但**本能力包完全不做任何调用者身份/权限校验**。
6
+
7
+ ## 为什么这么设计
8
+
9
+ 这不是接入 TRTC 能力本身的必要条件,是我们刻意做的边界收窄:
10
+
11
+ 1. **你的系统大概率已经有权限体系了**。如果你在接入一个已有的会议室/直播间/App,你自己的后端应该已经知道"当前请求是谁发的、他是不是管理员"。让 `meeting-ops` 再实现一套自己的权限判断,反而会跟你已有的权限体系打架,或者变成"两套互不认识的权限系统"。
12
+
13
+ 2. **权限规则因业务而异**。有的产品是"仅主持人可操作",有的是"任何管理员都可以",有的甚至是"付费用户才能开"——这些规则属于具体业务,不该固化进一个可复用能力包里。
14
+
15
+ ## 你应该怎么做
16
+
17
+ 在你自己的后端加一层转发前置校验:
18
+
19
+ ```
20
+ [你的前端] --请求--> [你的后端]
21
+
22
+ ├─ 校验调用者身份 + 权限(用你已有的鉴权体系)
23
+
24
+ ├─ 通过 --转发--> [meeting-ops /api/v1/meeting/session/start]
25
+
26
+ └─ 不通过 --> 直接拒绝,不转发
27
+ ```
28
+
29
+ 伪代码示例(Node/Express 风格,其他语言逻辑相同):
30
+
31
+ ```js
32
+ app.post('/my-api/ai-translate/start', requireAuth, async (req, res) => {
33
+ const room = await myRoomService.getRoom(req.body.roomId)
34
+ if (room.ownerId !== req.user.id) {
35
+ return res.status(403).json({ error: 'only room owner can start AI translation' })
36
+ }
37
+ const resp = await fetch('https://localhost:8020/api/v1/meeting/session/start', {
38
+ method: 'POST',
39
+ headers: { 'Content-Type': 'application/json' },
40
+ body: JSON.stringify({
41
+ room_id: room.id,
42
+ participants: room.participantUserIds,
43
+ capability: 'realtime-translation',
44
+ params: { mode: req.body.mode },
45
+ }),
46
+ })
47
+ res.json(await resp.json())
48
+ })
49
+ ```
50
+
51
+ ## 参考实现(仅供理解思路,不要直接照搬到生产)
52
+
53
+ `scenarios/meeting-interpreter/backend/app/server.py` 里有一个**演示用**的房主校验实现(内存字典记录"建房人=房主"),那是我们自己的会议室 demo 的产品规则,仅用来说明"这一层校验该长什么样子"。生产环境请换成你自己系统里真实的权限判断逻辑,而不是照搬这个内存字典。
@@ -0,0 +1,49 @@
1
+ # auto_adapters 索引 manifest(Path B:无 UI,直接接入已有系统)
2
+ #
3
+ # 与 Path A 的关系:Path A(scenarios/meeting-interpreter)交付的是一整套可运行的
4
+ # Vue3 会议室 demo;Path B 不生成任何 UI,只交付「API 契约 + 按目标模式挑选的
5
+ # 集成示例代码」,供集成方把能力接进自己已有的会议室/直播间/App。
6
+
7
+ version: "1.0.0"
8
+ description: "无 UI 集成资产:REST API 契约 + 前端片段(静默旁听+字幕解析)+ 后端反代示例"
9
+
10
+ # ---------------------------------------------------------------------------
11
+ # 目标模式(Path B 引导时二选一,决定装哪些能力包)
12
+ # ---------------------------------------------------------------------------
13
+ target_modes:
14
+ - id: single_target
15
+ label: "单目标:给一个人(主播/客服/任意角色)配一路实时翻译"
16
+ capabilities: ["conversation-core", "realtime-translation"]
17
+ api_prefix: "/api/v1/translation"
18
+ guide: "integration_templates/single-target-integration.md"
19
+
20
+ - id: multi_target_fanout
21
+ label: "多目标:多人房间场景,谁说话都要翻译(会议/多人直播间)"
22
+ capabilities: ["conversation-core", "realtime-translation", "meeting-ops"]
23
+ api_prefix: "/api/v1/meeting"
24
+ guide: "integration_templates/multi-target-fanout-integration.md"
25
+ note: "meeting-ops 不做权限校验,务必在你自己的后端先校验调用者权限再转发,见 room-owner-authz-note.md"
26
+
27
+ # ---------------------------------------------------------------------------
28
+ # 前端资产(框架无关,按需拷贝进集成方项目)
29
+ # ---------------------------------------------------------------------------
30
+ frontend_assets:
31
+ - source: "../capabilities/conversation-core/frontend/silent-listener.ts"
32
+ description: "静默旁听 TRTC 客户端封装(进房收自定义消息,不推流/不播音频)"
33
+ - source: "../capabilities/realtime-translation/frontend/subtitle-parser.ts"
34
+ description: "字幕/AI状态自定义消息解析(cmd 10000/10001),产出双语气泡+转写记录"
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # 后端反代模板(按检测到的技术栈渲染,转发到 conversation-core 的 REST API)
38
+ # ---------------------------------------------------------------------------
39
+ adapters:
40
+ - name: "python-backend"
41
+ path: "python"
42
+ tech_stack: ["flask", "fastapi", "django"]
43
+ description: "Python 后端反代示例:转发到 conversation-core / meeting-ops 的 REST API,并在转发前插入权限校验钩子"
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # 三级降级兜底
47
+ # ---------------------------------------------------------------------------
48
+ fallback_templates:
49
+ manual_rest_api: "integration_templates/generic-rest-api.md"
@@ -0,0 +1,11 @@
1
+ # python 反代适配器
2
+
3
+ `fastapi_reverse_proxy.py.tpl` —— 转发到骨架服务 `/api/v1/meeting/*` 的示例路由,转发前带一个必须实现的权限校验占位函数 `require_room_owner`。
4
+
5
+ 拷贝后:
6
+ 1. 去掉 `.tpl` 后缀
7
+ 2. 替换 `${SKELETON_BASE_URL}` 和 `${ROUTE_PREFIX}`
8
+ 3. 实现 `require_room_owner`,接入你自己系统的权限判断(见 `../integration_templates/room-owner-authz-note.md`)
9
+ 4. 挂到你的 FastAPI app:`app.include_router(router)`
10
+
11
+ 如果你是单目标场景(不需要 meeting-ops),把转发目标换成 `/api/v1/translation/start` / `/stop` 即可,不需要权限校验占位(该端点不是特权操作,但仍建议做基础鉴权)。
@@ -0,0 +1,84 @@
1
+ # -*- coding: utf-8 -*-
2
+ """FastAPI 反代示例:把已有系统的请求转发到 trtc-ai-realtime-interpreter 骨架服务。
3
+
4
+ 用法:把本文件拷进你的 FastAPI 项目(去掉 .tpl 后缀),修改 SKELETON_BASE_URL,
5
+ 把 `include_router(router)` 挂到你的 app 上。
6
+
7
+ 关键点:转发前先做权限校验(见 require_room_owner 的占位实现),再转发到骨架。
8
+ 骨架服务本身跑在 ${SKELETON_BASE_URL}(默认 https://localhost:8020)。
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ import httpx
15
+ from fastapi import APIRouter, Depends, HTTPException
16
+ from pydantic import BaseModel
17
+
18
+ SKELETON_BASE_URL = "${SKELETON_BASE_URL}" # 例如 https://localhost:8020
19
+
20
+ router = APIRouter(prefix="${ROUTE_PREFIX}", tags=["ai-realtime-interpreter"])
21
+
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # TODO:替换为你自己系统里真实的权限校验(见 room-owner-authz-note.md)
25
+ # ---------------------------------------------------------------------------
26
+ async def require_room_owner(room_id: str, caller_user_id: str) -> None:
27
+ """占位实现:请替换成你系统里"调用者是不是这个房间的管理员/主持人"的真实判断。"""
28
+ # 示例:
29
+ # room = await my_room_service.get_room(room_id)
30
+ # if room.owner_id != caller_user_id:
31
+ # raise HTTPException(status_code=403, detail="only room owner can operate")
32
+ raise NotImplementedError("请实现 require_room_owner:接入你自己系统的权限判断")
33
+
34
+
35
+ class FanoutStartRequest(BaseModel):
36
+ room_id: str
37
+ room_id_type: int = 1
38
+ caller_user_id: str # 你自己系统里发起这次操作的用户
39
+ participants: List[str]
40
+ mode: str = "zh-en"
41
+
42
+
43
+ @router.post("/session/start")
44
+ async def session_start(req: FanoutStartRequest) -> Dict[str, Any]:
45
+ await require_room_owner(req.room_id, req.caller_user_id)
46
+ async with httpx.AsyncClient(verify=False, timeout=10.0) as client:
47
+ resp = await client.post(
48
+ f"{SKELETON_BASE_URL}/api/v1/meeting/session/start",
49
+ json={
50
+ "room_id": req.room_id,
51
+ "room_id_type": req.room_id_type,
52
+ "participants": req.participants,
53
+ "capability": "realtime-translation",
54
+ "params": {"mode": req.mode},
55
+ },
56
+ )
57
+ if resp.status_code != 200:
58
+ raise HTTPException(status_code=resp.status_code, detail=resp.text)
59
+ return resp.json()
60
+
61
+
62
+ class FanoutStopRequest(BaseModel):
63
+ room_id: str
64
+ caller_user_id: str
65
+
66
+
67
+ @router.post("/session/stop")
68
+ async def session_stop(req: FanoutStopRequest) -> Dict[str, Any]:
69
+ await require_room_owner(req.room_id, req.caller_user_id)
70
+ async with httpx.AsyncClient(verify=False, timeout=10.0) as client:
71
+ resp = await client.post(f"{SKELETON_BASE_URL}/api/v1/meeting/session/stop", json={"room_id": req.room_id})
72
+ if resp.status_code != 200:
73
+ raise HTTPException(status_code=resp.status_code, detail=resp.text)
74
+ return resp.json()
75
+
76
+
77
+ @router.get("/session/state")
78
+ async def session_state(room_id: str) -> Dict[str, Any]:
79
+ # 只读查询,无需权限校验
80
+ async with httpx.AsyncClient(verify=False, timeout=10.0) as client:
81
+ resp = await client.get(f"{SKELETON_BASE_URL}/api/v1/meeting/session/state", params={"room_id": room_id})
82
+ if resp.status_code != 200:
83
+ raise HTTPException(status_code=resp.status_code, detail=resp.text)
84
+ return resp.json()
@@ -0,0 +1,17 @@
1
+ # 钥匙 1 · 腾讯云 API 密钥(console.tencentcloud.com/cam/capi)
2
+ TENCENT_CLOUD_SECRET_ID=
3
+ TENCENT_CLOUD_SECRET_KEY=
4
+ TENCENT_CLOUD_REGION=ap-guangzhou
5
+
6
+ # 钥匙 2 · TRTC 应用凭证
7
+ # intl = 国际站 console.trtc.io (ap-singapore)
8
+ TRTC_REGION=intl
9
+ TRTC_SDK_APP_ID=
10
+ TRTC_SDK_SECRET_KEY=
11
+
12
+ # 钥匙 3 · LLM 密钥(OpenAI 兼容协议)
13
+ LLM_API_KEY=
14
+ LLM_API_URL=https://api.openai.com/v1/chat/completions
15
+ LLM_MODEL=gpt-4o-mini
16
+
17
+ PORT=8020
@@ -0,0 +1,91 @@
1
+ /**
2
+ * 通用「静默旁听」TRTC Web 客户端封装(conversation-core 的前端配套工具)。
3
+ *
4
+ * 用途:不依赖上层是否把 TRTC 引擎暴露给业务方(比如接入了 Atomicx/RoomKit 这类
5
+ * 无 UI 会议 SDK 时,业务层通常拿不到底层 engine 实例去监听 CUSTOM_MESSAGE),
6
+ * 而是另起一个独立身份,静默进同一个 SdkAppId+RoomId,不推流、不订阅音视频,
7
+ * 只挂 CUSTOM_MESSAGE 监听 —— 零风险、不依赖任何会议 SDK 内部实现。
8
+ *
9
+ * 这是「怎么收到 AI 通道消息」的通用机制,跟「收到消息后怎么解析 payload」是两件事:
10
+ * 后者(比如翻译字幕解析)由具体业务能力包(realtime-translation)实现,通过
11
+ * onCustomMessage 回调接上去,不需要重新造进房/退房这一层轮子。
12
+ *
13
+ * 使用方需要自行 `npm install trtc-sdk-v5`(依赖由业务项目安装,本文件不打包依赖)。
14
+ */
15
+
16
+ export interface SilentListenerConfig {
17
+ sdkAppId: number
18
+ roomId: string
19
+ userId: string
20
+ userSig: string
21
+ /** TRTC Web SDK 静态资源路径,默认官方 CDN */
22
+ assetsPath?: string
23
+ }
24
+
25
+ export interface SilentListenerHandle {
26
+ enter: () => Promise<void>
27
+ exit: () => Promise<void>
28
+ onCustomMessage: (cb: (event: any) => void) => void
29
+ onError: (cb: (err: any) => void) => void
30
+ }
31
+
32
+ /**
33
+ * 创建一个静默旁听客户端。调用 enter() 后即进房收自定义消息,不会有任何本地
34
+ * 采集/推流/播放行为;调用 exit() 退房并销毁底层实例。
35
+ *
36
+ * @param TRTC 由调用方传入 `trtc-sdk-v5` 的默认导出(避免本文件强制依赖该包)
37
+ */
38
+ export function createSilentListener(TRTC: any, cfg: SilentListenerConfig): SilentListenerHandle {
39
+ let client: any = null
40
+ let customMessageCb: ((event: any) => void) | null = null
41
+ let errorCb: ((err: any) => void) | null = null
42
+
43
+ async function enter(): Promise<void> {
44
+ if (client) return
45
+ client = TRTC.create({
46
+ assetsPath: cfg.assetsPath || 'https://web.sdk.qcloud.com/trtc/webrtc/v5/assets/',
47
+ })
48
+ client.on(TRTC.EVENT.CUSTOM_MESSAGE, (event: any) => {
49
+ customMessageCb?.(event)
50
+ })
51
+ client.on(TRTC.EVENT.ERROR, (err: any) => {
52
+ errorCb?.(err)
53
+ })
54
+ await client.enterRoom({
55
+ strRoomId: cfg.roomId,
56
+ scene: 'rtc',
57
+ sdkAppId: cfg.sdkAppId,
58
+ userId: cfg.userId,
59
+ userSig: cfg.userSig,
60
+ // 旁听客户端不播音频:避免跟业务方自己的会议/直播客户端重复播放 AI 的 TTS
61
+ autoReceiveAudio: false,
62
+ })
63
+ // 静默旁听:不调用 startLocalAudio / startLocalVideo
64
+ }
65
+
66
+ async function exit(): Promise<void> {
67
+ if (!client) return
68
+ try {
69
+ await client.exitRoom()
70
+ } catch {
71
+ /* ignore */
72
+ }
73
+ try {
74
+ client.destroy()
75
+ } catch {
76
+ /* ignore */
77
+ }
78
+ client = null
79
+ }
80
+
81
+ return {
82
+ enter,
83
+ exit,
84
+ onCustomMessage: (cb) => {
85
+ customMessageCb = cb
86
+ },
87
+ onError: (cb) => {
88
+ errorCb = cb
89
+ },
90
+ }
91
+ }
@@ -0,0 +1,110 @@
1
+ # conversation-core 能力自描述 manifest
2
+ # 类型:骨架(必装;不含任何行业/场景业务逻辑)
3
+
4
+ name: "conversation-core"
5
+ version: "1.0.0"
6
+ type: "skeleton"
7
+ description: "通用语音 Agent 骨架:三把钥匙管理、UserSig 签发、单路 Conversational AI 起停/控制,无业务逻辑"
8
+
9
+ dependencies: [] # 骨架层无依赖
10
+
11
+ # ---------------------------------------------------------------------------
12
+ # 配置接口
13
+ # ---------------------------------------------------------------------------
14
+ config:
15
+ credentials:
16
+ - key: "TENCENT_CLOUD_SECRET_ID"
17
+ required: true
18
+ description: "腾讯云 API SecretId(钥匙 1)"
19
+ - key: "TENCENT_CLOUD_SECRET_KEY"
20
+ required: true
21
+ description: "腾讯云 API SecretKey(钥匙 1)"
22
+ - key: "TENCENT_CLOUD_REGION"
23
+ required: false
24
+ default: "ap-guangzhou"
25
+ - key: "TRTC_SDK_APP_ID"
26
+ required: true
27
+ description: "TRTC 应用 SDKAppID(钥匙 2)"
28
+ - key: "TRTC_SDK_SECRET_KEY"
29
+ required: true
30
+ description: "TRTC 应用 SDKSecretKey(钥匙 2)"
31
+ - key: "TRTC_REGION"
32
+ required: false
33
+ default: "intl"
34
+ description: "intl=国际站"
35
+ - key: "LLM_API_KEY"
36
+ required: true
37
+ description: "外部 LLM 访问密钥(钥匙 3)"
38
+ - key: "LLM_API_URL"
39
+ required: false
40
+ default: "https://api.openai.com/v1/chat/completions"
41
+ - key: "LLM_MODEL"
42
+ required: false
43
+ default: "gpt-4o-mini"
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # 对外暴露的 API
47
+ # ---------------------------------------------------------------------------
48
+ endpoints:
49
+ - method: GET
50
+ path: /api/v1/health
51
+ description: 三把钥匙实时连通性自检
52
+ - method: POST
53
+ path: /api/v1/usersig
54
+ description: 给任意 user_id 签发 UserSig(供旁听客户端等通用场景使用)
55
+ - method: POST
56
+ path: /api/v1/agent/start
57
+ description: 起一路 Conversational AI 会话(单目标,room_id 由调用方给定)
58
+ - method: POST
59
+ path: /api/v1/agent/stop
60
+ description: 停一路会话
61
+ - method: POST
62
+ path: /api/v1/agent/control
63
+ description: 文本注入 / 打断
64
+ - method: GET
65
+ path: /api/v1/sessions
66
+ description: 内存态会话列表(调试用)
67
+
68
+ # ---------------------------------------------------------------------------
69
+ # 业务契约:骨架只对接腾讯云 TRTC 控制面 + LLM,均为平台级依赖,不提供 contract-adapt
70
+ # ---------------------------------------------------------------------------
71
+ business_contract:
72
+ external_apis:
73
+ - name: llm.chat_completions
74
+ direction: outbound
75
+ method: POST
76
+ path: /v1/chat/completions
77
+ description: "调用外部 LLM 做文本生成(OpenAI Chat Completions 兼容协议)"
78
+ auth:
79
+ type: bearer
80
+ location: header
81
+ name: Authorization
82
+ timeout_ms: 30000
83
+ - name: trtc.start_ai_conversation
84
+ direction: outbound
85
+ method: POST
86
+ path: "tencentcloudapi.com/?Action=StartAIConversation"
87
+ description: "腾讯云 TRTC 控制面:启动 AI 会话(平台级协议,不可适配)"
88
+ timeout_ms: 10000
89
+
90
+ # ---------------------------------------------------------------------------
91
+ # 安全声明
92
+ # ---------------------------------------------------------------------------
93
+ security:
94
+ log_redaction:
95
+ enabled: true
96
+ patterns: ["secret_id", "secret_key", "api_key", "usersig", "authorization"]
97
+ credential_storage:
98
+ source: "env-only"
99
+ env_file_permission: "0600"
100
+ network:
101
+ enforce_https: true
102
+
103
+ # ---------------------------------------------------------------------------
104
+ # 验收标准
105
+ # ---------------------------------------------------------------------------
106
+ acceptance:
107
+ - "三把钥匙实时自检,全部通过后 /api/v1/health 返回 status=ok"
108
+ - "start/stop 不含任何行业 prompt / 语言对,纯协议编排"
109
+ - "同一 room_id 可被多次调用 start(供 meeting-ops 扇出场景),互不冲突"
110
+ - "日志脱敏生效,.env 权限 600,无明文密钥落盘/落日志"
@@ -0,0 +1,5 @@
1
+ fastapi>=0.110
2
+ uvicorn[standard]>=0.29
3
+ python-dotenv>=1.0
4
+ requests>=2.31
5
+ tencentcloud-sdk-python>=3.0.1000
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ """兄弟能力包(capabilities/*)的动态加载器(与 cwd / 目录名无关)。
3
+
4
+ 能力目录用连字符命名(realtime-translation / meeting-ops),Python import 语法不认连字符;
5
+ 且各能力包内部模块用「平铺 import」(不用包内相对导入),因此加载前需要把目标能力包的
6
+ src 目录临时加进 sys.path,再普通 import。
7
+
8
+ 用法:
9
+ from _capability_loader import try_load_capability
10
+ mod = try_load_capability("meeting-ops", "src/router.py")
11
+ if mod is not None:
12
+ app.include_router(mod.router, prefix="/api/v1/meeting")
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import importlib.util
17
+ import logging
18
+ import sys
19
+ from pathlib import Path
20
+ from types import ModuleType
21
+ from typing import Optional
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # 本文件位于 <skill_root>/capabilities/conversation-core/src/_capability_loader.py
26
+ # parents[0]=src parents[1]=conversation-core parents[2]=capabilities parents[3]=skill_root
27
+ _HERE = Path(__file__).resolve()
28
+ _SKILL_ROOT = _HERE.parents[3]
29
+ _CAPABILITIES_ROOT = _SKILL_ROOT / "capabilities"
30
+
31
+ _module_cache: dict[str, ModuleType] = {}
32
+
33
+
34
+ def skill_root() -> Path:
35
+ return _SKILL_ROOT
36
+
37
+
38
+ def capabilities_root() -> Path:
39
+ return _CAPABILITIES_ROOT
40
+
41
+
42
+ def load_capability(cap_name: str, module_rel: str) -> ModuleType:
43
+ """加载 capabilities/<cap_name>/<module_rel> 并返回模块对象。
44
+
45
+ 会把该能力包的 src 目录加入 sys.path(一次性、幂等),使其内部的平铺 import 生效。
46
+ """
47
+ cache_key = f"{cap_name}::{module_rel}"
48
+ cached = _module_cache.get(cache_key)
49
+ if cached is not None:
50
+ return cached
51
+
52
+ cap_dir = _CAPABILITIES_ROOT / cap_name
53
+ file_path = cap_dir / module_rel
54
+ if not file_path.is_file():
55
+ raise ModuleNotFoundError(f"capability '{cap_name}' module '{module_rel}' not found at {file_path}")
56
+
57
+ src_dir = str(file_path.parent)
58
+ if src_dir not in sys.path:
59
+ sys.path.insert(0, src_dir)
60
+
61
+ mod_name = f"_capabilities_{cap_name.replace('-', '_')}_{file_path.stem}"
62
+ cached_mod = sys.modules.get(mod_name)
63
+ if cached_mod is not None:
64
+ _module_cache[cache_key] = cached_mod
65
+ return cached_mod
66
+
67
+ spec = importlib.util.spec_from_file_location(mod_name, file_path)
68
+ if spec is None or spec.loader is None:
69
+ raise ModuleNotFoundError(f"failed to build spec for '{cap_name}'/'{module_rel}'")
70
+ module = importlib.util.module_from_spec(spec)
71
+ sys.modules[mod_name] = module
72
+ try:
73
+ spec.loader.exec_module(module)
74
+ except Exception:
75
+ sys.modules.pop(mod_name, None)
76
+ raise
77
+
78
+ _module_cache[cache_key] = module
79
+ logger.debug("capability loaded: %s -> %s", mod_name, file_path)
80
+ return module
81
+
82
+
83
+ def try_load_capability(cap_name: str, module_rel: str) -> Optional[ModuleType]:
84
+ """同 load_capability,但失败时返回 None(用于「可选安装」场景,静默降级)。"""
85
+ try:
86
+ return load_capability(cap_name, module_rel)
87
+ except Exception as exc: # noqa: BLE001
88
+ logger.info("capability '%s' module '%s' not loaded (skipped): %s", cap_name, module_rel, exc)
89
+ return None