Files
yu-zhi-ran/platform/backend/app/api/task_logs.py
T
Yuzhiran Dev 499c511140 chore: opencode冗余清理 + LLM任务级模型选择 + systemd服务化
- 删除 opencode_search.py / mcp_search_server.py 及所有 MCP 引用
- 移除搜索缓存定时任务(scheduled_refresh_search_cache)
- 清理前后端所有 opencode/MCP 代码和注释
- LLM 提供商量换:opencode-go→nvidia(默认)+sensenova(合规审查)
- llm_configs 新增 is_default 字段,API 层互斥逻辑
- 所有定时任务支持独立 LLM 模型选择(LLM_TASK_PROVIDER env)
- compliance_optimizer.py 修复:import os / 解硬编码 / 关键词过滤
- Scheduler 日志修复:始终 INSERT,避免僵尸 running 行
- Systemd 服务化:Restart=always / 单 worker / Type=exec
- 搜索提供商:替换 opencode→360/搜狗/微信(免 Key)
- 更新 AGENTS.md / PROGRESS.md
2026-06-02 15:38:16 +08:00

130 lines
5.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import or_
from typing import List, Optional
from datetime import datetime, timezone
from ..database import get_db
from ..models import TaskLog
from ..schemas import TaskLogBase, TaskLogResponse
from .auth import get_current_admin
router = APIRouter(prefix="/api/admin/task-logs", tags=["admin"])
MODULES = {
"scheduled_fetch_trends": "🔥 热点趋势",
"scheduled_collect": "📡 内容采集",
"scheduled_generate": "🤖 内容创作",
"scheduled_optimize": "🔍 合规审查",
"scheduled_optimize_sources": "📡 信息源优化",
"scheduled_metrics_sync": "📊 指标同步",
"scheduled_task_monitor": "⏰ 任务监控",
"scheduled_reset_search_usage": "🔁 搜索用量重置",
}
@router.get("", response_model=List[TaskLogResponse])
def list_task_logs(
db: Session = Depends(get_db),
admin_user=Depends(get_current_admin),
module_id: Optional[str] = None,
status: Optional[str] = None,
date: Optional[str] = None,
limit: int = 50,
):
query = db.query(TaskLog)
if module_id:
query = query.filter(TaskLog.module_id == module_id)
if status:
query = query.filter(TaskLog.status == status)
if date:
try:
dt = datetime.strptime(date, "%Y-%m-%d").replace(tzinfo=timezone.utc)
next_day = datetime(dt.year, dt.month, dt.day + 1, tzinfo=timezone.utc)
query = query.filter(TaskLog.started_at >= dt, TaskLog.started_at < next_day)
except ValueError:
pass
logs = query.order_by(TaskLog.started_at.desc()).limit(limit).all()
return [TaskLogResponse.model_validate(l) for l in logs]
@router.get("/modules")
def list_modules(db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
today = datetime.now(timezone.utc).date().isoformat()
result = []
for mid, name in MODULES.items():
latest = db.query(TaskLog).filter(TaskLog.module_id == mid).order_by(TaskLog.started_at.desc()).first()
total = db.query(TaskLog).filter(TaskLog.module_id == mid).count()
success = db.query(TaskLog).filter(TaskLog.module_id == mid, TaskLog.status == "success").count()
failed = db.query(TaskLog).filter(TaskLog.module_id == mid, TaskLog.status == "failed").count()
running = db.query(TaskLog).filter(TaskLog.module_id == mid, TaskLog.status == "running").count()
result.append({
"module_id": mid,
"name": name,
"last_run": latest.started_at.isoformat() if latest and latest.started_at else None,
"last_status": latest.status if latest else None,
"last_message": latest.message if latest else None,
"total_runs": total,
"success_runs": success,
"failed_runs": failed,
"running": running,
})
return result
@router.get("/log-types")
def list_log_types(db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
used = db.query(TaskLog.module_id).distinct().all()
used_ids = [r[0] for r in used]
result = []
for mid, name in MODULES.items():
if mid in used_ids or True:
log_file_map = {
"scheduled_fetch_trends": "trends",
"scheduled_collect": "collector",
"scheduled_generate": "creator",
"scheduled_optimize": "optimizer",
"scheduled_optimize_sources": "optimizer_sources",
"scheduled_metrics_sync": "metrics_sync",
"scheduled_reset_search_usage": "reset_search_usage",
"scheduled_task_monitor": "task_monitor",
}
result.append({"module_id": mid, "name": name, "log_file": log_file_map.get(mid, mid)})
for mid in used_ids:
if mid not in MODULES:
result.append({"module_id": mid, "name": mid, "log_file": mid})
return result
@router.get("/{log_id}", response_model=TaskLogResponse)
def get_task_log(log_id: int, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="记录不存在")
return log
@router.post("", response_model=TaskLogResponse)
def create_task_log(log_data: TaskLogBase, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
log = TaskLog(**log_data.model_dump())
db.add(log)
db.commit()
db.refresh(log)
return log
@router.put("/{log_id}", response_model=TaskLogResponse)
def update_task_log(log_id: int, log_update: TaskLogBase, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="记录不存在")
data = log_update.model_dump(exclude_unset=True)
for field, value in data.items():
setattr(log, field, value)
db.commit()
db.refresh(log)
return log
@router.delete("/{log_id}")
def delete_task_log(log_id: int, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="记录不存在")
db.delete(log)
db.commit()
return {"message": "删除成功"}