mirror of https://github.com/Mai-with-u/MaiBot.git
PersonInfo相关提交,添加注释,重命名文件
parent
6d196454ee
commit
8674f50d90
|
|
@ -12,7 +12,7 @@ import json
|
|||
from datetime import datetime
|
||||
|
||||
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 . import BaseDatabaseDataModel
|
||||
|
|
@ -48,21 +48,30 @@ class MaiMessage(BaseDatabaseDataModel[Messages]):
|
|||
# 定义其他属性
|
||||
self.message_info: MessageInfo # 初始化后赋值
|
||||
self.is_mentioned: bool = False
|
||||
"""机器人被提及标记,若被at,则提及也被标记"""
|
||||
self.is_at: bool = False
|
||||
"""机器人被at标记"""
|
||||
self.is_emoji: bool = False
|
||||
"""消息为纯表情包,在计算打字时长时候会被特殊处理"""
|
||||
self.is_picture: bool = False
|
||||
"""消息为纯图片,在计算打字时长时候会被特殊处理"""
|
||||
self.is_command: bool = False
|
||||
"""消息为命令消息,打字时长必定为0"""
|
||||
self.is_notify: bool = False
|
||||
"""消息为通知消息"""
|
||||
|
||||
self.session_id: str
|
||||
self.reply_to: Optional[str] = None
|
||||
|
||||
self.processed_plain_text: Optional[str] = None
|
||||
"""处理过后的纯文本内容"""
|
||||
self.display_message: Optional[str] = None
|
||||
"""最后显示给大模型的消息内容"""
|
||||
self.raw_message: MessageSequence
|
||||
"""原始消息数据"""
|
||||
|
||||
@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)
|
||||
|
||||
user_info = UserInfo(db_record.user_id, db_record.user_nickname, db_record.user_cardname)
|
||||
|
|
@ -117,7 +126,7 @@ class MaiMessage(BaseDatabaseDataModel[Messages]):
|
|||
)
|
||||
|
||||
@classmethod
|
||||
def from_maim_message(cls, message: MessageBase) -> "MaiMessage":
|
||||
def from_maim_message(cls, message: MessageBase):
|
||||
"""从 maim_message.MessageBase 创建 MaiMessage 实例,解析消息内容并提取相关信息"""
|
||||
msg_info = message.message_info
|
||||
assert msg_info, "MessageBase 的 message_info 不能为空"
|
||||
|
|
|
|||
|
|
@ -134,9 +134,18 @@ class AtComponent(BaseMessageComponentModel):
|
|||
def format_name(self) -> str:
|
||||
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
|
||||
"""目标用户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 必须是字符串类型"
|
||||
|
||||
async def to_seg(self) -> Seg:
|
||||
|
|
@ -214,12 +223,15 @@ class ForwardComponent(BaseMessageComponentModel):
|
|||
def __init__(
|
||||
self,
|
||||
user_nickname: str,
|
||||
message_id: str,
|
||||
content: List[StandardMessageComponents],
|
||||
user_id: Optional[str] = None,
|
||||
user_cardname: Optional[str] = None,
|
||||
):
|
||||
self.user_nickname: str = user_nickname
|
||||
"""转发节点的发送者昵称"""
|
||||
self.message_id: str = message_id
|
||||
"""转发节点的消息ID"""
|
||||
self.content: List[StandardMessageComponents] = content
|
||||
"""消息内容"""
|
||||
self.user_id: Optional[str] = user_id
|
||||
|
|
@ -277,7 +289,14 @@ class MessageSequence:
|
|||
raise RuntimeError("VoiceComponent content 未初始化")
|
||||
return {"type": "voice", "data": item.content, "hash": item.binary_hash}
|
||||
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):
|
||||
return {"type": "reply", "data": item.target_message_id}
|
||||
elif isinstance(item, ForwardNodeComponent):
|
||||
|
|
@ -288,6 +307,7 @@ class MessageSequence:
|
|||
"user_id": comp.user_id,
|
||||
"user_nickname": comp.user_nickname,
|
||||
"user_cardname": comp.user_cardname,
|
||||
"message_id": comp.message_id,
|
||||
"content": [self._item_2_dict(c) for c in comp.content],
|
||||
}
|
||||
for comp in item.forward_components
|
||||
|
|
@ -310,7 +330,11 @@ class MessageSequence:
|
|||
elif item_type == "voice":
|
||||
return VoiceComponent(binary_hash=item["hash"], content=item["data"])
|
||||
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":
|
||||
return ReplyComponent(target_message_id=item["data"])
|
||||
elif item_type == "forward":
|
||||
|
|
@ -321,6 +345,7 @@ class MessageSequence:
|
|||
user_nickname=fc["user_nickname"],
|
||||
user_id=fc.get("user_id"),
|
||||
user_cardname=fc.get("user_cardname"),
|
||||
message_id=fc.get("message_id"),
|
||||
content=content,
|
||||
)
|
||||
forward_components.append(forward_component)
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -93,11 +93,15 @@ class Images(SQLModel, table=True):
|
|||
query_count: int = Field(default=0) # 被查询次数
|
||||
is_registered: bool = Field(default=False) # 是否已经注册
|
||||
is_banned: bool = Field(default=False) # 被手动禁用
|
||||
|
||||
|
||||
no_file_flag: bool = Field(default=False) # 文件不存在标记,如果为True表示文件已经不存在,仅保留描述字段
|
||||
|
||||
record_time: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 记录时间(数据库记录被创建的时间)
|
||||
register_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 注册时间(被注册为可用表情包的时间)
|
||||
record_time: datetime = Field(
|
||||
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)) # 上次使用时间
|
||||
|
||||
vlm_processed: bool = Field(default=False) # 是否已经过VLM处理
|
||||
|
|
@ -171,7 +175,9 @@ class Expression(SQLModel, table=True):
|
|||
|
||||
content_list: str # 内容列表,JSON格式存储
|
||||
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)) # 创建时间
|
||||
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) # 问题答案
|
||||
|
||||
thinking_steps: Optional[str] = Field(default=None, nullable=True) # 思考步骤,JSON格式存储
|
||||
created_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 创建时间
|
||||
updated_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 最后更新时间
|
||||
created_timestamp: datetime = Field(
|
||||
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):
|
||||
|
|
@ -263,16 +273,18 @@ class PersonInfo(SQLModel, table=True):
|
|||
platform: str = Field(index=True, max_length=100) # 平台名称
|
||||
user_id: str = Field(index=True, max_length=255) # 用户ID
|
||||
user_nickname: str = Field(index=True, max_length=255) # 用户昵称
|
||||
group_nickname: Optional[str] = Field(
|
||||
group_cardname: Optional[str] = Field(
|
||||
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格式存储
|
||||
|
||||
# 认识次数和时间
|
||||
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)) # 最后认识时间
|
||||
|
||||
|
||||
|
|
@ -285,8 +297,12 @@ class ChatSession(SQLModel, table=True):
|
|||
|
||||
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)) # 创建时间
|
||||
last_active_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 最后活跃时间
|
||||
created_timestamp: datetime = Field(
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
from maim_message import MessageBase, Seg
|
||||
from typing import List
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import msgpack
|
||||
import re
|
||||
|
||||
from src.common.data_models.message_component_model import (
|
||||
from src.common.data_models.message_component_data_model import (
|
||||
MessageSequence,
|
||||
StandardMessageComponents,
|
||||
TextComponent,
|
||||
|
|
@ -16,6 +17,7 @@ from src.common.data_models.message_component_model import (
|
|||
ReplyComponent,
|
||||
DictComponent,
|
||||
)
|
||||
from src.config.config import global_config
|
||||
|
||||
|
||||
class MessageUtils:
|
||||
|
|
@ -85,3 +87,40 @@ class MessageUtils:
|
|||
return ReplyComponent(target_message_id=seg.data)
|
||||
else:
|
||||
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),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue