refactor: 重构异步任务系统和计费服务架构

- 重构任务系统:新增 lifecycle (TaskStatus/BillingStatus)、context、application 模块
- 将 video tasks 泛化为 async tasks,支持更通用的异步任务管理
- 新增 Gemini Files 管理模块和管理界面
- 重构 billing 服务:拆分 schema.py 和 service.py
- 新增 candidate 服务模块用于请求候选管理
- 数据库迁移:添加 billing_status、request_id、gemini_file_mappings 表和索引
- 移除废弃的 video_telemetry、task orchestrator 等模块
This commit is contained in:
fawney19
2026-02-02 03:16:52 +08:00
parent feb7484fda
commit 9e31efe26c
75 changed files with 7511 additions and 2068 deletions

View File

@@ -813,23 +813,31 @@ class DashboardRecentRequestsAdapter(DashboardAdapter):
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
db = context.db
user = context.user
query = db.query(Usage)
# Perf: select only required columns (avoid loading large JSON/BLOB fields).
query = db.query(
Usage.id,
Usage.user_id,
Usage.model,
Usage.total_tokens,
Usage.created_at,
Usage.is_stream,
DBUser.username,
).outerjoin(DBUser, DBUser.id == Usage.user_id)
if user.role != UserRole.ADMIN:
query = query.filter(Usage.user_id == user.id)
recent_requests = query.order_by(Usage.created_at.desc()).limit(self.limit).all()
rows = query.order_by(Usage.created_at.desc()).limit(self.limit).all()
results = []
for req in recent_requests:
owner = db.query(DBUser).filter(DBUser.id == req.user_id).first()
for req_id, _user_id, model, total_tokens, created_at, is_stream, username in rows:
results.append(
{
"id": req.id,
"user": owner.username if owner else "Unknown",
"model": req.model or "N/A",
"tokens": req.total_tokens,
"time": req.created_at.strftime("%H:%M") if req.created_at else None,
"is_stream": req.is_stream,
"id": req_id,
"user": username or "Unknown",
"model": model or "N/A",
"tokens": int(total_tokens or 0),
"time": created_at.strftime("%H:%M") if created_at else None,
"is_stream": bool(is_stream),
}
)
@@ -848,18 +856,25 @@ class DashboardProviderStatusAdapter(DashboardAdapter):
providers = db.query(Provider).filter(Provider.is_active.is_(True)).all()
since = datetime.now(timezone.utc) - timedelta(days=1)
# Avoid N+1: compute 24h request counts for all providers in one GROUP BY query.
provider_names = [p.name for p in providers if p and p.name]
counts: dict[str, int] = {}
if provider_names:
rows = (
db.query(Usage.provider_name, func.count(Usage.id))
.filter(and_(Usage.created_at >= since, Usage.provider_name.in_(provider_names)))
.group_by(Usage.provider_name)
.all()
)
counts = {str(name): int(cnt or 0) for name, cnt in rows if name}
entries = []
for provider in providers:
count = (
db.query(func.count(Usage.id))
.filter(and_(Usage.provider_name == provider.name, Usage.created_at >= since))
.scalar()
)
entries.append(
{
"name": provider.name,
"status": "active" if provider.is_active else "inactive",
"requests": count,
"requests": int(counts.get(provider.name, 0)),
}
)