PersonInfo相关提交,添加注释,重命名文件

pull/1496/head
UnCLAS-Prommer 2026-02-21 23:50:18 +08:00
parent 6d196454ee
commit 8674f50d90
No known key found for this signature in database
5 changed files with 202 additions and 19 deletions

View File

@ -12,7 +12,7 @@ import json
from datetime import datetime from datetime import datetime
from src.common.database.database_model import Messages from src.common.database.database_model import Messages
from src.common.data_models.message_component_model import MessageSequence from src.common.data_models.message_component_data_model import MessageSequence
from src.common.utils.utils_message import MessageUtils from src.common.utils.utils_message import MessageUtils
from . import BaseDatabaseDataModel from . import BaseDatabaseDataModel
@ -48,21 +48,30 @@ class MaiMessage(BaseDatabaseDataModel[Messages]):
# 定义其他属性 # 定义其他属性
self.message_info: MessageInfo # 初始化后赋值 self.message_info: MessageInfo # 初始化后赋值
self.is_mentioned: bool = False self.is_mentioned: bool = False
"""机器人被提及标记若被at则提及也被标记"""
self.is_at: bool = False self.is_at: bool = False
"""机器人被at标记"""
self.is_emoji: bool = False self.is_emoji: bool = False
"""消息为纯表情包,在计算打字时长时候会被特殊处理"""
self.is_picture: bool = False self.is_picture: bool = False
"""消息为纯图片,在计算打字时长时候会被特殊处理"""
self.is_command: bool = False self.is_command: bool = False
"""消息为命令消息打字时长必定为0"""
self.is_notify: bool = False self.is_notify: bool = False
"""消息为通知消息"""
self.session_id: str self.session_id: str
self.reply_to: Optional[str] = None self.reply_to: Optional[str] = None
self.processed_plain_text: Optional[str] = None self.processed_plain_text: Optional[str] = None
"""处理过后的纯文本内容"""
self.display_message: Optional[str] = None self.display_message: Optional[str] = None
"""最后显示给大模型的消息内容"""
self.raw_message: MessageSequence self.raw_message: MessageSequence
"""原始消息数据"""
@classmethod @classmethod
def from_db_instance(cls, db_record: "Messages") -> "MaiMessage": def from_db_instance(cls, db_record: "Messages"):
obj = cls(message_id=db_record.message_id, timestamp=db_record.timestamp) obj = cls(message_id=db_record.message_id, timestamp=db_record.timestamp)
user_info = UserInfo(db_record.user_id, db_record.user_nickname, db_record.user_cardname) user_info = UserInfo(db_record.user_id, db_record.user_nickname, db_record.user_cardname)
@ -117,7 +126,7 @@ class MaiMessage(BaseDatabaseDataModel[Messages]):
) )
@classmethod @classmethod
def from_maim_message(cls, message: MessageBase) -> "MaiMessage": def from_maim_message(cls, message: MessageBase):
"""从 maim_message.MessageBase 创建 MaiMessage 实例,解析消息内容并提取相关信息""" """从 maim_message.MessageBase 创建 MaiMessage 实例,解析消息内容并提取相关信息"""
msg_info = message.message_info msg_info = message.message_info
assert msg_info, "MessageBase 的 message_info 不能为空" assert msg_info, "MessageBase 的 message_info 不能为空"

View File

