Files
yu-zhi-ran/platform/backend/app/api/task_configs.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

102 lines
4.9 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import func as sa_func
from typing import List, Optional
from ..database import get_db
from ..models import TaskConfig, TaskLog
from ..schemas import TaskConfigBase, TaskConfigUpdate, TaskConfigResponse, TaskLogResponse
from .auth import get_current_admin
router = APIRouter(prefix="/api/admin/task-configs", tags=["admin"])
DEFAULT_CONFIGS = {
"scheduled_fetch_trends": {"name": "🔥 热点趋势", "cron": "01:10", "params": {"llm_provider": "nvidia"}},
"scheduled_collect": {"name": "📡 内容采集", "cron": "01:30", "params": {"max_topics": 20, "llm_provider": "nvidia"}},
"scheduled_generate": {"name": "🤖 内容创作", "cron": "02:00", "params": {"auto_review": True, "llm_provider": "nvidia"}},
"scheduled_optimize": {"name": "🔍 合规审查", "cron": "03:00", "params": {"auto_pass_threshold": 80, "llm_provider": "sensenova"}},
"scheduled_optimize_sources": {"name": "📡 信息源优化", "cron": "05:00", "params": {"llm_provider": "nvidia"}},
"scheduled_metrics_sync": {"name": "📊 指标同步", "cron": "06:00", "params": {"llm_provider": "nvidia"}},
"scheduled_task_monitor": {"name": "⏰ 任务监控", "cron": "*", "params": {"llm_provider": "nvidia"}},
}
def _attach_last_log(resp: TaskConfigResponse, db: Session, module_id: str) -> TaskConfigResponse:
"""从最近一次 TaskLog 中附加 last_run_at 和 result_data"""
last_log = db.query(TaskLog).filter(
TaskLog.module_id == module_id, TaskLog.status.in_(["success", "failed"])
).order_by(TaskLog.started_at.desc()).first()
if last_log:
resp.last_run_at = last_log.started_at
resp.result_data = last_log.result_data or {}
return resp
@router.get("", response_model=List[TaskConfigResponse])
def list_configs(db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
configs = db.query(TaskConfig).order_by(TaskConfig.id).all()
if not configs:
_ensure_defaults(db)
configs = db.query(TaskConfig).order_by(TaskConfig.id).all()
# 批量查询各模块最近一次运行记录
latest_ids = db.query(
sa_func.max(TaskLog.id).label('max_id')
).filter(
TaskLog.status.in_(["success", "failed"])
).group_by(TaskLog.module_id).subquery()
latest_logs = db.query(TaskLog).filter(
TaskLog.id.in_(db.query(latest_ids.c.max_id))
).all()
log_by_module = {log.module_id: log for log in latest_logs}
result = []
for cfg in configs:
resp = TaskConfigResponse.model_validate(cfg)
log = log_by_module.get(cfg.module_id)
if log:
resp.last_run_at = log.started_at
resp.result_data = log.result_data or {}
result.append(resp)
return result
@router.get("/{module_id}", response_model=TaskConfigResponse)
def get_config(module_id: str, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
cfg = db.query(TaskConfig).filter(TaskConfig.module_id == module_id).first()
if not cfg:
_ensure_defaults(db)
cfg = db.query(TaskConfig).filter(TaskConfig.module_id == module_id).first()
if not cfg:
default = DEFAULT_CONFIGS.get(module_id, {})
cfg = TaskConfig(module_id=module_id, enabled=True, params=default.get("params", {}), schedule=default.get("cron", ""))
db.add(cfg)
db.commit()
db.refresh(cfg)
resp = TaskConfigResponse.model_validate(cfg)
return _attach_last_log(resp, db, module_id)
@router.put("/{module_id}", response_model=TaskConfigResponse)
def update_config(module_id: str, data: TaskConfigUpdate, db: Session = Depends(get_db), admin_user=Depends(get_current_admin)):
cfg = db.query(TaskConfig).filter(TaskConfig.module_id == module_id).first()
if not cfg:
_ensure_defaults(db)
cfg = db.query(TaskConfig).filter(TaskConfig.module_id == module_id).first()
if data.enabled is not None:
cfg.enabled = data.enabled
if data.params is not None:
cfg.params = data.params
if data.schedule is not None:
cfg.schedule = data.schedule
if data.last_modified_by:
cfg.last_modified_by = data.last_modified_by
db.commit()
db.refresh(cfg)
return cfg
@router.get("/history/{module_id}", response_model=List[TaskLogResponse])
def get_module_history(module_id: str, db: Session = Depends(get_db), admin_user=Depends(get_current_admin), limit: int = 20):
logs = db.query(TaskLog).filter(TaskLog.module_id == module_id).order_by(TaskLog.started_at.desc()).limit(limit).all()
return [TaskLogResponse.model_validate(l) for l in logs]
def _ensure_defaults(db: Session):
existing = {c.module_id for c in db.query(TaskConfig).all()}
for mid, info in DEFAULT_CONFIGS.items():
if mid not in existing:
db.add(TaskConfig(module_id=mid, enabled=True, params=info.get("params", {}), schedule=info.get("cron", "")))
db.commit()