wangzhibo
2026-08-30 c8515170fd399b4d2dfaebb59128d4674e58915e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import asyncio
import logging
import os
import time
import threading
from typing import Dict
import yaml
from tabulate import tabulate
 
# 确保从 core.utils.tts 导入 create_tts_instance
from core.utils.tts import create_instance as create_tts_instance
from config.settings import load_config
 
# 设置全局日志级别为 WARNING
logging.basicConfig(level=logging.WARNING)
 
description = "非流式语音合成性能测试"
 
 
class TTSPerformanceTester:
    def __init__(self, config):
        self.config = config
        self.test_sentences = self.config.get("module_test", {}).get(
            "test_sentences",
            [
                "永和九年,岁在癸丑,暮春之初;",
                "夫人之相与,俯仰一世,或取诸怀抱,悟言一室之内;或因寄所托,放浪形骸之外。虽趣舍万殊,静躁不同,",
                "每览昔人兴感之由,若合一契,未尝不临文嗟悼,不能喻之于怀。固知一死生为虚诞,齐彭殇为妄作。",
            ],
        )
        self.results = {}
 
    async def _test_tts(self, tts_name: str, config: Dict) -> Dict:
        """测试单个TTS模块的性能"""
        try:
            token_fields = ["access_token", "api_key", "token"]
            if any(
                field in config
                and any(x in config[field] for x in ["你的", "placeholder"])
                for field in token_fields
            ):
                print(f"TTS {tts_name} 未配置access_token/api_key,已跳过")
                return {"name": tts_name, "errors": 1}
 
            module_type = config.get("type", tts_name)
            tts = create_tts_instance(module_type, config, delete_audio_file=True)
 
            # 设置 mock conn 对象,避免 TTS 实现访问 self.conn.sample_rate 时为 None
            class MockConn:
                sample_rate = 16000
                audio_format = "pcm"
                stop_event = threading.Event()  # 需要是真正的 Event 对象
                client_abort = False
                headers = {}
            tts.conn = MockConn()
 
            # 设置 mock opus_encoder,避免某些 TTS 访问 self.opus_encoder 时为 None
            class MockOpusEncoder:
                pass
            if not hasattr(tts, 'opus_encoder') or tts.opus_encoder is None:
                tts.opus_encoder = MockOpusEncoder()
 
            print(f"测试 TTS: {tts_name}")
 
            # 连接测试
            tmp_file = tts.generate_filename()
            await tts.text_to_speak("连接测试", tmp_file)
 
            if not tmp_file or not os.path.exists(tmp_file):
                print(f"{tts_name} 连接失败")
                return {"name": tts_name, "errors": 1}
 
            total_time = 0
            test_count = len(self.test_sentences[:3])
 
            for i, sentence in enumerate(self.test_sentences[:2], 1):
                start = time.time()
                tmp_file = tts.generate_filename()
                await tts.text_to_speak(sentence, tmp_file)
                duration = time.time() - start
                total_time += duration
 
                if tmp_file and os.path.exists(tmp_file):
                    print(f"{tts_name} [{i}/{test_count}] 测试成功")
                else:
                    print(f"{tts_name} [{i}/{test_count}] 测试失败")
                    return {"name": tts_name, "errors": 1}
 
            return {
                "name": tts_name,
                "avg_time": total_time / test_count,
                "errors": 0,
            }
 
        except Exception as e:
            print(f"{tts_name} 测试失败: {str(e)}")
            return {"name": tts_name, "errors": 1}
 
    def _print_results(self):
        """打印测试结果"""
        if not self.results:
            print("没有有效的TTS测试结果")
            return
 
        headers = ["TTS模块", "平均耗时(秒)", "测试句子数", "状态"]
        table_data = []
 
        # 收集所有数据并分类
        valid_results = []
        error_results = []
 
        for name, data in self.results.items():
            if data["errors"] == 0:
                # 正常结果
                avg_time = f"{data['avg_time']:.3f}"
                test_count = len(self.test_sentences[:3])
                status = "✅ 正常"
                
                # 保存用于排序的值
                valid_results.append({
                    "name": name,
                    "avg_time": avg_time,
                    "test_count": test_count,
                    "status": status,
                    "sort_key": data['avg_time']
                })
            else:
                # 错误结果
                avg_time = "-"
                test_count = "0/3"
                
                # 默认错误类型为网络错误
                error_type = "网络错误"
                status = f"❌ {error_type}"
                
                error_results.append([name, avg_time, test_count, status])
 
        # 按平均耗时升序排序
        valid_results.sort(key=lambda x: x["sort_key"])
 
        # 将排序后的有效结果转换为表格数据
        for result in valid_results:
            table_data.append([
                result["name"],
                result["avg_time"],
                result["test_count"],
                result["status"]
            ])
 
        # 将错误结果添加到表格数据末尾
        table_data.extend(error_results)
 
        print("\nTTS性能测试结果:")
        print(
            tabulate(
                table_data,
                headers=headers,
                tablefmt="grid",
                colalign=("left", "right", "right", "left"),
            )
        )
        print("\n测试说明:")
        print("- 超时控制: 单个请求最大等待时间为10秒")
        print("- 错误处理: 无法连接和超时的列为网络错误")
        print("- 排序规则: 按平均耗时从快到慢排序")
 
    async def run(self):
        """执行测试"""
        print("开始TTS性能测试...")
 
        if not self.config.get("TTS"):
            print("配置文件中未找到TTS配置")
            return
 
        # 遍历所有TTS配置
        tasks = []
        for tts_name, config in self.config.get("TTS", {}).items():
            tasks.append(self._test_tts(tts_name, config))
 
        # 并发执行测试
        results = await asyncio.gather(*tasks)
 
        # 保存所有结果,包括错误
        for result in results:
            self.results[result["name"]] = result
 
        # 打印结果
        self._print_results()
 
 
# 为了performance_tester.py的调用需求
async def main():
    config = await load_config()
    tester = TTSPerformanceTester(config)
    await tester.run()
 
 
if __name__ == "__main__":
    asyncio.run(main())