diff --git a/.gitignore b/.gitignore index a25b3401..dd00f71e 100644 --- a/.gitignore +++ b/.gitignore @@ -145,6 +145,7 @@ tmp .history .DS_Store main/xiaozhi-server/data +!main/xiaozhi-server/config/assets/wakeup_words.wav main/manager-web/node_modules .config.yaml .secrets.yaml diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index f2a18c84..2fe438cf 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -57,6 +57,8 @@ delete_audio: true close_connection_no_voice_time: 120 # TTS请求超时时间(秒) tts_timeout: 10 +# 开启唤醒词加速 +enable_wakeup_words_response_cache: true # 开场是否回复唤醒词 enable_greeting: true # 说完话是否开启提示音 diff --git a/main/xiaozhi-server/config/assets/wakeup_words.wav b/main/xiaozhi-server/config/assets/wakeup_words.wav new file mode 100644 index 00000000..53e58b04 Binary files /dev/null and b/main/xiaozhi-server/config/assets/wakeup_words.wav differ diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 54cc0947..c9a52b12 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -202,7 +202,7 @@ class ConnectionHandler: self.client_ip_info = get_ip_info(self.client_ip) if self.client_ip_info is not None and "city" in self.client_ip_info: self.logger.bind(tag=TAG).info(f"Client ip info: {self.client_ip_info}") - self.prompt = self.prompt + f"\n我在:{self.client_ip_info}" + self.prompt = self.prompt + f"\nuser location:{self.client_ip_info}" self.dialogue.update_system_message(self.prompt) def change_system_prompt(self, prompt): diff --git a/main/xiaozhi-server/core/handle/helloHandle.py b/main/xiaozhi-server/core/handle/helloHandle.py index bafcf09d..b978b4af 100644 --- a/main/xiaozhi-server/core/handle/helloHandle.py +++ b/main/xiaozhi-server/core/handle/helloHandle.py @@ -1,8 +1,68 @@ import json from config.logger import setup_logging +from core.handle.sendAudioHandle import send_stt_message +from core.utils.util import remove_punctuation_and_length +import shutil +import asyncio +import os +import random +import time logger = setup_logging() +WAKEUP_CONFIG = {"dir": "config/assets/", "file_name": "wakeup_words", "create_time": time.time(), "refresh_time": 10, + "words": ["很高兴见到你", "你好啊", "我们又见面了", "最近可好?", "很高兴再次和你谈话", "在干嘛"]} + async def handleHelloMessage(conn): await conn.websocket.send(json.dumps(conn.welcome_msg)) + + +async def checkWakeupWords(conn, text): + enable_wakeup_words_response_cache = conn.config["enable_wakeup_words_response_cache"] + """是否开启唤醒词加速""" + if not enable_wakeup_words_response_cache: + return False + """检查是否是唤醒词""" + _, text = remove_punctuation_and_length(text) + if text in conn.config.get("wakeup_words"): + await send_stt_message(conn, text) + conn.tts_first_text_index = 0 + conn.tts_last_text_index = 0 + conn.llm_finish_task = True + + file = getWakeupWordFile() + if file is None: + asyncio.create_task(wakeupWordsResponse(conn)) + return False + opus_packets, duration = conn.tts.audio_to_opus_data(file) + conn.audio_play_queue.put((opus_packets, text, 0)) + if time.time() - WAKEUP_CONFIG["create_time"] > WAKEUP_CONFIG["refresh_time"]: + asyncio.create_task(wakeupWordsResponse(conn)) + return True + return False + + +def getWakeupWordFile(): + """查找config/assets/目录下名称为wakeup_words的文件""" + for file in os.listdir(WAKEUP_CONFIG["dir"]): + if WAKEUP_CONFIG["file_name"] in file: + return f"config/assets/{file}" + return None + + +async def wakeupWordsResponse(conn): + """唤醒词响应""" + wakeup_word = random.choice(WAKEUP_CONFIG["words"]) + result = conn.llm.response_no_stream(conn.prompt, wakeup_word) + tts_file = await asyncio.to_thread(conn.tts.to_tts, result) + if tts_file is not None and os.path.exists(tts_file): + file_type = os.path.splitext(tts_file)[1] + if file_type: + file_type = file_type.lstrip('.') + old_file = getWakeupWordFile() + if old_file is not None: + os.remove(old_file) + """将文件挪到"wakeup_words.mp3""" + shutil.move(tts_file, WAKEUP_CONFIG["dir"] + WAKEUP_CONFIG["file_name"] + "." + file_type) + WAKEUP_CONFIG["create_time"] = time.time() diff --git a/main/xiaozhi-server/core/handle/intentHandler.py b/main/xiaozhi-server/core/handle/intentHandler.py index 1799516c..d8440fc6 100644 --- a/main/xiaozhi-server/core/handle/intentHandler.py +++ b/main/xiaozhi-server/core/handle/intentHandler.py @@ -2,6 +2,7 @@ from config.logger import setup_logging import json import uuid from core.handle.sendAudioHandle import send_stt_message +from core.handle.helloHandle import checkWakeupWords from core.utils.util import remove_punctuation_and_length TAG = __name__ @@ -12,6 +13,10 @@ async def handle_user_intent(conn, text): # 检查是否有明确的退出命令 if await check_direct_exit(conn, text): return True + # 检查是否是唤醒词 + if await checkWakeupWords(conn, text): + return True + if conn.use_function_call_mode: # 使用支持function calling的聊天方法,不再进行意图分析 return False @@ -35,6 +40,7 @@ async def check_direct_exit(conn, text): return False + async def analyze_intent_with_llm(conn, text): """使用LLM分析用户意图""" if not hasattr(conn, 'intent') or not conn.intent: diff --git a/main/xiaozhi-server/core/providers/tts/base.py b/main/xiaozhi-server/core/providers/tts/base.py index 3146dc06..e39ca65c 100644 --- a/main/xiaozhi-server/core/providers/tts/base.py +++ b/main/xiaozhi-server/core/providers/tts/base.py @@ -36,7 +36,7 @@ class TTSProviderBase(ABC): return tmp_file except Exception as e: - logger.bind(tag=TAG).info(f"Failed to generate TTS file: {e}") + logger.bind(tag=TAG).error(f"Failed to generate TTS file: {e}") return None @abstractmethod diff --git a/main/xiaozhi-server/core/utils/util.py b/main/xiaozhi-server/core/utils/util.py index 63cb5b9c..51841baf 100644 --- a/main/xiaozhi-server/core/utils/util.py +++ b/main/xiaozhi-server/core/utils/util.py @@ -73,9 +73,7 @@ def get_ip_info(ip_addr): resp = requests.get(url).json() ip_info = { - "city": resp.get("cityName"), - "region": resp.get("regionName"), - "country": resp.get("countryName") + "city": resp.get("cityName") } return ip_info except Exception as e: