Files
xiaozhi-esp32-server/main/xiaozhi-server/core/handle/helloHandle.py
T

127 lines
4.3 KiB
Python
Raw Normal View History

2025-05-27 18:06:44 +08:00
import time
2025-02-02 23:01:14 +08:00
import json
2025-05-27 18:06:44 +08:00
import random
2025-03-23 22:02:13 +08:00
import asyncio
from core.utils.util import audio_to_data
2025-05-27 18:06:44 +08:00
from core.handle.sendAudioHandle import send_stt_message
from core.utils.util import remove_punctuation_and_length, opus_datas_to_wav_bytes
from core.providers.tts.dto.dto import ContentType, SentenceType
from core.handle.mcpHandle import (
MCPClient,
send_mcp_initialize_message,
send_mcp_tools_list_request,
)
2025-06-07 22:08:22 +08:00
from core.utils.wakeup_word import WakeupWordsConfig
2025-02-02 23:01:14 +08:00
2025-04-12 17:36:04 +08:00
TAG = __name__
2025-02-02 23:01:14 +08:00
2025-03-31 22:54:37 +08:00
WAKEUP_CONFIG = {
2025-06-07 22:08:22 +08:00
"refresh_time": 5,
2025-03-31 22:54:37 +08:00
"words": ["你好小智", "你好啊小智", "小智你好", "小智"],
}
2025-03-23 22:02:13 +08:00
2025-06-07 22:08:22 +08:00
# 创建全局的唤醒词配置管理器
wakeup_words_config = WakeupWordsConfig()
# 用于防止并发调用wakeupWordsResponse的锁
_wakeup_response_lock = asyncio.Lock()
2025-02-02 23:01:14 +08:00
2025-05-06 14:57:29 +08:00
async def handleHelloMessage(conn, msg_json):
"""处理hello消息"""
audio_params = msg_json.get("audio_params")
if audio_params:
format = audio_params.get("format")
2025-05-08 11:31:12 +08:00
conn.logger.bind(tag=TAG).info(f"客户端音频格式: {format}")
2025-05-06 14:57:29 +08:00
conn.audio_format = format
2025-05-08 11:11:28 +08:00
conn.welcome_msg["audio_params"] = audio_params
2025-05-28 11:49:18 +08:00
features = msg_json.get("features")
if features:
conn.logger.bind(tag=TAG).info(f"客户端特性: {features}")
conn.features = features
2025-05-28 18:32:15 +08:00
if features.get("mcp"):
conn.logger.bind(tag=TAG).info("客户端支持MCP")
2025-05-29 13:42:31 +08:00
conn.mcp_client = MCPClient()
2025-05-28 18:32:15 +08:00
# 发送初始化
2025-05-29 13:42:31 +08:00
asyncio.create_task(send_mcp_initialize_message(conn))
2025-05-28 18:32:15 +08:00
# 发送mcp消息,获取tools列表
2025-05-29 13:42:31 +08:00
asyncio.create_task(send_mcp_tools_list_request(conn))
2025-05-06 14:57:29 +08:00
2025-02-02 23:01:14 +08:00
await conn.websocket.send(json.dumps(conn.welcome_msg))
2025-03-23 22:02:13 +08:00
async def checkWakeupWords(conn, text):
2025-03-31 22:54:37 +08:00
enable_wakeup_words_response_cache = conn.config[
"enable_wakeup_words_response_cache"
]
2025-06-07 22:08:22 +08:00
if not enable_wakeup_words_response_cache or not conn.tts:
2025-05-27 18:51:08 +08:00
return False
2025-05-19 15:18:01 +08:00
_, filtered_text = remove_punctuation_and_length(text)
2025-06-07 22:08:22 +08:00
if filtered_text not in conn.config.get("wakeup_words"):
return False
2025-03-23 22:02:13 +08:00
2025-06-07 22:48:23 +08:00
conn.just_woken_up = True
2025-06-07 22:08:22 +08:00
await send_stt_message(conn, text)
# 获取当前音色
voice = getattr(conn.tts, "voice", "default")
# 获取唤醒词回复配置
response = wakeup_words_config.get_wakeup_response(voice)
# 播放唤醒词回复
conn.client_abort = False
opus_packets, _ = audio_to_data(response["file_path"])
conn.tts.tts_audio_queue.put((SentenceType.FIRST, opus_packets, response["text"]))
conn.tts.tts_audio_queue.put((SentenceType.LAST, [], None))
2025-06-07 22:08:22 +08:00
# 检查是否需要更新唤醒词回复
if time.time() - response["time"] > WAKEUP_CONFIG["refresh_time"]:
if not _wakeup_response_lock.locked():
2025-03-23 22:02:13 +08:00
asyncio.create_task(wakeupWordsResponse(conn))
2025-06-07 22:08:22 +08:00
return True
2025-03-23 22:02:13 +08:00
async def wakeupWordsResponse(conn):
2025-06-07 22:08:22 +08:00
if not conn.tts or not conn.llm or not conn.llm.response_no_stream:
2025-04-16 16:44:44 +08:00
return
2025-06-07 22:08:22 +08:00
try:
# 尝试获取锁,如果获取不到就返回
if not await _wakeup_response_lock.acquire():
return
# 生成唤醒词回复
wakeup_word = random.choice(WAKEUP_CONFIG["words"])
question = (
"此刻用户正在和你说```"
+ wakeup_word
+ "```。\n请你根据以上用户的内容进行简短回复。要像一个人正常人一样说话,不要像机器人一样说话。\n"
+ "请勿对这条内容本身进行任何解释和回应,请勿返回表情符号,仅返回对用户的内容的回复。"
)
result = conn.llm.response_no_stream(conn.config["prompt"], question)
if not result or len(result) == 0:
return
# 生成TTS音频
tts_result = await asyncio.to_thread(conn.tts.to_tts, result)
2025-06-05 14:11:50 +08:00
if not tts_result:
return
2025-06-07 22:08:22 +08:00
# 获取当前音色
voice = getattr(conn.tts, "voice", "default")
2025-06-05 14:11:50 +08:00
wav_bytes = opus_datas_to_wav_bytes(tts_result, sample_rate=16000)
2025-06-07 22:08:22 +08:00
file_path = wakeup_words_config.generate_file_path(voice)
2025-06-05 14:11:50 +08:00
with open(file_path, "wb") as f:
f.write(wav_bytes)
2025-06-07 22:08:22 +08:00
# 更新配置
wakeup_words_config.update_wakeup_response(voice, file_path, result)
finally:
# 确保在任何情况下都释放锁
if _wakeup_response_lock.locked():
_wakeup_response_lock.release()