fay自然进行

1.优化认知机制;
2.funasr依赖更新;
3.更换公共配置中心服务器;
4.优化mcp管理;
5.去除单独情绪计算(llm已经支持);
6.优化think的“请稍等”提醒逻辑;
7.流式推送给数字人接口的文本补充会话id及消息序号。
This commit is contained in:
xszyou
2025-08-05 00:40:02 +08:00
parent 7965cf511a
commit d2d4e8fdb8
6 changed files with 31 additions and 83 deletions

View File

@@ -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 "<think>" in text:
is_start_think = True
self.think_mode_users[uid] = True
text = "请稍等..."
self.think_time_users[uid] = time.time()
# 如果既没有结束标记也没有开始标记,但用户当前处于思考模式
# 这种情况是流式输出中间部分,应该被忽略
elif "</think>" not in text and "<think>" 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 "</think>" 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()
#停止核心服务

View File

@@ -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")

View File

@@ -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

View File

@@ -6,4 +6,4 @@ huggingface_hub
funasr>=1.1.3
numpy<=1.26.4
gradio
websockets
websockets~=10.4

View File

@@ -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()

View File

@@ -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):