Files
yu-zhi-ran/scripts/creator.py
T
Yuzhiran Dev 233e23016c feat: 内容数据迁移至数据库,合规审查全链路打通
- 文章 HTML 存储从文件系统迁移至 articles 表,删除 releases 目录
- 合规审查从 DB 读取 HTML,审查结果写回 DB,通过后自动推进至待发布
- 新增 todayCount 筛选按钮,与系统概览统计数据一致
- 全屏预览修复:提升 z-index 超过侧边栏,添加退出全屏/关闭按钮
- 统一 '优化' → '审查' 命名,消除前后端术语不一致
- 调度器创作完成后自动触发审查(生成 → 审查 → 待发布)
- 清理旧备份/调试文件、过期大纲和研究笔记
2026-05-13 17:33:56 +08:00

130 lines
5.0 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
宇之然内容创作流水线(研究 → 大纲 → 撰写 → 合规优化)v3 - DB version
"""
import json, datetime, logging, sys, subprocess
from pathlib import Path
from typing import Dict
PROJECT_ROOT = Path('/root/openclaw-workspace/projects/yu-zhi-ran')
sys.path.insert(0, str(PROJECT_ROOT))
# 导入数据库辅助模块
from db_helper import get_topic_by_id, get_next_topic, update_topic_status
DATA_DIR = PROJECT_ROOT / "automation" / "data"
LOGS_DIR = PROJECT_ROOT / "automation" / "logs"
TODAY = datetime.datetime.now().strftime("%Y-%m-%d")
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOGS_DIR / f"creator_{TODAY}.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def select_next_topic(topic_id: str = None) -> Dict:
"""选择并锁定要创作的选题(趋势引擎匹配 → 回退优先级)"""
if topic_id:
topic = get_topic_by_id(topic_id)
if not topic:
raise ValueError(f"Topic {topic_id} not found")
current_status = topic.get('status')
if current_status in ['已发布', 'published']:
raise ValueError(f"Topic {topic_id} is already published, cannot recreate")
update_topic_status(topic_id, 'review')
return topic
try:
from topic_selector import select_best_topic as engine_select
topic = engine_select()
if topic:
logger.info(f"选题引擎推荐: {topic['id']} {topic['title']}")
update_topic_status(topic['id'], 'review')
return topic
except Exception as e:
logger.warning(f"选题引擎失效,回退简单策略: {e}")
topic = get_next_topic(priority='') or get_next_topic()
if not topic:
raise ValueError("No available topics to create (all locked or wrong status)")
update_topic_status(topic['id'], 'review')
return topic
def run_step(script_name: str, topic_id: str) -> bool:
"""运行一个流水线步骤(research/outline/writer"""
script_path = PROJECT_ROOT / "scripts" / script_name
cmd = ["python3", str(script_path), "--topic-id", topic_id]
logger.info(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd, cwd=str(PROJECT_ROOT), capture_output=True, text=True, timeout=1800)
if result.returncode != 0:
logger.error(f"{script_name} 失败: {result.stderr}")
return False
logger.info(f"{script_name} 完成: {result.stdout.strip()}")
return True
def run_optimizer_step(topic_id: str) -> bool:
"""运行合规优化步骤(只针对单个选题)"""
script_path = PROJECT_ROOT / "scripts" / "compliance_optimizer.py"
cmd = ["python3", str(script_path), "--topic-ids", topic_id]
logger.info(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd, cwd=str(PROJECT_ROOT), capture_output=True, text=True, timeout=600)
if result.returncode != 0:
logger.error(f"compliance_optimizer 失败: {result.stderr}")
return False
logger.info(f"compliance_optimizer 完成: {result.stdout.strip()}")
return True
def run_pipeline(topic_id: str = None) -> Dict:
"""运行完整流水线:研究 → 大纲 → 撰写 → 合规优化"""
tid = None
try:
topic = select_next_topic(topic_id)
tid = topic['id']
logger.info(f"开始创作流水线: topic_id={tid}, title={topic.get('title')}")
# 1. 研究
if not run_step("research.py", tid):
update_topic_status(tid, 'pending')
return {"ok": False, "error": "research step failed"}
# 2. 大纲
if not run_step("outline.py", tid):
update_topic_status(tid, 'pending')
return {"ok": False, "error": "outline step failed"}
# 3. 撰写
if not run_step("writer.py", tid):
update_topic_status(tid, 'pending')
return {"ok": False, "error": "writer step failed"}
# 4. 合规优化(自动审核并标记为「待发布」)
if not run_optimizer_step(tid):
update_topic_status(tid, 'pending')
return {"ok": False, "error": "optimizer step failed"}
logger.info(f"创作流水线完成: topic_id={tid}")
return {"ok": True, "topic_id": tid, "stdout": f"SUCCESS: Topic {tid} processed through full pipeline"}
except Exception as e:
logger.exception("流水线执行失败")
if tid:
update_topic_status(tid, 'pending')
return {"ok": False, "error": str(e)}
def main():
import argparse
parser = argparse.ArgumentParser(description='内容创作流水线(研究→大纲→撰写→合规优化)')
parser.add_argument('--topic-id', help='指定选题ID,不指定则自动选择待处理选题')
args = parser.parse_args()
result = run_pipeline(args.topic_id)
print(json.dumps(result, ensure_ascii=False))
sys.exit(0 if result['ok'] else 1)
if __name__ == "__main__":
main()