837 lines
27 KiB
Python
837 lines
27 KiB
Python
"""
|
|
语音合成器模块
|
|
负责文字转语音功能
|
|
"""
|
|
|
|
import time
|
|
import threading
|
|
import queue
|
|
from typing import Dict, Any, List, Optional
|
|
|
|
class SpeechSynthesizer:
|
|
"""
|
|
语音合成器
|
|
负责文字转语音功能
|
|
"""
|
|
|
|
def __init__(self, plugin):
|
|
"""
|
|
初始化语音合成器
|
|
|
|
Args:
|
|
plugin: 语音控制插件实例
|
|
"""
|
|
self.plugin = plugin
|
|
self.enabled = False
|
|
self.initialized = False
|
|
|
|
# 音频输出配置
|
|
self.audio_config = {
|
|
'sample_rate': 22050,
|
|
'channels': 1,
|
|
'format': 'int16',
|
|
'buffer_size': 4096
|
|
}
|
|
|
|
# 合成配置
|
|
self.synthesis_config = {
|
|
'language': 'zh-CN',
|
|
'voice': 'default',
|
|
'speed': 1.0,
|
|
'volume': 1.0,
|
|
'pitch': 1.0,
|
|
'enable_ssml': False,
|
|
'output_device': 'default'
|
|
}
|
|
|
|
# 合成队列
|
|
self.synthesis_queue = queue.Queue(maxsize=10)
|
|
self.playback_queue = queue.Queue(maxsize=5)
|
|
|
|
# 合成状态
|
|
self.synthesis_state = {
|
|
'is_synthesizing': False,
|
|
'is_playing': False,
|
|
'current_text': '',
|
|
'progress': 0.0,
|
|
'last_synthesis_time': 0.0
|
|
}
|
|
|
|
# 音频输出管理
|
|
self.audio_output = None
|
|
self.audio_stream = None
|
|
|
|
# 线程管理
|
|
self.synthesis_thread = None
|
|
self.playback_thread = None
|
|
self.running = False
|
|
|
|
# 语音库
|
|
self.voice_library = {}
|
|
|
|
# 统计信息
|
|
self.stats = {
|
|
'texts_synthesized': 0,
|
|
'synthesis_attempts': 0,
|
|
'successful_syntheses': 0,
|
|
'failed_syntheses': 0,
|
|
'playback_count': 0,
|
|
'synthesis_time_total': 0.0
|
|
}
|
|
|
|
# 回调函数
|
|
self.synthesis_callbacks = {
|
|
'synthesis_started': [],
|
|
'synthesis_completed': [],
|
|
'synthesis_error': [],
|
|
'playback_started': [],
|
|
'playback_completed': [],
|
|
'playback_error': []
|
|
}
|
|
|
|
# 时间戳记录
|
|
self.last_synthesis_time = 0.0
|
|
self.last_playback_time = 0.0
|
|
|
|
print("✓ 语音合成器已创建")
|
|
|
|
def initialize(self) -> bool:
|
|
"""
|
|
初始化语音合成器
|
|
|
|
Returns:
|
|
是否初始化成功
|
|
"""
|
|
try:
|
|
# 初始化音频输出设备
|
|
self._initialize_audio_output()
|
|
|
|
# 初始化语音库
|
|
self._initialize_voice_library()
|
|
|
|
self.initialized = True
|
|
print("✓ 语音合成器初始化完成")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器初始化失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
def enable(self) -> bool:
|
|
"""
|
|
启用语音合成器
|
|
|
|
Returns:
|
|
是否启用成功
|
|
"""
|
|
try:
|
|
if not self.initialized:
|
|
print("✗ 语音合成器未初始化")
|
|
return False
|
|
|
|
self.enabled = True
|
|
self.running = True
|
|
|
|
# 启动合成线程
|
|
self.synthesis_thread = threading.Thread(target=self._synthesis_loop, daemon=True)
|
|
self.synthesis_thread.start()
|
|
|
|
# 启动播放线程
|
|
self.playback_thread = threading.Thread(target=self._playback_loop, daemon=True)
|
|
self.playback_thread.start()
|
|
|
|
print("✓ 语音合成器已启用")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器启用失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
def disable(self):
|
|
"""禁用语音合成器"""
|
|
try:
|
|
self.enabled = False
|
|
self.running = False
|
|
|
|
# 等待线程结束
|
|
if self.synthesis_thread and self.synthesis_thread.is_alive():
|
|
self.synthesis_thread.join(timeout=2.0)
|
|
|
|
if self.playback_thread and self.playback_thread.is_alive():
|
|
self.playback_thread.join(timeout=2.0)
|
|
|
|
# 停止音频流
|
|
self._stop_audio_stream()
|
|
|
|
print("✓ 语音合成器已禁用")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器禁用失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def finalize(self):
|
|
"""清理语音合成器资源"""
|
|
try:
|
|
self.disable()
|
|
self.synthesis_callbacks.clear()
|
|
|
|
# 清理队列
|
|
while not self.synthesis_queue.empty():
|
|
try:
|
|
self.synthesis_queue.get_nowait()
|
|
except queue.Empty:
|
|
break
|
|
|
|
while not self.playback_queue.empty():
|
|
try:
|
|
self.playback_queue.get_nowait()
|
|
except queue.Empty:
|
|
break
|
|
|
|
self.initialized = False
|
|
print("✓ 语音合成器资源已清理")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器资源清理失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def update(self, dt: float):
|
|
"""
|
|
更新语音合成器状态
|
|
|
|
Args:
|
|
dt: 时间增量
|
|
"""
|
|
try:
|
|
if not self.enabled:
|
|
return
|
|
|
|
current_time = time.time()
|
|
self.last_synthesis_time = current_time
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器更新失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def _initialize_audio_output(self):
|
|
"""初始化音频输出设备"""
|
|
try:
|
|
# 这里应该初始化实际的音频输出设备
|
|
# 由于这是一个模拟实现,我们只打印信息
|
|
print("✓ 音频输出设备初始化完成")
|
|
print(f" 采样率: {self.audio_config['sample_rate']} Hz")
|
|
print(f" 声道数: {self.audio_config['channels']}")
|
|
print(f" 格式: {self.audio_config['format']}")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 音频输出设备初始化失败: {e}")
|
|
|
|
def _initialize_voice_library(self):
|
|
"""初始化语音库"""
|
|
try:
|
|
# 创建模拟语音库
|
|
self.voice_library = {
|
|
'default': {
|
|
'name': '默认语音',
|
|
'language': 'zh-CN',
|
|
'gender': 'neutral',
|
|
'description': '系统默认语音'
|
|
},
|
|
'male': {
|
|
'name': '男声',
|
|
'language': 'zh-CN',
|
|
'gender': 'male',
|
|
'description': '标准男声'
|
|
},
|
|
'female': {
|
|
'name': '女声',
|
|
'language': 'zh-CN',
|
|
'gender': 'female',
|
|
'description': '标准女声'
|
|
},
|
|
'child': {
|
|
'name': '童声',
|
|
'language': 'zh-CN',
|
|
'gender': 'child',
|
|
'description': '儿童语音'
|
|
}
|
|
}
|
|
|
|
print("✓ 语音库初始化完成")
|
|
print(f" 可用语音: {list(self.voice_library.keys())}")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音库初始化失败: {e}")
|
|
|
|
def _start_audio_stream(self) -> bool:
|
|
"""
|
|
启动音频流
|
|
|
|
Returns:
|
|
是否启动成功
|
|
"""
|
|
try:
|
|
# 这里应该启动实际的音频流
|
|
# 由于这是一个模拟实现,我们只设置状态
|
|
self.audio_stream = "simulated_audio_stream"
|
|
print("✓ 音频流已启动")
|
|
return True
|
|
except Exception as e:
|
|
print(f"✗ 音频流启动失败: {e}")
|
|
return False
|
|
|
|
def _stop_audio_stream(self):
|
|
"""停止音频流"""
|
|
try:
|
|
# 这里应该停止实际的音频流
|
|
self.audio_stream = None
|
|
print("✓ 音频流已停止")
|
|
except Exception as e:
|
|
print(f"✗ 音频流停止失败: {e}")
|
|
|
|
def _synthesis_loop(self):
|
|
"""合成循环线程"""
|
|
try:
|
|
# 启动音频流
|
|
if not self._start_audio_stream():
|
|
return
|
|
|
|
while self.running and self.enabled:
|
|
try:
|
|
# 从队列获取合成任务
|
|
if not self.synthesis_queue.empty():
|
|
synthesis_task = self.synthesis_queue.get_nowait()
|
|
self._process_synthesis_task(synthesis_task)
|
|
|
|
# 控制处理频率
|
|
time.sleep(0.01)
|
|
|
|
except queue.Empty:
|
|
time.sleep(0.01)
|
|
except Exception as e:
|
|
print(f"✗ 合成循环错误: {e}")
|
|
time.sleep(0.1)
|
|
|
|
except Exception as e:
|
|
print(f"✗ 合成循环失败: {e}")
|
|
|
|
def _playback_loop(self):
|
|
"""播放循环线程"""
|
|
try:
|
|
while self.running and self.enabled:
|
|
try:
|
|
# 从队列获取播放任务
|
|
if not self.playback_queue.empty():
|
|
playback_task = self.playback_queue.get_nowait()
|
|
self._process_playback_task(playback_task)
|
|
|
|
# 控制播放频率
|
|
time.sleep(0.01)
|
|
|
|
except queue.Empty:
|
|
time.sleep(0.01)
|
|
except Exception as e:
|
|
print(f"✗ 播放循环错误: {e}")
|
|
time.sleep(0.1)
|
|
|
|
except Exception as e:
|
|
print(f"✗ 播放循环失败: {e}")
|
|
|
|
def _process_synthesis_task(self, task: Dict[str, Any]):
|
|
"""
|
|
处理合成任务
|
|
|
|
Args:
|
|
task: 合成任务字典
|
|
"""
|
|
try:
|
|
start_time = time.time()
|
|
|
|
text = task.get('text', '')
|
|
speed = task.get('speed', 1.0)
|
|
volume = task.get('volume', 1.0)
|
|
blocking = task.get('blocking', False)
|
|
|
|
# 更新合成状态
|
|
self.synthesis_state['is_synthesizing'] = True
|
|
self.synthesis_state['current_text'] = text
|
|
self.synthesis_state['last_synthesis_time'] = start_time
|
|
|
|
# 触发合成开始回调
|
|
self._trigger_synthesis_callback('synthesis_started', {
|
|
'text': text,
|
|
'speed': speed,
|
|
'volume': volume
|
|
})
|
|
|
|
# 模拟语音合成过程
|
|
synthesized_audio = self._synthesize_text(text, speed, volume)
|
|
|
|
if synthesized_audio is not None:
|
|
# 添加到播放队列
|
|
try:
|
|
self.playback_queue.put_nowait({
|
|
'audio': synthesized_audio,
|
|
'text': text,
|
|
'blocking': blocking,
|
|
'timestamp': time.time()
|
|
})
|
|
|
|
# 更新统计信息
|
|
self.stats['successful_syntheses'] += 1
|
|
|
|
# 触发合成完成回调
|
|
self._trigger_synthesis_callback('synthesis_completed', {
|
|
'text': text,
|
|
'audio_length': len(synthesized_audio),
|
|
'synthesis_time': time.time() - start_time
|
|
})
|
|
|
|
except queue.Full:
|
|
print("✗ 播放队列已满,丢弃合成结果")
|
|
self.stats['failed_syntheses'] += 1
|
|
|
|
# 触发合成错误回调
|
|
self._trigger_synthesis_callback('synthesis_error', {
|
|
'text': text,
|
|
'error': 'Playback queue full'
|
|
})
|
|
else:
|
|
self.stats['failed_syntheses'] += 1
|
|
|
|
# 触发合成错误回调
|
|
self._trigger_synthesis_callback('synthesis_error', {
|
|
'text': text,
|
|
'error': 'Synthesis failed'
|
|
})
|
|
|
|
# 更新统计信息
|
|
synthesis_time = time.time() - start_time
|
|
self.stats['synthesis_time_total'] += synthesis_time
|
|
self.stats['synthesis_attempts'] += 1
|
|
self.last_synthesis_time = time.time()
|
|
|
|
except Exception as e:
|
|
print(f"✗ 合成任务处理失败: {e}")
|
|
self.stats['failed_syntheses'] += 1
|
|
|
|
finally:
|
|
# 重置合成状态
|
|
self.synthesis_state['is_synthesizing'] = False
|
|
self.synthesis_state['progress'] = 0.0
|
|
|
|
def _process_playback_task(self, task: Dict[str, Any]):
|
|
"""
|
|
处理播放任务
|
|
|
|
Args:
|
|
task: 播放任务字典
|
|
"""
|
|
try:
|
|
audio_data = task.get('audio', b'')
|
|
text = task.get('text', '')
|
|
blocking = task.get('blocking', False)
|
|
|
|
# 更新播放状态
|
|
self.synthesis_state['is_playing'] = True
|
|
self.synthesis_state['current_text'] = text
|
|
|
|
# 触发播放开始回调
|
|
self._trigger_synthesis_callback('playback_started', {
|
|
'text': text,
|
|
'audio_length': len(audio_data)
|
|
})
|
|
|
|
# 模拟音频播放
|
|
playback_success = self._play_audio(audio_data, blocking)
|
|
|
|
if playback_success:
|
|
self.stats['playback_count'] += 1
|
|
|
|
# 触发播放完成回调
|
|
self._trigger_synthesis_callback('playback_completed', {
|
|
'text': text,
|
|
'playback_time': len(audio_data) / self.audio_config['sample_rate']
|
|
})
|
|
else:
|
|
# 触发播放错误回调
|
|
self._trigger_synthesis_callback('playback_error', {
|
|
'text': text,
|
|
'error': 'Playback failed'
|
|
})
|
|
|
|
self.last_playback_time = time.time()
|
|
|
|
except Exception as e:
|
|
print(f"✗ 播放任务处理失败: {e}")
|
|
|
|
# 触发播放错误回调
|
|
self._trigger_synthesis_callback('playback_error', {
|
|
'text': task.get('text', ''),
|
|
'error': str(e)
|
|
})
|
|
|
|
finally:
|
|
# 重置播放状态
|
|
self.synthesis_state['is_playing'] = False
|
|
|
|
def _synthesize_text(self, text: str, speed: float, volume: float) -> Optional[bytes]:
|
|
"""
|
|
合成文本为音频
|
|
|
|
Args:
|
|
text: 要合成的文本
|
|
speed: 语速
|
|
volume: 音量
|
|
|
|
Returns:
|
|
音频数据或None
|
|
"""
|
|
try:
|
|
# 模拟文本到语音的转换过程
|
|
import random
|
|
import struct
|
|
|
|
# 根据文本长度计算音频长度
|
|
char_count = len(text)
|
|
# 假设每个字符大约需要0.1秒
|
|
duration_seconds = char_count * 0.1 * (1.0 / speed)
|
|
|
|
# 计算样本数
|
|
sample_rate = self.audio_config['sample_rate']
|
|
total_samples = int(duration_seconds * sample_rate)
|
|
|
|
# 生成模拟的音频数据
|
|
audio_data = bytearray()
|
|
|
|
# 生成简单的正弦波作为语音模拟
|
|
frequency = 440.0 # A音
|
|
for i in range(total_samples):
|
|
# 添加一些变化使声音更自然
|
|
t = i / sample_rate
|
|
wave_value = math.sin(2 * math.pi * frequency * t)
|
|
|
|
# 添加谐波
|
|
wave_value += 0.3 * math.sin(2 * math.pi * frequency * 2 * t)
|
|
wave_value += 0.2 * math.sin(2 * math.pi * frequency * 3 * t)
|
|
|
|
# 应用音量
|
|
wave_value *= volume
|
|
|
|
# 转换为16位整数
|
|
sample = int(wave_value * 32767 * 0.3) # 降低整体音量
|
|
audio_data.extend(struct.pack('<h', sample))
|
|
|
|
return bytes(audio_data)
|
|
|
|
except Exception as e:
|
|
print(f"✗ 文本合成失败: {e}")
|
|
return None
|
|
|
|
def _play_audio(self, audio_data: bytes, blocking: bool = False) -> bool:
|
|
"""
|
|
播放音频数据
|
|
|
|
Args:
|
|
audio_data: 音频数据
|
|
blocking: 是否阻塞等待播放完成
|
|
|
|
Returns:
|
|
是否播放成功
|
|
"""
|
|
try:
|
|
# 模拟音频播放
|
|
import time
|
|
import math
|
|
|
|
# 计算播放时间
|
|
sample_count = len(audio_data) // 2 # 16位音频
|
|
duration = sample_count / self.audio_config['sample_rate']
|
|
|
|
print(f"✓ 播放音频: {duration:.2f}秒")
|
|
|
|
# 如果是阻塞模式,等待播放完成
|
|
if blocking:
|
|
time.sleep(duration)
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ 音频播放失败: {e}")
|
|
return False
|
|
|
|
def synthesize_speech(self, text: str, blocking: bool = False,
|
|
speed: float = 1.0, volume: float = 1.0) -> bool:
|
|
"""
|
|
合成并播放语音
|
|
|
|
Args:
|
|
text: 要合成的文本
|
|
blocking: 是否阻塞等待播放完成
|
|
speed: 语速(0.5-2.0)
|
|
volume: 音量(0.0-1.0)
|
|
|
|
Returns:
|
|
是否合成成功
|
|
"""
|
|
try:
|
|
if not self.enabled:
|
|
print("✗ 语音合成器未启用")
|
|
return False
|
|
|
|
# 限制参数范围
|
|
speed = max(0.5, min(2.0, speed))
|
|
volume = max(0.0, min(1.0, volume))
|
|
|
|
# 创建合成任务
|
|
synthesis_task = {
|
|
'text': text,
|
|
'speed': speed,
|
|
'volume': volume,
|
|
'blocking': blocking,
|
|
'timestamp': time.time()
|
|
}
|
|
|
|
# 添加到合成队列
|
|
try:
|
|
self.synthesis_queue.put_nowait(synthesis_task)
|
|
self.stats['texts_synthesized'] += 1
|
|
return True
|
|
except queue.Full:
|
|
print("✗ 合成队列已满")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音合成失败: {e}")
|
|
self.stats['failed_syntheses'] += 1
|
|
return False
|
|
|
|
def stop_speech(self) -> bool:
|
|
"""
|
|
停止当前语音播放
|
|
|
|
Returns:
|
|
是否停止成功
|
|
"""
|
|
try:
|
|
# 清空播放队列
|
|
while not self.playback_queue.empty():
|
|
try:
|
|
self.playback_queue.get_nowait()
|
|
except queue.Empty:
|
|
break
|
|
|
|
# 重置播放状态
|
|
self.synthesis_state['is_playing'] = False
|
|
self.synthesis_state['current_text'] = ''
|
|
|
|
print("✓ 语音播放已停止")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ 语音播放停止失败: {e}")
|
|
return False
|
|
|
|
def get_available_voices(self) -> Dict[str, Dict[str, Any]]:
|
|
"""
|
|
获取可用语音列表
|
|
|
|
Returns:
|
|
语音信息字典
|
|
"""
|
|
return self.voice_library.copy()
|
|
|
|
def set_voice(self, voice_name: str) -> bool:
|
|
"""
|
|
设置语音
|
|
|
|
Args:
|
|
voice_name: 语音名称
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
try:
|
|
if voice_name in self.voice_library:
|
|
self.synthesis_config['voice'] = voice_name
|
|
print(f"✓ 语音已设置为: {voice_name}")
|
|
return True
|
|
else:
|
|
print(f"✗ 语音不存在: {voice_name}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"✗ 语音设置失败: {e}")
|
|
return False
|
|
|
|
def set_synthesis_config(self, config: Dict[str, Any]) -> bool:
|
|
"""
|
|
设置合成配置
|
|
|
|
Args:
|
|
config: 配置字典
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
try:
|
|
self.synthesis_config.update(config)
|
|
print(f"✓ 合成配置已更新: {self.synthesis_config}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"✗ 合成配置设置失败: {e}")
|
|
return False
|
|
|
|
def get_synthesis_config(self) -> Dict[str, Any]:
|
|
"""
|
|
获取合成配置
|
|
|
|
Returns:
|
|
配置字典
|
|
"""
|
|
return self.synthesis_config.copy()
|
|
|
|
def set_audio_config(self, config: Dict[str, Any]) -> bool:
|
|
"""
|
|
设置音频配置
|
|
|
|
Args:
|
|
config: 配置字典
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
try:
|
|
self.audio_config.update(config)
|
|
print(f"✓ 音频配置已更新: {self.audio_config}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"✗ 音频配置设置失败: {e}")
|
|
return False
|
|
|
|
def get_audio_config(self) -> Dict[str, Any]:
|
|
"""
|
|
获取音频配置
|
|
|
|
Returns:
|
|
配置字典
|
|
"""
|
|
return self.audio_config.copy()
|
|
|
|
def is_speaking(self) -> bool:
|
|
"""
|
|
检查是否正在播放语音
|
|
|
|
Returns:
|
|
是否正在播放语音
|
|
"""
|
|
return self.synthesis_state['is_playing']
|
|
|
|
def is_synthesizing(self) -> bool:
|
|
"""
|
|
检查是否正在合成语音
|
|
|
|
Returns:
|
|
是否正在合成语音
|
|
"""
|
|
return self.synthesis_state['is_synthesizing']
|
|
|
|
def get_synthesis_progress(self) -> float:
|
|
"""
|
|
获取合成进度
|
|
|
|
Returns:
|
|
合成进度(0.0-1.0)
|
|
"""
|
|
return self.synthesis_state['progress']
|
|
|
|
def _trigger_synthesis_callback(self, callback_type: str, data: Dict[str, Any]):
|
|
"""
|
|
触发合成回调
|
|
|
|
Args:
|
|
callback_type: 回调类型
|
|
data: 回调数据
|
|
"""
|
|
try:
|
|
if callback_type in self.synthesis_callbacks:
|
|
for callback in self.synthesis_callbacks[callback_type]:
|
|
try:
|
|
callback(data)
|
|
except Exception as e:
|
|
print(f"✗ 合成回调执行失败: {e}")
|
|
except Exception as e:
|
|
print(f"✗ 合成回调触发失败: {e}")
|
|
|
|
def register_synthesis_callback(self, callback_type: str, callback: callable):
|
|
"""
|
|
注册合成回调
|
|
|
|
Args:
|
|
callback_type: 回调类型
|
|
callback: 回调函数
|
|
"""
|
|
try:
|
|
if callback_type in self.synthesis_callbacks:
|
|
self.synthesis_callbacks[callback_type].append(callback)
|
|
print(f"✓ 合成回调已注册: {callback_type}")
|
|
else:
|
|
print(f"✗ 无效的回调类型: {callback_type}")
|
|
except Exception as e:
|
|
print(f"✗ 合成回调注册失败: {e}")
|
|
|
|
def unregister_synthesis_callback(self, callback_type: str, callback: callable):
|
|
"""
|
|
注销合成回调
|
|
|
|
Args:
|
|
callback_type: 回调类型
|
|
callback: 回调函数
|
|
"""
|
|
try:
|
|
if callback_type in self.synthesis_callbacks:
|
|
if callback in self.synthesis_callbacks[callback_type]:
|
|
self.synthesis_callbacks[callback_type].remove(callback)
|
|
print(f"✓ 合成回调已注销: {callback_type}")
|
|
except Exception as e:
|
|
print(f"✗ 合成回调注销失败: {e}")
|
|
|
|
def get_stats(self) -> Dict[str, Any]:
|
|
"""
|
|
获取统计信息
|
|
|
|
Returns:
|
|
统计信息字典
|
|
"""
|
|
stats = self.stats.copy()
|
|
if self.stats['successful_syntheses'] > 0:
|
|
stats['average_synthesis_time'] = (
|
|
self.stats['synthesis_time_total'] / self.stats['successful_syntheses']
|
|
)
|
|
else:
|
|
stats['average_synthesis_time'] = 0.0
|
|
return stats
|
|
|
|
def reset_stats(self):
|
|
"""重置统计信息"""
|
|
try:
|
|
self.stats = {
|
|
'texts_synthesized': 0,
|
|
'synthesis_attempts': 0,
|
|
'successful_syntheses': 0,
|
|
'failed_syntheses': 0,
|
|
'playback_count': 0,
|
|
'synthesis_time_total': 0.0
|
|
}
|
|
print("✓ 语音合成器统计信息已重置")
|
|
except Exception as e:
|
|
print(f"✗ 语音合成器统计信息重置失败: {e}")
|
|
|
|
# 导入math模块用于正弦波计算
|
|
import math |