- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
TTS Guarder 是 TEN Framework AI Agents 仓库中面向 TTS(文本转语音)扩展的一体化集成测试套件,位于 ai_agents/agents/integration_tests/tts_guarder 目录。它以 pytest + TEN Runtime 测试框架为底座,通过向真实 TTS 扩展注入tts_text_input数据并校验tts_audio_start、tts_audio_end、tts_text_result等输出事件,验证语音合成扩展的正确性。阅读本文后,你将掌握 TTS Guarder 的环境配置、命令行运行方式、Taskfile 任务封装,以及字幕对齐(Subtitle Alignment)这类高级校验的启用与原理。
TTS Guarder 定位与套件结构
TTS Guarder 与同目录下的 ASR Guarder 共同构成 AI Agents 的双向语音链路验证体系:ASR Guarder 校验语音识别,TTS Guarder 校验语音合成。二者共享同一套"动态注入被测扩展 + 独立测试用例"的设计模式。
从仓库目录结构看,TTS Guarder 套件由以下部分组成:
| 路径 | 作用 |
|---|---|
| tests/ | 全部 pytest 测试用例(含 conftest.py 与测试数据) |
| tests/conftest.py | pytest 插件与全局 fixture,负责启动 FakeApp、解析命令行选项 |
| manifest-tmpl.json | 应用 manifest 模板,运行前动态替换{{extension_name}} |
| scripts/install_deps_and_build.sh | 依赖安装与构建脚本 |
| property.json | 应用属性(当前为空对象) |
其中manifest-tmpl.json是套件可针对任意 TTS 扩展复用的关键:它以{{extension_name}}作为占位符声明依赖ten_packages/extension/{{extension_name}},在运行时被替换为真实的扩展名(详见下文 Taskfile 解析),从而让同一套测试用例直接套用在 ElevenLabs、Cartesia、字节跳动(Bytedance)等不同厂商的 TTS 扩展上。
第一步:配置 TTS 厂商 API Key
运行测试前必须先为被测的 TTS 厂商服务配置 API Key。TTS Guarder 支持两种配置方式:
方式一:环境变量(export)
# TTS Vendor Services API Key export VENDOR_TTS_API_KEY=your_api_key_here # 例如 ElevenLabs: export ELEVENLABS_TTS_API_KEY=your_elevenlabs_api_key方式二:项目根目录的.env文件
# .env file ELEVENLABS_TTS_API_KEY=your_elevenlabs_api_key需要说明的是:VENDOR_TTS_API_KEY是通用占位变量,具体被测扩展实际读取的 Key 名称由该扩展自身的配置决定。例如 ElevenLabs 扩展对应ELEVENLABS_TTS_API_KEY。.env文件方式与 ai_agents/Taskfile.yml 中的dotenv: [".env"]声明相衔接——Taskfile 在执行tts-guarder-test等任务时会自动加载.env中的变量,因此直接task tts-guarder-test EXTENSION=xxx即可读取配置,无需手动 export。
第二步:准备测试文本
README 明确指出:需要为不同测试场景准备多段文本("prepare mutiple text for testing different scenario")。这一要求在测试代码中有多处印证:
- tests/test_data/short.txt:短文本测试数据,供
test_short_text类用例读取; - test_basic_audio_setting.py 中直接内置了
"hello world, hello agora, hello shanghai, nice to meet you!"作为采样率对比测试的输入文本; - test_subtitle_alignment.py 中则使用一段英文长句验证字幕与音频的时序对齐。
文本通过tts_text_input数据(Data)对象发送,携带text、request_id、text_input_end以及含session_id/turn_id的metadata字段。建议至少准备:短文本、长文本、空文本/非法文本、带特殊字符的文本,以覆盖测试用例集中不同场景。
第三步:运行测试
命令行直接运行
# 运行单个测试用例 bash tests/bin/start tests/test_elevenlabs_tts_basic.py::test_short_text --extension_name=elevenlbas_tts_python其中tests/bin/start是测试套件的统一启动入口(由安装脚本生成/下载),tests/test_elevenlabs_tts_basic.py::test_short_text指定要执行的测试文件与用例节点,--extension_name=elevenlbas_tts_python指定被测 TTS 扩展。
通过 Taskfile 运行整套测试
更推荐的方式是通过 ai_agents/Taskfile.yml 中定义的tts-guarder-test任务:
# 默认扩展(bytedance_tts_duplex) task tts-guarder-test # 指定被测扩展 task tts-guarder-test EXTENSION=cartesia_tts该任务的完整执行流程(可从 ai_agents/Taskfile.yml 源码确认)为:
- 用
sed将manifest-tmpl.json中的{{extension_name}}替换为实际扩展名,生成manifest.json; - 执行
./scripts/install_deps_and_build.sh linux x64:该脚本会调用tman -y install安装 manifest 声明的全部依赖,并遍历ten_packages/extension与ten_packages/system目录逐个安装各扩展的requirements.txt(见 install_deps_and_build.sh); - 运行
./tests/bin/start --extension_name <EXTENSION> --config_dir <扩展配置目录>,并透传{{ .CLI_ARGS }}中的附加参数。
任务还通过TEN_ENABLE_BACKTRACE_DUMP: "true"开启运行时回溯转储,便于测试失败时定位 C 核心层的崩溃现场。
关键 pytest 命令行选项
套件在 tests/conftest.py 中通过pytest_addoption注册了以下选项:
| 选项 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
--extension_name | 是 | 无 | 被测 TTS 扩展名,如elevenlabs_tts_python、cartesia_tts |
--config_dir | 是 | 无 | 扩展配置目录的绝对路径,通常指向agents/ten_packages/extension/<扩展名>/tests/configs |
--enable_sample_rate | 否 | True | 是否启用采样率对比校验(True/False) |
--enable_subtitle_alignment | 否 | False | 是否启用字幕对齐测试(True/False) |
测试用例矩阵
套件的 tests/ 目录按功能维度组织了完整的 TTS 场景覆盖:
| 测试文件 | 验证目标 |
|---|---|
test_basic_audio_setting.py | 基础音频设置:不同配置下采样率是否按预期生效,音频时长是否与 PCM 数据一致(容差 50ms) |
test_connection_status.py | WebSocket 型 TTS 扩展的连接状态事件(支持 bytedance/minimax/rime 等,见源码SUPPORTED_WEBSOCKET_TTS_EXTENSIONS) |
test_append_input.py/test_append_input_stress.py/test_append_input_without_text_input_end.py | 追加式文本输入、压力场景、未发送结束标记的追加输入 |
test_interleaved_requests.py | 交错/并发请求处理 |
test_interrupt.py | 合成中断处理 |
test_corner_input.py/test_empty_text_request.py/test_invalid_text_handling.py | 边界与非法输入:空文本、非法文本、角落输入 |
test_invalid_required_params.py/test_miss_required_params.py | 缺失/非法必填参数的报错行为 |
test_flush.py | 冲刷(flush)语义 |
test_dump.py/test_dump_each_request_id.py | 音频 dump 与按 request_id 维度 dump |
test_metrics.py | 指标输出 |
test_subtitle_alignment.py | 字幕(词级时间戳)与音频帧对齐(默认关闭,见下文) |
以 test_basic_audio_setting.py 为例:它依次读取两份配置文件property_basic_audio_setting1.json与property_basic_audio_setting2.json运行两次合成,若两份配置期望不同的采样率(如 16K 与 32K),则断言两次测试拿到的audio_frame.get_sample_rate()不同,从而验证扩展的采样率配置确实生效。
字幕对齐测试(Subtitle Alignment Test)
默认禁用与启用方式
字幕对齐测试在 TTS Guarder 中默认禁用,原因在于它依赖 TTS 厂商返回词级时间戳(word-level timing),并非所有厂商都支持。README 给出的用法如下:
# 默认运行:跳过字幕对齐测试 task tts-guarder-test EXTENSION=cartesia_tts # 显式启用字幕对齐测试 task tts-guarder-test EXTENSION=cartesia_tts -- --enable_subtitle_alignment=True目前test_subtitle_alignment.py仅针对cartesia_tts运行。这一限制在源码中有两处强校验(见 test_subtitle_alignment.py):
- 若
--enable_subtitle_alignment未开启,测试直接pytest.skip; - 若被测扩展不在
SUPPORTED_TTS_EXTENSIONS = {"cartesia_tts"}集合内,同样跳过; - 若配置目录下不存在
property_subtitle_alignment.json配置文件,也会跳过("Subtitle alignment is optional for providers without text timing")。
六条对齐验证规则
SubtitleAlignmentTester 在收到tts_audio_end后延时 0.5 秒等待词级结果收齐,然后依次执行六个校验器:
| 规则 | 校验内容 | 源码函数 |
|---|---|---|
| 1 | 首条文本的start_ms不得早于首个音频帧时间戳 | _validate_first_timestamp |
| 2 | 文本start_ms必须严格递增 | _validate_text_timestamps_ascending |
| 3 | 音频帧时间戳严格递增,且下一帧 ≈ 上一帧时间戳 + 上一帧时长(容差 ±10ms) | _validate_audio_frames_ascending |
| 4 | 文本总时长与音频总时长差值不超过阈值DURATION_MISMATCH_THRESHOLD_MS = 1000ms | _validate_duration_match |
| 5 | turn_seq_id递增、request_id全程一致 | _validate_turn_sequence |
| 6 | 最后一条结果的turn_status必须为 1(正常结束)或 2(被打断) | _validate_turn_status |
校验失败时通过ten_env.stop_test(TenError.create(...))终止测试并抛出错误;全部通过则打印✅ All subtitle alignment validations passed并正常结束。音频帧时长由帧内样本数换算:duration_ms = samples * 1000 // sample_rate(见 test_subtitle_alignment.py)。
这六条规则共同保证了一个对语音交互产品至关重要的性质:字幕出现时机与听到的语音严格对齐——字幕不能先于声音、不能后于声音超过 1 秒、且各词序与音频帧序一致。
测试运行机制:FakeApp 与测试器
理解 TTS Guarder 的运行机制有助于排查失败用例。tests/conftest.py 中的 session 级 autouse fixture 会启动一个独立的FakeApp线程:FakeApp 在on_init中释放事件锁(使 fixture 得以继续执行),在on_configure中通过init_property_from_json注入控制台日志 handler,随后app.run(False)启动运行时;teardown 阶段关闭 app 并 join 线程。
测试用例本身继承AsyncExtensionTester,通过set_test_mode_single(extension_name, json.dumps(config))将扩展与配置绑定,然后:
on_start中构造Data.create("tts_text_input")并设置text、request_id、text_input_end、metadata后send_data;on_data中按tts_audio_start/tts_audio_end/tts_text_result/error等消息名分派处理;on_audio_frame中检查采样率、累积音频字节并核对时间戳。
这套"发送输入 → 收集输出 → 规则校验"的模型与真实 AI Agent 运行时中 TTS 扩展的接入方式一致,因此 TTS Guarder 的测试结果可以直接反映扩展在真实场景中的行为。
小结与排查建议
综合 README 与仓库源码,TTS Guarder 的完整使用路径可归纳为:
- 配置 API Key(export 或
.env); - 准备覆盖多场景的测试文本;
- 选择运行方式:
bash tests/bin/start ... --extension_name=<ext>或task tts-guarder-test EXTENSION=<ext>; - 按需追加
--enable_sample_rate/--enable_subtitle_alignment等选项; - 针对
cartesia_tts等支持词级时间戳的扩展,可启用字幕对齐测试验证时序。
常见问题定位线索:若用例被跳过,优先检查--enable_subtitle_alignment是否开启、扩展名是否在SUPPORTED_TTS_EXTENSIONS集合内、config_dir下是否存在对应property_*.json配置文件;若用例失败,可借助TEN_ENABLE_BACKTRACE_DUMP=true(Taskfile 默认开启)的崩溃转储与测试日志中的❌错误信息定位具体校验规则。
- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
相关推荐
Czkawka:免费开源的一体化磁盘清理工具,一个扫描找重复文件、相似图片
Czkawka:免费开源的一体化磁盘清理工具,一个扫描找重复文件、相似图片 下载完素材拷进硬盘,系统提示空间不足,但翻半天找不到该删什么?Czkawka 是一个
人工智能AI Agent多模态语音AI 应用TEN Framework 集成 EZAI 繁中 TTS 扩展:ezai_tw_tts_python 配置与实现全解析
TEN Framework 集成 EZAI 繁中 TTS 扩展:ezai_tw_tts_python 配置与实现全解析 本文档以 ezai_tw_tts_pyt
人工智能AI Agent多模态语音AI 应用AIRI 集成 CometAPI 语音合成(TTS):从 API Key 配置到实时语音回复的完整指南
AIRI 集成 CometAPI 语音合成(TTS):从 API Key 配置到实时语音回复的完整指南 CometAPI 通过 OpenAI 兼容接口为 AIR
AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考