新增功能: - 添加 gRPC-Web 协议工具用于 NSFW API 调用 - 添加批量执行工具支持并发控制 - 添加 NSFW 服务及管理 API 端点 POST /api/v1/admin/tokens/nsfw/enable - 添加 Token 状态筛选标签页(全部/正常/限流/失效)支持 ARIA 无障碍 - 添加批量启用 NSFW 按钮到 Token 管理工具栏 缺陷修复: - 修复 use_count 统计:在 chat/video/image 完成后调用 consume() - 修复 use_count 计算:使用 actual_cost 替代 cost 避免过度计数 - 修复 toggleSelectAll 仅选择当前筛选结果 配置变更: - 添加 NSFW 相关配置项到 config.defaults.toml
69 lines
1.7 KiB
Python
69 lines
1.7 KiB
Python
"""
|
|
批量执行工具
|
|
|
|
提供分批并发、单项失败隔离的通用批量处理能力。
|
|
"""
|
|
|
|
import asyncio
|
|
from typing import Any, Awaitable, Callable, Dict, List, TypeVar
|
|
|
|
from app.core.logger import logger
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
async def run_in_batches(
|
|
items: List[str],
|
|
worker: Callable[[str], Awaitable[T]],
|
|
*,
|
|
max_concurrent: int = 10,
|
|
batch_size: int = 50,
|
|
) -> Dict[str, Dict[str, Any]]:
|
|
"""
|
|
分批并发执行,单项失败不影响整体
|
|
|
|
Args:
|
|
items: 待处理项列表
|
|
worker: 异步处理函数
|
|
max_concurrent: 最大并发数
|
|
batch_size: 每批大小
|
|
|
|
Returns:
|
|
{item: {"ok": bool, "data": ..., "error": ...}}
|
|
"""
|
|
try:
|
|
max_concurrent = int(max_concurrent)
|
|
except Exception:
|
|
max_concurrent = 10
|
|
try:
|
|
batch_size = int(batch_size)
|
|
except Exception:
|
|
batch_size = 50
|
|
|
|
max_concurrent = max(1, max_concurrent)
|
|
batch_size = max(1, batch_size)
|
|
|
|
sem = asyncio.Semaphore(max_concurrent)
|
|
|
|
async def _one(item: str) -> tuple[str, dict]:
|
|
async with sem:
|
|
try:
|
|
data = await worker(item)
|
|
return item, {"ok": True, "data": data}
|
|
except Exception as e:
|
|
logger.warning(f"Batch item failed: {item[:16]}... - {e}")
|
|
return item, {"ok": False, "error": str(e)}
|
|
|
|
results: Dict[str, dict] = {}
|
|
|
|
# 分批执行,避免一次性创建所有 task
|
|
for i in range(0, len(items), batch_size):
|
|
chunk = items[i : i + batch_size]
|
|
pairs = await asyncio.gather(*(_one(x) for x in chunk))
|
|
results.update(dict(pairs))
|
|
|
|
return results
|
|
|
|
|
|
__all__ = ["run_in_batches"]
|