WebUI 后端类型注解补全,使用全 typing 库类型注解
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
from .routes import router
|
||||
|
||||
__all__ = ["router"]
|
||||
__all__ = ["router"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user