feat: 数据源统一与前端预览修复
=== 后端核心 === - db_helper: 统一数据库访问抽象层 - system.py API: * 参数绑定修复: 使用 Body(embed=True) 接收 JSON * 添加请求日志记录 - sync.py: 仅导出 DB→JSON(备份) === 合规与流水线 === - compliance_checker: 标签检测优化(仅检查容器,避免正文误判) - 所有脚本(creator/collector/writer/outline/research等)统一使用数据库 === 前端改版 === - topics.html: * 创作/优化 API 路径修正 * 预览弹窗重设计:多平台并行加载、富文本显示、单复制按钮 * 状态中文映射(getStatusLabel) * 认证检查 - 所有 HTML 静态资源路径修复(移除 /static 前缀) === 数据一致性 === - 数据库状态统一为英文(pending/review/ready/published) - 前端显示中文化映射 已测试 A03 流水线完整通过。
This commit is contained in:
@@ -1,40 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
批量合规审查脚本
|
||||
批量合规审查脚本 - 数据库版
|
||||
遍历指定日期所有发布版本,执行合规检查,生成汇总报告
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import json, re, datetime
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from scripts.compliance_checker import check_article
|
||||
|
||||
# 尝试导入数据库
|
||||
try:
|
||||
from db_helper import export_topics_to_json
|
||||
HAVE_DB = True
|
||||
except ImportError:
|
||||
HAVE_DB = False
|
||||
|
||||
# 配置
|
||||
RELEASE_DIR = PROJECT_ROOT / "automation" / "data" / "releases"
|
||||
TOPICS_FILE = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json"
|
||||
TODAY = "2026-04-16" # 可参数化
|
||||
TODAY = datetime.date.today().isoformat() # 默认今天,可修改
|
||||
|
||||
def load_topics():
|
||||
with open(TOPICS_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
def load_topics_from_db():
|
||||
if not HAVE_DB:
|
||||
raise RuntimeError("Database not available")
|
||||
topics = export_topics_to_json()
|
||||
return {t['id']: t for t in topics}
|
||||
|
||||
def extract_topic_id(filename: str) -> str:
|
||||
"""从文件名提取 topic ID,如 zhihu_A01_zhihu.html -> A01"""
|
||||
parts = filename.stem.split('_')
|
||||
def load_topics_from_json():
|
||||
json_path = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json"
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
topics = json.load(f)
|
||||
return {t['id']: t for t in topics}
|
||||
|
||||
def extract_topic_id(filename: Path) -> str:
|
||||
stem = filename.stem
|
||||
parts = stem.split('_')
|
||||
if len(parts) >= 2:
|
||||
return parts[1]
|
||||
return None
|
||||
|
||||
def main():
|
||||
topics = load_topics()
|
||||
topics_by_id = {t['id']: t for t in topics}
|
||||
def main(target_date: str = None):
|
||||
if target_date is None:
|
||||
target_date = TODAY
|
||||
print(f"批量合规审查: {target_date}")
|
||||
|
||||
release_path = RELEASE_DIR / TODAY
|
||||
# 加载选题数据(优先DB,失败则备援JSON)
|
||||
try:
|
||||
topics_by_id = load_topics_from_db()
|
||||
print("[数据源] 数据库")
|
||||
except Exception as e:
|
||||
print(f"[数据源] 数据库失败: {e}, 改用 JSON")
|
||||
topics_by_id = load_topics_from_json()
|
||||
|
||||
release_path = RELEASE_DIR / target_date
|
||||
if not release_path.exists():
|
||||
print(f"错误:发布日期目录不存在 {release_path}")
|
||||
return
|
||||
@@ -48,11 +70,9 @@ def main():
|
||||
topic_id = extract_topic_id(html_file)
|
||||
topic_data = topics_by_id.get(topic_id) if topic_id else None
|
||||
|
||||
# 读取HTML
|
||||
with open(html_file, 'r', encoding='utf-8') as f:
|
||||
html_content = f.read()
|
||||
|
||||
# 执行合规检查
|
||||
result = check_article(html_content, platform, topic_data)
|
||||
result['file'] = str(html_file.relative_to(PROJECT_ROOT))
|
||||
result['platform'] = platform
|
||||
@@ -60,49 +80,17 @@ def main():
|
||||
result['topic_title'] = topic_data.get('title') if topic_data else "未知"
|
||||
results.append(result)
|
||||
|
||||
status = "✅ PASS" if result['passed'] else "❌ FAIL"
|
||||
print(f"{status} {topic_id} {platform:12} {result['topic_title'][:30]:30} 问题数: {len(result['issues'])} 得分: {result['score']}")
|
||||
|
||||
# 汇总报告
|
||||
# 输出摘要
|
||||
passed = sum(1 for r in results if r['passed'])
|
||||
failed = len(results) - passed
|
||||
avg_score = sum(r['score'] for r in results) / len(results) if results else 0
|
||||
|
||||
print(f"\n========== 合规审查汇总 ==========")
|
||||
print(f"总计: {len(results)} 篇")
|
||||
print(f"通过: {passed} 篇")
|
||||
print(f"失败: {failed} 篇")
|
||||
print(f"平均分: {avg_score:.1f}")
|
||||
|
||||
# 保存详细报告
|
||||
report = {
|
||||
"date": TODAY,
|
||||
"summary": {
|
||||
"total": len(results),
|
||||
"passed": passed,
|
||||
"failed": failed,
|
||||
"average_score": avg_score
|
||||
},
|
||||
"details": results
|
||||
}
|
||||
report_file = PROJECT_ROOT / "automation" / "data" / "drafts" / TODAY / "compliance_summary.json"
|
||||
report_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(report_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(report, f, ensure_ascii=False, indent=2)
|
||||
print(f"\n📁 详细报告已保存: {report_file}")
|
||||
|
||||
# 列出失败项
|
||||
if failed > 0:
|
||||
print("\n⚠️ 需要修复的文章:")
|
||||
for r in results:
|
||||
if not r['passed']:
|
||||
print(f" {r['file']}")
|
||||
for issue in r['issues'][:3]: # 只显示前3个问题
|
||||
print(f" - {issue['type']}/{issue.get('category','')}: {issue.get('suggestion','')}")
|
||||
if len(r['issues']) > 3:
|
||||
print(f" ... 等共{len(r['issues'])}个问题")
|
||||
else:
|
||||
print("\n🎉 所有文章均通过合规审查!")
|
||||
print(f"\n✅ 通过: {passed}, ⚠️ 需人工: {failed}")
|
||||
for r in results:
|
||||
status = "✅" if r['passed'] else "⚠️"
|
||||
print(f" {status} {r['topic_id']} {r['topic_title'][:40]}...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--date', help='审查的日期目录,默认今天')
|
||||
args = parser.parse_args()
|
||||
main(args.date)
|
||||
|
||||
Reference in New Issue
Block a user