WebUI 后端类型注解补全,使用全 typing 库类型注解

This commit is contained in:
DrSmoothl
2026-03-16 13:09:12 +08:00
parent df088205dd
commit e7ac064a80
47 changed files with 572 additions and 365 deletions

View File

@@ -1,3 +1,3 @@
from .routes import router
__all__ = ["router"]
__all__ = ["router"]

View File

@@ -1,13 +1,12 @@
"""表情包管理 API 路由"""
from datetime import datetime
from pathlib import Path
from typing import Any, Optional
import asyncio
import hashlib
import io
import os
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from fastapi import APIRouter, Cookie, HTTPException, Query
from fastapi.responses import FileResponse, JSONResponse
@@ -17,7 +16,8 @@ from sqlmodel import col, select
from src.common.database.database import get_db_session
from src.common.database.database_model import Images, ImageType
from src.webui.core import get_token_manager, verify_auth_token_from_cookie_or_header as verify_auth_token
from src.webui.core import get_token_manager
from src.webui.core import verify_auth_token_from_cookie_or_header as verify_auth_token
from .schemas import (
BatchDeleteRequest,
@@ -219,7 +219,7 @@ async def delete_emoji(emoji_id: int, maibot_session: Optional[str] = Cookie(Non
@router.get("/stats/summary")
async def get_emoji_stats(maibot_session: Optional[str] = Cookie(None)) -> dict[str, Any]:
async def get_emoji_stats(maibot_session: Optional[str] = Cookie(None)) -> Dict[str, Any]:
"""获取表情包统计数据。"""
try:
verify_auth_token(maibot_session)
@@ -247,7 +247,7 @@ async def get_emoji_stats(maibot_session: Optional[str] = Cookie(None)) -> dict[
registered = session.exec(registered_statement).one()
banned = session.exec(banned_statement).one()
formats: dict[str, int] = {}
formats: Dict[str, int] = {}
format_statement = select(Images.full_path).where(col(Images.image_type) == ImageType.EMOJI)
for full_path in session.exec(format_statement).all():
suffix = Path(full_path).suffix.lower().lstrip(".")
@@ -443,7 +443,7 @@ async def batch_delete_emojis(
deleted_count = 0
failed_count = 0
failed_ids: list[int] = []
failed_ids: List[int] = []
for emoji_id in request.emoji_ids:
try:
@@ -582,12 +582,12 @@ async def batch_upload_emoji(
emotion: EmotionForm = "",
is_registered: IsRegisteredForm = True,
maibot_session: Optional[str] = Cookie(None),
) -> dict[str, Any]:
) -> Dict[str, Any]:
"""批量上传表情包。"""
try:
verify_auth_token(maibot_session)
results: dict[str, Any] = {
results: Dict[str, Any] = {
"success": True,
"total": len(files),
"uploaded": 0,
@@ -614,9 +614,7 @@ async def batch_upload_emoji(
file_content = await file.read()
if not file_content:
results["failed"] += 1
results["details"].append(
{"filename": file.filename, "success": False, "error": "文件内容为空"}
)
results["details"].append({"filename": file.filename, "success": False, "error": "文件内容为空"})
continue
try:
@@ -677,14 +675,10 @@ async def batch_upload_emoji(
session.flush()
results["uploaded"] += 1
results["details"].append(
{"filename": file.filename, "success": True, "id": emoji.id}
)
results["details"].append({"filename": file.filename, "success": True, "id": emoji.id})
except Exception as e:
results["failed"] += 1
results["details"].append(
{"filename": file.filename, "success": False, "error": str(e)}
)
results["details"].append({"filename": file.filename, "success": False, "error": str(e)})
results["message"] = f"成功上传 {results['uploaded']} 个,失败 {results['failed']}"
return results
@@ -787,7 +781,9 @@ async def preheat_thumbnail_cache(
try:
loop = asyncio.get_event_loop()
await loop.run_in_executor(get_thumbnail_executor(), generate_thumbnail, emoji.full_path, emoji.image_hash)
await loop.run_in_executor(
get_thumbnail_executor(), generate_thumbnail, emoji.full_path, emoji.image_hash
)
generated += 1
except Exception as e:
logger.warning(f"预热缩略图失败 {emoji.image_hash}: {e}")
@@ -840,4 +836,4 @@ async def clear_all_thumbnail_cache(maibot_session: Optional[str] = Cookie(None)
raise
except Exception as e:
logger.exception(f"清空缩略图缓存失败: {e}")
raise HTTPException(status_code=500, detail=f"清空失败: {str(e)}") from e
raise HTTPException(status_code=500, detail=f"清空失败: {str(e)}") from e

View File

@@ -137,4 +137,4 @@ def emoji_to_response(image: Images) -> EmojiResponse:
record_time=image.record_time.timestamp() if image.record_time else 0.0,
register_time=image.register_time.timestamp() if image.register_time else None,
last_used_time=image.last_used_time.timestamp() if image.last_used_time else None,
)
)

View File

@@ -1,8 +1,8 @@
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
import os
import threading
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from typing import Dict, Set, Tuple
from PIL import Image
from sqlmodel import col, select
@@ -18,10 +18,10 @@ THUMBNAIL_SIZE = (200, 200)
THUMBNAIL_QUALITY = 80
EMOJI_REGISTERED_DIR = os.path.join("data", "emoji_registed")
_thumbnail_locks: dict[str, threading.Lock] = {}
_thumbnail_locks: Dict[str, threading.Lock] = {}
_locks_lock = threading.Lock()
_thumbnail_executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="thumbnail")
_generating_thumbnails: set[str] = set()
_generating_thumbnails: Set[str] = set()
_generating_lock = threading.Lock()
@@ -35,7 +35,7 @@ def get_generating_lock() -> threading.Lock:
return _generating_lock
def get_generating_thumbnails() -> set[str]:
def get_generating_thumbnails() -> Set[str]:
"""获取正在生成的缩略图哈希集合。"""
return _generating_thumbnails
@@ -112,7 +112,7 @@ def background_generate_thumbnail(source_path: str, file_hash: str) -> None:
_background_generate_thumbnail(source_path, file_hash)
def cleanup_orphaned_thumbnails() -> tuple[int, int]:
def cleanup_orphaned_thumbnails() -> Tuple[int, int]:
"""清理孤立的缩略图缓存。"""
if not THUMBNAIL_CACHE_DIR.exists():
return 0, 0
@@ -139,4 +139,4 @@ def cleanup_orphaned_thumbnails() -> tuple[int, int]:
if cleaned > 0:
logger.info(f"清理孤立缩略图: 删除 {cleaned} 个,保留 {kept}")
return cleaned, kept
return cleaned, kept