检查是否为冲突导致的bug
This commit is contained in:
214
src/plugins/person_info/person_info.py
Normal file
214
src/plugins/person_info/person_info.py
Normal file
@@ -0,0 +1,214 @@
|
||||
from src.common.logger import get_module_logger
|
||||
from ...common.database import db
|
||||
import copy
|
||||
import hashlib
|
||||
from typing import Any, Callable, Dict, TypeVar
|
||||
T = TypeVar('T') # 泛型类型
|
||||
|
||||
"""
|
||||
PersonInfoManager 类方法功能摘要:
|
||||
1. get_person_id - 根据平台和用户ID生成MD5哈希的唯一person_id
|
||||
2. create_person_info - 创建新个人信息文档(自动合并默认值)
|
||||
3. update_one_field - 更新单个字段值(若文档不存在则创建)
|
||||
4. del_one_document - 删除指定person_id的文档
|
||||
5. get_value - 获取单个字段值(返回实际值或默认值)
|
||||
6. get_values - 批量获取字段值(任一字段无效则返回空字典)
|
||||
7. del_all_undefined_field - 清理全集合中未定义的字段
|
||||
8. get_specific_value_list - 根据指定条件,返回person_id,value字典
|
||||
"""
|
||||
|
||||
logger = get_module_logger("person_info")
|
||||
|
||||
person_info_default = {
|
||||
"person_id" : None,
|
||||
"platform" : None,
|
||||
"user_id" : None,
|
||||
"nickname" : None,
|
||||
# "age" : 0,
|
||||
"relationship_value" : 0,
|
||||
# "saved" : True,
|
||||
# "impression" : None,
|
||||
# "gender" : Unkown,
|
||||
"konw_time" : 0,
|
||||
} # 个人信息的各项与默认值在此定义,以下处理会自动创建/补全每一项
|
||||
|
||||
class PersonInfoManager:
|
||||
def __init__(self):
|
||||
if "person_info" not in db.list_collection_names():
|
||||
db.create_collection("person_info")
|
||||
db.person_info.create_index("person_id", unique=True)
|
||||
|
||||
def get_person_id(self, platform:str, user_id:int):
|
||||
"""获取唯一id"""
|
||||
components = [platform, str(user_id)]
|
||||
key = "_".join(components)
|
||||
return hashlib.md5(key.encode()).hexdigest()
|
||||
|
||||
async def create_person_info(self, person_id:str, data:dict = {}):
|
||||
"""创建一个项"""
|
||||
if not person_id:
|
||||
logger.debug("创建失败,personid不存在")
|
||||
return
|
||||
|
||||
_person_info_default = copy.deepcopy(person_info_default)
|
||||
_person_info_default["person_id"] = person_id
|
||||
|
||||
if data:
|
||||
for key in _person_info_default:
|
||||
if key != "person_id" and key in data:
|
||||
_person_info_default[key] = data[key]
|
||||
|
||||
db.person_info.insert_one(_person_info_default)
|
||||
|
||||
async def update_one_field(self, person_id:str, field_name:str, value, Data:dict = {}):
|
||||
"""更新某一个字段,会补全"""
|
||||
if not field_name in person_info_default.keys():
|
||||
logger.debug(f"更新'{field_name}'失败,未定义的字段")
|
||||
return
|
||||
|
||||
document = db.person_info.find_one({"person_id": person_id})
|
||||
|
||||
if document:
|
||||
db.person_info.update_one(
|
||||
{"person_id": person_id},
|
||||
{"$set": {field_name: value}}
|
||||
)
|
||||
else:
|
||||
Data[field_name] = value
|
||||
logger.debug(f"更新时{person_id}不存在,已新建")
|
||||
await self.create_person_info(person_id, Data)
|
||||
|
||||
async def del_one_document(self, person_id: str):
|
||||
"""删除指定 person_id 的文档"""
|
||||
if not person_id:
|
||||
logger.debug("删除失败:person_id 不能为空")
|
||||
return
|
||||
|
||||
result = db.person_info.delete_one({"person_id": person_id})
|
||||
if result.deleted_count > 0:
|
||||
logger.debug(f"删除成功:person_id={person_id}")
|
||||
else:
|
||||
logger.debug(f"删除失败:未找到 person_id={person_id}")
|
||||
|
||||
async def get_value(self, person_id: str, field_name: str):
|
||||
"""获取指定person_id文档的字段值,若不存在该字段,则返回该字段的全局默认值"""
|
||||
if not person_id:
|
||||
logger.debug("get_value获取失败:person_id不能为空")
|
||||
return None
|
||||
|
||||
if field_name not in person_info_default:
|
||||
logger.debug(f"get_value获取失败:字段'{field_name}'未定义")
|
||||
return None
|
||||
|
||||
document = db.person_info.find_one(
|
||||
{"person_id": person_id},
|
||||
{field_name: 1}
|
||||
)
|
||||
|
||||
if document and field_name in document:
|
||||
return document[field_name]
|
||||
else:
|
||||
logger.debug(f"获取{person_id}的{field_name}失败,已返回默认值{person_info_default[field_name]}")
|
||||
return person_info_default[field_name]
|
||||
|
||||
async def get_values(self, person_id: str, field_names: list) -> dict:
|
||||
"""获取指定person_id文档的多个字段值,若不存在该字段,则返回该字段的全局默认值"""
|
||||
if not person_id:
|
||||
logger.debug("get_values获取失败:person_id不能为空")
|
||||
return {}
|
||||
|
||||
# 检查所有字段是否有效
|
||||
for field in field_names:
|
||||
if field not in person_info_default:
|
||||
logger.debug(f"get_values获取失败:字段'{field}'未定义")
|
||||
return {}
|
||||
|
||||
# 构建查询投影(所有字段都有效才会执行到这里)
|
||||
projection = {field: 1 for field in field_names}
|
||||
|
||||
document = db.person_info.find_one(
|
||||
{"person_id": person_id},
|
||||
projection
|
||||
)
|
||||
|
||||
result = {}
|
||||
for field in field_names:
|
||||
result[field] = document.get(field, person_info_default[field]) if document else person_info_default[field]
|
||||
|
||||
return result
|
||||
|
||||
async def del_all_undefined_field(self):
|
||||
"""删除所有项里的未定义字段"""
|
||||
# 获取所有已定义的字段名
|
||||
defined_fields = set(person_info_default.keys())
|
||||
|
||||
try:
|
||||
# 遍历集合中的所有文档
|
||||
for document in db.person_info.find({}):
|
||||
# 找出文档中未定义的字段
|
||||
undefined_fields = set(document.keys()) - defined_fields - {'_id'}
|
||||
|
||||
if undefined_fields:
|
||||
# 构建更新操作,使用$unset删除未定义字段
|
||||
update_result = db.person_info.update_one(
|
||||
{'_id': document['_id']},
|
||||
{'$unset': {field: 1 for field in undefined_fields}}
|
||||
)
|
||||
|
||||
if update_result.modified_count > 0:
|
||||
logger.debug(f"已清理文档 {document['_id']} 的未定义字段: {undefined_fields}")
|
||||
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"清理未定义字段时出错: {e}")
|
||||
return
|
||||
|
||||
async def get_specific_value_list(
|
||||
self,
|
||||
field_name: str,
|
||||
way: Callable[[Any], bool], # 接受任意类型值
|
||||
) ->Dict[str, Any]:
|
||||
"""
|
||||
获取满足条件的字段值字典
|
||||
|
||||
Args:
|
||||
field_name: 目标字段名
|
||||
way: 判断函数 (value: Any) -> bool
|
||||
convert_type: 强制类型转换(如float/int等)
|
||||
|
||||
Returns:
|
||||
{person_id: value} | {}
|
||||
|
||||
Example:
|
||||
# 查找所有nickname包含"admin"的用户
|
||||
result = manager.specific_value_list(
|
||||
"nickname",
|
||||
lambda x: "admin" in x.lower()
|
||||
)
|
||||
"""
|
||||
if field_name not in person_info_default:
|
||||
logger.error(f"字段检查失败:'{field_name}'未定义")
|
||||
return {}
|
||||
|
||||
try:
|
||||
result = {}
|
||||
for doc in db.person_info.find(
|
||||
{field_name: {"$exists": True}},
|
||||
{"person_id": 1, field_name: 1, "_id": 0}
|
||||
):
|
||||
try:
|
||||
value = doc[field_name]
|
||||
if way(value):
|
||||
result[doc["person_id"]] = value
|
||||
except (KeyError, TypeError, ValueError) as e:
|
||||
logger.debug(f"记录{doc.get('person_id')}处理失败: {str(e)}")
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库查询失败: {str(e)}", exc_info=True)
|
||||
return {}
|
||||
|
||||
person_info_manager = PersonInfoManager()
|
||||
187
src/plugins/person_info/relationship_manager.py
Normal file
187
src/plugins/person_info/relationship_manager.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from src.common.logger import get_module_logger, LogConfig, RELATION_STYLE_CONFIG
|
||||
from ..chat.chat_stream import ChatStream
|
||||
import math
|
||||
from bson.decimal128 import Decimal128
|
||||
from .person_info import person_info_manager
|
||||
import time
|
||||
|
||||
relationship_config = LogConfig(
|
||||
# 使用关系专用样式
|
||||
console_format=RELATION_STYLE_CONFIG["console_format"],
|
||||
file_format=RELATION_STYLE_CONFIG["file_format"],
|
||||
)
|
||||
logger = get_module_logger("rel_manager", config=relationship_config)
|
||||
|
||||
class RelationshipManager:
|
||||
def __init__(self):
|
||||
self.positive_feedback_dict = {} # 正反馈系统
|
||||
|
||||
def positive_feedback_sys(self, person_id, value, label: str, stance: str):
|
||||
"""正反馈系统"""
|
||||
|
||||
positive_list = [
|
||||
"开心",
|
||||
"惊讶",
|
||||
"害羞",
|
||||
]
|
||||
|
||||
negative_list = [
|
||||
"愤怒",
|
||||
"悲伤",
|
||||
"恐惧",
|
||||
"厌恶",
|
||||
]
|
||||
|
||||
if person_id not in self.positive_feedback_dict:
|
||||
self.positive_feedback_dict[person_id] = 0
|
||||
|
||||
if label in positive_list and stance != "反对":
|
||||
if 7 > self.positive_feedback_dict[person_id] >= 0:
|
||||
self.positive_feedback_dict[person_id] += 1
|
||||
elif self.positive_feedback_dict[person_id] < 0:
|
||||
self.positive_feedback_dict[person_id] = 0
|
||||
return value
|
||||
elif label in negative_list and stance != "支持":
|
||||
if -7 < self.positive_feedback_dict[person_id] <= 0:
|
||||
self.positive_feedback_dict[person_id] -= 1
|
||||
elif self.positive_feedback_dict[person_id] > 0:
|
||||
self.positive_feedback_dict[person_id] = 0
|
||||
return value
|
||||
else:
|
||||
return value
|
||||
|
||||
gain_coefficient = [1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0]
|
||||
value *= gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]
|
||||
if abs(self.positive_feedback_dict[person_id]) - 1:
|
||||
logger.info(f"触发增益,当前增益系数:{gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]}")
|
||||
|
||||
return value
|
||||
|
||||
|
||||
async def calculate_update_relationship_value(self, chat_stream: ChatStream, label: str, stance: str) -> None:
|
||||
"""计算并变更关系值
|
||||
新的关系值变更计算方式:
|
||||
将关系值限定在-1000到1000
|
||||
对于关系值的变更,期望:
|
||||
1.向两端逼近时会逐渐减缓
|
||||
2.关系越差,改善越难,关系越好,恶化越容易
|
||||
3.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢
|
||||
4.连续正面或负面情感会正反馈
|
||||
"""
|
||||
stancedict = {
|
||||
"支持": 0,
|
||||
"中立": 1,
|
||||
"反对": 2,
|
||||
}
|
||||
|
||||
valuedict = {
|
||||
"开心": 1.5,
|
||||
"愤怒": -2.0,
|
||||
"悲伤": -0.5,
|
||||
"惊讶": 0.6,
|
||||
"害羞": 2.0,
|
||||
"平静": 0.3,
|
||||
"恐惧": -1.5,
|
||||
"厌恶": -1.0,
|
||||
"困惑": 0.5,
|
||||
}
|
||||
|
||||
person_id = person_info_manager.get_person_id(chat_stream.user_info.platform, chat_stream.user_info.user_id)
|
||||
data = {
|
||||
"platform" : chat_stream.user_info.platform,
|
||||
"user_id" : chat_stream.user_info.user_id,
|
||||
"nickname" : chat_stream.user_info.user_nickname,
|
||||
"konw_time" : int(time.time())
|
||||
}
|
||||
old_value = await person_info_manager.get_value(person_id, "relationship_value")
|
||||
old_value = self.ensure_float(old_value, person_id)
|
||||
|
||||
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:
|
||||
rdict = await person_info_manager.get_specific_value_list("relationship_value", lambda x: x > 700)
|
||||
high_value_count = len(rdict)
|
||||
if old_value > 700:
|
||||
value *= 3 / (high_value_count + 2) # 排除自己
|
||||
else:
|
||||
value *= 3 / (high_value_count + 3)
|
||||
elif valuedict[label] < 0 and stancedict[stance] != 0:
|
||||
value = value * math.exp(old_value / 2000)
|
||||
else:
|
||||
value = 0
|
||||
elif old_value < 0:
|
||||
if valuedict[label] >= 0 and stancedict[stance] != 2:
|
||||
value = value * math.exp(old_value / 2000)
|
||||
elif valuedict[label] < 0 and stancedict[stance] != 0:
|
||||
value = value * math.cos(math.pi * old_value / 2000)
|
||||
else:
|
||||
value = 0
|
||||
|
||||
value = self.positive_feedback_sys(person_id, value, label, stance)
|
||||
|
||||
level_num = self.calculate_level_num(old_value + value)
|
||||
relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"]
|
||||
logger.info(
|
||||
f"当前关系: {relationship_level[level_num]}, "
|
||||
f"关系值: {old_value:.2f}, "
|
||||
f"当前立场情感: {stance}-{label}, "
|
||||
f"变更: {value:+.5f}"
|
||||
)
|
||||
|
||||
await person_info_manager.update_one_field(person_id, "relationship_value", old_value + value, data)
|
||||
|
||||
async def build_relationship_info(self, person) -> str:
|
||||
person_id = person_info_manager.get_person_id(person[0], person[1])
|
||||
relationship_value = await person_info_manager.get_value(person_id, "relationship_value")
|
||||
level_num = self.calculate_level_num(relationship_value)
|
||||
relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"]
|
||||
relation_prompt2_list = [
|
||||
"厌恶回应",
|
||||
"冷淡回复",
|
||||
"保持理性",
|
||||
"愿意回复",
|
||||
"积极回复",
|
||||
"无条件支持",
|
||||
]
|
||||
|
||||
return (
|
||||
f"你对昵称为'({person[1]}){person[2]}'的用户的态度为{relationship_level[level_num]},"
|
||||
f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}。"
|
||||
)
|
||||
|
||||
def calculate_level_num(self, relationship_value) -> int:
|
||||
"""关系等级计算"""
|
||||
if -1000 <= relationship_value < -227:
|
||||
level_num = 0
|
||||
elif -227 <= relationship_value < -73:
|
||||
level_num = 1
|
||||
elif -73 <= 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
|
||||
return level_num
|
||||
|
||||
def ensure_float(elsf, value, person_id):
|
||||
"""确保返回浮点数,转换失败返回0.0"""
|
||||
if isinstance(value, float):
|
||||
return value
|
||||
try:
|
||||
return float(value.to_decimal() if isinstance(value, Decimal128) else value)
|
||||
except (ValueError, TypeError, AttributeError):
|
||||
logger.warning(f"[关系管理] {person_id}值转换失败(原始值:{value}),已重置为0")
|
||||
return 0.0
|
||||
|
||||
relationship_manager = RelationshipManager()
|
||||
Reference in New Issue
Block a user