Merge pull request #398 from na10xi27da/relationship

关系系统构建与启用(非紧急)
This commit is contained in:
晴猫
2025-03-17 17:21:48 +08:00
committed by GitHub
5 changed files with 201 additions and 84 deletions

View File

@@ -83,7 +83,7 @@ class ChatBot:
chat_stream=chat,
)
await relationship_manager.update_relationship_value(
chat_stream=chat, relationship_value=0.5
chat_stream=chat, relationship_value=0
)
await message.process()
@@ -255,20 +255,11 @@ class ChatBot:
)
message_manager.add_message(bot_message)
emotion = await self.gpt._get_emotion_tags(raw_content)
logger.debug(f"'{response}' 获取到的情感标签为:{emotion}")
valuedict = {
"happy": 0.5,
"angry": -1,
"sad": -0.5,
"surprised": 0.2,
"disgusted": -1.5,
"fearful": -0.7,
"neutral": 0.1,
}
await relationship_manager.update_relationship_value(
chat_stream=chat, relationship_value=valuedict[emotion[0]]
)
# 获取立场和情感标签,更新关系值
stance, emotion = await self.gpt._get_emotion_tags(raw_content, message.processed_plain_text)
logger.debug(f"'{response}' 立场为:{stance} 获取到的情感标签为:{emotion}")
await relationship_manager.calculate_update_relationship_value(chat_stream=chat, label=emotion, stance=stance)
# 使用情绪管理器更新情绪
self.mood_manager.update_mood_from_emotion(
emotion[0], global_config.mood_intensity_factor

View File

@@ -63,25 +63,19 @@ class ResponseGenerator:
async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request) -> Optional[str]:
"""使用指定的模型生成回复"""
sender_name = message.chat_stream.user_info.user_nickname or f"用户{message.chat_stream.user_info.user_id}"
if message.chat_stream.user_info.user_cardname:
sender_name = ""
if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname:
sender_name = f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]{message.chat_stream.user_info.user_cardname}"
# 获取关系值
relationship_value = (
relationship_manager.get_relationship(message.chat_stream).relationship_value
if relationship_manager.get_relationship(message.chat_stream)
else 0.0
)
if relationship_value != 0.0:
# print(f"\033[1;32m[关系管理]\033[0m 回复中_当前关系值: {relationship_value}")
pass
elif message.chat_stream.user_info.user_nickname:
sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}"
else:
sender_name = f"用户({message.chat_stream.user_info.user_id})"
# 构建prompt
prompt, prompt_check = await prompt_builder._build_prompt(
message.chat_stream,
message_txt=message.processed_plain_text,
sender_name=sender_name,
relationship_value=relationship_value,
stream_id=message.chat_stream.stream_id,
)
@@ -151,32 +145,48 @@ class ResponseGenerator:
}
)
async def _get_emotion_tags(self, content: str) -> List[str]:
"""提取情感标签"""
async def _get_emotion_tags(
self, content: str, processed_plain_text: str
):
"""提取情感标签,结合立场和情绪"""
try:
prompt = f"""请从以下内容中,从"happy,angry,sad,surprised,disgusted,fearful,neutral"中选出最匹配的1个情感标签并输出
只输出标签就好,不要输出其他内容:
内容:{content}
输出:
# 构建提示词,结合回复内容、被回复的内容以及立场分析
prompt = f"""
请根据以下对话内容,完成以下任务:
1. 判断回复者的立场是"supportive"(支持)、"opposed"(反对)还是"neutrality"(中立)。
2. 从"happy,angry,sad,surprised,disgusted,fearful,neutral"中选出最匹配的1个情感标签。
3. 按照"立场-情绪"的格式输出结果,例如:"supportive-happy"
被回复的内容:
{processed_plain_text}
回复内容:
{content}
请分析回复者的立场和情感倾向,并输出结果:
"""
content, _ = await self.model_v25.generate_response(prompt)
content = content.strip()
if content in [
"happy",
"angry",
"sad",
"surprised",
"disgusted",
"fearful",
"neutral",
]:
return [content]
# 调用模型生成结果
result, _ = await self.model_v25.generate_response(prompt)
result = result.strip()
# 解析模型输出的结果
if "-" in result:
stance, emotion = result.split("-", 1)
valid_stances = ["supportive", "opposed", "neutrality"]
valid_emotions = [
"happy", "angry", "sad", "surprised", "disgusted", "fearful", "neutral"
]
if stance in valid_stances and emotion in valid_emotions:
return stance, emotion # 返回有效的立场-情绪组合
else:
return "neutrality", "neutral" # 默认返回中立-中性
else:
return ["neutral"]
return "neutrality", "neutral" # 格式错误时返回默认值
except Exception as e:
print(f"获取情感标签时出错: {e}")
return ["neutral"]
return "neutrality", "neutral" # 出错时返回默认值
async def _process_response(self, content: str) -> Tuple[List[str], List[str]]:
"""处理响应内容,返回处理后的内容和情感标签"""

View File

@@ -7,8 +7,9 @@ from ..memory_system.memory import hippocampus, memory_graph
from ..moods.moods import MoodManager
from ..schedule.schedule_generator import bot_schedule
from .config import global_config
from .utils import get_embedding, get_recent_group_detailed_plain_text
from .utils import get_embedding, get_recent_group_detailed_plain_text, get_recent_group_speaker
from .chat_stream import chat_manager
from .relationship_manager import relationship_manager
from src.common.logger import get_module_logger
logger = get_module_logger("prompt")
@@ -21,34 +22,36 @@ class PromptBuilder:
self.prompt_built = ""
self.activate_messages = ""
async def _build_prompt(
self,
message_txt: str,
sender_name: str = "某人",
relationship_value: float = 0.0,
stream_id: Optional[int] = None,
) -> tuple[str, str]:
async def _build_prompt(self,
chat_stream,
message_txt: str,
sender_name: str = "某人",
stream_id: Optional[int] = None) -> tuple[str, str]:
"""构建prompt
Args:
message_txt: 消息文本
sender_name: 发送者昵称
relationship_value: 关系值
# relationship_value: 关系值
group_id: 群组ID
Returns:
str: 构建好的prompt
"""
# 先禁用关系
if 0 > 30:
relation_prompt = "关系特别特别好,你很喜欢喜欢他"
relation_prompt_2 = "热情发言或者回复"
elif 0 < -20:
relation_prompt = "关系很差,你很讨厌他"
relation_prompt_2 = "骂他"
else:
relation_prompt = "关系一般"
relation_prompt_2 = "发言或者回复"
# 关系(载入当前聊天记录里部分人的关系)
who_chat_in_group = [chat_stream]
who_chat_in_group += get_recent_group_speaker(
stream_id,
(chat_stream.user_info.user_id, chat_stream.user_info.platform),
limit=global_config.MAX_CONTEXT_SIZE
)
relation_prompt = ""
for person in who_chat_in_group:
relation_prompt += relationship_manager.build_relationship_info(person)
relation_prompt_all = (
f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录,根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。"
)
# 开始构建prompt
@@ -70,10 +73,10 @@ class PromptBuilder:
)
chat_stream = chat_manager.get_stream(stream_id)
if chat_stream.group_info:
chat_talking_prompt = f"以下是群里正在聊天的内容:\n{chat_talking_prompt}"
chat_talking_prompt = chat_talking_prompt
else:
chat_in_group = False
chat_talking_prompt = f"以下是你正在和{sender_name}私聊的内容:\n{chat_talking_prompt}"
chat_talking_prompt = chat_talking_prompt
# print(f"\033[1;34m[调试]\033[0m 已从数据库获取群 {group_id} 的消息记录:{chat_talking_prompt}")
# 使用新的记忆获取方法
@@ -123,10 +126,7 @@ class PromptBuilder:
probability_3 = global_config.PERSONALITY_3
personality_choice = random.random()
if chat_in_group:
prompt_in_group = f"你正在浏览{chat_stream.platform}"
else:
prompt_in_group = f"你正在{chat_stream.platform}上和{sender_name}私聊"
if personality_choice < probability_1: # 第一种人格
prompt_personality = personality[0]
elif personality_choice < probability_1 + probability_2: # 第二种人格
@@ -143,15 +143,6 @@ class PromptBuilder:
if random.random() < 0.01:
prompt_ger += "你喜欢用文言文"
# 合并prompt
# prompt = ""
# prompt += f"{prompt_info}\n"
# prompt += f"{prompt_date}\n"
# prompt += f"{chat_talking_prompt}\n"
# prompt += f"{prompt_personality}\n"
# prompt += f"{prompt_ger}\n"
# prompt += f"{extra_info}\n"
# 知识构建
start_time = time.time()
@@ -176,7 +167,7 @@ class PromptBuilder:
`<UserMessage>`
{message_txt}
`</UserMessage>`\
引起了你的注意,你和ta{relation_prompt},{mood_prompt},你想要{relation_prompt_2}
引起了你的注意,{relation_prompt_all}{mood_prompt}
`<MainRule>`
你的网名叫{global_config.BOT_NICKNAME},你还有很多别名:{"/".join(global_config.BOT_ALIAS_NAMES)}{prompt_personality}
@@ -198,8 +189,8 @@ class PromptBuilder:
# prompt_personality_check = f"""你的网名叫{global_config.BOT_NICKNAME}{personality[2]}, 你正在浏览qq群{promt_info_prompt} {activate_prompt_check} {extra_check_info}"""
#
# prompt_check_if_response = f"{prompt_info}\n{prompt_date}\n{chat_talking_prompt}\n{prompt_personality_check}"
prompt_check_if_response = ""
prompt_check_if_response = ""
return prompt, prompt_check_if_response
def _build_initiative_prompt_select(self, group_id, probability_1=0.8, probability_2=0.1):

View File

@@ -5,6 +5,7 @@ from src.common.logger import get_module_logger
from ...common.database import db
from .message_base import UserInfo
from .chat_stream import ChatStream
import math
logger = get_module_logger("rel_manager")
@@ -251,5 +252,100 @@ class RelationshipManager:
else:
return "某人"
async def calculate_update_relationship_value(self,
chat_stream: ChatStream,
label: str,
stance: str) -> None:
"""计算变更关系值
新的关系值变更计算方式:
将关系值限定在-1000到1000
对于关系值的变更,期望:
1.向两端逼近时会逐渐减缓
2.关系越差,改善越难,关系越好,恶化越容易
3.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢
"""
stancedict = {
"supportive": 0,
"neutrality": 1,
"opposed": 2,
}
valuedict = {
"happy": 1.5,
"angry": -3.0,
"sad": -1.5,
"surprised": 0.6,
"disgusted": -4.5,
"fearful": -2.1,
"neutral": 0.3,
}
if self.get_relationship(chat_stream):
old_value = self.get_relationship(chat_stream).relationship_value
else:
return
if old_value > 1000:
old_value = 1000
elif old_value < -1000:
old_value = -1000
value = valuedict[label]
if old_value >= 0:
if valuedict[label] >= 0 and stancedict[stance] != 2:
value = value*math.cos(math.pi*old_value/2000)
if old_value > 500:
high_value_count = 0
for key, relationship in self.relationships.items():
if relationship.relationship_value >= 850:
high_value_count += 1
value *= 3/(high_value_count + 3)
elif valuedict[label] < 0 and stancedict[stance] != 0:
value = value*math.exp(old_value/1000)
else:
value = 0
elif old_value < 0:
if valuedict[label] >= 0 and stancedict[stance] != 2:
value = value*math.exp(old_value/1000)
elif valuedict[label] < 0 and stancedict[stance] != 0:
value = value*math.cos(math.pi*old_value/2000)
else:
value = 0
logger.info(f"[关系变更] 立场:{stance} 标签:{label} 关系值:{value}")
await self.update_relationship_value(
chat_stream=chat_stream, relationship_value=value
)
def build_relationship_info(self,person) -> str:
relationship_value = relationship_manager.get_relationship(person).relationship_value
if -1000 <= relationship_value < -227:
level_num = 0
elif -227 <= relationship_value < -73:
level_num = 1
elif -76 <= relationship_value < 227:
level_num = 2
elif 227 <= relationship_value < 587:
level_num = 3
elif 587 <= relationship_value < 900:
level_num = 4
elif 900 <= relationship_value <= 1000:
level_num = 5
else:
level_num = 5 if relationship_value > 1000 else 0
relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"]
relation_prompt2_list = [
"冷漠回应或直接辱骂", "冷淡回复",
"保持理性", "愿意回复",
"积极回复", "无条件支持",
]
if person.user_info.user_cardname:
return (f"你对昵称为'[({person.user_info.user_id}){person.user_info.user_nickname}]{person.user_info.user_cardname}'的用户的态度为{relationship_level[level_num]}"
f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}")
else:
return (f"你对昵称为'({person.user_info.user_id}){person.user_info.user_nickname}'的用户的态度为{relationship_level[level_num]}"
f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}")
relationship_manager = RelationshipManager()

View File

@@ -197,6 +197,35 @@ def get_recent_group_detailed_plain_text(chat_stream_id: int, limit: int = 12, c
return message_detailed_plain_text_list
def get_recent_group_speaker(chat_stream_id: int, sender, limit: int = 12) -> list:
# 获取当前群聊记录内发言的人
recent_messages = list(db.messages.find(
{"chat_id": chat_stream_id},
{
"chat_info": 1,
"user_info": 1,
}
).sort("time", -1).limit(limit))
if not recent_messages:
return []
who_chat_in_group = [] # ChatStream列表
duplicate_removal = []
for msg_db_data in recent_messages:
user_info = UserInfo.from_dict(msg_db_data["user_info"])
if (user_info.user_id, user_info.platform) != sender \
and (user_info.user_id, user_info.platform) != (global_config.BOT_QQ, "qq") \
and (user_info.user_id, user_info.platform) not in duplicate_removal \
and len(duplicate_removal) < 5: # 排除重复排除消息发送者排除bot(此处bot的平台强制为了qq可能需要更改),限制加载的关系数目
duplicate_removal.append((user_info.user_id, user_info.platform))
chat_info = msg_db_data.get("chat_info", {})
who_chat_in_group.append(ChatStream.from_dict(chat_info))
return who_chat_in_group
def split_into_sentences_w_remove_punctuation(text: str) -> List[str]:
"""将文本分割成句子,但保持书名号中的内容完整
Args: