mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 09:33:55 +08:00
refactor: 优化超时配置,响应社区反馈
- 工具调用超时改为可配置项 tool_call_timeout,默认30秒 - OpenAI 超时恢复可配置机制,支持细粒度配置和单一值 - TTS 超时保护统一添加到所有流式TTS实现 - 将 ActionResponse 导入移到文件顶部 - 修复超时配置边界情况处理
This commit is contained in:
@@ -61,6 +61,8 @@ delete_audio: true
|
|||||||
close_connection_no_voice_time: 120
|
close_connection_no_voice_time: 120
|
||||||
# TTS请求超时时间(秒)
|
# TTS请求超时时间(秒)
|
||||||
tts_timeout: 10
|
tts_timeout: 10
|
||||||
|
# 工具调用超时时间(秒)
|
||||||
|
tool_call_timeout: 30
|
||||||
# 开启唤醒词加速
|
# 开启唤醒词加速
|
||||||
enable_wakeup_words_response_cache: true
|
enable_wakeup_words_response_cache: true
|
||||||
# 开场是否回复唤醒词
|
# 开场是否回复唤醒词
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ from core.providers.asr.dto.dto import InterfaceType
|
|||||||
from core.handle.textHandle import handleTextMessage
|
from core.handle.textHandle import handleTextMessage
|
||||||
from core.providers.tools.unified_tool_handler import UnifiedToolHandler
|
from core.providers.tools.unified_tool_handler import UnifiedToolHandler
|
||||||
from plugins_func.loadplugins import auto_import_modules
|
from plugins_func.loadplugins import auto_import_modules
|
||||||
from plugins_func.register import Action
|
from plugins_func.register import Action, ActionResponse
|
||||||
from core.auth import AuthenticationError
|
from core.auth import AuthenticationError
|
||||||
from config.config_loader import get_private_config_from_api
|
from config.config_loader import get_private_config_from_api
|
||||||
from core.providers.tts.dto.dto import ContentType, TTSMessageDTO, SentenceType
|
from core.providers.tts.dto.dto import ContentType, TTSMessageDTO, SentenceType
|
||||||
@@ -997,19 +997,19 @@ class ConnectionHandler:
|
|||||||
)
|
)
|
||||||
futures_with_data.append((future, tool_call_data))
|
futures_with_data.append((future, tool_call_data))
|
||||||
|
|
||||||
TOOL_CALL_TIMEOUT = 30
|
# 工具调用超时时间,可配置,默认30秒
|
||||||
|
tool_call_timeout = int(self.config.get("tool_call_timeout", 30))
|
||||||
# 等待协程结束(实际等待时长为最慢的那个)
|
# 等待协程结束(实际等待时长为最慢的那个)
|
||||||
tool_results = []
|
tool_results = []
|
||||||
for future, tool_call_data in futures_with_data:
|
for future, tool_call_data in futures_with_data:
|
||||||
try:
|
try:
|
||||||
result = future.result(timeout=TOOL_CALL_TIMEOUT)
|
result = future.result(timeout=tool_call_timeout)
|
||||||
tool_results.append((result, tool_call_data))
|
tool_results.append((result, tool_call_data))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.bind(tag=TAG).error(
|
self.logger.bind(tag=TAG).error(
|
||||||
f"工具调用超时或异常: {tool_call_data['name']}, 错误: {e}"
|
f"工具调用超时或异常: {tool_call_data['name']}, 错误: {e}"
|
||||||
)
|
)
|
||||||
# 超时时返回错误响应,避免整个流程卡死
|
# 超时时返回错误响应,避免整个流程卡死
|
||||||
from plugins_func.register import Action, ActionResponse
|
|
||||||
tool_results.append((
|
tool_results.append((
|
||||||
ActionResponse(action=Action.ERROR, result="哎呀,网络遇到点问题,请稍后再试下!"),
|
ActionResponse(action=Action.ERROR, result="哎呀,网络遇到点问题,请稍后再试下!"),
|
||||||
tool_call_data
|
tool_call_data
|
||||||
|
|||||||
@@ -150,8 +150,8 @@ async def process_intent_result(
|
|||||||
def process_function_call():
|
def process_function_call():
|
||||||
conn.dialogue.put(Message(role="user", content=original_text))
|
conn.dialogue.put(Message(role="user", content=original_text))
|
||||||
|
|
||||||
# 使用统一工具处理器处理所有工具调用,添加超时保护
|
# 工具调用超时时间
|
||||||
TOOL_CALL_TIMEOUT = 30
|
tool_call_timeout = int(conn.config.get("tool_call_timeout", 30))
|
||||||
# 使用统一工具处理器处理所有工具调用
|
# 使用统一工具处理器处理所有工具调用
|
||||||
try:
|
try:
|
||||||
result = asyncio.run_coroutine_threadsafe(
|
result = asyncio.run_coroutine_threadsafe(
|
||||||
@@ -159,7 +159,7 @@ async def process_intent_result(
|
|||||||
conn, function_call_data
|
conn, function_call_data
|
||||||
),
|
),
|
||||||
conn.loop,
|
conn.loop,
|
||||||
).result(timeout=TOOL_CALL_TIMEOUT)
|
).result(timeout=tool_call_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
conn.logger.bind(tag=TAG).error(f"工具调用失败: {e}")
|
conn.logger.bind(tag=TAG).error(f"工具调用失败: {e}")
|
||||||
result = ActionResponse(
|
result = ActionResponse(
|
||||||
|
|||||||
@@ -17,12 +17,22 @@ class LLMProvider(LLMProviderBase):
|
|||||||
self.base_url = config.get("base_url")
|
self.base_url = config.get("base_url")
|
||||||
else:
|
else:
|
||||||
self.base_url = config.get("url")
|
self.base_url = config.get("url")
|
||||||
custom_timeout = httpx.Timeout(
|
|
||||||
pool=2.0,
|
timeout_config = config.get("timeout")
|
||||||
connect=3.0,
|
if isinstance(timeout_config, dict):
|
||||||
write=5.0,
|
# 细粒度超时配置
|
||||||
read=10.0
|
custom_timeout = httpx.Timeout(
|
||||||
)
|
pool=timeout_config.get("pool", 2.0),
|
||||||
|
connect=timeout_config.get("connect", 3.0),
|
||||||
|
write=timeout_config.get("write", 5.0),
|
||||||
|
read=timeout_config.get("read", 60.0)
|
||||||
|
)
|
||||||
|
elif isinstance(timeout_config, (int, float)) and timeout_config > 0:
|
||||||
|
# 兼容旧的单一超时配置(整数或浮点数)
|
||||||
|
custom_timeout = httpx.Timeout(timeout_config)
|
||||||
|
else:
|
||||||
|
# 未配置或配置无效,使用默认值
|
||||||
|
custom_timeout = httpx.Timeout(300)
|
||||||
|
|
||||||
param_defaults = {
|
param_defaults = {
|
||||||
"max_tokens": int,
|
"max_tokens": int,
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.start_session(self.conn.sentence_id),
|
self.start_session(self.conn.sentence_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
self.before_stop_play_files.clear()
|
self.before_stop_play_files.clear()
|
||||||
logger.bind(tag=TAG).info("TTS会话启动成功")
|
logger.bind(tag=TAG).info("TTS会话启动成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -144,7 +144,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.text_to_speak(message.content_detail, None),
|
self.text_to_speak(message.content_detail, None),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
||||||
@@ -165,7 +165,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.finish_session(self.conn.sentence_id),
|
self.finish_session(self.conn.sentence_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.start_session(self.task_id),
|
self.start_session(self.task_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
self.before_stop_play_files.clear()
|
self.before_stop_play_files.clear()
|
||||||
logger.bind(tag=TAG).debug("TTS会话启动成功")
|
logger.bind(tag=TAG).debug("TTS会话启动成功")
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.text_to_speak(message.content_detail, None),
|
self.text_to_speak(message.content_detail, None),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
||||||
@@ -270,7 +270,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.finish_session(self.task_id),
|
self.finish_session(self.task_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class TTSProviderBase(ABC):
|
|||||||
self.delete_audio_file = delete_audio_file
|
self.delete_audio_file = delete_audio_file
|
||||||
self.audio_file_type = "wav"
|
self.audio_file_type = "wav"
|
||||||
self.output_file = config.get("output_dir", "tmp/")
|
self.output_file = config.get("output_dir", "tmp/")
|
||||||
|
self.tts_timeout = int(config.get("tts_timeout", 15))
|
||||||
self.tts_text_queue = queue.Queue()
|
self.tts_text_queue = queue.Queue()
|
||||||
self.tts_audio_queue = queue.Queue()
|
self.tts_audio_queue = queue.Queue()
|
||||||
self.tts_audio_first_sentence = True
|
self.tts_audio_first_sentence = True
|
||||||
@@ -357,7 +358,7 @@ class TTSProviderBase(ABC):
|
|||||||
sendAudioMessage(self.conn, sentence_type, audio_datas, text),
|
sendAudioMessage(self.conn, sentence_type, audio_datas, text),
|
||||||
self.conn.loop,
|
self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result(timeout=15)
|
future.result(timeout=self.tts_timeout)
|
||||||
|
|
||||||
# 记录输出和报告
|
# 记录输出和报告
|
||||||
if self.conn.max_output_size > 0 and text:
|
if self.conn.max_output_size > 0 and text:
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.cluster = config.get("cluster")
|
self.cluster = config.get("cluster")
|
||||||
self.resource_id = config.get("resource_id")
|
self.resource_id = config.get("resource_id")
|
||||||
self.activate_session = False
|
self.activate_session = False
|
||||||
self.timeout = 30
|
|
||||||
if config.get("private_voice"):
|
if config.get("private_voice"):
|
||||||
self.voice = config.get("private_voice")
|
self.voice = config.get("private_voice")
|
||||||
else:
|
else:
|
||||||
@@ -308,7 +307,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.start_session(self.conn.sentence_id),
|
self.start_session(self.conn.sentence_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result(self.timeout)
|
future.result(timeout=self.tts_timeout)
|
||||||
self.before_stop_play_files.clear()
|
self.before_stop_play_files.clear()
|
||||||
logger.bind(tag=TAG).debug("TTS会话启动成功")
|
logger.bind(tag=TAG).debug("TTS会话启动成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -325,7 +324,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.text_to_speak(message.content_detail, None),
|
self.text_to_speak(message.content_detail, None),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result(self.timeout)
|
future.result(timeout=self.tts_timeout)
|
||||||
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
||||||
@@ -345,7 +344,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.finish_session(self.conn.sentence_id),
|
self.finish_session(self.conn.sentence_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result(self.timeout)
|
future.result(timeout=self.tts_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"结束TTS会话失败: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.start_session(self.conn.sentence_id),
|
self.start_session(self.conn.sentence_id),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
self.before_stop_play_files.clear()
|
self.before_stop_play_files.clear()
|
||||||
logger.bind(tag=TAG).info("TTS会话启动成功")
|
logger.bind(tag=TAG).info("TTS会话启动成功")
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.text_to_speak(message.content_detail, None),
|
self.text_to_speak(message.content_detail, None),
|
||||||
loop=self.conn.loop,
|
loop=self.conn.loop,
|
||||||
)
|
)
|
||||||
future.result()
|
future.result(timeout=self.tts_timeout)
|
||||||
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
logger.bind(tag=TAG).debug("TTS文本发送成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
logger.bind(tag=TAG).error(f"发送TTS文本失败: {str(e)}")
|
||||||
|
|||||||
Reference in New Issue
Block a user