Files
grok2api/app/services/grok/batch.py
T
piexian 41d5a8d48f feat: 添加 NSFW 启用功能、Token 筛选标签页及修复 use_count 统计
新增功能:
- 添加 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
2026-02-03 08:00:45 +08:00

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"]