Fix calendar filter, module triggers, API cleanup, consolidate get_current_admin, fix LLM schema
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
可持续性内容收集脚本
|
||||
每天凌晨5:00运行,收集全球可持续性趋势信息,提炼选题和案例
|
||||
内容采集:趋势抓取 → 选题生成 → 存入选题库
|
||||
收集热点趋势信息,经LLM分析后生成选题建议并存入数据库
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
合规审查:文章合规检查 → LLM迭代修复
|
||||
从articles表读取待审文章,进行合规评分;不合格文章由LLM修复(最多3次),通过后更新选题状态为待发布
|
||||
"""
|
||||
import json, datetime, logging, sys, re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
宇之然内容创作流水线(研究 → 大纲 → 撰写 → 合规优化)v3 - DB version
|
||||
内容创作流水线:研究 → 大纲 → 撰写 → 合规审查
|
||||
基于选题ID,依次执行research/outline/writer各阶段,创作三平台文章并存入articles表
|
||||
"""
|
||||
|
||||
import json, datetime, logging, sys, subprocess
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime, date
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
# 加载 .env(在 scripts/ 目录下运行时需要)
|
||||
_env_path = Path(__file__).parent.parent / 'platform' / 'backend' / '.env'
|
||||
if _env_path.exists():
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(_env_path)
|
||||
|
||||
# 添加项目根和 backend 路径
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
选题研究:信息收集与结构化整理
|
||||
基于选题方向,收集相关数据/案例/趋势,输出结构化研究笔记供大纲生成使用
|
||||
"""
|
||||
import json, datetime, logging, sys, re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
选题引擎 v2:多趋势加权匹配 + 趋势缺口检测 + 新选题生成
|
||||
选题引擎:多趋势加权匹配 + 趋势缺口检测 + 新选题生成
|
||||
结合采集到的热点趋势和当前选题库,推荐最优选题并检测趋势缺口
|
||||
"""
|
||||
|
||||
import sys, json, logging
|
||||
|
||||
+39
-14
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
平台适配文章撰写
|
||||
根据大纲和平台配置(字数/格式/配图要求),为知乎/公众号/小红书各平台生成适配内容
|
||||
"""
|
||||
import json, datetime, logging, sys, re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
@@ -92,15 +96,17 @@ class Writer:
|
||||
if line.startswith("# "):
|
||||
if current:
|
||||
sections.append(current)
|
||||
current = {"level": 1, "title": line[2:].strip(), "content": ""}
|
||||
current = {"level": 1, "title": line[2:].strip(), "content": "", "section_type": "normal"}
|
||||
elif line.startswith("## "):
|
||||
if current:
|
||||
sections.append(current)
|
||||
current = {"level": 2, "title": line[3:].strip(), "content": ""}
|
||||
title = line[3:].strip()
|
||||
stype = "noise" if title in ("文章大纲", "大纲", "文章结构", "结构") else "normal"
|
||||
current = {"level": 2, "title": title, "content": "", "section_type": stype}
|
||||
elif line.startswith("### "):
|
||||
if current:
|
||||
sections.append(current)
|
||||
current = {"level": 3, "title": line[4:].strip(), "content": ""}
|
||||
current = {"level": 3, "title": line[4:].strip(), "content": "", "section_type": "normal"}
|
||||
else:
|
||||
if current and line.strip():
|
||||
current['content'] = current.get('content', '') + line + "\n"
|
||||
@@ -112,7 +118,13 @@ class Writer:
|
||||
def _clean_markdown(text: str) -> str:
|
||||
lines = text.split('\n')
|
||||
cleaned = []
|
||||
in_code_fence = False
|
||||
for line in lines:
|
||||
if line.strip().startswith('```'):
|
||||
in_code_fence = not in_code_fence
|
||||
continue
|
||||
if in_code_fence:
|
||||
continue
|
||||
line = re.sub(r'^#{1,6}\s+', '', line)
|
||||
line = re.sub(r'^[\-\*\+]\s+', '', line)
|
||||
line = re.sub(r'^\d+[\.\)]\s+', '', line)
|
||||
@@ -133,12 +145,19 @@ class Writer:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_bullet_only(self, text: str) -> bool:
|
||||
"""检查内容是否主要是要点列表(大纲格式),需要 LLM 展开"""
|
||||
lines = [l.strip() for l in text.split('\n') if l.strip()]
|
||||
if not lines:
|
||||
return False
|
||||
bullet_count = sum(1 for l in lines if l.startswith(('- ', '* ', '**', '+ ')))
|
||||
return bullet_count / len(lines) > 0.4
|
||||
|
||||
def _expand_section(self, section: Dict) -> str:
|
||||
content = section.get('content', '').strip()
|
||||
if len(content) > 200:
|
||||
return content
|
||||
if HAVE_LLM and len(content) < 150:
|
||||
logger.info(f"使用 LLM 扩写章节: {section['title']}")
|
||||
# 大纲要点格式(>40% 行以 -/*/** 开头)应始终由 LLM 展开为连贯段落
|
||||
if HAVE_LLM and self._is_bullet_only(content):
|
||||
logger.info(f"使用 LLM 扩写章节(要点→段落): {section['title']}")
|
||||
prompt = f"""你是一个资深作者,正在写一篇关于「{self.topic['title']}」的文章。请写「{section['title']}」这一节。
|
||||
|
||||
今天日期:{datetime.datetime.now().strftime('%Y年%m月%d日')}。
|
||||
@@ -147,7 +166,7 @@ class Writer:
|
||||
{content}
|
||||
|
||||
【输出要求】
|
||||
输出3-5段纯粹、流畅的段落文字,共400-800字。
|
||||
输出3-6段纯粹、流畅的段落文字,每节内容根据平台需求控制在200-800字之间。
|
||||
|
||||
格式:
|
||||
- 禁止任何标题/列表/格式标记(#、-、*、1.、**等)
|
||||
@@ -187,7 +206,8 @@ class Writer:
|
||||
text += '。'
|
||||
sentences.append(text)
|
||||
if sentences:
|
||||
return ' '.join(sentences)
|
||||
result = ' '.join(sentences)
|
||||
return self._clean_markdown(result)
|
||||
return ''
|
||||
|
||||
def generate_full_markdown(self) -> str:
|
||||
@@ -200,6 +220,12 @@ class Writer:
|
||||
if expanded:
|
||||
parts.append(expanded + "\n")
|
||||
continue
|
||||
# 跳过大纲结构噪音节点
|
||||
title_stripped = sec['title'].strip()
|
||||
if title_stripped in ('文章大纲', '大纲', '文章结构', '结构'):
|
||||
continue
|
||||
if sec.get('section_type') == 'noise':
|
||||
continue
|
||||
heading = f"{'#' * sec['level']} {sec['title']}"
|
||||
parts.append(heading)
|
||||
if sec.get('content'):
|
||||
@@ -246,11 +272,6 @@ class Writer:
|
||||
else:
|
||||
result.append(line)
|
||||
adapted = '\n'.join(result)
|
||||
if len(adapted) > max_c:
|
||||
adapted = adapted[:max_c]
|
||||
last = max(adapted.rfind('。'), adapted.rfind('\n'), adapted.rfind('!'))
|
||||
if last > max_c // 2:
|
||||
adapted = adapted[:last + 1]
|
||||
return adapted
|
||||
|
||||
return markdown
|
||||
@@ -429,6 +450,10 @@ class Writer:
|
||||
|
||||
html = html.replace("<!-- CONTENT -->", html_content)
|
||||
|
||||
# 防御:清理可能在 LLM 输出中混入的 markdown 代码围栏和文件头
|
||||
html = re.sub(r'^```+\w*\s*\n?', '', html)
|
||||
html = html.strip()
|
||||
|
||||
tags_html = self._get_platform_tags(platform)
|
||||
if tags_html:
|
||||
html = html.replace("<!-- TAGS -->", tags_html)
|
||||
|
||||
Reference in New Issue
Block a user