Files
zhenxun_bot/zhenxun/models/chat_history.py
T
8b16126e40 添加uv支持 (#2119)
* bugfix:修复内存泄露和信号量饥饿问题

* 修复图片渲染按高度截断问题

* 优化图片渲染速度

* 权限检查去掉无效引用代码

* 添加uv支持

* 🚨 auto fix by pre-commit hooks

* bugfix:修改gitignore换行

* bugfix:修复测试没有新生成uv.lock

* 修复导入错误

* bugfix:移除重复调用

* 🚨 auto fix by pre-commit hooks

* 清理残余poetry引用

* 更新uv安装方式

* 修复阿里云获取问题

* 增加资源下载提示

* 🚨 auto fix by pre-commit hooks

* 修改资源下载为流式

* 🚨 auto fix by pre-commit hooks

* 提高启动速度

* 移除bot.py支持

* 🚨 auto fix by pre-commit hooks

* 优化win脚本逻辑

* 🚨 auto fix by pre-commit hooks

* 清理残余无效逻辑

* 代码改进

* 🚨 auto fix by pre-commit hooks

* 增加数据库迁移存在性检查

* 🚨 auto fix by pre-commit hooks

* chore(test): 添加pytest超时控制和优雅关闭机制

- 在GitHub Actions工作流中添加作业级和步骤级超时限制,防止测试无限期挂起
- 添加pytest-timeout依赖并配置全局超时为120秒
- 在send_queue服务添加关闭钩子,确保worker任务正确取消
- 在priority_manager添加on_shutdown钩子,支持优先级生命周期的关闭阶段

* chore(lint): 禁用超长行的lint警告

* Modify restart logic for Windows platform

* 🚨 auto fix by pre-commit hooks

* bugfix:修复sys导入问题

* 清理无效结构

* bugfix:修复路径问题

* bugfix:修复shell语法传递给git导致资源获取失败问题

* 优化关闭显示

* bugfix:修复路径问题

* bugfix:增加路径安全

* bugfix:修复orm绕过问题

* 放宽numpy版本限制

* 修改重启方案

* bugfix:修复循环导入

* 优化逻辑

* Enhance disconnect function with error handling

Added error handling for disconnect function and imported ConfigurationError.

* Implement emergency restart mechanism

Added emergency restart mechanism using atexit to ensure process restart even on severe exceptions during shutdown.

* 🚨 auto fix by pre-commit hooks

* 重启行为归一化

* 修复测试检测问题

* bugfix:修复测试侧类型报错问题

* 引入launcher机制

* 移除重启测试

* 收紧缓存调用路径

* 类型注解收敛

* 优化浏览器回收行为

* 优化浏览器渲染

* bugfix:解决重复关闭浏览器问题

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: ManyManyTomato <93612024+ATTomatoo@users.noreply.github.com>
Co-authored-by: AkashiCoin <l1040186796@gmail.com>
2026-04-18 23:42:10 +08:00

141 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import datetime, timedelta
from typing import ClassVar, Literal
from typing_extensions import Self
from tortoise import fields
from tortoise.functions import Count
from zhenxun.services.db_context import Model
class ChatHistory(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_id = fields.CharField(255)
"""用户id"""
group_id = fields.CharField(255, null=True)
"""群聊id"""
text = fields.TextField(null=True)
"""文本内容"""
plain_text = fields.TextField(null=True)
"""纯文本"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
bot_id = fields.CharField(255, null=True)
"""bot记录id"""
platform = fields.CharField(255, null=True)
"""平台"""
class Meta: # pyright: ignore [reportIncompatibleVariableOverride]
table = "chat_history"
table_description = "聊天记录数据表"
indexes: ClassVar = [
("user_id", "create_time"),
("group_id", "create_time"),
("user_id", "group_id"),
]
@classmethod
async def get_group_msg_rank(
cls,
gid: str | None,
limit: int = 10,
order: str = "DESC",
date_scope: tuple[datetime, datetime] | None = None,
) -> list[Self]:
"""获取排行数据
参数:
gid: 群号
limit: 获取数量
order: 排序类型,desc,des
date_scope: 日期范围
"""
o = "-" if order == "DESC" else ""
query = cls.filter(group_id=gid) if gid else cls
if date_scope:
filter_scope = (date_scope[0].isoformat(" "), date_scope[1].isoformat(" "))
query = query.filter(create_time__range=filter_scope)
return list(
await query.annotate(count=Count("user_id"))
.order_by(f"{o}count")
.group_by("user_id")
.limit(limit)
.values_list("user_id", "count")
) # type: ignore
@classmethod
async def get_group_first_msg_datetime(
cls, group_id: str | None
) -> datetime | None:
"""获取群第一条记录消息时间
参数:
group_id: 群组id
"""
if group_id:
message = (
await cls.filter(group_id=group_id).order_by("create_time").first()
)
else:
message = await cls.all().order_by("create_time").first()
return message.create_time if message else None
@classmethod
async def get_message(
cls,
uid: str,
gid: str,
type_: Literal["user", "group"],
msg_type: Literal["private", "group"] | None = None,
days: int | tuple[datetime, datetime] | None = None,
) -> list[Self]:
"""获取消息查询query
参数:
uid: 用户id
gid: 群聊id
type_: 类型,私聊或群聊
msg_type: 消息类型,用户或群聊
days: 限制日期
"""
if type_ == "user":
query = cls.filter(user_id=uid)
if msg_type == "private":
query = query.filter(group_id__isnull=True)
elif msg_type == "group":
query = query.filter(group_id__not_isnull=True)
else:
query = cls.filter(group_id=gid)
if uid:
query = query.filter(user_id=uid)
if days:
if isinstance(days, int):
query = query.filter(
create_time__gte=datetime.now() - timedelta(days=days)
)
elif isinstance(days, tuple):
query = query.filter(create_time__range=days)
return await query.all() # type: ignore
@classmethod
async def _run_script(cls):
return [
# 允许 group_id 为空
"alter table chat_history alter group_id drop not null;",
# 允许 text 为空
"alter table chat_history alter text drop not null;",
# 允许 plain_text 为空
"alter table chat_history alter plain_text drop not null;",
# 将user_id改为user_id
"ALTER TABLE chat_history RENAME COLUMN user_qq TO user_id;",
"ALTER TABLE chat_history "
"ALTER COLUMN user_id TYPE character varying(255);",
"ALTER TABLE chat_history "
"ALTER COLUMN group_id TYPE character varying(255);",
# 添加bot_id字段
"ALTER TABLE chat_history ADD bot_id VARCHAR(255);",
"ALTER TABLE chat_history ALTER COLUMN bot_id TYPE character varying(255);",
"ALTER TABLE chat_history ADD COLUMN platform character varying(255);",
]