feat: 创作工作台统一 + AI味检测/白标 + 移动端补全 + 合规发布闭环
- 新增创作工作台 studio.html:合并选题/内容工厂/文章管理为单一 tab 入口(iframe embed 模式) - 新增 AI味检测模块(ai_slop API + 页面,合规软硬问题分级) - 新增白标品牌配置(branding API + 页面 + deploy 私有化交付包) - 发布闭环:publishing 放宽至 editor + records/mark-published 接口 - 移动端响应式补全(admin/calendar/ai-slop 表格卡片兜底) - 修复菜单幂等播种缺陷(按 path 对齐,避免功能页孤立) - 新增短视频脚本 shortvideo.py 与 2026 市场调研简报
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import desc
|
||||
from typing import Optional
|
||||
@@ -6,10 +12,18 @@ from datetime import datetime, timezone
|
||||
|
||||
from ..database import get_db
|
||||
from ..models import ExternalProduct, PromotionCampaign, CampaignKeyword, SEOAudit, KeywordRanking, OptimizationTask, User
|
||||
from .auth import get_current_user, org_filter
|
||||
from .auth import get_current_user, get_current_admin, org_filter
|
||||
|
||||
router = APIRouter(prefix="/api/external", tags=["external_promotion"])
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.parent.parent.parent
|
||||
SEO_AUDITOR_PATH = PROJECT_ROOT / "scripts" / "seo_auditor.py"
|
||||
|
||||
|
||||
class AuditRunRequest(BaseModel):
|
||||
product_id: Optional[str] = None
|
||||
url: Optional[str] = None
|
||||
|
||||
|
||||
def _org_filtered_query(db, model, current_user):
|
||||
query = db.query(model)
|
||||
@@ -467,3 +481,44 @@ def external_overview(
|
||||
"type_breakdown": type_breakdown,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ===== Run SEO Audit (delegate to scripts/seo_auditor.py) =====
|
||||
|
||||
@router.post("/audit/run")
|
||||
def run_audit(
|
||||
body: AuditRunRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_admin),
|
||||
):
|
||||
cmd = [sys.executable, str(SEO_AUDITOR_PATH)]
|
||||
if body.product_id:
|
||||
cmd += ["--product-id", str(body.product_id)]
|
||||
elif body.url:
|
||||
cmd += ["--url", body.url]
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="product_id 或 url 至少提供一个")
|
||||
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
|
||||
except subprocess.TimeoutExpired:
|
||||
raise HTTPException(status_code=408, detail="SEO 审计超时")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"审计执行失败: {str(e)}")
|
||||
|
||||
if result.returncode != 0:
|
||||
raise HTTPException(
|
||||
status_code=502,
|
||||
detail={
|
||||
"message": "SEO 审计脚本返回错误",
|
||||
"stderr": result.stderr,
|
||||
"stdout": result.stdout,
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr,
|
||||
"returncode": result.returncode,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user