mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
refactor(asr): 重构speech_to_text方法以接收artifacts参数
移除各ASR提供者中重复的get_current_artifacts调用,改为通过参数传递artifacts 修改base类中process_audio方法,根据combined_pcm_data长度决定是否创建artifacts 更新所有speech_to_text方法签名,添加artifacts可选参数并更新文档字符串
This commit is contained in:
@@ -213,7 +213,7 @@ class ASRProvider(ASRProviderBase):
|
||||
return None
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
if self._is_token_expired():
|
||||
@@ -221,7 +221,6 @@ class ASRProvider(ASRProviderBase):
|
||||
self._refresh_token()
|
||||
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
# 发送请求并获取文本
|
||||
|
||||
@@ -341,7 +341,7 @@ class ASRProvider(ASRProviderBase):
|
||||
|
||||
logger.bind(tag=TAG).debug("ASR会话清理完成")
|
||||
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format):
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format, artifacts=None):
|
||||
"""获取识别结果"""
|
||||
result = self.text
|
||||
self.text = ""
|
||||
|
||||
@@ -325,7 +325,7 @@ class ASRProvider(ASRProviderBase):
|
||||
|
||||
logger.bind(tag=TAG).debug("ASR会话清理完成")
|
||||
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format):
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format, artifacts=None):
|
||||
"""获取识别结果"""
|
||||
result = self.text
|
||||
self.text = ""
|
||||
|
||||
@@ -30,7 +30,7 @@ class ASRProvider(ASRProviderBase):
|
||||
os.makedirs(self.output_dir, exist_ok=True)
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
if not opus_data:
|
||||
@@ -43,7 +43,6 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).error("百度语音识别配置未设置,无法进行识别")
|
||||
return None, None
|
||||
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ logger = setup_logging()
|
||||
|
||||
class ASRProviderBase(ABC):
|
||||
def __init__(self):
|
||||
self._current_artifacts: Optional[ASRProviderBase.AudioArtifacts] = None
|
||||
"""当前正在处理的音频 artifact"""
|
||||
pass
|
||||
|
||||
# 打开音频通道
|
||||
async def open_audio_channels(self, conn):
|
||||
@@ -215,9 +214,13 @@ class ASRProviderBase(ABC):
|
||||
|
||||
class AudioArtifacts(NamedTuple):
|
||||
pcm_frames: List[bytes]
|
||||
"""PCM音频帧列表"""
|
||||
pcm_bytes: bytes
|
||||
"""合并后的PCM音频字节数据"""
|
||||
file_path: Optional[str]
|
||||
"""WAV文件路径"""
|
||||
temp_path: Optional[str]
|
||||
"""临时WAV文件路径"""
|
||||
|
||||
def get_current_artifacts(self) -> Optional["ASRProviderBase.AudioArtifacts"]:
|
||||
return self._current_artifacts
|
||||
@@ -282,14 +285,19 @@ class ASRProviderBase(ABC):
|
||||
):
|
||||
file_path = self.save_audio_to_file(pcm_data, session_id)
|
||||
|
||||
self._current_artifacts = ASRProviderBase.AudioArtifacts(
|
||||
pcm_frames=pcm_data,
|
||||
pcm_bytes=combined_pcm_data,
|
||||
file_path=file_path,
|
||||
temp_path=temp_path,
|
||||
)
|
||||
if len(combined_pcm_data) == 0:
|
||||
artifacts = None
|
||||
else:
|
||||
artifacts = ASRProviderBase.AudioArtifacts(
|
||||
pcm_frames=pcm_data,
|
||||
pcm_bytes=combined_pcm_data,
|
||||
file_path=file_path,
|
||||
temp_path=temp_path,
|
||||
)
|
||||
|
||||
text, _ = await self.speech_to_text(opus_data, session_id, audio_format)
|
||||
text, _ = await self.speech_to_text(
|
||||
opus_data, session_id, audio_format, artifacts
|
||||
)
|
||||
return text, file_path
|
||||
except OSError as e:
|
||||
logger.bind(tag=TAG).error(f"文件操作错误: {e}")
|
||||
@@ -313,9 +321,20 @@ class ASRProviderBase(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self,
|
||||
opus_data: List[bytes],
|
||||
session_id: str,
|
||||
audio_format="opus",
|
||||
artifacts: Optional[AudioArtifacts] = None,
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
"""将语音数据转换为文本
|
||||
|
||||
:param opus_data: 输入的Opus音频数据
|
||||
:param session_id: 会话ID
|
||||
:param audio_format: 音频格式,默认"opus"
|
||||
:param artifacts: 音频工件,包含PCM数据、文件路径等
|
||||
:return: 识别结果文本和文件路径(如果有)
|
||||
"""
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -232,12 +232,11 @@ class ASRProvider(ASRProviderBase):
|
||||
yield data[offset:data_len], True
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
|
||||
|
||||
@@ -408,7 +408,7 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).error(f"原始响应数据: {res.hex()}")
|
||||
raise
|
||||
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format):
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format, artifacts=None):
|
||||
result = self.text
|
||||
self.text = "" # 清空text
|
||||
return result, None
|
||||
|
||||
@@ -64,14 +64,13 @@ class ASRProvider(ASRProviderBase):
|
||||
)
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""语音转文本主处理逻辑"""
|
||||
retry_count = 0
|
||||
|
||||
while retry_count < MAX_RETRIES:
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).debug(f"Sent end message: {end_message}")
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""
|
||||
Convert speech data to text using FunASR.
|
||||
@@ -109,7 +109,6 @@ class ASRProvider(ASRProviderBase):
|
||||
:param session_id: Unique session identifier.
|
||||
:return: Tuple containing recognized text and optional timestamp.
|
||||
"""
|
||||
artifacts = self.get_current_artifacts()
|
||||
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
|
||||
@@ -24,10 +24,9 @@ class ASRProvider(ASRProviderBase):
|
||||
def requires_file(self) -> bool:
|
||||
return True
|
||||
|
||||
async def speech_to_text(self, opus_data: List[bytes], session_id: str, audio_format="opus") -> Tuple[Optional[str], Optional[str]]:
|
||||
async def speech_to_text(self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None) -> Tuple[Optional[str], Optional[str]]:
|
||||
file_path = None
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
file_path = artifacts.file_path
|
||||
|
||||
@@ -41,13 +41,12 @@ class ASRProvider(ASRProviderBase):
|
||||
return True
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
temp_file_path = None
|
||||
file_path = None
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
temp_file_path = artifacts.temp_path
|
||||
|
||||
@@ -124,12 +124,11 @@ class ASRProvider(ASRProviderBase):
|
||||
return True
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""语音转文本主处理逻辑"""
|
||||
file_path = None
|
||||
try:
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
file_path = artifacts.file_path
|
||||
|
||||
@@ -32,7 +32,7 @@ class ASRProvider(ASRProviderBase):
|
||||
os.makedirs(self.output_dir, exist_ok=True)
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
if not opus_data:
|
||||
@@ -45,7 +45,6 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).error("腾讯云语音识别配置未设置,无法进行识别")
|
||||
return None, None
|
||||
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class ASRProvider(ASRProviderBase):
|
||||
raise
|
||||
|
||||
async def speech_to_text(
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus"
|
||||
self, opus_data: List[bytes], session_id: str, audio_format="opus", artifacts=None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""将语音数据转换为文本"""
|
||||
try:
|
||||
@@ -53,7 +53,6 @@ class ASRProvider(ASRProviderBase):
|
||||
logger.bind(tag=TAG).error("VOSK模型未加载,无法进行识别")
|
||||
return "", None
|
||||
|
||||
artifacts = self.get_current_artifacts()
|
||||
if artifacts is None:
|
||||
return "", None
|
||||
if not artifacts.pcm_bytes:
|
||||
|
||||
@@ -334,7 +334,7 @@ class ASRProvider(ASRProviderBase):
|
||||
|
||||
logger.bind(tag=TAG).debug("ASR会话清理完成")
|
||||
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format):
|
||||
async def speech_to_text(self, opus_data, session_id, audio_format, artifacts=None):
|
||||
"""获取识别结果"""
|
||||
result = self.text
|
||||
self.text = ""
|
||||
|
||||
Reference in New Issue
Block a user