diff --git a/PROGRESS.md b/PROGRESS.md index e379a2f..c684eac 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -86,10 +86,11 @@ | 步骤 | 触发方式 | 说明 | |------|---------|------| -| 采集 | 定时 01:30 | 热点趋势采集→生成选题建议→存入选题库 | -| 同步 | 定时 02:30 | DB → JSON 备份同步 | -| 创作 | 手动点击 / 定时 03:30 | 生成三平台文章 → 存入 articles 表 → 状态→待审查 | -| 审查 | 手动点击 / 创作后自动 | 从 articles 表读取 → 合规检查 → LLM迭代修复(最多3次)→合规分回写→状态→待发布 | +| 内容采集 | 定时 01:30 | 热点趋势采集→生成选题建议→存入选题库 | +| 内容创作 | 手动点击 / 定时 03:30 | 研究→大纲→撰写文章→合规审查→存入 articles 表 | +| 合规审查 | 手动点击 / 定时 04:30 | 从 articles 表读取 draft→合规检查→LLM迭代修复(最多3次)→状态→待发布 | +| 信息源优化 | 定时 05:00 | AI评估采集类别与信息源配置,给出调整建议 | +| 指标同步 | 定时 06:00 | 同步统计数据 | | 发布 | 手动点击 | 仅待发布状态可选 | --- diff --git a/platform/backend/app/api/admin.py b/platform/backend/app/api/admin.py index 64cb69e..79d4ae0 100644 --- a/platform/backend/app/api/admin.py +++ b/platform/backend/app/api/admin.py @@ -9,23 +9,11 @@ from ..database import get_db from ..models import User, Topic, SystemConfig from ..schemas import UserCreate, UserUpdate, UserResponse from ..core.audit_logger import audit_log -from .auth import org_filter +from .auth import get_current_admin, org_filter import json router = APIRouter(prefix="/api/admin", tags=["admin"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - from .auth import verify_token, org_filter - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("/users", response_model=List[UserResponse]) def list_users( request: Request, diff --git a/platform/backend/app/api/audit.py b/platform/backend/app/api/audit.py index ed96480..799eae2 100644 --- a/platform/backend/app/api/audit.py +++ b/platform/backend/app/api/audit.py @@ -4,28 +4,17 @@ from typing import List, Optional from datetime import datetime, timedelta from ..database import get_db -from ..models import AuditLog +from ..models import AuditLog, User from ..schemas import AuditLogResponse -from .auth import verify_token +from .auth import get_current_admin router = APIRouter(prefix="/api/audit", tags=["audit"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("/logs", response_model=List[AuditLogResponse]) def list_audit_logs( request: Request, db: Session = Depends(get_db), - admin_user: bool = Depends(get_current_admin), + admin_user: User = Depends(get_current_admin), username: Optional[str] = Query(None, description="按用户名筛选"), action: Optional[str] = Query(None, description="按操作类型筛选"), resource_type: Optional[str] = Query(None, description="按资源类型筛选"), @@ -64,7 +53,7 @@ def list_audit_actions( def list_audit_users( request: Request, db: Session = Depends(get_db), - admin_user: bool = Depends(get_current_admin), + admin_user: User = Depends(get_current_admin), limit: int = Query(50, ge=1, le=200) ): """获取最近产生审计记录的用户列表""" diff --git a/platform/backend/app/api/cases.py b/platform/backend/app/api/cases.py index 49d4a9f..bd1f10f 100644 --- a/platform/backend/app/api/cases.py +++ b/platform/backend/app/api/cases.py @@ -5,21 +5,10 @@ from typing import List from ..database import get_db from ..models import Case from ..schemas import CaseBase, CaseResponse +from .auth import get_current_admin router = APIRouter(prefix="/api/admin/cases", tags=["admin"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - from .auth import verify_token - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("", response_model=List[CaseResponse]) def list_cases( request: Request, diff --git a/platform/backend/app/api/llm_configs.py b/platform/backend/app/api/llm_configs.py index eca6c85..b6e42b3 100644 --- a/platform/backend/app/api/llm_configs.py +++ b/platform/backend/app/api/llm_configs.py @@ -5,21 +5,10 @@ from typing import List from ..database import get_db from ..models import LLMConfig from ..schemas import LLMConfigBase, LLMConfigResponse +from .auth import get_current_admin router = APIRouter(prefix="/api/admin/llmconfigs", tags=["admin"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - from .auth import verify_token - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("", response_model=List[LLMConfigResponse]) def list_llm_configs( request: Request, diff --git a/platform/backend/app/api/system.py b/platform/backend/app/api/system.py index 14a509f..e4ad49c 100644 --- a/platform/backend/app/api/system.py +++ b/platform/backend/app/api/system.py @@ -11,6 +11,7 @@ from ..database import get_db from ..models import Topic, Article from ..core.generator import run_creator from ..core.optimizer import run_optimizer +from ..core.collector import run_collector from ..core.sync import sync_all_topics from ..core.scheduler import scheduler from .auth import get_current_user, org_filter @@ -69,6 +70,15 @@ def trigger_generation(topic_id: str = Body(None, embed=True), db: Session = Dep except Exception as e: raise HTTPException(status_code=500, detail=str(e)) +@router.post("/collect/run", dependencies=[Depends(get_current_user)]) +def trigger_collection(db: Session = Depends(get_db), current_user=Depends(get_current_user)): + logger.info(f"Manual collection triggered by {current_user.username}") + try: + result = run_collector() + return {"message": "内容采集已完成", "result": result} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + @router.post("/review/run", dependencies=[Depends(get_current_user)]) def trigger_review(topic_ids: List[str] = Body(None, embed=True), db: Session = Depends(get_db), current_user=Depends(get_current_user)): try: @@ -212,7 +222,7 @@ def get_modules_status(): log_based: dict = { "scheduled_collect": {"name": "📡 内容采集", "log": LOGS_DIR / f"collector_{today_str}.log"}, "scheduled_generate": {"name": "🤖 内容创作", "log": LOGS_DIR / f"creator_{today_str}.log"}, - "scheduled_optimize": {"name": "🔍 内容优化", "log": LOGS_DIR / f"optimizer_{today_str}.log"}, + "scheduled_optimize": {"name": "🔍 合规审查", "log": LOGS_DIR / f"optimizer_{today_str}.log"}, "scheduled_optimize_sources": {"name": "📡 信息源优化", "log": LOGS_DIR / f"optimizer_sources_{today_str}.log"}, "scheduled_metrics_sync": {"name": "📊 指标同步", "log": LOGS_DIR / f"metrics_sync_{today_str}.log"}, } diff --git a/platform/backend/app/api/system_configs.py b/platform/backend/app/api/system_configs.py index a6e4f0b..2f72391 100644 --- a/platform/backend/app/api/system_configs.py +++ b/platform/backend/app/api/system_configs.py @@ -5,21 +5,10 @@ from typing import List, Dict, Any from ..database import get_db from ..models import SystemConfig from ..schemas import SystemConfigBase, SystemConfigResponse +from .auth import get_current_admin router = APIRouter(prefix="/api/admin/systemconfigs", tags=["admin"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - from .auth import verify_token - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("", response_model=List[SystemConfigResponse]) def list_system_configs( request: Request, diff --git a/platform/backend/app/api/task_logs.py b/platform/backend/app/api/task_logs.py index aad6c2e..7dacd58 100644 --- a/platform/backend/app/api/task_logs.py +++ b/platform/backend/app/api/task_logs.py @@ -5,21 +5,10 @@ from typing import List, Optional 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/tasklogs", tags=["admin"]) -def get_current_admin(request: Request, db: Session = Depends(get_db)): - """依赖项:验证管理员权限""" - from .auth import verify_token - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - raise HTTPException(status_code=401, detail="未提供认证令牌") - token = auth_header.split(" ")[1] - user = verify_token(token, db) - if user.role != "admin": - raise HTTPException(status_code=403, detail="需要管理员权限") - return user - @router.get("", response_model=List[TaskLogResponse]) def list_task_logs( request: Request, diff --git a/platform/backend/app/api/topics.py b/platform/backend/app/api/topics.py index da52cdb..50c4067 100644 --- a/platform/backend/app/api/topics.py +++ b/platform/backend/app/api/topics.py @@ -6,10 +6,9 @@ from datetime import datetime, date from pathlib import Path from ..database import get_db -from ..models import Topic, TopicField, TopicConfigField, Article, PublishRecord, ContentMetrics +from ..models import Topic, TopicField, TopicConfigField, Article, ContentMetrics from ..schemas import ( TopicCreate, TopicUpdate, TopicResponse, TopicScoreRequest, - PublishRequest, PublishActionRequest, PublishRecordResponse ) from .auth import get_current_user, org_filter @@ -241,32 +240,6 @@ def score_topic( return {"priority_score": topic.priority_score, "total_score": topic.total_score} -@router.post("/{topic_id}/publish") -def publish_topic(topic_id: str, req: PublishRequest, db: Session = Depends(get_db), current_user=Depends(get_current_user)): - topic = db.query(Topic).filter(Topic.id == topic_id).first() - if not topic: - raise HTTPException(status_code=404, detail="Topic not found") - _check_org(topic, current_user, db) - if topic.status not in ("pending", "ready", "draft"): - raise HTTPException(status_code=400, detail=f"选题状态({topic.status})不允许发布") - - topic.status = "published" - topic.published_at = date.today() - topic.updated_at = datetime.now() - topic.platform_urls = req.platform_urls - - record = PublishRecord( - topic_id=topic_id, - platform="all", - action="publish", - status="success", - description=f"选题 {topic_id} 已发布" - ) - db.add(record) - db.commit() - return {"ok": True, "topic_id": topic_id} - - @router.get("/{topic_id}/articles", response_model=List[Dict[str, Any]]) def get_topic_articles(topic_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)): topic = db.query(Topic).filter(Topic.id == topic_id).first() diff --git a/platform/backend/app/core/collector.py b/platform/backend/app/core/collector.py index 97c3e1d..5d80062 100644 --- a/platform/backend/app/core/collector.py +++ b/platform/backend/app/core/collector.py @@ -19,8 +19,13 @@ def run_collector(): script_path = PROJECT_ROOT / "scripts" / "collector.py" if not script_path.exists(): raise FileNotFoundError(f"Collector script not found: {script_path}") + venv_python = PROJECT_ROOT / "platform" / "backend" / "venv" / "bin" / "python" + if venv_python.exists(): + cmd = [str(venv_python), str(script_path)] + else: + cmd = ["python3", str(script_path)] result = subprocess.run( - ["python", str(script_path)], + cmd, capture_output=True, text=True, cwd=PROJECT_ROOT, diff --git a/platform/backend/app/core/scheduler.py b/platform/backend/app/core/scheduler.py index 18f92b9..c9b9766 100644 --- a/platform/backend/app/core/scheduler.py +++ b/platform/backend/app/core/scheduler.py @@ -62,7 +62,7 @@ class TaskScheduler: ) self.scheduler.start() self._started = True - logger.info("Scheduler started with daily cron triggers (01:30 collect, 02:30 sync, 03:30 generate, 04:30 optimize, 05:00 optimize_sources, 06:00 metrics_sync)") + logger.info("Scheduler started: 01:30 collect, 03:30 generate, 04:30 review, 05:00 optimize_sources, 06:00 metrics_sync") def shutdown(self): if self.scheduler.running: self.scheduler.shutdown() @@ -86,11 +86,11 @@ class TaskScheduler: def _run_optimize(self): try: - logger.info("[Scheduled] Starting compliance optimization...") + logger.info("[Scheduled] Starting compliance review...") result = run_optimizer() - logger.info("[Scheduled] Optimization completed: %s", result) + logger.info("[Scheduled] Review completed: %s", result) except Exception as e: - logger.exception("[Scheduled] Optimization failed: %s", e) + logger.exception("[Scheduled] Review failed: %s", e) def _run_collect(self): try: diff --git a/platform/backend/app/schemas.py b/platform/backend/app/schemas.py index 913fd93..d302fca 100644 --- a/platform/backend/app/schemas.py +++ b/platform/backend/app/schemas.py @@ -490,8 +490,6 @@ class LLMConfigResponse(LLMConfigBase): id: int created_at: Optional[datetime] = None updated_at: Optional[datetime] = None - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) @@ -519,9 +517,3 @@ class SystemStatus(BaseModel): execution_time: Optional[float] = None -class OptimizationRequest(BaseModel): - topic_ids: Optional[List[str]] = None - - -class BatchPublishRequest(BaseModel): - date: str \ No newline at end of file diff --git a/platform/frontend/index.html b/platform/frontend/index.html index 9def6be..f73464a 100644 --- a/platform/frontend/index.html +++ b/platform/frontend/index.html @@ -106,8 +106,7 @@