自然进化

1、修复透传打断功能。
2、修复新消息无法采纳功能。
This commit is contained in:
guo zebin
2025-09-12 23:39:07 +08:00
parent 30d342670c
commit 4e0507df78
4 changed files with 135 additions and 64 deletions

View File

@@ -64,6 +64,29 @@ class Content_Db:
conn.close()
return last_id
# 更新对话内容
@synchronized
def update_content(self, msg_id, content):
"""
更新指定ID的消息内容
:param msg_id: 消息ID
:param content: 新的内容
:return: 是否更新成功
"""
conn = sqlite3.connect("memory/fay.db")
conn.text_factory = str
cur = conn.cursor()
try:
cur.execute("UPDATE T_Msg SET content = ? WHERE id = ?", (content, msg_id))
conn.commit()
affected_rows = cur.rowcount
except Exception as e:
util.log(1, f"更新消息内容失败: {e}")
conn.close()
return False
conn.close()
return affected_rows > 0
# 根据ID查询对话记录
@synchronized
def get_content_by_id(self, msg_id):

View File

@@ -190,21 +190,22 @@ class FeiFei:
index = interact.interact_type
username = interact.data.get("user", "User")
uid = member_db.new_instance().find_user(username)
# 切换到新会话,令上一会话的流式输出/音频尽快结束
util.printInfo(1, username, "重置中断标志,开始新的对话处理")
try:
sm = stream_manager.new_instance()
import uuid
conv_id = "conv_" + str(uuid.uuid4())
sm.set_current_conversation(username, conv_id)
# 将当前会话ID附加到交互数据
interact.data["conversation_id"] = conv_id
# 允许新的生成
sm.set_stop_generation(username, stop=False)
except Exception:
pass
if index == 1: #语音、文字交互
util.printInfo(1, username, "重置中断标志,开始新的对话处理")
# 切换到新会话,令上一会话的流式输出/音频尽快结束
try:
sm = stream_manager.new_instance()
import uuid
conv_id = "conv_" + str(uuid.uuid4())
sm.set_current_conversation(username, conv_id)
# 将当前会话ID附加到交互数据
interact.data["conversation_id"] = conv_id
# 允许新的生成
sm.set_stop_generation(username, stop=False)
except Exception:
pass
# 已通过上方 sm.set_stop_generation(username, False) 复位
#记录用户问题,方便obs等调用
self.write_to_file("./logs", "asr_result.txt", interact.data["msg"])
@@ -237,19 +238,36 @@ class FeiFei:
# 使用流式分割处理Q&A答案
self.__process_qa_stream(text, username)
#完整文本记录回复并输出到各个终端
self.__process_text_output(text, username, uid )
return text
elif (index == 2):#透传模式用于适配自动播报控制及agent的通知工具
elif (index == 2):#透传模式:有音频则仅播音频;仅文本则流式+TTS
audio_url = interact.data.get("audio")
text = interact.data.get("text")
if interact.data.get("text"):
text = interact.data.get("text")
# 使用统一的文本处理方法
self.__process_text_output(text, username, uid)
# 使用流式处理,按标点分割发送
self.__process_stream_output(text, username, f"type2_{interact.interleaver}")
# 1) 存在音频:忽略文本,仅播放音频
if audio_url and str(audio_url).strip():
try:
audio_interact = Interact(
"stream", 1,
{"user": username, "msg": "", "isfirst": True, "isend": True, "audio": audio_url}
)
self.say(audio_interact, "")
except Exception:
pass
return 'success'
# 2) 只有文本执行流式切分并TTS
if text and str(text).strip():
# 进行流式处理用于TTS流式处理中会记录到数据库
self.__process_stream_output(text, username, f"type2_{interact.interleaver}")
# 不再需要额外记录,因为流式处理已经记录了
# self.__process_text_output(text, username, uid)
return 'success'
# 没有有效内容
return 'success'
except BaseException as e:
@@ -294,6 +312,8 @@ class FeiFei:
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)
username = interact.data.get("user", "User")
# 提前进行会话有效性与中断检查,避免产生多余面板/数字人输出
try:
user_for_stop = interact.data.get("user", "User")
@@ -302,13 +322,38 @@ class FeiFei:
return None
except Exception:
pass
# 初始化content_id变量
content_id = 0
if is_first == True:
conv = interact.data.get("conversation_id") or ("conv_" + str(uuid.uuid4()))
conv_no = 0
self.user_conv_map[interact.data.get("user", "User")] = {"conversation_id" : conv, "conversation_msg_no" : conv_no}
# 创建第一条数据库记录获得content_id
if text and text.strip():
content_id = content_db.new_instance().add_content('fay', 'speak', text, username, uid)
else:
content_id = content_db.new_instance().add_content('fay', 'speak', '', username, uid)
# 保存content_id到会话映射中
self.user_conv_map[username] = {
"conversation_id": conv,
"conversation_msg_no": conv_no,
"content_id": content_id # 新增保存content_id
}
else:
self.user_conv_map[interact.data.get("user", "User")]["conversation_msg_no"] += 1
self.user_conv_map[username]["conversation_msg_no"] += 1
# 获取之前保存的content_id
content_id = self.user_conv_map.get(username, {}).get("content_id", 0)
# 如果有新内容,更新数据库
if content_id > 0 and text and text.strip():
# 获取当前已有内容
existing_content = content_db.new_instance().get_content_by_id(content_id)
if existing_content:
# 累积内容
accumulated_text = existing_content[3] + text
content_db.new_instance().update_content(content_id, accumulated_text)
if not is_first and not is_end and (text is None or text.strip() == ""):
return None
@@ -317,9 +362,9 @@ class FeiFei:
user_for_stop = interact.data.get("user", "User")
conv_id_for_stop = interact.data.get("conversation_id")
if not stream_manager.new_instance().should_stop_generation(user_for_stop, conversation_id=conv_id_for_stop):
self.__send_panel_message(text, interact.data.get('user'), uid, 0, type)
self.__process_text_output(text, interact.data.get('user'), uid, content_id, type)
except Exception:
self.__send_panel_message(text, interact.data.get('user'), uid, 0, type)
self.__process_text_output(text, interact.data.get('user'), uid, content_id, type)
# 处理think标签
is_start_think = False
@@ -700,9 +745,9 @@ class FeiFei:
}
wsa_server.get_instance().add_cmd(content)
def __process_text_output(self, text, username, uid):
def __process_text_output(self, text, username, uid, content_id, type):
"""
处理文本输出到各个终端
完整文本输出到各个终端
:param text: 主要回复文本
:param textlist: 额外回复列表
:param username: 用户名
@@ -713,10 +758,10 @@ class FeiFei:
text = text.strip()
# 记录主回复
content_id = self.__record_response(text, username, uid)
# content_id = self.__record_response(text, username, uid)
# 发送主回复到面板和数字人
# self.__send_panel_message(text, username, uid, content_id, type)
self.__send_panel_message(text, username, uid, content_id, type)
self.__send_digital_human_message(text, username)
# 打印日志

View File

@@ -614,14 +614,19 @@ def transparent_pass():
data = request.get_json()
else:
data = json.loads(data)
user = data.get('user', 'User')
response_text = data.get('text', '')
username = data.get('user', 'User')
response_text = data.get('text', None)
audio_url = data.get('audio', None)
interact = Interact('transparent_pass', 2, {'user': user, 'text': response_text, 'audio': audio_url, 'isend':True, 'isfirst':True})
util.printInfo(1, user, '透传播放:{}{}'.format(response_text, audio_url), time.time())
success = fay_booter.feiFei.on_interact(interact)
if (success == 'success'):
return jsonify({'code': 200, 'message' : '成功'})
if response_text or audio_url:
# 新消息到达,立即中断该用户之前的所有处理(文本流+音频队列)
util.printInfo(1, username, f'[API中断] 新消息到达,完整中断用户 {username} 之前的所有处理')
stream_manager.new_instance().clear_Stream_with_audio(username)
util.printInfo(1, username, f'[API中断] 用户 {username} 的文本流和音频队列已清空,准备处理新消息')
interact = Interact('transparent_pass', 2, {'user': username, 'text': response_text, 'audio': audio_url, 'isend':True, 'isfirst':True})
util.printInfo(1, username, '透传播放:{}{}'.format(response_text, audio_url), time.time())
success = fay_booter.feiFei.on_interact(interact)
if (success == 'success'):
return jsonify({'code': 200, 'message' : '成功'})
return jsonify({'code': 500, 'message' : '未知原因出错'})
except Exception as e:
return jsonify({'code': 500, 'message': f'出错: {e}'}), 500

View File

@@ -204,32 +204,30 @@ class FayInterface {
}
if (vueInstance.selectedUser && data.panelReply.username === vueInstance.selectedUser[1]) {
// 处理content_id为0的消息
if (data.panelReply.id === 0) {
// 查找最后一条消息
const lastIndex = vueInstance.messages.length - 1;
if (lastIndex >= 0) {
const lastMessage = vueInstance.messages[lastIndex];
// 如果最后一条消息也是content_id为0,则更新它
if (lastMessage.id === 0) {
lastMessage.content = lastMessage.content + data.panelReply.content;
lastMessage.timetext = this.getTime();
// 强制更新视图
vueInstance.$forceUpdate();
return;
}
}
}
// 查找是否已存在相同content_id的消息
const existingMessageIndex = vueInstance.messages.findIndex(
msg => msg.id === data.panelReply.id && msg.type === data.panelReply.type
);
// 添加新消息
vueInstance.messages.push({
id: data.panelReply.id,
username: data.panelReply.username,
content: data.panelReply.content,
type: data.panelReply.type,
timetext: this.getTime(),
is_adopted: data.panelReply.is_adopted ? 1 : 0
});
if (existingMessageIndex !== -1) {
// 更新现有消息(拼接内容)
const existingMessage = vueInstance.messages[existingMessageIndex];
// 拼接新内容到现有内容
existingMessage.content = existingMessage.content + data.panelReply.content;
existingMessage.timetext = this.getTime();
// 强制更新视图
vueInstance.$forceUpdate();
} else {
// 添加新消息
vueInstance.messages.push({
id: data.panelReply.id,
username: data.panelReply.username,
content: data.panelReply.content,
type: data.panelReply.type,
timetext: this.getTime(),
is_adopted: data.panelReply.is_adopted ? 1 : 0
});
}
// 滚动到底部
vueInstance.$nextTick(() => {