mirror of
https://github.com/xszyou/Fay.git
synced 2026-03-12 17:51:28 +08:00
fay自然进行
1.优化认知机制; 2.funasr依赖更新; 3.更换公共配置中心服务器; 4.优化mcp管理; 5.去除单独情绪计算(llm已经支持); 6.优化think的“请稍等”提醒逻辑; 7.流式推送给数字人接口的文本补充会话id及消息序号。
This commit is contained in:
@@ -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()
|
||||
|
||||
#停止核心服务
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,4 +6,4 @@ huggingface_hub
|
||||
funasr>=1.1.3
|
||||
numpy<=1.26.4
|
||||
gradio
|
||||
websockets
|
||||
websockets~=10.4
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user