@ -134,9 +134,18 @@ class AtComponent(BaseMessageComponentModel):
def format_name(self) -> str: def format_name(self) -> str:
return "at" return "at"
def __init__(self, target_user_id: str) -> None: def __init__(
self,
target_user_id: str,
target_user_nickname: Optional[str] = None,
target_user_cardname: Optional[str] = None,
) -> None:
self.target_user_id = target_user_id self.target_user_id = target_user_id
"""目标用户ID""" """目标用户ID"""
self.target_user_nickname = target_user_nickname
"""目标用户昵称"""
self.target_user_cardname = target_user_cardname
"""目标用户备注名"""
assert isinstance(target_user_id, str), "AtComponent 的 target_user_id 必须是字符串类型" assert isinstance(target_user_id, str), "AtComponent 的 target_user_id 必须是字符串类型"
async def to_seg(self) -> Seg: async def to_seg(self) -> Seg:
@ -214,12 +223,15 @@ class ForwardComponent(BaseMessageComponentModel):
def __init__( def __init__(
self, self,
user_nickname: str, user_nickname: str,
message_id: str,
content: List[StandardMessageComponents], content: List[StandardMessageComponents],
user_id: Optional[str] = None, user_id: Optional[str] = None,
user_cardname: Optional[str] = None, user_cardname: Optional[str] = None,
): ):
self.user_nickname: str = user_nickname self.user_nickname: str = user_nickname
"""转发节点的发送者昵称""" """转发节点的发送者昵称"""
self.message_id: str = message_id
"""转发节点的消息ID"""
self.content: List[StandardMessageComponents] = content self.content: List[StandardMessageComponents] = content
"""消息内容""" """消息内容"""
self.user_id: Optional[str] = user_id self.user_id: Optional[str] = user_id
@ -277,7 +289,14 @@ class MessageSequence:
raise RuntimeError("VoiceComponent content 未初始化") raise RuntimeError("VoiceComponent content 未初始化")
return {"type": "voice", "data": item.content, "hash": item.binary_hash} return {"type": "voice", "data": item.content, "hash": item.binary_hash}
elif isinstance(item, AtComponent): elif isinstance(item, AtComponent):
return {"type": "at", "data": item.target_user_id} return {
"type": "at",
"data": {
"target_user_id": item.target_user_id,
"target_user_nickname": item.target_user_nickname,
"target_user_cardname": item.target_user_cardname,
},
}
elif isinstance(item, ReplyComponent): elif isinstance(item, ReplyComponent):
return {"type": "reply", "data": item.target_message_id} return {"type": "reply", "data": item.target_message_id}
elif isinstance(item, ForwardNodeComponent): elif isinstance(item, ForwardNodeComponent):
@ -288,6 +307,7 @@ class MessageSequence:
"user_id": comp.user_id, "user_id": comp.user_id,
"user_nickname": comp.user_nickname, "user_nickname": comp.user_nickname,
"user_cardname": comp.user_cardname, "user_cardname": comp.user_cardname,
"message_id": comp.message_id,
"content": [self._item_2_dict(c) for c in comp.content], "content": [self._item_2_dict(c) for c in comp.content],
} }
for comp in item.forward_components for comp in item.forward_components
@ -310,7 +330,11 @@ class MessageSequence:
elif item_type == "voice": elif item_type == "voice":
return VoiceComponent(binary_hash=item["hash"], content=item["data"]) return VoiceComponent(binary_hash=item["hash"], content=item["data"])
elif item_type == "at": elif item_type == "at":
return AtComponent(target_user_id=item["data"]) return AtComponent(
target_user_id=item["data"]["target_user_id"],
target_user_nickname=item["data"].get("target_user_nickname"),
target_user_cardname=item["data"].get("target_user_cardname"),
)
elif item_type == "reply": elif item_type == "reply":
return ReplyComponent(target_message_id=item["data"]) return ReplyComponent(target_message_id=item["data"])
elif item_type == "forward": elif item_type == "forward":
@ -321,6 +345,7 @@ class MessageSequence:
user_nickname=fc["user_nickname"], user_nickname=fc["user_nickname"],
user_id=fc.get("user_id"), user_id=fc.get("user_id"),
user_cardname=fc.get("user_cardname"), user_cardname=fc.get("user_cardname"),
message_id=fc.get("message_id"),
content=content, content=content,
) )
forward_components.append(forward_component) forward_components.append(forward_component)

View File

