mirror of https://github.com/Mai-with-u/MaiBot.git
311 lines
14 KiB
Python
311 lines
14 KiB
Python
from typing import Optional
|
||
from sqlalchemy import Column, Float, Enum as SQLEnum, DateTime
|
||
from sqlmodel import SQLModel, Field, LargeBinary
|
||
from enum import Enum
|
||
from datetime import datetime
|
||
|
||
|
||
class ModelUser(str, Enum):
|
||
SYSTEM = "system"
|
||
PLUGIN = "plugin"
|
||
|
||
|
||
class ImageType(str, Enum):
|
||
EMOJI = "emoji"
|
||
IMAGE = "image"
|
||
|
||
|
||
class Messages(SQLModel, table=True):
|
||
__tablename__ = "mai_messages" # type: ignore
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 消息元数据
|
||
message_id: str = Field(index=True, max_length=255) # 消息id
|
||
timestamp: datetime = Field(sa_column=Column(DateTime)) # 消息时间,单位为秒
|
||
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) # 发送者昵称
|
||
user_cardname: Optional[str] = Field(default=None, max_length=255, nullable=True) # 发送者备注名
|
||
# 群聊信息(如果有)
|
||
group_id: Optional[str] = Field(index=True, default=None, max_length=255, nullable=True) # 群组id
|
||
group_name: Optional[str] = Field(default=None, max_length=255, nullable=True) # 群组名称
|
||
# 被提及/at字段
|
||
is_mentioned: bool = Field(default=False) # 被提及
|
||
is_at: bool = Field(default=False) # 被at
|
||
|
||
# 消息内部元数据
|
||
session_id: str = Field(index=True, max_length=255) # 聊天会话id
|
||
reply_to: Optional[str] = Field(default=None, max_length=255, nullable=True) # 回复的消息id
|
||
is_emoji: bool = Field(default=False) # 是否为表情包消息
|
||
is_picture: bool = Field(default=False) # 是否为图片消息
|
||
is_command: bool = Field(default=False) # 是否为命令
|
||
is_notify: bool = Field(default=False) # 是否为通知消息
|
||
|
||
# 消息内容
|
||
raw_content: bytes = Field(sa_column=Column(LargeBinary)) # msgpack后的原始消息内容
|
||
processed_plain_text: Optional[str] = Field(default=None) # 平面化处理后的纯文本消息
|
||
display_message: Optional[str] = Field(default=None) # 显示的消息内容(被放入Prompt)
|
||
|
||
# 其他配置
|
||
additional_config: Optional[str] = Field(default=None) # 额外配置,JSON格式存储
|
||
|
||
|
||
class ModelUsage(SQLModel, table=True):
|
||
__tablename__ = "llm_usage" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 模型相关信息
|
||
model_name: str = Field(index=True, max_length=255) # 模型实际名称(供应商名称)
|
||
model_assign_name: Optional[str] = Field(index=True, default=None, max_length=255) # 模型分配名称(用户自定义名称)
|
||
model_api_provider_name: str = Field(index=True, max_length=255) # 模型API供应商名称
|
||
|
||
# 请求相关信息
|
||
endpoint: Optional[str] = Field(default=None, max_length=255, nullable=True) # 模型API的具体endpoint
|
||
user_type: ModelUser = Field(sa_column=Column(SQLEnum(ModelUser)), default=ModelUser.SYSTEM) # 模型使用者类型
|
||
request_type: str = Field(max_length=50) # 内部请求类型,记录哪种模块使用了此模型
|
||
time_cost: float = Field(sa_column=Column(Float)) # 本次请求耗时,单位秒
|
||
timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 请求时间戳
|
||
|
||
# Token使用情况
|
||
prompt_tokens: int # 提示词令牌数
|
||
completion_tokens: int # 完成词令牌数
|
||
total_tokens: int # 总令牌数
|
||
cost: float # 本次请求的费用,单位元
|
||
|
||
|
||
class Images(SQLModel, table=True):
|
||
"""用于同时存储表情包和图片的数据库模型。"""
|
||
|
||
__tablename__ = "images" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 元信息
|
||
image_hash: str = Field(index=True, max_length=255) # 图片哈希,使用sha256哈希值,亦作为图片唯一ID
|
||
description: str # 图片的描述
|
||
full_path: str = Field(max_length=1024) # 文件的完整路径 (包括文件名)
|
||
image_type: ImageType = Field(sa_column=Column(SQLEnum(ImageType)), default=ImageType.EMOJI)
|
||
"""图片类型,例如 'emoji' 或 'image'"""
|
||
emotion: Optional[str] = Field(default=None, nullable=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)
|
||
) # 注册时间(被注册为可用表情包的时间)
|
||
last_used_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 上次使用时间
|
||
|
||
vlm_processed: bool = Field(default=False) # 是否已经过VLM处理
|
||
|
||
|
||
class ActionRecord(SQLModel, table=True):
|
||
"""存储动作记录"""
|
||
|
||
__tablename__ = "action_records" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 元信息
|
||
action_id: str = Field(index=True, max_length=255) # 动作ID
|
||
timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 记录时间戳
|
||
session_id: str = Field(index=True, max_length=255) # 对应的 ChatSession session_id
|
||
|
||
# 调用信息
|
||
action_name: str = Field(index=True, max_length=255) # 动作名称
|
||
action_reasoning: Optional[str] = Field(default=None) # 动作推理过程
|
||
action_data: Optional[str] = Field(default=None) # 动作数据,JSON格式存储
|
||
|
||
action_builtin_prompt: Optional[str] = Field(default=None) # 内置动作提示
|
||
action_display_prompt: Optional[str] = Field(default=None) # 最终输入到Prompt的内容
|
||
|
||
|
||
class CommandRecord(SQLModel, table=True):
|
||
"""记录命令执行情况"""
|
||
|
||
__tablename__ = "command_records" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 元信息
|
||
timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 记录时间戳
|
||
session_id: str = Field(index=True, max_length=255) # 对应的 ChatSession session_id
|
||
|
||
# 调用信息
|
||
command_name: str = Field(index=True, max_length=255) # 命令名称
|
||
command_data: Optional[str] = Field(default=None) # 命令数据,JSON格式存储
|
||
command_result: Optional[str] = Field(default=None) # 命令执行结果
|
||
|
||
|
||
class OnlineTime(SQLModel, table=True):
|
||
"""
|
||
用于存储在线时长记录的模型。
|
||
"""
|
||
|
||
__tablename__ = "online_time" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime, index=True)) # 时间戳
|
||
duration_minutes: int = Field() # 时长,单位秒
|
||
start_timestamp: datetime = Field(default_factory=datetime.now, sa_column=Column(DateTime)) # 上线时间
|
||
end_timestamp: datetime = Field(sa_column=Column(DateTime)) # 下线时间
|
||
|
||
|
||
class Expression(SQLModel, table=True):
|
||
"""用于存储表达方式的模型"""
|
||
|
||
__tablename__ = "expressions" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
situation: str = Field(index=True, max_length=255, primary_key=True) # 情景
|
||
style: str = Field(index=True, max_length=255, primary_key=True) # 风格
|
||
|
||
context: str # 上下文
|
||
up_content: str
|
||
|
||
content_list: str # 内容列表,JSON格式存储
|
||
count: int = Field(default=0) # 使用次数
|
||
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,区分是否为全局表达方式
|
||
|
||
|
||
class Jargon(SQLModel, table=True):
|
||
"""存黑话的模型"""
|
||
|
||
__tablename__ = "jargons" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
content: str = Field(index=True, max_length=255, primary_key=True) # 黑话内容
|
||
raw_content: Optional[str] = Field(default=None, nullable=True) # 原始内容,未处理的黑话内容
|
||
|
||
meaning: str # 黑话含义
|
||
session_id: Optional[str] = Field(default=None, max_length=255, nullable=True) # 会话ID,区分是否为全局黑话
|
||
|
||
count: int = Field(default=0) # 使用次数
|
||
is_jargon: Optional[bool] = Field(default=True) # 是否为黑话,False表示为白话
|
||
is_complete: bool = Field(default=False) # 是否为已经完成全部推断(count > 100后不再推断)
|
||
inference_with_context: Optional[str] = Field(default=None, nullable=True) # 带上下文的推断结果,JSON格式
|
||
inference_with_content_only: Optional[str] = Field(default=None, nullable=True) # 只基于词条的推断结果,JSON格式
|
||
|
||
|
||
class ChatHistory(SQLModel, table=True):
|
||
"""存储聊天历史记录的模型"""
|
||
|
||
__tablename__ = "chat_history" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 元信息
|
||
session_id: str = Field(index=True, max_length=255) # 聊天会话ID
|
||
start_timestamp: datetime = Field(sa_column=Column(DateTime, index=True)) # 聊天开始时间
|
||
end_timestamp: datetime = Field(sa_column=Column(DateTime, index=True)) # 聊天结束时间
|
||
query_count: int = Field(default=0) # 被检索次数
|
||
query_forget_count: int = Field(default=0) # 被遗忘检查的次数
|
||
|
||
# 历史消息内容
|
||
original_messages: str # 对话原文
|
||
participants: str # 参与者列表,JSON格式存储
|
||
theme: str # 对话主题:这段对话的主要内容,一个简短的标题
|
||
keywords: str # 关键词:这段对话的关键词,JSON格式存储
|
||
summary: str # 概括:对这段话的平文本概括
|
||
|
||
|
||
class ThinkingQuestion(SQLModel, table=True):
|
||
"""存储思考型问题的模型"""
|
||
|
||
__tablename__ = "thinking_questions" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
# 问答对
|
||
question: str # 问题内容
|
||
context: Optional[str] = Field(default=None, nullable=True) # 上下文
|
||
found_answer: bool = Field(default=False) # 是否找到答案
|
||
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)
|
||
) # 最后更新时间
|
||
|
||
|
||
class BinaryData(SQLModel, table=True):
|
||
"""存储二进制数据的模型"""
|
||
|
||
__tablename__ = "binary_data" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
data_hash: str = Field(index=True, max_length=255) # 数据哈希,使用sha256哈希值,亦作为数据唯一ID
|
||
full_path: str = Field(max_length=1024) # 文件的完整路径 (包括文件名)
|
||
|
||
|
||
class PersonInfo(SQLModel, table=True):
|
||
"""存储个人信息的模型"""
|
||
|
||
__tablename__ = "person_info" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=True) # 自增主键
|
||
|
||
is_known: bool = Field(default=False) # 是否为已知人
|
||
person_id: str = Field(unique=True, index=True, max_length=255) # 人员ID
|
||
person_name: Optional[str] = Field(default=None, max_length=255, nullable=True) # 人员名称
|
||
name_reason: Optional[str] = Field(default=None, nullable=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(
|
||
default=None, nullable=True
|
||
) # 群昵称 (JSON, [{"group_id": str, "group_nick_name": 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)
|
||
) # 首次认识时间
|
||
last_known_time: Optional[datetime] = Field(default=None, sa_column=Column(DateTime, nullable=True)) # 最后认识时间
|
||
|
||
|
||
class ChatSession(SQLModel, table=True):
|
||
"""存储聊天会话的模型"""
|
||
|
||
__tablename__ = "chat_sessions" # type: ignore
|
||
|
||
id: Optional[int] = Field(default=None, primary_key=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)
|
||
) # 最后活跃时间
|
||
|
||
# 身份元数据
|
||
user_id: Optional[str] = Field(index=True, max_length=255, nullable=True) # 用户ID
|
||
group_id: Optional[str] = Field(index=True, default=None, max_length=255, nullable=True) # 群组id
|
||
platform: str = Field(index=True, max_length=100) # 会话所在平台
|