重构绝大部分模块以适配新版本的数据库和数据模型,修复缺少依赖问题,更新 pyproject

This commit is contained in:
DrSmoothl
2026-02-13 20:39:11 +08:00
parent c14736ffca
commit 16b16d2ca6
29 changed files with 2459 additions and 1737 deletions

View File

@@ -3,12 +3,16 @@
from fastapi import APIRouter, HTTPException, Header, Query, Cookie
from pydantic import BaseModel
from typing import Optional, List, Dict
from datetime import datetime
from sqlalchemy import case
from sqlmodel import col, select, delete
from src.common.logger import get_logger
from src.common.database.database import get_db_session
from src.common.database.database_model import PersonInfo
from src.webui.core import verify_auth_token_from_cookie_or_header
import json
import time
logger = get_logger("webui.person")
@@ -29,7 +33,7 @@ class PersonInfoResponse(BaseModel):
nickname: Optional[str]
group_nick_name: Optional[List[Dict[str, str]]] # 解析后的 JSON
memory_points: Optional[str]
know_times: Optional[float]
know_times: Optional[int]
know_since: Optional[float]
last_know: Optional[float]
@@ -112,20 +116,22 @@ def parse_group_nick_name(group_nick_name_str: Optional[str]) -> Optional[List[D
def person_to_response(person: PersonInfo) -> PersonInfoResponse:
"""将 PersonInfo 模型转换为响应对象"""
know_since = person.first_known_time.timestamp() if person.first_known_time else None
last_know = person.last_known_time.timestamp() if person.last_known_time else None
return PersonInfoResponse(
id=person.id,
id=person.id or 0,
is_known=person.is_known,
person_id=person.person_id,
person_name=person.person_name,
name_reason=person.name_reason,
platform=person.platform,
user_id=person.user_id,
nickname=person.nickname,
group_nick_name=parse_group_nick_name(person.group_nick_name),
nickname=person.user_nickname,
group_nick_name=parse_group_nick_name(person.group_nickname),
memory_points=person.memory_points,
know_times=person.know_times,
know_since=person.know_since,
last_know=person.last_know,
know_times=person.know_counts,
know_since=know_since,
last_know=last_know,
)
@@ -157,36 +163,50 @@ async def get_person_list(
verify_auth_token(maibot_session, authorization)
# 构建查询
query = PersonInfo.select()
statement = select(PersonInfo)
# 搜索过滤
if search:
query = query.where(
(PersonInfo.person_name.contains(search))
| (PersonInfo.nickname.contains(search))
| (PersonInfo.user_id.contains(search))
statement = statement.where(
(col(PersonInfo.person_name).contains(search))
| (col(PersonInfo.user_nickname).contains(search))
| (col(PersonInfo.user_id).contains(search))
)
# 已认识状态过滤
if is_known is not None:
query = query.where(PersonInfo.is_known == is_known)
statement = statement.where(col(PersonInfo.is_known) == is_known)
# 平台过滤
if platform:
query = query.where(PersonInfo.platform == platform)
statement = statement.where(col(PersonInfo.platform) == platform)
# 排序最后更新时间倒序NULL 值放在最后)
# Peewee 不支持 nulls_last使用 CASE WHEN 来实现
query = query.order_by(case((PersonInfo.last_know.is_null(), 1), else_=0), PersonInfo.last_know.desc())
statement = statement.order_by(
case((col(PersonInfo.last_known_time).is_(None), 1), else_=0),
col(PersonInfo.last_known_time).desc(),
)
# 获取总数
total = query.count()
# 分页
offset = (page - 1) * page_size
persons = query.offset(offset).limit(page_size)
statement = statement.offset(offset).limit(page_size)
with get_db_session() as session:
persons = session.exec(statement).all()
count_statement = select(PersonInfo.id)
if search:
count_statement = count_statement.where(
(col(PersonInfo.person_name).contains(search))
| (col(PersonInfo.user_nickname).contains(search))
| (col(PersonInfo.user_id).contains(search))
)
if is_known is not None:
count_statement = count_statement.where(col(PersonInfo.is_known) == is_known)
if platform:
count_statement = count_statement.where(col(PersonInfo.platform) == platform)
total = len(session.exec(count_statement).all())
# 转换为响应对象
data = [person_to_response(person) for person in persons]
return PersonListResponse(success=True, total=total, page=page, page_size=page_size, data=data)
@@ -215,7 +235,9 @@ async def get_person_detail(
try:
verify_auth_token(maibot_session, authorization)
person = PersonInfo.get_or_none(PersonInfo.person_id == person_id)
with get_db_session() as session:
statement = select(PersonInfo).where(col(PersonInfo.person_id) == person_id).limit(1)
person = session.exec(statement).first()
if not person:
raise HTTPException(status_code=404, detail=f"未找到 ID 为 {person_id} 的人物信息")
@@ -250,7 +272,9 @@ async def update_person(
try:
verify_auth_token(maibot_session, authorization)
person = PersonInfo.get_or_none(PersonInfo.person_id == person_id)
with get_db_session() as session:
statement = select(PersonInfo).where(col(PersonInfo.person_id) == person_id).limit(1)
person = session.exec(statement).first()
if not person:
raise HTTPException(status_code=404, detail=f"未找到 ID 为 {person_id} 的人物信息")
@@ -262,13 +286,18 @@ async def update_person(
raise HTTPException(status_code=400, detail="未提供任何需要更新的字段")
# 更新最后修改时间
update_data["last_know"] = time.time()
update_data["last_known_time"] = datetime.now()
# 执行更新
for field, value in update_data.items():
setattr(person, field, value)
person.save()
with get_db_session() as session:
db_person = session.exec(select(PersonInfo).where(col(PersonInfo.person_id) == person_id).limit(1)).first()
if not db_person:
raise HTTPException(status_code=404, detail=f"未找到 ID 为 {person_id} 的人物信息")
for field, value in update_data.items():
if hasattr(db_person, field):
setattr(db_person, field, value)
session.add(db_person)
person = db_person
logger.info(f"人物信息已更新: {person_id}, 字段: {list(update_data.keys())}")
@@ -300,16 +329,19 @@ async def delete_person(
try:
verify_auth_token(maibot_session, authorization)
person = PersonInfo.get_or_none(PersonInfo.person_id == person_id)
with get_db_session() as session:
statement = select(PersonInfo).where(col(PersonInfo.person_id) == person_id).limit(1)
person = session.exec(statement).first()
if not person:
raise HTTPException(status_code=404, detail=f"未找到 ID 为 {person_id} 的人物信息")
# 记录删除信息
person_name = person.person_name or person.nickname or person.user_id
person_name = person.person_name or person.user_nickname or person.user_id
# 执行删除
person.delete_instance()
with get_db_session() as session:
session.exec(delete(PersonInfo).where(col(PersonInfo.person_id) == person_id))
logger.info(f"人物信息已删除: {person_id} ({person_name})")
@@ -336,15 +368,17 @@ async def get_person_stats(maibot_session: Optional[str] = Cookie(None), authori
try:
verify_auth_token(maibot_session, authorization)
total = PersonInfo.select().count()
known = PersonInfo.select().where(PersonInfo.is_known).count()
with get_db_session() as session:
total = len(session.exec(select(PersonInfo.id)).all())
known = len(session.exec(select(PersonInfo.id).where(col(PersonInfo.is_known) == True)).all())
unknown = total - known
# 按平台统计
platforms = {}
for person in PersonInfo.select(PersonInfo.platform):
platform = person.platform
platforms[platform] = platforms.get(platform, 0) + 1
with get_db_session() as session:
for platform in session.exec(select(PersonInfo.platform)).all():
if platform:
platforms[platform] = platforms.get(platform, 0) + 1
return {"success": True, "data": {"total": total, "known": known, "unknown": unknown, "platforms": platforms}}
@@ -383,14 +417,17 @@ async def batch_delete_persons(
for person_id in request.person_ids:
try:
person = PersonInfo.get_or_none(PersonInfo.person_id == person_id)
if person:
person.delete_instance()
deleted_count += 1
logger.info(f"批量删除: {person_id}")
else:
failed_count += 1
failed_ids.append(person_id)
with get_db_session() as session:
person = session.exec(
select(PersonInfo).where(col(PersonInfo.person_id) == person_id).limit(1)
).first()
if person:
session.exec(delete(PersonInfo).where(col(PersonInfo.person_id) == person_id))
deleted_count += 1
logger.info(f"批量删除: {person_id}")
else:
failed_count += 1
failed_ids.append(person_id)
except Exception as e:
logger.error(f"删除 {person_id} 失败: {e}")
failed_count += 1