@ -0,0 +1,94 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, List
import json
from src.common.database.database_model import PersonInfo
from . import BaseDatabaseDataModel
@dataclass
class GroupCardnameInfo:
group_id: str
group_cardname: str
class MaiPersonInfo(BaseDatabaseDataModel[PersonInfo]):
def __init__(
self,
*,
is_known: bool,
person_id: str,
platform: str,
user_id: str,
user_nickname: str,
know_counts: int,
person_name: Optional[str] = None,
name_reason: Optional[str] = None,
group_cardname_list: Optional[List[GroupCardnameInfo]] = None,
memory_points: Optional[List[str]] = None,
first_known_time: Optional[datetime] = None,
last_known_time: Optional[datetime] = None,
):
self.is_known = is_known
"""标记是否为已知用户,已知用户指在数据库中存在记录的用户"""
self.person_id: str = person_id
"""用户专有ID"""
self.person_name: Optional[str] = person_name
"""用户名称"""
self.name_reason: Optional[str] = name_reason
"""用户名称的来源或变更原因说明"""
self.platform: str = platform
"""平台标识"""
self.user_id: str = user_id
"""用户在平台上的ID"""
self.user_nickname: str = user_nickname
"""用户在平台上的昵称"""
self.group_cardname_list: Optional[List[GroupCardnameInfo]] = group_cardname_list
"""用户在不同群中的昵称列表"""
self.memory_points: Optional[List[str]] = memory_points
"""与用户相关的记忆点列表"""
self.know_counts: int = know_counts
"""已知用户被认识的次数"""
self.first_known_time: Optional[datetime] = first_known_time
"""第一次被认识的时间"""
self.last_known_time: Optional[datetime] = last_known_time
"""最后一次被认识的时间"""
@classmethod
def from_db_instance(cls, db_record: "PersonInfo"):
nickname_json = json.loads(db_record.group_cardname) if db_record.group_cardname else None
group_cardname_list = [GroupCardnameInfo(**item) for item in nickname_json] if nickname_json else None
memory_points = json.loads(db_record.memory_points) if db_record.memory_points else None
return cls(
is_known=db_record.is_known,
person_id=db_record.person_id,
person_name=db_record.person_name,
name_reason=db_record.name_reason,
platform=db_record.platform,
user_id=db_record.user_id,
user_nickname=db_record.user_nickname,
group_cardname_list=group_cardname_list,
memory_points=memory_points,
know_counts=db_record.know_counts,
first_known_time=db_record.first_known_time,
last_known_time=db_record.last_known_time,
)
def to_db_instance(self) -> "PersonInfo":
return PersonInfo(
is_known=self.is_known,
person_id=self.person_id,
person_name=self.person_name,
name_reason=self.name_reason,
platform=self.platform,
user_id=self.user_id,
user_nickname=self.user_nickname,
group_cardname=json.dumps([gn.__dict__ for gn in self.group_cardname_list]) if self.group_cardname_list else None,
memory_points=json.dumps(self.memory_points) if self.memory_points else None,
know_counts=self.know_counts,
first_known_time=self.first_known_time,
last_known_time=self.last_known_time,
)

View File

