mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 13:42:56 +08:00
Some checks failed
检查bot是否运行正常 / bot check (push) Has been cancelled
CodeQL Code Security Analysis / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL Code Security Analysis / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled
Sequential Lint and Type Check / ruff-call (push) Has been cancelled
Release Drafter / Update Release Draft (push) Has been cancelled
Force Sync to Aliyun / sync (push) Has been cancelled
Update Version / update-version (push) Has been cancelled
Sequential Lint and Type Check / pyright-call (push) Has been cancelled
* ♻️ refactor: 统一图片渲染架构并引入通用UI组件系统 🎨 **渲染服务重构** - 统一图片渲染入口,引入主题系统支持 - 优化Jinja2环境管理,支持主题覆盖和插件命名空间 - 新增UI缓存机制和主题重载功能 ✨ **通用UI组件系统** - 新增 zhenxun.ui 模块,提供数据模型和构建器 - 引入BaseBuilder基类,支持链式调用 - 新增多种UI构建器:InfoCard, Markdown, Table, Chart, Layout等 - 新增通用组件:Divider, Badge, ProgressBar, UserInfoBlock 🔄 **插件迁移** - 迁移9个内置插件至新渲染系统 - 移除各插件中分散的图片生成工具 - 优化数据处理和渲染逻辑 💥 **Breaking Changes** - 移除旧的图片渲染接口和模板路径 - TEMPLATE_PATH 更名为 THEMES_PATH - 插件需适配新的RendererService和zhenxun.ui模块 * ✅ test(check): 更新自检插件测试中的渲染服务模拟 * ♻️ refactor(renderer): 将缓存文件名哈希算法切换到 SHA256 * ♻️ refactor(shop): 移除商店HTML图片生成模块 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
202 lines
4.9 KiB
Python
202 lines
4.9 KiB
Python
from datetime import datetime, timedelta
|
|
import random
|
|
|
|
from nonebot_plugin_uninfo import Uninfo
|
|
from tortoise.expressions import RawSQL
|
|
from tortoise.functions import Count
|
|
|
|
from zhenxun.models.chat_history import ChatHistory
|
|
from zhenxun.models.level_user import LevelUser
|
|
from zhenxun.models.sign_user import SignUser
|
|
from zhenxun.models.statistics import Statistics
|
|
from zhenxun.models.user_console import UserConsole
|
|
from zhenxun.services import renderer_service
|
|
from zhenxun.utils.platform import PlatformUtils
|
|
|
|
RACE = [
|
|
"龙族",
|
|
"魅魔",
|
|
"森林精灵",
|
|
"血精灵",
|
|
"暗夜精灵",
|
|
"狗头人",
|
|
"狼人",
|
|
"猫人",
|
|
"猪头人",
|
|
"骷髅",
|
|
"僵尸",
|
|
"虫族",
|
|
"人类",
|
|
"天使",
|
|
"恶魔",
|
|
"甲壳虫",
|
|
"猎猫",
|
|
"人鱼",
|
|
"哥布林",
|
|
"地精",
|
|
"泰坦",
|
|
"矮人",
|
|
"山巨人",
|
|
"石巨人",
|
|
]
|
|
|
|
SEX = ["男", "女", "雌", "雄"]
|
|
|
|
OCC = [
|
|
"猎人",
|
|
"战士",
|
|
"魔法师",
|
|
"狂战士",
|
|
"魔战士",
|
|
"盗贼",
|
|
"术士",
|
|
"牧师",
|
|
"骑士",
|
|
"刺客",
|
|
"游侠",
|
|
"召唤师",
|
|
"圣骑士",
|
|
"魔使",
|
|
"龙骑士",
|
|
"赏金猎手",
|
|
"吟游诗人",
|
|
"德鲁伊",
|
|
"祭司",
|
|
"符文师",
|
|
"狂暴术士",
|
|
"萨满",
|
|
"裁决者",
|
|
"角斗士",
|
|
]
|
|
|
|
lik2level = {
|
|
400: 8,
|
|
270: 7,
|
|
200: 6,
|
|
140: 5,
|
|
90: 4,
|
|
50: 3,
|
|
25: 2,
|
|
10: 1,
|
|
0: 0,
|
|
}
|
|
|
|
|
|
def get_level(impression: float) -> int:
|
|
"""获取好感度等级"""
|
|
return next((level for imp, level in lik2level.items() if impression >= imp), 0)
|
|
|
|
|
|
async def get_chat_history(
|
|
user_id: str, group_id: str | None
|
|
) -> tuple[list[str], list[int]]:
|
|
"""获取用户聊天记录
|
|
|
|
参数:
|
|
user_id: 用户id
|
|
group_id: 群id
|
|
|
|
返回:
|
|
tuple[list[str], list[int]]: 日期列表, 次数列表
|
|
|
|
"""
|
|
now = datetime.now()
|
|
filter_date = now - timedelta(days=7)
|
|
date_list = (
|
|
await ChatHistory.filter(
|
|
user_id=user_id, group_id=group_id, create_time__gte=filter_date
|
|
)
|
|
.annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
|
|
.group_by("date")
|
|
.values("date", "count")
|
|
)
|
|
chart_date: list[str] = []
|
|
count_list: list[int] = []
|
|
date2cnt = {str(item["date"]): item["count"] for item in date_list}
|
|
current_date = now.date()
|
|
for _ in range(7):
|
|
date_str = str(current_date)
|
|
count_list.append(date2cnt.get(date_str, 0))
|
|
chart_date.append(date_str[5:])
|
|
current_date -= timedelta(days=1)
|
|
chart_date.reverse()
|
|
count_list.reverse()
|
|
return chart_date, count_list
|
|
|
|
|
|
async def get_user_info(
|
|
session: Uninfo, user_id: str, group_id: str | None, nickname: str
|
|
) -> bytes:
|
|
"""获取用户个人信息
|
|
|
|
参数:
|
|
session: Uninfo
|
|
user_id: 用户id
|
|
group_id: 群id
|
|
nickname: 用户昵称
|
|
|
|
返回:
|
|
bytes: 图片数据
|
|
"""
|
|
platform = PlatformUtils.get_platform(session) or "qq"
|
|
avatar_url = (
|
|
PlatformUtils.get_user_avatar_url(user_id, platform, session.self_id) or ""
|
|
)
|
|
|
|
user = await UserConsole.get_user(user_id, platform)
|
|
permission_level = await LevelUser.get_user_level(user_id, group_id)
|
|
|
|
sign_level = 0
|
|
if sign_user := await SignUser.get_or_none(user_id=user_id):
|
|
sign_level = get_level(float(sign_user.impression))
|
|
|
|
chat_count = await ChatHistory.filter(user_id=user_id, group_id=group_id).count()
|
|
stat_count = await Statistics.filter(user_id=user_id, group_id=group_id).count()
|
|
|
|
selected_indices = [""] * 9
|
|
selected_indices[sign_level] = "select"
|
|
|
|
uid = f"{user.uid}".rjust(8, "0")
|
|
uid_formatted = f"{uid[:4]} {uid[4:]}"
|
|
|
|
now = datetime.now()
|
|
weather_icon_name = "moon" if now.hour < 6 or now.hour > 19 else "sun"
|
|
|
|
chart_labels, chart_data = await get_chat_history(user_id, group_id)
|
|
|
|
profile_data = {
|
|
"page": {
|
|
"date": str(now.date()),
|
|
"weather_icon_name": weather_icon_name,
|
|
},
|
|
"info": {
|
|
"avatar_url": avatar_url,
|
|
"nickname": nickname,
|
|
"title": "勇 者",
|
|
"race": random.choice(RACE),
|
|
"sex": random.choice(SEX),
|
|
"occupation": random.choice(OCC),
|
|
"uid": uid_formatted,
|
|
"description": (
|
|
"这是一个传奇的故事,人类的赞歌是勇气的赞歌,人类的伟大是勇气的伟大"
|
|
),
|
|
},
|
|
"stats": {
|
|
"gold": user.gold,
|
|
"prop_count": len(user.props),
|
|
"call_count": stat_count,
|
|
"chat_count": chat_count,
|
|
},
|
|
"favorability": {
|
|
"level": sign_level,
|
|
"selected_indices": selected_indices,
|
|
},
|
|
"permission_level": permission_level,
|
|
"chart": {
|
|
"labels": chart_labels,
|
|
"data": chart_data,
|
|
},
|
|
}
|
|
|
|
return await renderer_service.render("pages/builtin/my_info", data=profile_data)
|