@tencent-rtc/trtc-agent-skills 0.1.3 → 0.1.4
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.
- package/.cursor/rules/main.mdc +12 -0
- package/AGENTS.md +14 -104
- package/CLAUDE.md +15 -127
- package/CODEBUDDY.md +32 -118
- package/README.md +7 -5
- package/README.zh.md +7 -5
- package/bin/cli.js +133 -41
- package/hooks/__pycache__/cursor-adapter.cpython-313.pyc +0 -0
- package/hooks/cursor-adapter.py +45 -18
- package/hooks/hooks-cursor.json +5 -18
- package/hooks/hooks.json +6 -31
- package/knowledge-base/conference/web/index.yaml +143 -0
- package/knowledge-base/platform-slice-template.md +1041 -133
- package/knowledge-base/products.yaml +76 -0
- package/knowledge-base/scenario-spec.md +1316 -115
- package/knowledge-base/scenarios/conference/base/general-conference.md +22 -2
- package/knowledge-base/scenarios/conference/base/webinar-conference.md +14 -0
- package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +19 -0
- package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +13 -0
- package/knowledge-base/scenarios/live/entertainment-live-room.md +12 -0
- package/knowledge-base/slice-spec.md +2377 -299
- package/knowledge-base/slices/conference/web/integration-audit.md +1 -1
- package/knowledge-base/slices/conference/web/login-auth.md +14 -1
- package/knowledge-base/tooling/aliases.yaml +92 -0
- package/knowledge-base/tooling/intent-signals.yaml +181 -0
- package/knowledge-base/tooling/symptom-keywords.yaml +21 -0
- package/package.json +1 -1
- package/skills/trtc/SKILL.md +202 -245
- package/skills/trtc/hooks/__pycache__/report_prompt.cpython-313.pyc +0 -0
- package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_read.py +12 -8
- package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_write.py +16 -12
- package/skills/{trtc-topic/guardrails → trtc/hooks}/stop_require_apply_evidence.py +22 -14
- package/skills/trtc/hooks/topic_phase_gate.py +161 -0
- package/skills/{trtc-topic → trtc}/runtime/README.md +2 -2
- package/skills/{trtc-onboarding/reference/reporting-protocol.md → trtc/runtime/REPORTING.md} +5 -5
- package/skills/{trtc-topic → trtc}/runtime/RUNTIME.md +5 -5
- package/skills/trtc/runtime/lib/__init__.py +0 -0
- package/skills/{trtc-topic → trtc}/runtime/package-lock.json +2 -2
- package/skills/{trtc-topic → trtc}/runtime/package.json +2 -2
- package/skills/{trtc-topic → trtc}/runtime/telemetry-bridge.mjs +1 -1
- package/skills/{trtc-topic/scripts → trtc/tools}/STATE-MACHINE-GUIDE.md +23 -23
- package/skills/trtc/tools/__init__.py +2 -0
- package/skills/trtc/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/skills/trtc/tools/__pycache__/query_classifier.cpython-313.pyc +0 -0
- package/skills/trtc/tools/__pycache__/reporting.cpython-313.pyc +0 -0
- package/skills/trtc/tools/__pycache__/search.cpython-313.pyc +0 -0
- package/skills/trtc/tools/__pycache__/session.cpython-313.pyc +0 -0
- package/skills/trtc/tools/apply.py +540 -0
- package/skills/trtc/tools/docs.py +712 -0
- package/skills/trtc/tools/docsbot.py +182 -0
- package/skills/trtc/tools/entry/render_ai_instructions.py +92 -0
- package/skills/trtc/tools/flow.py +1089 -0
- package/skills/{trtc-topic/scripts → trtc/tools}/init_slice_queue.py +5 -4
- package/skills/{trtc-topic/scripts → trtc/tools}/next_slice.py +5 -4
- package/skills/trtc/tools/query_classifier.py +301 -0
- package/skills/trtc/tools/reporting.py +447 -0
- package/skills/trtc/tools/search.py +817 -0
- package/skills/trtc/tools/session.py +1261 -0
- package/skills/trtc/tools/state_machine.py +690 -0
- package/skills/trtc-ai-service/README.md +195 -0
- package/skills/trtc-ai-service/README.zh-CN.md +193 -0
- package/skills/trtc-ai-service/SKILL.md +945 -0
- package/skills/trtc-ai-service/auto_adapters/README.md +40 -0
- package/skills/trtc-ai-service/auto_adapters/frontend-spa/README.md +27 -0
- package/skills/trtc-ai-service/auto_adapters/frontend-spa/angular/voice-agent.component.ts.tpl +131 -0
- package/skills/trtc-ai-service/auto_adapters/frontend-spa/manifest.yaml +57 -0
- package/skills/trtc-ai-service/auto_adapters/frontend-spa/react/VoiceAgent.tsx.tpl +142 -0
- package/skills/trtc-ai-service/auto_adapters/frontend-spa/vue/VoiceAgent.vue.tpl +121 -0
- package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-backend.md +45 -0
- package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-frontend.md +51 -0
- package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-rest-api.md +93 -0
- package/skills/trtc-ai-service/auto_adapters/java-backend/README.md +25 -0
- package/skills/trtc-ai-service/auto_adapters/java-backend/manifest.yaml +30 -0
- package/skills/trtc-ai-service/auto_adapters/java-backend/quarkus/VoiceAgentFilter.java.tpl +64 -0
- package/skills/trtc-ai-service/auto_adapters/java-backend/springboot/VoiceAgentFilter.java.tpl +91 -0
- package/skills/trtc-ai-service/auto_adapters/manifest.yaml +43 -0
- package/skills/trtc-ai-service/auto_adapters/node-backend/README.md +25 -0
- package/skills/trtc-ai-service/auto_adapters/node-backend/express.js.tpl +40 -0
- package/skills/trtc-ai-service/auto_adapters/node-backend/fastify.js.tpl +27 -0
- package/skills/trtc-ai-service/auto_adapters/node-backend/koa.js.tpl +31 -0
- package/skills/trtc-ai-service/auto_adapters/node-backend/manifest.yaml +47 -0
- package/skills/trtc-ai-service/auto_adapters/python-backend/README.md +22 -0
- package/skills/trtc-ai-service/auto_adapters/python-backend/django.py.tpl +32 -0
- package/skills/trtc-ai-service/auto_adapters/python-backend/fastapi.py.tpl +35 -0
- package/skills/trtc-ai-service/auto_adapters/python-backend/flask.py.tpl +31 -0
- package/skills/trtc-ai-service/auto_adapters/python-backend/manifest.yaml +45 -0
- package/skills/trtc-ai-service/capabilities/__init__.py +43 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/.env.example +29 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/INTEGRATION.md +134 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/INTERFACE_ADAPT.md +111 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/QUICK_START.md +62 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/manifest.yaml +250 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/requirements.txt +6 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/__init__.py +10 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/_capability_loader.py +218 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/agent.py +231 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/credentials.py +132 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/health.py +355 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/log_filter.py +76 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/modality.py +109 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/server.py +312 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/trtc_client.py +315 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/src/usersig.py +90 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/tests/test_skeleton.py +216 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/README.md +48 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/app.js +415 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/index.html +68 -0
- package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/styles.css +136 -0
- package/skills/trtc-ai-service/capabilities/digital-human/README.md +31 -0
- package/skills/trtc-ai-service/capabilities/digital-human/manifest.yaml +64 -0
- package/skills/trtc-ai-service/capabilities/digital-human/src/__init__.py +2 -0
- package/skills/trtc-ai-service/capabilities/digital-human/src/router.py +43 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/INTERFACE_ADAPT.md +353 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/README.md +44 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/manifest.yaml +227 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/__init__.py +2 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/__init__.py +9 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/default_rest.py +242 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/factory.py +89 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/local_queue.py +258 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/mock.py +132 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/core/__init__.py +25 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/core/intent_detector.py +75 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/core/models.py +163 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/core/service.py +192 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/feedback_store.py +54 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/__init__.py +4 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/handoff_client.py +86 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/queue.py +62 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/router.py +201 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/summary_link.py +77 -0
- package/skills/trtc-ai-service/capabilities/human-handoff/src/trigger.py +25 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/INTERFACE_ADAPT.md +297 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/README.md +51 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/data/faq.json +20 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/manifest.yaml +211 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/__init__.py +8 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/__init__.py +9 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/default_rest.py +209 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/factory.py +86 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/local_json.py +172 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/mock.py +91 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/__init__.py +12 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/models.py +77 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/scoring.py +73 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/service.py +78 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/__init__.py +4 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/kb_client.py +61 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/retriever.py +56 -0
- package/skills/trtc-ai-service/capabilities/knowledge-base/src/router.py +85 -0
- package/skills/trtc-ai-service/capabilities/session-summary/INTERFACE_ADAPT.md +99 -0
- package/skills/trtc-ai-service/capabilities/session-summary/README.md +47 -0
- package/skills/trtc-ai-service/capabilities/session-summary/data/test_session.json +18 -0
- package/skills/trtc-ai-service/capabilities/session-summary/manifest.yaml +165 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/__init__.py +2 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/__init__.py +5 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/base.py +31 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/default_rest.py +67 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/factory.py +51 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/local_json.py +42 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/mock.py +22 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/recorder.py +210 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/router.py +93 -0
- package/skills/trtc-ai-service/capabilities/session-summary/src/summarizer.py +163 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/INTERFACE_ADAPT.md +158 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/README.md +50 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/data/tools.yaml +58 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/examples/__init__.py +1 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/examples/local_tools.py +101 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/manifest.yaml +146 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/src/__init__.py +8 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/src/dispatcher.py +54 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/src/registry.py +219 -0
- package/skills/trtc-ai-service/capabilities/tool-calling/src/router.py +50 -0
- package/skills/trtc-ai-service/references/business-contract-spec.md +263 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/README.md +86 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/output-templates/recipe.yaml.j2 +194 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q1-business-scenario.md +43 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q2-io-modality.md +57 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q3-ui-form.md +55 -0
- package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q4-capabilities.md +78 -0
- package/skills/trtc-ai-service/scenarios/customer-service/README.md +114 -0
- package/skills/trtc-ai-service/scenarios/customer-service/recipe.yaml +154 -0
- package/skills/trtc-ai-service/scenarios/customer-service/sample-data/README.md +32 -0
- package/skills/trtc-ai-service/scenarios/customer-service/sample-data/faq-sample.json +37 -0
- package/skills/trtc-ai-service/scenarios/customer-service/system-prompt.template.md +94 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/app.js +347 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/index.html +125 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/styles.css +487 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/tokens.css +71 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/design-system/DESIGN_GUIDELINES.md +370 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/README.md +68 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/app.js +1307 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/data.js +40 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/index.html +233 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/mock-shop.json +21 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/styles.css +603 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/tokens.css +71 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/agent-link.js +323 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/app.js +458 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/index.html +109 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/styles.css +489 -0
- package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/tokens.css +59 -0
- package/skills/trtc-ai-service/scripts/add-capability.py +364 -0
- package/skills/trtc-ai-service/scripts/contract-adapt.py +334 -0
- package/skills/trtc-ai-service/scripts/detect-stack.py +40 -0
- package/skills/trtc-ai-service/scripts/lib/__init__.py +20 -0
- package/skills/trtc-ai-service/scripts/lib/adapter_codegen.py +509 -0
- package/skills/trtc-ai-service/scripts/lib/arbitrator.py +152 -0
- package/skills/trtc-ai-service/scripts/lib/contract_resolver.py +519 -0
- package/skills/trtc-ai-service/scripts/lib/credential_validators.py +253 -0
- package/skills/trtc-ai-service/scripts/lib/curl_parser.py +303 -0
- package/skills/trtc-ai-service/scripts/lib/degrader.py +140 -0
- package/skills/trtc-ai-service/scripts/lib/injector.py +347 -0
- package/skills/trtc-ai-service/scripts/lib/manifest_resolver.py +288 -0
- package/skills/trtc-ai-service/scripts/lib/openapi_parser.py +289 -0
- package/skills/trtc-ai-service/scripts/lib/stack_detector.py +159 -0
- package/skills/trtc-ai-service/scripts/lib/tokens_compile.py +204 -0
- package/skills/trtc-ai-service/scripts/post-install-patch.py +225 -0
- package/skills/trtc-ai-service/scripts/setup-credentials.py +393 -0
- package/skills/trtc-ai-service/scripts/verify-credentials.py +108 -0
- package/skills/trtc-ai-service/start.sh +111 -0
- package/skills/trtc-ai-service/tests/__init__.py +1 -0
- package/skills/trtc-ai-service/tests/test_arbitrator.py +64 -0
- package/skills/trtc-ai-service/tests/test_capability_overlay.py +85 -0
- package/skills/trtc-ai-service/tests/test_contract_resolver.py +190 -0
- package/skills/trtc-ai-service/tests/test_handoff_ports.py +195 -0
- package/skills/trtc-ai-service/tests/test_kb_ports.py +195 -0
- package/skills/trtc-ai-service/tests/test_manifest_resolver.py +95 -0
- package/skills/trtc-ai-service/tests/test_recipe_assembly.py +175 -0
- package/skills/trtc-ai-service/tests/test_stack_and_degrader.py +101 -0
- package/skills/trtc-ai-service/tests/test_verify_credentials.py +285 -0
- package/skills/trtc-ai-service/triggers.yaml +29 -0
- package/skills/trtc-conference/SKILL.md +324 -0
- package/skills/trtc-conference/flows/onboarding.md +205 -0
- package/skills/trtc-conference/flows/topic.md +474 -0
- package/skills/trtc-conference/flows/troubleshoot.md +85 -0
- package/skills/trtc-conference/hooks/pretooluse_require_business_decisions.py +213 -0
- package/skills/trtc-conference/playbooks/medical-quickstart.md +84 -0
- package/skills/trtc-conference/playbooks/official-roomkit.md +97 -0
- package/skills/trtc-conference/references/local-usersig/basic-info-config.ts +39 -0
- package/skills/trtc-conference/references/usersig-handling.md +134 -0
- package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
- package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
- package/skills/trtc-conference/tests/__pycache__/test_conference_onboarding_contract.cpython-313-pytest-9.0.2.pyc +0 -0
- package/skills/trtc-conference/tests/__pycache__/test_conference_topic_flow_contract.cpython-313-pytest-9.0.2.pyc +0 -0
- package/skills/trtc-conference/tests/test_conference_index_contract.py +43 -0
- package/skills/trtc-conference/tests/test_conference_onboarding_contract.py +103 -0
- package/skills/trtc-conference/tests/test_conference_template_contract.py +25 -0
- package/skills/trtc-conference/tests/test_conference_topic_flow_contract.py +132 -0
- package/skills/trtc-conference/tools/apply_checks.py +328 -0
- package/skills/trtc-conference/verify_lib/__init__.py +0 -0
- package/skills/{trtc-apply/guardrails/apply_lib → trtc-conference/verify_lib}/rule_parser.py +1 -1
- package/skills/trtc-docs/SKILL.md +91 -119
- package/.cursor/rules/ui-mode.mdc +0 -99
- package/ai-instructions/base.md +0 -13
- package/ai-instructions/ui-mode.md +0 -93
- package/knowledge-base/index.yaml +0 -462
- package/skills/trtc/room-builder/SKILL.md +0 -133
- package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +0 -108
- package/skills/trtc/room-builder/tools/render_ai_instructions.py +0 -226
- package/skills/trtc-apply/SKILL.md +0 -97
- package/skills/trtc-onboarding/SKILL.md +0 -841
- package/skills/trtc-onboarding/reference/path-a1-demo.md +0 -103
- package/skills/trtc-onboarding/reference/path-a2-integrate.md +0 -737
- package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +0 -186
- package/skills/trtc-onboarding/reference/path-c-expand.md +0 -43
- package/skills/trtc-onboarding/reference/supported-matrix.md +0 -100
- package/skills/trtc-search/SKILL.md +0 -228
- package/skills/trtc-topic/SKILL.md +0 -622
- package/skills/trtc-topic/scripts/apply.py +0 -581
- package/skills/trtc-topic/scripts/lib/state_machine.py +0 -328
- package/skills/trtc-topic/tests/README.md +0 -70
- package/skills/trtc-topic/tests/conftest.py +0 -72
- package/skills/trtc-topic/tests/test_apply_cli.py +0 -480
- package/skills/trtc-topic/tests/test_end_to_end.py +0 -305
- package/skills/trtc-topic/tests/test_finalize_session.py +0 -51
- package/skills/trtc-topic/tests/test_gates.py +0 -316
- package/skills/trtc-topic/tests/test_session_resolver.py +0 -260
- package/skills/trtc-topic/tests/test_state_machine.py +0 -414
- package/skills/trtc-topic/tests/test_stop_require_apply.py +0 -99
- package/skills/trtc-topic/tests/test_topic_skill_invariants.py +0 -130
- /package/skills/{trtc-topic → trtc}/runtime/lib/platforms.py +0 -0
- /package/skills/{trtc-topic → trtc}/runtime/telemetry_collector.py +0 -0
- /package/skills/{trtc-onboarding/reference → trtc/runtime}/usersig-handling.md +0 -0
- /package/skills/{trtc-topic/scripts → trtc/tools}/finalize_session.py +0 -0
- /package/skills/{trtc-apply/guardrails/apply_lib → trtc-ai-service/capabilities/conversation-core/tests}/__init__.py +0 -0
- /package/skills/{trtc-topic → trtc-conference}/references/execution-units.yaml +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.d.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.js +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/backend-contract.zh-CN.md +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/integration.zh-CN.md +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/theme.zh-CN.md +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/index.html +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/package.json +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/postcss.config.js +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/App.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/ConsultationManagePanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LanguageSwitch.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LoadingSpinner.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalAlert.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalBusinessPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalButton.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalConfirmDialog.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalDataPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalRecordPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/PrescriptionPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/basic-info-config.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/runtime-config.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/env.d.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/types.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationChat.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationDevices.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationParticipants.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationPermissions.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/utils.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/en-US/index.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/index.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/medicalTranslate.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/state.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/zh-CN/index.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/main.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/appointments.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/users.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/router/index.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/index.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/appointmentService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/authService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/launchContext.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/userService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/appointmentService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/authService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/userService.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/types.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/shared/icons.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/index.css +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/tailwind.css +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/theme.css +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/auth.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/format.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/navigation.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/session.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorConsultationView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorDashboardView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/LoginView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationFinishedView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientSelectDoctorView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientWaitingView.vue +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.json +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.node.json +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/vite.config.ts +0 -0
- /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md" +0 -0
- /package/skills/{trtc-topic/runtime/lib → trtc-conference/tools}/__init__.py +0 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"""FastAPI entry point: exposes skeleton REST API + static Web Demo.
|
|
2
|
+
|
|
3
|
+
Routes:
|
|
4
|
+
GET /api/v1/health —— Real-time connectivity check for 3 keys
|
|
5
|
+
POST /api/v1/get_config —— Generate RoomId / UserSig / modality config
|
|
6
|
+
POST /api/v1/agent/start —— Start AI conversation task
|
|
7
|
+
POST /api/v1/agent/stop —— Stop AI conversation task
|
|
8
|
+
POST /api/v1/agent/control —— Text injection / interrupt
|
|
9
|
+
GET / —— Web Demo static page
|
|
10
|
+
|
|
11
|
+
Design principles (aligned with §3.3):
|
|
12
|
+
- Zero industry assumptions: all routes only do protocol orchestration, no built-in business prompts
|
|
13
|
+
- Configuration as verification: health endpoint provides data source for Web Demo's three LEDs
|
|
14
|
+
- Security compliance: log redaction filter installed at startup; credentials from env vars only
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any, Dict, Optional
|
|
22
|
+
|
|
23
|
+
from dotenv import load_dotenv
|
|
24
|
+
|
|
25
|
+
# Load .env before importing business modules to ensure credentials module reads correct env vars
|
|
26
|
+
_BASE_DIR = Path(__file__).resolve().parent.parent
|
|
27
|
+
load_dotenv(_BASE_DIR / ".env.local")
|
|
28
|
+
load_dotenv(_BASE_DIR / ".env")
|
|
29
|
+
|
|
30
|
+
from fastapi import APIRouter, FastAPI, HTTPException
|
|
31
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
32
|
+
from fastapi.responses import FileResponse
|
|
33
|
+
from fastapi.staticfiles import StaticFiles
|
|
34
|
+
from pydantic import BaseModel, Field
|
|
35
|
+
|
|
36
|
+
from .agent import ConversationAgent
|
|
37
|
+
from .credentials import load_from_env
|
|
38
|
+
from .health import check_all
|
|
39
|
+
from .log_filter import install_redacting_filter
|
|
40
|
+
from .modality import IoModality
|
|
41
|
+
from .trtc_client import AgentLifecycleConfig
|
|
42
|
+
|
|
43
|
+
logger = logging.getLogger("conversation_core")
|
|
44
|
+
|
|
45
|
+
# Install log redaction filter (P0 security requirement)
|
|
46
|
+
logging.basicConfig(
|
|
47
|
+
level=os.getenv("LOG_LEVEL", "INFO"),
|
|
48
|
+
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
49
|
+
)
|
|
50
|
+
install_redacting_filter(logging.getLogger())
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Global Agent singleton (startup failure does not prevent /api/v1/health from giving clear diagnostics)
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
_credentials = load_from_env()
|
|
57
|
+
_io_modality = IoModality() # Phase 1 default: all modalities enabled
|
|
58
|
+
_agent: Optional[ConversationAgent] = None
|
|
59
|
+
_init_error: Optional[str] = None
|
|
60
|
+
try:
|
|
61
|
+
_agent = ConversationAgent(_credentials, _io_modality)
|
|
62
|
+
logger.info("ConversationAgent initialized")
|
|
63
|
+
except Exception as exc: # Credential missing etc. must not crash the process
|
|
64
|
+
_init_error = str(exc)
|
|
65
|
+
logger.warning("ConversationAgent not initialized: %s", _init_error)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Pydantic Models
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
class GetConfigRequest(BaseModel):
|
|
72
|
+
user_id: Optional[str] = None
|
|
73
|
+
room_id: Optional[str] = None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class StartAgentRequest(BaseModel):
|
|
77
|
+
session_id: str = Field(..., description="session_id returned by get_config")
|
|
78
|
+
instructions: Optional[str] = None
|
|
79
|
+
greeting: Optional[str] = None
|
|
80
|
+
language: Optional[str] = "en" # en | zh
|
|
81
|
+
voice_id: Optional[str] = None # Leave empty to use DEFAULT_VOICE_IDS selected by language
|
|
82
|
+
max_idle_time: Optional[int] = 60
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class StopAgentRequest(BaseModel):
|
|
86
|
+
session_id: str
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ControlRequest(BaseModel):
|
|
90
|
+
session_id: str
|
|
91
|
+
text: str
|
|
92
|
+
interrupt: bool = True
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# FastAPI App
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
app = FastAPI(
|
|
99
|
+
title="conversation-core",
|
|
100
|
+
version="1.0.0",
|
|
101
|
+
description="TRTC Voice Agent generic skeleton (no business assumptions)",
|
|
102
|
+
)
|
|
103
|
+
app.add_middleware(
|
|
104
|
+
CORSMiddleware,
|
|
105
|
+
allow_origins=["*"],
|
|
106
|
+
allow_credentials=True,
|
|
107
|
+
allow_methods=["*"],
|
|
108
|
+
allow_headers=["*"],
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
api = APIRouter(prefix="/api/v1")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _to_http_error(exc: Exception) -> HTTPException:
|
|
115
|
+
if isinstance(exc, ValueError):
|
|
116
|
+
return HTTPException(status_code=400, detail=str(exc))
|
|
117
|
+
if isinstance(exc, RuntimeError):
|
|
118
|
+
return HTTPException(status_code=500, detail=str(exc))
|
|
119
|
+
return HTTPException(status_code=500, detail=f"internal: {exc}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _require_agent() -> ConversationAgent:
|
|
123
|
+
if _agent is None:
|
|
124
|
+
raise HTTPException(
|
|
125
|
+
status_code=503,
|
|
126
|
+
detail={
|
|
127
|
+
"code": "credentials_missing",
|
|
128
|
+
"message": _init_error or "credentials not configured",
|
|
129
|
+
"hint": "run scripts/setup-credentials.py first",
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return _agent
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
# Health
|
|
137
|
+
# ---------------------------------------------------------------------------
|
|
138
|
+
@api.get("/health")
|
|
139
|
+
def health() -> Dict[str, Any]:
|
|
140
|
+
"""Real-time probe of 3 keys' connectivity, used by Web Demo top status bar."""
|
|
141
|
+
cred = load_from_env()
|
|
142
|
+
tc, trtc, llm = check_all(cred.tencent_cloud, cred.trtc, cred.llm)
|
|
143
|
+
overall = "ok" if tc.ok and trtc.ok and llm.ok else "partial_failure"
|
|
144
|
+
return {
|
|
145
|
+
"status": overall,
|
|
146
|
+
"checks": {
|
|
147
|
+
"tencent_cloud": tc.to_dict(),
|
|
148
|
+
"trtc": trtc.to_dict(),
|
|
149
|
+
"llm": llm.to_dict(),
|
|
150
|
+
},
|
|
151
|
+
"configured": cred.fully_configured,
|
|
152
|
+
"missing": cred.missing(),
|
|
153
|
+
"io_modality": _io_modality.to_dict(),
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
# Config / Lifecycle
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
@api.post("/get_config")
|
|
161
|
+
def get_config(req: GetConfigRequest) -> Dict[str, Any]:
|
|
162
|
+
agent = _require_agent()
|
|
163
|
+
try:
|
|
164
|
+
data = agent.issue_config(user_id=req.user_id, room_id=req.room_id)
|
|
165
|
+
return {"code": 0, "msg": "success", "data": data}
|
|
166
|
+
except Exception as exc:
|
|
167
|
+
raise _to_http_error(exc)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@api.post("/agent/start")
|
|
171
|
+
def agent_start(req: StartAgentRequest) -> Dict[str, Any]:
|
|
172
|
+
agent = _require_agent()
|
|
173
|
+
try:
|
|
174
|
+
defaults = AgentLifecycleConfig()
|
|
175
|
+
cfg = AgentLifecycleConfig(
|
|
176
|
+
instructions=req.instructions or defaults.instructions,
|
|
177
|
+
greeting=req.greeting or defaults.greeting,
|
|
178
|
+
language=req.language or "en",
|
|
179
|
+
voice_id=req.voice_id or "",
|
|
180
|
+
max_idle_time=req.max_idle_time or 60,
|
|
181
|
+
)
|
|
182
|
+
return {"code": 0, "msg": "success", "data": agent.start_agent(req.session_id, cfg)}
|
|
183
|
+
except Exception as exc:
|
|
184
|
+
raise _to_http_error(exc)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@api.post("/agent/stop")
|
|
188
|
+
def agent_stop(req: StopAgentRequest) -> Dict[str, Any]:
|
|
189
|
+
agent = _require_agent()
|
|
190
|
+
try:
|
|
191
|
+
return {"code": 0, "msg": "success", "data": agent.stop_agent(req.session_id)}
|
|
192
|
+
except Exception as exc:
|
|
193
|
+
raise _to_http_error(exc)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@api.post("/agent/control")
|
|
197
|
+
def agent_control(req: ControlRequest) -> Dict[str, Any]:
|
|
198
|
+
agent = _require_agent()
|
|
199
|
+
try:
|
|
200
|
+
return {
|
|
201
|
+
"code": 0,
|
|
202
|
+
"msg": "success",
|
|
203
|
+
"data": agent.push_text(req.session_id, req.text, req.interrupt),
|
|
204
|
+
}
|
|
205
|
+
except Exception as exc:
|
|
206
|
+
raise _to_http_error(exc)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@api.get("/sessions")
|
|
210
|
+
def sessions_list() -> Dict[str, Any]:
|
|
211
|
+
agent = _require_agent()
|
|
212
|
+
return {"code": 0, "data": agent.list_sessions()}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ---------------------------------------------------------------------------
|
|
216
|
+
# Debug endpoint: for troubleshooting InvalidParameter.UserSig etc.
|
|
217
|
+
# Outputs current config + a test UserSig for comparison against the TRTC official tool:
|
|
218
|
+
# https://console.cloud.tencent.com/trtc/usersigtools
|
|
219
|
+
# Security: only returns SDKAppID / region / endpoint / test UserSig; never exposes plaintext SecretKey
|
|
220
|
+
# ---------------------------------------------------------------------------
|
|
221
|
+
@api.get("/debug/usersig")
|
|
222
|
+
def debug_usersig(user_id: str = "test_user_001") -> Dict[str, Any]:
|
|
223
|
+
cred = load_from_env()
|
|
224
|
+
if not cred.trtc.configured:
|
|
225
|
+
raise HTTPException(status_code=503, detail="TRTC credential not configured")
|
|
226
|
+
from .usersig import gen_user_sig
|
|
227
|
+
|
|
228
|
+
sig = gen_user_sig(
|
|
229
|
+
sdk_app_id=cred.trtc.sdk_app_id,
|
|
230
|
+
sdk_secret_key=cred.trtc.sdk_secret_key,
|
|
231
|
+
user_id=user_id,
|
|
232
|
+
expire_seconds=86400,
|
|
233
|
+
)
|
|
234
|
+
return {
|
|
235
|
+
"sdk_app_id": cred.trtc.sdk_app_id,
|
|
236
|
+
"region": cred.trtc.region,
|
|
237
|
+
"trtc_endpoint": cred.trtc.trtc_endpoint,
|
|
238
|
+
"test_user_id": user_id,
|
|
239
|
+
"test_user_sig": sig,
|
|
240
|
+
"user_sig_length": len(sig),
|
|
241
|
+
"verify_url": "https://console.cloud.tencent.com/trtc/usersigtools",
|
|
242
|
+
"hint": (
|
|
243
|
+
"Paste sdk_app_id / test_user_id / test_user_sig into the TRTC console official verification tool. "
|
|
244
|
+
"If the tool shows UserSig verification passed → SDKSecretKey is correct; "
|
|
245
|
+
"If the tool shows verification failed → the TRTC_SDK_SECRET_KEY you entered does not match this SDKAppID. "
|
|
246
|
+
"Please re-check the SDKSecretKey in the TRTC console (note: this is NOT the Tencent Cloud API SecretKey)."
|
|
247
|
+
),
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
app.include_router(api)
|
|
252
|
+
# [human-handoff] mount sub-router
|
|
253
|
+
from ._capability_loader import try_load_capability as _try_load_capability
|
|
254
|
+
_hh_router_mod = _try_load_capability("human-handoff", "src/router.py")
|
|
255
|
+
if _hh_router_mod is not None and hasattr(_hh_router_mod, "router"):
|
|
256
|
+
app.include_router(
|
|
257
|
+
_hh_router_mod.router, prefix="/api/v1/handoff", tags=["human-handoff"]
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# [session-summary] mount sub-router (default installed; supplies ticket context summaries)
|
|
261
|
+
_ss_router_mod = _try_load_capability("session-summary", "src/router.py")
|
|
262
|
+
if _ss_router_mod is not None and hasattr(_ss_router_mod, "router"):
|
|
263
|
+
app.include_router(
|
|
264
|
+
_ss_router_mod.router, prefix="/api/v1/summary", tags=["session-summary"]
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# ---------------------------------------------------------------------------
|
|
268
|
+
# Capability route mounting (optional; dynamically loaded via _capability_loader, silently
|
|
269
|
+
# skipped if the capability package is not installed).
|
|
270
|
+
# Injected by add-capability; all use try_load_capability to avoid hyphenated import failures.
|
|
271
|
+
# ---------------------------------------------------------------------------
|
|
272
|
+
from ._capability_loader import try_load_capability as _try_load_capability # noqa: E402
|
|
273
|
+
|
|
274
|
+
# [knowledge-base] mount sub-router
|
|
275
|
+
_kb_router_mod = _try_load_capability("knowledge-base", "src/router.py")
|
|
276
|
+
if _kb_router_mod is not None and hasattr(_kb_router_mod, "router"):
|
|
277
|
+
app.include_router(
|
|
278
|
+
_kb_router_mod.router, prefix="/api/v1/kb", tags=["knowledge-base"]
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# ---------------------------------------------------------------------------
|
|
283
|
+
# Web Demo static pages (minimal verification page, no business content)
|
|
284
|
+
# Can point to a custom demo directory (e.g. Path A artifact directory) via
|
|
285
|
+
# the WEB_DEMO_DIR environment variable. Defaults to conversation-core's own web-demo self-check page.
|
|
286
|
+
# ---------------------------------------------------------------------------
|
|
287
|
+
_DEMO_DIR = Path(os.getenv("WEB_DEMO_DIR", str(_BASE_DIR / "web-demo")))
|
|
288
|
+
if _DEMO_DIR.exists():
|
|
289
|
+
app.mount(
|
|
290
|
+
"/static",
|
|
291
|
+
StaticFiles(directory=str(_DEMO_DIR), html=True),
|
|
292
|
+
name="static",
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
@app.get("/")
|
|
296
|
+
def index() -> FileResponse:
|
|
297
|
+
return FileResponse(str(_DEMO_DIR / "index.html"))
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# ---------------------------------------------------------------------------
|
|
301
|
+
# Entry point
|
|
302
|
+
# ---------------------------------------------------------------------------
|
|
303
|
+
def main() -> None:
|
|
304
|
+
import uvicorn
|
|
305
|
+
|
|
306
|
+
port = int(os.getenv("PORT", "3000"))
|
|
307
|
+
host = os.getenv("HOST", "0.0.0.0")
|
|
308
|
+
uvicorn.run(app, host=host, port=port)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
if __name__ == "__main__":
|
|
312
|
+
main()
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""TRTC Conversational AI control plane client.
|
|
2
|
+
|
|
3
|
+
Encapsulates the minimal call chain for three REST APIs:
|
|
4
|
+
StartAIConversation / StopAIConversation / ControlAIConversation.
|
|
5
|
+
The skeleton layer only does "protocol encapsulation + credential signing",
|
|
6
|
+
with no built-in business prompts, industry knowledge bases, or FAQ templates.
|
|
7
|
+
|
|
8
|
+
API docs:
|
|
9
|
+
- StartAIConversation: https://cloud.tencent.com/document/product/647/108514
|
|
10
|
+
- StopAIConversation: https://cloud.tencent.com/document/product/647/108513
|
|
11
|
+
- ControlAIConversation: https://cloud.tencent.com/document/product/647/109408
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import hmac
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import time
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from datetime import datetime, timezone
|
|
22
|
+
from typing import Any, Dict, Optional
|
|
23
|
+
|
|
24
|
+
import requests
|
|
25
|
+
|
|
26
|
+
from .credentials import LlmCredential, TencentCloudCredential, TrtcCredential
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
_SERVICE = "trtc"
|
|
31
|
+
_VERSION = "2019-07-22"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _sign_tc3(secret_key: str, date: str, string_to_sign: str) -> str:
|
|
35
|
+
k_date = hmac.new(
|
|
36
|
+
("TC3" + secret_key).encode("utf-8"),
|
|
37
|
+
date.encode("utf-8"),
|
|
38
|
+
hashlib.sha256,
|
|
39
|
+
).digest()
|
|
40
|
+
k_service = hmac.new(k_date, _SERVICE.encode("utf-8"), hashlib.sha256).digest()
|
|
41
|
+
k_signing = hmac.new(k_service, b"tc3_request", hashlib.sha256).digest()
|
|
42
|
+
return hmac.new(k_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _signed_request(
|
|
46
|
+
cred: TencentCloudCredential,
|
|
47
|
+
host: str,
|
|
48
|
+
region: str,
|
|
49
|
+
action: str,
|
|
50
|
+
payload: Dict[str, Any],
|
|
51
|
+
timeout: float = 5.0,
|
|
52
|
+
) -> Dict[str, Any]:
|
|
53
|
+
body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)
|
|
54
|
+
timestamp = int(time.time())
|
|
55
|
+
date = datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%d")
|
|
56
|
+
|
|
57
|
+
canonical_headers = (
|
|
58
|
+
f"content-type:application/json; charset=utf-8\n"
|
|
59
|
+
f"host:{host}\n"
|
|
60
|
+
f"x-tc-action:{action.lower()}\n"
|
|
61
|
+
)
|
|
62
|
+
signed_headers = "content-type;host;x-tc-action"
|
|
63
|
+
hashed_payload = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
|
64
|
+
canonical_request = f"POST\n/\n\n{canonical_headers}\n{signed_headers}\n{hashed_payload}"
|
|
65
|
+
credential_scope = f"{date}/{_SERVICE}/tc3_request"
|
|
66
|
+
hashed_canonical = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
|
|
67
|
+
string_to_sign = f"TC3-HMAC-SHA256\n{timestamp}\n{credential_scope}\n{hashed_canonical}"
|
|
68
|
+
signature = _sign_tc3(cred.secret_key, date, string_to_sign)
|
|
69
|
+
authorization = (
|
|
70
|
+
f"TC3-HMAC-SHA256 Credential={cred.secret_id}/{credential_scope}, "
|
|
71
|
+
f"SignedHeaders={signed_headers}, Signature={signature}"
|
|
72
|
+
)
|
|
73
|
+
headers = {
|
|
74
|
+
"Authorization": authorization,
|
|
75
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
76
|
+
"Host": host,
|
|
77
|
+
"X-TC-Action": action,
|
|
78
|
+
"X-TC-Timestamp": str(timestamp),
|
|
79
|
+
"X-TC-Version": _VERSION,
|
|
80
|
+
"X-TC-Region": region,
|
|
81
|
+
}
|
|
82
|
+
resp = requests.post(
|
|
83
|
+
f"https://{host}",
|
|
84
|
+
headers=headers,
|
|
85
|
+
data=body.encode("utf-8"),
|
|
86
|
+
timeout=timeout,
|
|
87
|
+
)
|
|
88
|
+
if resp.status_code != 200:
|
|
89
|
+
raise RuntimeError(f"TRTC API HTTP {resp.status_code}: {resp.text[:200]}")
|
|
90
|
+
parsed = resp.json()
|
|
91
|
+
response_obj = parsed.get("Response", {})
|
|
92
|
+
err = response_obj.get("Error")
|
|
93
|
+
request_id = response_obj.get("RequestId", "n/a")
|
|
94
|
+
if err:
|
|
95
|
+
raise RuntimeError(
|
|
96
|
+
f"TRTC API error {err.get('Code')}: {err.get('Message')} "
|
|
97
|
+
f"[endpoint={host}, action={action}, RequestId={request_id}]"
|
|
98
|
+
)
|
|
99
|
+
return response_obj
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Generic voice-assistant guardrails (NO industry/business assumptions).
|
|
103
|
+
#固化在骨架默认值里,确保:① 任何环境/任何 LLM 模型 ② 前端不传 instructions 时
|
|
104
|
+
# 都能避免 TTS 朗读 markdown 特殊符号,并让 AI 采信系统注入的权威上下文。
|
|
105
|
+
_DEFAULT_INSTRUCTIONS = (
|
|
106
|
+
"You are a helpful voice assistant for an online store's customer service. "
|
|
107
|
+
"Always answer in plain spoken language suitable for text-to-speech. "
|
|
108
|
+
"Do NOT use any Markdown or formatting symbols such as asterisks (*), underscores (_), "
|
|
109
|
+
"pound signs (#), backticks (`), tildes (~) or bullet / numbered-list markup, and never "
|
|
110
|
+
"read such symbols aloud. "
|
|
111
|
+
"Keep replies concise, ideally one to three sentences. "
|
|
112
|
+
"For general questions such as product recommendations or shopping advice, answer helpfully "
|
|
113
|
+
"and freely from your own knowledge — never claim you lack a product catalog or cannot help "
|
|
114
|
+
"with general guidance; offer concrete, natural suggestions instead. "
|
|
115
|
+
"Any information provided to you inside a message that begins with [system] is authoritative "
|
|
116
|
+
"context: use it directly to answer the user, and never say you cannot find it or ask the user "
|
|
117
|
+
"to repeat an identifier (such as an order number) that was already given to you."
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class AgentLifecycleConfig:
|
|
123
|
+
"""Session lifecycle parameters (business-logic independent)."""
|
|
124
|
+
|
|
125
|
+
instructions: str = _DEFAULT_INSTRUCTIONS
|
|
126
|
+
greeting: str = "Hello, how can I help you?"
|
|
127
|
+
max_idle_time: int = 60 # seconds
|
|
128
|
+
welcome_message: str = ""
|
|
129
|
+
language: str = "en" # Default English (widest compatibility; Chinese requires TRTC app to enable corresponding capability)
|
|
130
|
+
voice_id: str = "v-female-A4b9KqP2" # TRTC FlowTTS default female voice (English Articulate Narrator)
|
|
131
|
+
tts_model: str = "flow_01_turbo"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# TRTC FlowTTS verified voice IDs (taken from oral-coach project, confirmed working)
|
|
135
|
+
# Full voice list: https://trtc.io/document/79682?product=conversationalai
|
|
136
|
+
DEFAULT_VOICE_IDS = {
|
|
137
|
+
("en", "female"): "v-female-p9Xy7Q1L", # Articulate Narrator
|
|
138
|
+
("en", "male"): "v-male-A4b9KqP2", # Scholarly Lecturer
|
|
139
|
+
("zh", "female"): "female-kefu-xiaoyue",
|
|
140
|
+
("zh", "male"): "male-kefu-xiaoxu",
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TrtcConversationClient:
|
|
145
|
+
"""Thin wrapper around TRTC ConversationAI control plane.
|
|
146
|
+
|
|
147
|
+
Constructor parameters:
|
|
148
|
+
tencent: Tencent Cloud API keys (used to sign REST requests).
|
|
149
|
+
trtc: TRTC SDKAppID / SDKSecretKey (the SdkAppId in StartAIConversation).
|
|
150
|
+
llm: LLM credentials, used to populate LLMConfig (passthrough only, not called within the skeleton).
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
tencent: TencentCloudCredential,
|
|
156
|
+
trtc: TrtcCredential,
|
|
157
|
+
llm: LlmCredential,
|
|
158
|
+
) -> None:
|
|
159
|
+
if not tencent.configured:
|
|
160
|
+
raise ValueError("tencent cloud credential not configured")
|
|
161
|
+
if not trtc.configured:
|
|
162
|
+
raise ValueError("trtc credential not configured")
|
|
163
|
+
if not llm.configured:
|
|
164
|
+
raise ValueError("llm credential not configured")
|
|
165
|
+
self.tencent = tencent
|
|
166
|
+
self.trtc = trtc
|
|
167
|
+
self.llm = llm
|
|
168
|
+
|
|
169
|
+
# ------------------------------------------------------------------
|
|
170
|
+
# StartAIConversation
|
|
171
|
+
# ------------------------------------------------------------------
|
|
172
|
+
def start(
|
|
173
|
+
self,
|
|
174
|
+
room_id: str,
|
|
175
|
+
agent_user_id: str,
|
|
176
|
+
agent_user_sig: str,
|
|
177
|
+
target_user_id: str,
|
|
178
|
+
config: Optional[AgentLifecycleConfig] = None,
|
|
179
|
+
room_id_type: int = 0,
|
|
180
|
+
) -> Dict[str, Any]:
|
|
181
|
+
cfg = config or AgentLifecycleConfig()
|
|
182
|
+
# Resolve voice_id: user explicit > default per language
|
|
183
|
+
voice_id = cfg.voice_id or DEFAULT_VOICE_IDS.get(
|
|
184
|
+
(cfg.language, "female"),
|
|
185
|
+
DEFAULT_VOICE_IDS[("en", "female")],
|
|
186
|
+
)
|
|
187
|
+
payload: Dict[str, Any] = {
|
|
188
|
+
"SdkAppId": self.trtc.sdk_app_id,
|
|
189
|
+
"RoomId": str(room_id),
|
|
190
|
+
"RoomIdType": room_id_type,
|
|
191
|
+
"AgentConfig": {
|
|
192
|
+
"UserId": agent_user_id,
|
|
193
|
+
"UserSig": agent_user_sig,
|
|
194
|
+
"MaxIdleTime": cfg.max_idle_time,
|
|
195
|
+
"TargetUserId": target_user_id,
|
|
196
|
+
"WelcomeMessage": cfg.welcome_message or cfg.greeting,
|
|
197
|
+
# Smart interrupt (critical):
|
|
198
|
+
# InterruptMode 2 = auto + manual dual-track
|
|
199
|
+
# • Auto: user speaks beyond InterruptSpeechDuration ms → stop TTS
|
|
200
|
+
# • Manual: frontend sends type:20001 custom message → immediately stop TTS
|
|
201
|
+
# (for text input: send interrupt before text, then type:20000 triggers new turn)
|
|
202
|
+
"InterruptMode": 2,
|
|
203
|
+
"InterruptSpeechDuration": 500,
|
|
204
|
+
# Subtitle mode: 1 = deliver both user and AI subtitles to client
|
|
205
|
+
"SubtitleMode": 1,
|
|
206
|
+
# Single-word filter: prevent ASR from splitting filler sounds like "um/ah" into single words
|
|
207
|
+
"FilterOneWord": True,
|
|
208
|
+
# Turn detection: 3 = semantic + VAD dual-signal to detect when user has finished speaking
|
|
209
|
+
"TurnDetectionMode": 3,
|
|
210
|
+
"TurnDetection": {"SemanticEagerness": "auto"},
|
|
211
|
+
},
|
|
212
|
+
"STTConfig": {
|
|
213
|
+
"Language": cfg.language,
|
|
214
|
+
"VadLevel": 3,
|
|
215
|
+
"VadSilenceTime": 1000,
|
|
216
|
+
},
|
|
217
|
+
"LLMConfig": json.dumps(
|
|
218
|
+
{
|
|
219
|
+
"LLMType": self.llm.llm_type,
|
|
220
|
+
"Model": self.llm.model,
|
|
221
|
+
"APIKey": self.llm.api_key,
|
|
222
|
+
"APIUrl": self.llm.api_url,
|
|
223
|
+
"Streaming": True,
|
|
224
|
+
"SystemPrompt": cfg.instructions,
|
|
225
|
+
"History": 20,
|
|
226
|
+
"Temperature": 0.4,
|
|
227
|
+
},
|
|
228
|
+
separators=(",", ":"),
|
|
229
|
+
ensure_ascii=False,
|
|
230
|
+
),
|
|
231
|
+
"TTSConfig": json.dumps(
|
|
232
|
+
{
|
|
233
|
+
"TTSType": "flow",
|
|
234
|
+
"Model": cfg.tts_model,
|
|
235
|
+
"VoiceId": voice_id,
|
|
236
|
+
"Speed": 1.0,
|
|
237
|
+
"Volume": 1.0,
|
|
238
|
+
"Pitch": 0,
|
|
239
|
+
"Language": cfg.language,
|
|
240
|
+
},
|
|
241
|
+
separators=(",", ":"),
|
|
242
|
+
ensure_ascii=False,
|
|
243
|
+
),
|
|
244
|
+
}
|
|
245
|
+
# Log key diagnostics before starting (UserSig redacted)
|
|
246
|
+
logger.info(
|
|
247
|
+
"StartAIConversation: endpoint=%s region=%s SdkAppId=%s RoomId=%s "
|
|
248
|
+
"agent=%s target=%s userSig=%s...%s(len=%d) lang=%s voice=%s",
|
|
249
|
+
self.trtc.trtc_endpoint,
|
|
250
|
+
self.trtc.trtc_region,
|
|
251
|
+
self.trtc.sdk_app_id,
|
|
252
|
+
room_id,
|
|
253
|
+
agent_user_id,
|
|
254
|
+
target_user_id,
|
|
255
|
+
agent_user_sig[:6],
|
|
256
|
+
agent_user_sig[-4:],
|
|
257
|
+
len(agent_user_sig),
|
|
258
|
+
cfg.language,
|
|
259
|
+
voice_id,
|
|
260
|
+
)
|
|
261
|
+
resp = _signed_request(
|
|
262
|
+
self.tencent,
|
|
263
|
+
host=self.trtc.trtc_endpoint,
|
|
264
|
+
region=self.trtc.trtc_region,
|
|
265
|
+
action="StartAIConversation",
|
|
266
|
+
payload=payload,
|
|
267
|
+
timeout=10.0,
|
|
268
|
+
)
|
|
269
|
+
return {
|
|
270
|
+
"task_id": resp.get("TaskId"),
|
|
271
|
+
"request_id": resp.get("RequestId"),
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
# ------------------------------------------------------------------
|
|
275
|
+
# StopAIConversation
|
|
276
|
+
# ------------------------------------------------------------------
|
|
277
|
+
def stop(self, task_id: str) -> None:
|
|
278
|
+
if not task_id:
|
|
279
|
+
raise ValueError("task_id is required")
|
|
280
|
+
_signed_request(
|
|
281
|
+
self.tencent,
|
|
282
|
+
host=self.trtc.trtc_endpoint,
|
|
283
|
+
region=self.trtc.trtc_region,
|
|
284
|
+
action="StopAIConversation",
|
|
285
|
+
payload={"TaskId": task_id},
|
|
286
|
+
timeout=5.0,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# ------------------------------------------------------------------
|
|
290
|
+
# ControlAIConversation: used for text injection / interrupt
|
|
291
|
+
# ------------------------------------------------------------------
|
|
292
|
+
def control(
|
|
293
|
+
self,
|
|
294
|
+
task_id: str,
|
|
295
|
+
command: str,
|
|
296
|
+
text: Optional[str] = None,
|
|
297
|
+
interrupt: bool = True,
|
|
298
|
+
) -> Dict[str, Any]:
|
|
299
|
+
"""Inject text or issue a control command to a running conversation task."""
|
|
300
|
+
if not task_id or not command:
|
|
301
|
+
raise ValueError("task_id and command are required")
|
|
302
|
+
payload: Dict[str, Any] = {"TaskId": task_id, "Command": command}
|
|
303
|
+
if text is not None:
|
|
304
|
+
payload["ServerPushText"] = {
|
|
305
|
+
"Text": text,
|
|
306
|
+
"Interrupt": interrupt,
|
|
307
|
+
}
|
|
308
|
+
return _signed_request(
|
|
309
|
+
self.tencent,
|
|
310
|
+
host=self.trtc.trtc_endpoint,
|
|
311
|
+
region=self.trtc.trtc_region,
|
|
312
|
+
action="ControlAIConversation",
|
|
313
|
+
payload=payload,
|
|
314
|
+
timeout=5.0,
|
|
315
|
+
)
|