@ -96,8 +96,12 @@ class Images(SQLModel, table=True):
no_file_flag: bool = Field(default=False) # 文件不存在标记如果为True表示文件已经不存在仅保留描述字段 no_file_flag: bool = Field(default=False) # 文件不存在标记如果为True表示文件已经不存在仅保留描述字段
record_time: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 记录时间(数据库记录被创建的时间) record_time: datetime = Field(
register_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 注册时间(被注册为可用表情包的时间) default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 记录时间(数据库记录被创建的时间)
register_time: Optional[datetime] = Field(
default=None, sa_column=Column(DateTime, nullable=True)
) # 注册时间(被注册为可用表情包的时间)
last_used_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 上次使用时间 last_used_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 上次使用时间
vlm_processed: bool = Field(default=False) # 是否已经过VLM处理 vlm_processed: bool = Field(default=False) # 是否已经过VLM处理
@ -171,7 +175,9 @@ class Expression(SQLModel, table=True):
content_list: str # 内容列表JSON格式存储 content_list: str # 内容列表JSON格式存储
count: int = Field(default=0) # 使用次数 count: int = Field(default=0) # 使用次数
last_active_time: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 上次使用时间 last_active_time: datetime = Field(
default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 上次使用时间
create_time: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime)) # 创建时间 create_time: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime)) # 创建时间
session_id: Optional[str] = Field(default=None, max_length=255, nullable=True) # 会话ID区分是否为全局表达方式 session_id: Optional[str] = Field(default=None, max_length=255, nullable=True) # 会话ID区分是否为全局表达方式
@ -232,8 +238,12 @@ class ThinkingQuestion(SQLModel, table=True):
answer: Optional[str] = Field(default=None, nullable=True) # 问题答案 answer: Optional[str] = Field(default=None, nullable=True) # 问题答案
thinking_steps: Optional[str] = Field(default=None, nullable=True) # 思考步骤JSON格式存储 thinking_steps: Optional[str] = Field(default=None, nullable=True) # 思考步骤JSON格式存储
created_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 创建时间 created_timestamp: datetime = Field(
updated_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 最后更新时间 default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 创建时间
updated_timestamp: datetime = Field(
default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 最后更新时间
class BinaryData(SQLModel, table=True): class BinaryData(SQLModel, table=True):
@ -263,16 +273,18 @@ class PersonInfo(SQLModel, table=True):
platform: str = Field(index=True, max_length=100) # 平台名称 platform: str = Field(index=True, max_length=100) # 平台名称
user_id: str = Field(index=True, max_length=255) # 用户ID user_id: str = Field(index=True, max_length=255) # 用户ID
user_nickname: str = Field(index=True, max_length=255) # 用户昵称 user_nickname: str = Field(index=True, max_length=255) # 用户昵称
group_nickname: Optional[str] = Field( group_cardname: Optional[str] = Field(
default=None, nullable=True default=None, nullable=True
) # 群昵称 (JSON, [{"group_id": str, "group_nick_name": str}]) ) # 群昵称 (JSON, [{"group_id": str, "group_cardname": str}])
# 印象 # 印象
memory_points: Optional[str] = Field(default=None, nullable=True) # 记忆要点JSON格式存储 memory_points: Optional[str] = Field(default=None, nullable=True) # 记忆要点JSON格式存储
# 认识次数和时间 # 认识次数和时间
know_counts: int = Field(default=0) # 认识次数 know_counts: int = Field(default=0) # 认识次数
first_known_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 首次认识时间 first_known_time: Optional[datetime] = Field(
default=None, sa_column=Column(DateTime, nullable=True)
) # 首次认识时间
last_known_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 最后认识时间 last_known_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 最后认识时间
@ -285,8 +297,12 @@ class ChatSession(SQLModel, table=True):
session_id: str = Field(unique=True, index=True, max_length=255) # 聊天会话ID session_id: str = Field(unique=True, index=True, max_length=255) # 聊天会话ID
created_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 创建时间 created_timestamp: datetime = Field(
last_active_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 最后活跃时间 default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 创建时间
last_active_timestamp: datetime = Field(
default_factory=datetime.now, sa_column=Column(DateTime, index=True)
) # 最后活跃时间
# 身份元数据 # 身份元数据
user_id: Optional[str] = Field(index=True, max_length=255, nullable=True) # 用户ID user_id: Optional[str] = Field(index=True, max_length=255, nullable=True) # 用户ID

View File

@ -1,11 +1,12 @@
from maim_message import MessageBase, Seg from maim_message import MessageBase, Seg
from typing import List from typing import List, Tuple, Optional
import base64 import base64
import hashlib import hashlib
import msgpack import msgpack
import re
from src.common.data_models.message_component_model import ( from src.common.data_models.message_component_data_model import (
MessageSequence, MessageSequence,
StandardMessageComponents, StandardMessageComponents,
TextComponent, TextComponent,
@ -16,6 +17,7 @@ from src.common.data_models.message_component_model import (
ReplyComponent, ReplyComponent,
DictComponent, DictComponent,
) )
from src.config.config import global_config
class MessageUtils: class MessageUtils:
@ -85,3 +87,40 @@ class MessageUtils:
return ReplyComponent(target_message_id=seg.data) return ReplyComponent(target_message_id=seg.data)
else: else:
raise NotImplementedError(f"暂时不支持的消息片段类型: {seg.type}") raise NotImplementedError(f"暂时不支持的消息片段类型: {seg.type}")
@staticmethod
def check_ban_words(text: str) -> Tuple[bool, Optional[str]]:
"""检查消息是否包含过滤词
Args:
text: 待检查的文本
Returns:
bool: 是否包含过滤词
"""
if not text:
return False, None
return next(
((True, word) for word in global_config.message_receive.ban_words if word in text),
(False, None),
)
@staticmethod
def check_ban_regex(text: str) -> Tuple[bool, Optional[str]]:
"""检查消息是否匹配过滤正则表达式
Args:
text: 待检查的文本
chat: 聊天对象
userinfo: 用户信息
Returns:
bool: 是否匹配过滤正则
"""
# 检查text是否为None或空字符串
if not text:
return False, None
return next(
((True, pattern) for pattern in global_config.message_receive.ban_msgs_regex if re.search(pattern, text)),
(False, None),
)