Files
xiaozhi-esp32-server/main/xiaozhi-server/core/utils/dialogue.py
T

119 lines
4.5 KiB
Python
Raw Normal View History

2025-02-02 23:01:14 +08:00
import uuid
from typing import List, Dict
from datetime import datetime
2025-07-08 11:25:54 +08:00
from config.settings import load_config
2025-02-02 23:01:14 +08:00
class Message:
2025-05-07 18:06:13 +08:00
def __init__(
self,
role: str,
content: str = None,
uniq_id: str = None,
tool_calls=None,
tool_call_id=None,
):
2025-02-02 23:01:14 +08:00
self.uniq_id = uniq_id if uniq_id is not None else str(uuid.uuid4())
self.role = role
self.content = content
2025-03-15 11:48:14 +08:00
self.tool_calls = tool_calls
self.tool_call_id = tool_call_id
2025-02-02 23:01:14 +08:00
class Dialogue:
def __init__(self):
self.dialogue: List[Message] = []
# 获取当前时间
2025-05-07 18:06:13 +08:00
self.current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
2025-02-02 23:01:14 +08:00
def put(self, message: Message):
self.dialogue.append(message)
2025-03-15 11:48:14 +08:00
def getMessages(self, m, dialogue):
if m.tool_calls is not None:
dialogue.append({"role": m.role, "tool_calls": m.tool_calls})
elif m.role == "tool":
2025-05-07 18:06:13 +08:00
dialogue.append(
2025-05-09 11:39:32 +08:00
{
"role": m.role,
"tool_call_id": (
str(uuid.uuid4()) if m.tool_call_id is None else m.tool_call_id
),
"content": m.content,
}
2025-05-07 18:06:13 +08:00
)
2025-03-15 11:48:14 +08:00
else:
dialogue.append({"role": m.role, "content": m.content})
2025-02-02 23:01:14 +08:00
def get_llm_dialogue(self) -> List[Dict[str, str]]:
2025-07-08 11:25:54 +08:00
# 直接调用get_llm_dialogue_with_memory,传入None作为memory_str
# 这样确保说话人功能在所有调用路径下都生效
return self.get_llm_dialogue_with_memory(None)
2025-03-03 15:00:04 +08:00
2025-03-22 20:39:52 +08:00
def update_system_message(self, new_content: str):
"""更新或添加系统消息"""
# 查找第一个系统消息
system_msg = next((msg for msg in self.dialogue if msg.role == "system"), None)
if system_msg:
system_msg.content = new_content
else:
self.put(Message(role="system", content=new_content))
2025-05-07 18:06:13 +08:00
def get_llm_dialogue_with_memory(
self, memory_str: str = None
) -> List[Dict[str, str]]:
2025-07-08 11:25:54 +08:00
# 构建对话
2025-03-03 15:00:04 +08:00
dialogue = []
2025-05-07 18:06:13 +08:00
2025-03-03 15:00:04 +08:00
# 添加系统提示和记忆
system_message = next(
(msg for msg in self.dialogue if msg.role == "system"), None
)
if system_message:
2025-07-08 11:25:54 +08:00
# 基础系统提示
enhanced_system_prompt = system_message.content
# 添加说话人识别功能说明
speaker_guidance = "\n\n[说话人识别功能说明]\n" \
2025-07-08 11:25:54 +08:00
"当用户消息为JSON格式包含speaker字段时(如:{\"speaker\": \"张三\", \"content\": \"消息内容\"}),表示系统已识别出说话人身份。\n" \
"请根据说话人的身份特征来调整回应风格和内容。\n" \
"你可以称呼说话人的名字,并参考他们的特点进行个性化回应。"
2025-07-08 11:25:54 +08:00
enhanced_system_prompt += speaker_guidance
# 添加说话人个性化描述
try:
config = load_config()
2025-07-09 14:23:47 +08:00
voiceprint_config = config.get("voiceprint", {})
2025-07-08 11:25:54 +08:00
speakers = voiceprint_config.get("speakers", [])
if speakers:
enhanced_system_prompt += "\n\n[已知说话人信息]"
for speaker_str in speakers:
try:
parts = speaker_str.split(",", 2)
if len(parts) >= 2:
speaker_id = parts[0].strip()
name = parts[1].strip()
# 如果描述为空,则为""
description = parts[2].strip() if len(parts) >= 3 else ""
enhanced_system_prompt += f"\n- {name}{description}"
except:
continue
except:
# 配置读取失败时忽略错误,不影响其他功能
pass
# 只有当有记忆时才添加记忆部分
if memory_str and len(memory_str) > 0:
enhanced_system_prompt += f"\n\n以下是用户的历史记忆:\n```\n{memory_str}\n```"
2025-03-03 15:00:04 +08:00
dialogue.append({"role": "system", "content": enhanced_system_prompt})
# 添加用户和助手的对话
2025-03-15 11:48:14 +08:00
for m in self.dialogue:
if m.role != "system": # 跳过原始的系统消息
self.getMessages(m, dialogue)
2025-03-03 15:00:04 +08:00
return dialogue