from fastapi import APIRouter, HTTPException, Depends from sqlalchemy.orm import Session from sqlalchemy import func from datetime import datetime, date, timedelta from typing import Dict, Any, List, Optional from pathlib import Path from .auth import get_current_user import os import json from ..database import get_db from ..models import Topic, Article from ..schemas import SystemStatus from ..core.generator import run_creator from ..core.optimizer import run_optimizer from ..core.sync import sync_topic_to_db, sync_all_topics PROJECT_ROOT = Path(__file__).resolve().parents[4] if os.getenv('PROJECT_ROOT'): PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT')) LOGS_DIR = PROJECT_ROOT / "automation" / "logs" DATA_DIR = PROJECT_ROOT / "automation" / "data" router = APIRouter(prefix="/api/system", tags=["system"]) @router.get("/status") def get_status(db: Session = Depends(get_db)): """系统状态概览 - 返回前端兼容格式""" total = db.query(Topic).count() by_status_result = db.query(Topic.status, func.count()).group_by(Topic.status).all() by_status = {status: count for status, count in by_status_result} # 确保返回所有状态 status_map = { 'pending': by_status.get('pending', 0), 'review': by_status.get('review', 0), 'ready': by_status.get('ready', 0), 'published': by_status.get('published', 0) } # 计算今日新增 today = date.today() today_count = db.query(Topic).filter( func.date(Topic.created_at) == today ).count() return { "stats": { "total": total, "pending": status_map['待处理'], "review": status_map['待审查'], "ready": status_map['待发布'], "published": status_map['已发布'], "today": today_count } } @router.post("/generate/run", dependencies=[Depends(get_current_user)]) def trigger_generation(topic_id: str = None, db: Session = Depends(get_db)): """手动触发内容创作任务""" try: result = run_creator(topic_id) if not result["ok"]: raise HTTPException(status_code=500, detail=result["error"]) sync_all_topics() return {"message": "Generation triggered", "result": result} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.post("/optimize/run", dependencies=[Depends(get_current_user)]) def trigger_optimization(topic_ids: List[str] = None, db: Session = Depends(get_db)): """手动触发合规优化任务""" try: result = run_optimizer(topic_ids) if not result["ok"]: raise HTTPException(status_code=500, detail=result["error"]) report = result.get("report") if report: sync_all_topics() return {"message": "Optimization completed", "summary": report["summary"]} else: return {"message": "Optimization completed", "stdout": result.get("stdout", "")} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.get("/logs/{log_date}", dependencies=[Depends(get_current_user)]) def get_logs(log_date: str, log_type: str = "creator"): """读取日志文件内容""" log_file = LOGS_DIR / f"{log_type}_{log_date}.log" if not log_file.exists(): raise HTTPException(status_code=404, detail=f"Log file not found: {log_file}") content = log_file.read_text(encoding='utf-8') lines = content.splitlines()[-100:] if log_type != "collector" else content.splitlines()[-200:] return {"log_date": log_date, "log_type": log_type, "content": lines} @router.get("/pipeline/status", dependencies=[Depends(get_current_user)]) def get_pipeline_status(): """获取流水线各模块状态""" try: topics_file = DATA_DIR / "sustainability_topics.json" topics = [] if topics_file.exists(): topics = json.loads(topics_file.read_text(encoding='utf-8')) status_counts = {} for t in topics: s = t.get('status', 'unknown') status_counts[s] = status_counts.get(s, 0) + 1 log_files = { "collector": LOGS_DIR / f"collector_{date.today().isoformat()}.log", "creator": LOGS_DIR / f"creator_{date.today().isoformat()}.log", "optimizer": LOGS_DIR / f"optimizer_{date.today().isoformat()}.log", } pipeline_status = {} for name, log_file in log_files.items(): if log_file.exists(): mtime = datetime.fromtimestamp(log_file.stat().st_mtime) pipeline_status[name] = {"last_run": mtime.isoformat(), "exists": True} else: pipeline_status[name] = {"exists": False, "last_run": None} return {"topics_count": len(topics), "status_distribution": status_counts, "pipeline_modules": pipeline_status} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.post("/sync/run") def run_sync(): """手动触发数据同步""" try: sync_all_topics() return {"message": "Sync completed"} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.get("/automation/topics") def list_automation_topics(): """直接读取自动化流水线的选题 JSON""" try: topics_file = DATA_DIR / "sustainability_topics.json" if not topics_file.exists(): raise HTTPException(status_code=404, detail="Topics JSON not found") topics = json.loads(topics_file.read_text(encoding='utf-8')) return {"count": len(topics), "topics": topics[-50:]} except json.JSONDecodeError as e: raise HTTPException(status_code=500, detail=f"JSON parse error: {e}") except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.post("/refresh") def refresh_all(): """刷新所有数据""" try: sync_all_topics() return {"message": "Refresh completed"} except Exception as e: raise HTTPException(status_code=500, detail=str(e))