From d2d4e8fdb8cb08f8035516058808ac50f7887bf6 Mon Sep 17 00:00:00 2001 From: xszyou Date: Tue, 5 Aug 2025 00:40:02 +0800 Subject: [PATCH] =?UTF-8?q?fay=E8=87=AA=E7=84=B6=E8=BF=9B=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.优化认知机制; 2.funasr依赖更新; 3.更换公共配置中心服务器; 4.优化mcp管理; 5.去除单独情绪计算(llm已经支持); 6.优化think的“请稍等”提醒逻辑; 7.流式推送给数字人接口的文本补充会话id及消息序号。 --- core/fay_core.py | 96 +++++--------------- faymcp/mcp_service.py | 6 +- llm/nlp_cognitive_stream.py | 3 +- test/FunAudioLLM/SenseVoice/requirements.txt | 2 +- utils/config_util.py | 6 +- utils/stream_state_manager.py | 1 - 6 files changed, 31 insertions(+), 83 deletions(-) diff --git a/core/fay_core.py b/core/fay_core.py index f759a41..d68c02b 100644 --- a/core/fay_core.py +++ b/core/fay_core.py @@ -8,6 +8,7 @@ import requests from pydub import AudioSegment from queue import Queue import re # 添加正则表达式模块用于过滤表情符号 +import uuid # 适应模型使用 import numpy as np @@ -75,6 +76,8 @@ class FeiFei: self.timer = None self.sound_query = Queue() self.think_mode_users = {} # 使用字典存储每个用户的think模式状态 + self.think_time_users = {} #使用字典存储每个用户的think开始时间 + self.user_conv_map = {} #存储用户对话id及句子流序号 def __remove_emojis(self, text): """ @@ -224,7 +227,6 @@ class FeiFei: #触发语音交互 def on_interact(self, interact: Interact): - MyThread(target=self.__update_mood, args=[interact]).start() #创建用户 username = interact.data.get("user", "User") if member_db.new_instance().is_username_exist(username) == "notexists": @@ -232,58 +234,6 @@ class FeiFei: MyThread(target=self.__process_interact, args=[interact]).start() return None - # 发送情绪 - def __send_mood(self): - while self.__running: - time.sleep(3) - if wsa_server.get_instance().is_connected("User"): - if self.old_mood != self.mood: - content = {'Topic': 'human', 'Data': {'Key': 'mood', 'Value': self.mood}} - wsa_server.get_instance().add_cmd(content) - self.old_mood = self.mood - - #TODO 考虑重构这个逻辑 - # 更新情绪 - def __update_mood(self, interact): - perception = config_util.config["interact"]["perception"] - if interact.interact_type == 1: - try: - if cfg.ltp_mode == "cemotion": - result = nlp_cemotion.get_sentiment(self.cemotion, interact.data["msg"]) - chat_perception = perception["chat"] - if result >= 0.5 and result <= 1: - self.mood = self.mood + (chat_perception / 150.0) - elif result <= 0.2: - self.mood = self.mood - (chat_perception / 100.0) - else: - if str(cfg.baidu_emotion_api_key) == '' or str(cfg.baidu_emotion_app_id) == '' or str(cfg.baidu_emotion_secret_key) == '': - self.mood = 0 - else: - result = int(baidu_emotion.get_sentiment(interact.data["msg"])) - chat_perception = perception["chat"] - if result >= 2: - self.mood = self.mood + (chat_perception / 150.0) - elif result == 0: - self.mood = self.mood - (chat_perception / 100.0) - except BaseException as e: - self.mood = 0 - print("[System] 情绪更新错误!") - print(e) - - elif interact.interact_type == 2: - self.mood = self.mood + (perception["join"] / 100.0) - - elif interact.interact_type == 3: - self.mood = self.mood + (perception["gift"] / 100.0) - - elif interact.interact_type == 4: - self.mood = self.mood + (perception["follow"] / 100.0) - - if self.mood >= 1: - self.mood = 1 - if self.mood <= -1: - self.mood = -1 - #获取不同情绪声音 def __get_mood_voice(self): voice = tts_voice.get_voice_of(config_util.config["attribute"]["voice"]) @@ -291,25 +241,23 @@ class FeiFei: voice = EnumVoice.XIAO_XIAO styleList = voice.value["styleList"] sayType = styleList["calm"] - if -1 <= self.mood < -0.5: - sayType = styleList["angry"] - if -0.5 <= self.mood < -0.1: - sayType = styleList["lyrical"] - if -0.1 <= self.mood < 0.1: - sayType = styleList["calm"] - if 0.1 <= self.mood < 0.5: - sayType = styleList["assistant"] - if 0.5 <= self.mood <= 1: - sayType = styleList["cheerful"] return sayType # 合成声音 - def say(self, interact, text, type = ""): #TODO 对is_end及is_first的处理有问题 + def say(self, interact, text, type = ""): try: - uid = member_db.new_instance().find_user(interact.data.get('user')) + uid = member_db.new_instance().find_user(interact.data.get("user")) is_end = interact.data.get("isend", False) is_first = interact.data.get("isfirst", False) + if is_first == True: + conv = "conv_" + str(uuid.uuid4()) + conv_no = 0 + self.user_conv_map[interact.data.get("user", "User")] = {"conversation_id" : conv, "conversation_msg_no" : conv_no} + else: + self.user_conv_map[interact.data.get("user", "User")]["conversation_msg_no"] += 1 + + if not is_first and not is_end and (text is None or text.strip() == ""): return None @@ -337,13 +285,8 @@ class FeiFei: if "" in text: is_start_think = True self.think_mode_users[uid] = True - text = "请稍等..." + self.think_time_users[uid] = time.time() - # 如果既没有结束标记也没有开始标记,但用户当前处于思考模式 - # 这种情况是流式输出中间部分,应该被忽略 - elif "" not in text and "" not in text and self.think_mode_users.get(uid, False): - return None - if self.think_mode_users.get(uid, False) and is_start_think: if wsa_server.get_web_instance().is_connected(interact.data.get('user')): wsa_server.get_web_instance().add_cmd({"panelMsg": "思考中...", "Username" : interact.data.get('user'), 'robot': f'{cfg.fay_url}/robot/Thinking.jpg'}) @@ -351,8 +294,12 @@ class FeiFei: content = {'Topic': 'human', 'Data': {'Key': 'log', 'Value': "思考中..."}, 'Username' : interact.data.get('user'), 'robot': f'{cfg.fay_url}/robot/Thinking.jpg'} wsa_server.get_instance().add_cmd(content) - # 如果用户在think模式中,不进行语音合成 - if self.think_mode_users.get(uid, False) and not is_start_think: + if self.think_mode_users[uid] == True and time.time() - self.think_time_users[uid] >= 5: + self.think_time_users[uid] = time.time() + text = "请稍等..." + + # 流式输出think中的内容 + elif self.think_mode_users.get(uid, False) == True and "" not in text: return None result = None @@ -522,7 +469,7 @@ class FeiFei: #发送音频给数字人接口 if file_url is not None and wsa_server.get_instance().is_connected(interact.data.get("user")): - content = {'Topic': 'human', 'Data': {'Key': 'audio', 'Value': os.path.abspath(file_url), 'HttpValue': f'{cfg.fay_url}/audio/' + os.path.basename(file_url), 'Text': text, 'Time': audio_length, 'Type': interact.interleaver, 'IsFirst': 1 if interact.data.get("isfirst", False) else 0, 'IsEnd': 1 if interact.data.get("isend", False) else 0}, 'Username' : interact.data.get('user'), 'robot': f'{cfg.fay_url}/robot/Speaking.jpg'} + content = {'Topic': 'human', 'Data': {'Key': 'audio', 'Value': os.path.abspath(file_url), 'HttpValue': f'{cfg.fay_url}/audio/' + os.path.basename(file_url), 'Text': text, 'Time': audio_length, 'Type': interact.interleaver, 'IsFirst': 1 if interact.data.get("isfirst", False) else 0, 'IsEnd': 1 if interact.data.get("isend", False) else 0, 'CONV_ID' : self.user_conv_map[interact.data.get("user", "User")]["conversation_id"], 'CONV_MSG_NO' : self.user_conv_map[interact.data.get("user", "User")]["conversation_msg_no"] }, 'Username' : interact.data.get('user'), 'robot': f'{cfg.fay_url}/robot/Speaking.jpg'} #计算lips if platform.system() == "Windows": try: @@ -574,7 +521,6 @@ class FeiFei: if cfg.ltp_mode == "cemotion": from cemotion import Cemotion self.cemotion = Cemotion() - MyThread(target=self.__send_mood).start() MyThread(target=self.__play_sound).start() #停止核心服务 diff --git a/faymcp/mcp_service.py b/faymcp/mcp_service.py index 95186d6..6bcf7e5 100644 --- a/faymcp/mcp_service.py +++ b/faymcp/mcp_service.py @@ -772,7 +772,7 @@ def check_mcp_connections(): # 尝试调用一个简单的工具来测试连接 test_success, test_result = client.call_tool("ping", {}) if not test_success: - util.log(1, f"服务器 {server['name']} (ID: {server_id}) 测试调用失败,尝试重新连接...") + # util.log(1, f"服务器 {server['name']} (ID: {server_id}) 测试调用失败,尝试重新连接...") # 调用失败,可能已断开连接,尝试重新连接 success, updated_server, tools = connect_to_real_mcp(server) if success: @@ -814,7 +814,7 @@ def check_mcp_connections(): # util.log(1, f"已自动重新连接以下服务器: {', '.join(reconnected_servers)}") # 安排下一次检查 - schedule_connection_check() + schedule_connection_check() # 安排连接检查定时任务 def schedule_connection_check(): @@ -862,7 +862,7 @@ def run(): # 启动MCP服务器 def start(): # 启动连接检查定时任务 - start_connection_check() + # start_connection_check() TODO 暂时取消定时检查任务 # 输出启动信息 util.log(1, "MCP服务已启动在端口5010") diff --git a/llm/nlp_cognitive_stream.py b/llm/nlp_cognitive_stream.py index d49604f..2e2b571 100644 --- a/llm/nlp_cognitive_stream.py +++ b/llm/nlp_cognitive_stream.py @@ -756,7 +756,7 @@ def question(content, username, observation=None): current_time_step, # 当前时间步 n_count=100, # 获取5条相关记忆 curr_filter="all", # 获取所有类型的记忆 - hp=[0, 1, 0.5], # 权重:[时间近度权重recency_w, 相关性权重relevance_w, 重要性权重importance_w] + hp=[0.8, 0.5, 0.5], # 权重:[时间近度权重recency_w, 相关性权重relevance_w, 重要性权重importance_w] stateless=False ) @@ -812,6 +812,7 @@ def question(content, username, observation=None): """ # 构建消息列表 messages = [SystemMessage(content=system_prompt), HumanMessage(content=content)] + # 1. 获取mcp工具 mcp_tools = get_mcp_tools() # 2. 存在mcp工具,走react agent diff --git a/test/FunAudioLLM/SenseVoice/requirements.txt b/test/FunAudioLLM/SenseVoice/requirements.txt index b3e2afa..7ec6a92 100644 --- a/test/FunAudioLLM/SenseVoice/requirements.txt +++ b/test/FunAudioLLM/SenseVoice/requirements.txt @@ -6,4 +6,4 @@ huggingface_hub funasr>=1.1.3 numpy<=1.26.4 gradio -websockets \ No newline at end of file +websockets~=10.4 \ No newline at end of file diff --git a/utils/config_util.py b/utils/config_util.py index 208328c..65baa3d 100644 --- a/utils/config_util.py +++ b/utils/config_util.py @@ -56,7 +56,7 @@ config_json_path = None # config server中心配置,system.conf与config.json存在时不会使用配置中心 CONFIG_SERVER = { - 'BASE_URL': 'http://219.135.170.56:5500', # 默认API服务器地址 + 'BASE_URL': 'http://1.12.69.110:5500', # 默认API服务器地址 'API_KEY': 'your-api-key-here', # 默认API密钥 'PROJECT_ID': 'd19f7b0a-2b8a-4503-8c0d-1a587b90eb69' # 项目ID,需要在使用前设置 } @@ -205,7 +205,9 @@ def load_config(): system_conf_path = os.path.join(os.getcwd(), 'cache_data', 'system.conf') config_json_path = os.path.join(os.getcwd(), 'cache_data', 'config.json') save_api_config_to_local(api_config, system_conf_path, config_json_path) - + + if CONFIG_SERVER['PROJECT_ID'] == 'd19f7b0a-2b8a-4503-8c0d-1a587b90eb69': + print("\033[1;33;41m警告:你正在使用社区公共配置,请尽快更换!\033[0m") # 如果本地文件存在,从本地文件加载 # 加载system.conf system_config = ConfigParser() diff --git a/utils/stream_state_manager.py b/utils/stream_state_manager.py index 380d4ac..73e0436 100644 --- a/utils/stream_state_manager.py +++ b/utils/stream_state_manager.py @@ -51,7 +51,6 @@ class StreamStateManager: 'is_end_sent': False } - util.log(1, f"开始新会话: {session_id}") return session_id def prepare_sentence(self, username, text, force_first=False, force_end=False):