From 10996ce6ce31ea6f8c8b537225d6eecfb61e3cc8 Mon Sep 17 00:00:00 2001 From: Yuzhiran Dev Date: Thu, 21 May 2026 08:02:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=85=E7=90=86=E5=9F=8E=E5=B8=82=E5=86=9C?= =?UTF-8?q?=E4=B8=9A=E7=B1=BB=E5=88=AB=20+=20=E4=BF=AE=E5=A4=8D=E9=87=87?= =?UTF-8?q?=E9=9B=86=E5=99=A8LLM=E7=9B=B4=E6=8E=A5=E9=80=89=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 清理: - sustainability_cases.json移除GLO-001/CHN-001城市农业案例,替换为循环消费 - initial_cases.json移除case8东京垂直农场/case26城市屋顶农场 - strategy_topics_to_json.py移除B01/B05/D05三个种菜选题 - collector.py移除城市农业→循环消费映射,更新注释 - 删除fix_collector.py/test_image_gen.py/generate_images.py等遗留脚本 - 删除import_topics.py和automation/下旧版生成脚本 修复: - collector.py _generate_topic_with_llm不再依赖搜索结果,无搜索时LLM直接生成 - run()始终调用LLM,不再要求web_search_results非空 - 替换sources.yaml中已失效的RSS源(澎湃/虎嗅/中新网→36氪/少数派) --- automation/add_md_separators.py | 24 --- automation/add_separators.py | 39 ---- automation/data/initial_cases.json | 24 --- automation/data/sustainability_cases.json | 39 ++-- automation/generate_docx.py | 138 -------------- automation/generate_docx_fixed.py | 93 --------- automation/generate_html_fixed.py | 74 -------- automation/generate_html_inline.py | 90 --------- automation/generate_optimized_md.py | 50 ----- config/sources.yaml | 55 ++---- scripts/collector.py | 57 +++--- scripts/fix_collector.py | 40 ---- scripts/generate_images.py | 48 ----- scripts/import_topics.py | 220 ---------------------- scripts/strategy_topics_to_json.py | 4 +- scripts/test_image_gen.py | 32 ---- 16 files changed, 47 insertions(+), 980 deletions(-) delete mode 100644 automation/add_md_separators.py delete mode 100644 automation/add_separators.py delete mode 100644 automation/generate_docx.py delete mode 100644 automation/generate_docx_fixed.py delete mode 100644 automation/generate_html_fixed.py delete mode 100644 automation/generate_html_inline.py delete mode 100644 automation/generate_optimized_md.py delete mode 100644 scripts/fix_collector.py delete mode 100644 scripts/generate_images.py delete mode 100644 scripts/import_topics.py delete mode 100644 scripts/test_image_gen.py diff --git a/automation/add_md_separators.py b/automation/add_md_separators.py deleted file mode 100644 index 677fd17..0000000 --- a/automation/add_md_separators.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -""" -在 Markdown 的 H2 标题前插入分隔线,第一个除外 -""" - -MD_PATH = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md" - -with open(MD_PATH, "r", encoding="utf-8") as f: - lines = f.readlines() - -new_lines = [] -first_h2_seen = False -for line in lines: - if line.startswith("## "): - if first_h2_seen: - new_lines.append("---\n\n") - else: - first_h2_seen = True - new_lines.append(line) - -with open(MD_PATH, "w", encoding="utf-8") as f: - f.writelines(new_lines) - -print(f"✅ 已处理 {MD_PATH}") diff --git a/automation/add_separators.py b/automation/add_separators.py deleted file mode 100644 index 4a6e594..0000000 --- a/automation/add_separators.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -""" -在章节标题(h2)前插入分隔线,第一个除外 -""" - -import re - -HTML_PATH = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/article-optimized.html" - -with open(HTML_PATH, "r", encoding="utf-8") as f: - html = f.read() - -# 分隔线HTML -separator = '
\n' - -# 找到所有 h2 标题 -h2_pattern = re.compile(r'(

.*?

)', re.DOTALL) -matches = list(h2_pattern.finditer(html)) - -# 跳过第一个 h2,对其余每个插入分隔 -insertions = [] -for i, m in enumerate(matches[1:], start=1): # 从第二个开始 - insert_pos = m.start() - insertions.append((insert_pos, separator)) - -# 按位置逆序插入,避免影响后续位置 -insertions.sort(reverse=True, key=lambda x: x[0]) -html_list = list(html) -for pos, sep in insertions: - html_list.insert(pos, sep) - -new_html = ''.join(html_list) - -# 写回 -with open(HTML_PATH, "w", encoding="utf-8") as f: - f.write(new_html) - -print(f"✅ 已插入 {len(insertions)} 个章节分隔") -print(f"📄 文件: {HTML_PATH}") diff --git a/automation/data/initial_cases.json b/automation/data/initial_cases.json index ec0d7c6..7b746e5 100644 --- a/automation/data/initial_cases.json +++ b/automation/data/initial_cases.json @@ -83,18 +83,6 @@ "credibility_rating": "⭐⭐⭐⭐", "china_applicability": "⭐⭐⭐⭐" }, - { - "id": 8, - "title": "东京垂直农场", - "field": "可持续生活系统", - "summary": "利用高层建筑内部空间进行多层种植,实现都市粮食自给。", - "key_metrics": "单位面积产量是传统农业的10倍,节水90%", - "date": "2024", - "source": "Spread 公司", - "source_url": "https://www.spread.co.jp/", - "credibility_rating": "⭐⭐⭐⭐⭐", - "china_applicability": "⭐⭐⭐" - }, { "id": 9, "title": "纽约社区花园政策", @@ -299,18 +287,6 @@ "credibility_rating": "⭐⭐⭐", "china_applicability": "⭐⭐⭐⭐⭐" }, - { - "id": 26, - "title": "城市屋顶农场:上海社区的粮食自给实验", - "field": "可持续生活系统", - "summary": "在上海某小区屋顶建设 200㎡ 农场,一年内生产 600kg 蔬菜,减少碳足迹 1.2 吨。", - "key_metrics": "蔬菜自给率 40%, 参与家庭 50 户, 社区互动提升 300%", - "date": "2024", - "source": "城市农业网", - "source_url": "https://www.urbanfarming.org/", - "credibility_rating": "⭐⭐⭐⭐", - "china_applicability": "⭐⭐⭐⭐⭐" - }, { "id": 27, "title": "数字游民签证地图:2026 最新政策对比", diff --git a/automation/data/sustainability_cases.json b/automation/data/sustainability_cases.json index c80ee7a..c664632 100644 --- a/automation/data/sustainability_cases.json +++ b/automation/data/sustainability_cases.json @@ -1,21 +1,4 @@ [ - { - "id": "GLO-001", - "country": "Japan", - "category": "城市农业", - "title": "东京垂直农场:10平米 balcony 年产蔬菜 100kg", - "core_idea": "利用多层种植架和 LED 生长灯,在狭小阳台实现全年蔬菜生产", - "data_facts": "每平米年产 10kg,较传统方式节水 90%,投资回收期 1.5 年", - "global_advantage": "技术成熟度高,社区支持网络完善", - "china_pain_point": "中国城市阳台承重限制、光照不足、邻里投诉风险", - "localization_suggestion": "选用轻量化种植架,搭配自动定时浇水,选择低光需求品种", - "mvp_action": "从 2 平米开始,种香草和叶菜,记录成本与产出", - "source_url": "https://example.com/tokyo-vertical-farm", - "credibility_rating": "⭐⭐⭐⭐⭐", - "china_applicability": "⭐⭐⭐", - "collection_date": "2026-04-19", - "status": "已验证" - }, { "id": "GLO-002", "country": "Sweden", @@ -87,18 +70,18 @@ { "id": "CHN-001", "country": "China", - "category": "城市农业", - "title": "上海阳台种菜年省 3000 元:居民自种调查", - "core_idea": "利用阳台空间种菜,实现部分蔬菜自给,降低生活成本", - "data_facts": "20 平米阳台年产蔬菜 100kg,节省买菜支出 3000 元,投入成本 2000 元", - "global_advantage": "中国城市人口密集,阳台空间普遍存在", - "china_pain_point": "缺乏种植知识,病虫害防治困难,物业可能干涉", - "localization_suggestion": "选择易种品种(番茄、辣椒、生菜),使用有机土,与邻居共享收获", - "mvp_action": "先种 5 盆香草,成功后再扩大", - "source_url": "https://www.bilibili.com/video/BV1xx411", - "credibility_rating": "⭐⭐⭐", + "category": "循环消费", + "title": "中国二手交易平台崛起:闲鱼转转让闲置物品年交易额超5000亿", + "core_idea": "通过二手交易平台,用户可以将闲置物品变现,降低消费成本", + "data_facts": "闲鱼年交易额超5000亿,用户数超3亿,每天上架商品超200万件", + "global_advantage": "中国移动互联网普及率高,二手交易习惯逐渐养成", + "china_pain_point": "信任机制不完善,假货和退换货纠纷多", + "localization_suggestion": "选择信誉高的卖家,优先购买有质检服务的商品", + "mvp_action": "整理家中闲置物品,本月在二手平台卖出3件", + "source_url": "https://www.goofish.com/", + "credibility_rating": "⭐⭐⭐⭐", "china_applicability": "⭐⭐⭐⭐⭐", - "collection_date": "2026-04-19", + "collection_date": "2026-05-20", "status": "已验证" } ] \ No newline at end of file diff --git a/automation/generate_docx.py b/automation/generate_docx.py deleted file mode 100644 index bd2acc5..0000000 --- a/automation/generate_docx.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python3 -""" -将 Markdown 文章转换为 Word 文档,嵌入图片 -""" - -import os -import re -from docx import Document -from docx.shared import Inches, Pt, RGBColor -from docx.enum.text import WD_ALIGN_PARAGRAPH - -# 路径配置 -MARKDOWN_FILE = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md" -IMAGES_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images" -OUTPUT_DOCX = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/上海阳台种菜一年_最终版.docx" - -# 读取 Markdown -with open(MARKDOWN_FILE, "r", encoding="utf-8") as f: - lines = f.readlines() - -doc = Document() -doc.styles['Normal'].font.name = '微软雅黑' -doc.styles['Normal'].font.size = Pt(11) - -# 样式函数 -def add_heading(text, level=1): - heading = doc.add_heading(text, level=level) - heading.alignment = WD_ALIGN_PARAGRAPH.LEFT - return heading - -def add_paragraph(text, bold=False, italic=False): - p = doc.add_paragraph() - run = p.add_run(text) - run.bold = bold - run.italic = italic - return p - -# 解析 Markdown -in_code_block = False -in_table = False -table_data = [] - -for i, line in enumerate(lines): - line = line.rstrip('\n') - - # 代码块跳过 - if line.startswith('```'): - in_code_block = not in_code_block - continue - if in_code_block: - continue - - # 标题 - if line.startswith('# '): - add_heading(line[2:], level=1) - continue - if line.startswith('## '): - add_heading(line[3:], level=2) - continue - if line.startswith('### '): - add_heading(line[4:], level=3) - continue - - # 表格处理(简化:将表格转为文本,图片位置用占位) - if line.startswith('|'): - in_table = True - table_data.append(line) - continue - if in_table and not line.startswith('|'): - in_table = False - # 可以在此转换表格,为简化直接跳过 - continue - - # 图片:![alt](path) - img_match = re.match(r'!\[(.*?)\]\((images/.*?)\)', line) - if img_match: - alt, path = img_match.groups() - img_full_path = os.path.join(os.path.dirname(MARKDOWN_FILE), path) - if os.path.exists(img_full_path): - try: - # 插入图片,宽度 6 英寸(约 15cm) - doc.add_picture(img_full_path, width=Inches(6)) - # 居中 - last_para = doc.paragraphs[-1] - last_para.alignment = WD_ALIGN_PARAGRAPH.CENTER - # 添加图片说明(可选) - if alt: - cap = doc.add_paragraph(alt) - cap.alignment = WD_ALIGN_PARAGRAPH.CENTER - cap.style = 'Caption' - except Exception as e: - doc.add_paragraph(f"[图片加载失败: {path}]") - else: - doc.add_paragraph(f"[图片缺失: {img_full_path}]") - continue - - # 引用 - if line.startswith('> '): - p = doc.add_paragraph(line[2:]) - p.paragraph_format.left_indent = Inches(0.5) - p.italic = True - continue - - # 列表 - if re.match(r'^[-*] ', line): - p = doc.add_paragraph(line[2:], style='List Bullet') - continue - if re.match(r'^\d+\. ', line): - p = doc.add_paragraph(line[line.find('.')+2:], style='List Number') - continue - - # 分隔线 - if line.strip() == '---': - doc.add_paragraph('_' * 50) - continue - - # 普通段落 - if line.strip(): - # 处理行内加粗、斜体 - p = doc.add_paragraph() - parts = re.split(r'(\*\*[^*]+\*\*|\*[^*]+\*)', line) - for part in parts: - if part.startswith('**') and part.endswith('**'): - run = p.add_run(part[2:-2]) - run.bold = True - elif part.startswith('*') and part.endswith('*'): - run = p.add_run(part[1:-1]) - run.italic = True - else: - run = p.add_run(part) - else: - doc.add_paragraph() # 空行 - -# 保存文档 -doc.save(OUTPUT_DOCX) -print(f"✅ Word 文档已生成: {OUTPUT_DOCX}") -print(f"📄 页数: {len(doc.paragraphs)} 段落") -print(f"🖼️ 图片路径: {IMAGES_DIR}") diff --git a/automation/generate_docx_fixed.py b/automation/generate_docx_fixed.py deleted file mode 100644 index e1272f0..0000000 --- a/automation/generate_docx_fixed.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -""" -生成 Word 文档,图片从发布目录的 images 文件夹读取 -""" - -import os -from docx import Document -from docx.shared import Inches, Pt -from docx.enum.text import WD_ALIGN_PARAGRAPH - -BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年" -MD_FILE = os.path.join(BASE_DIR, "final-article.md") -IMAGES_DIR = os.path.join(BASE_DIR, "images") # 已复制的图片 -OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_最终版.docx") - -with open(MD_FILE, "r", encoding="utf-8") as f: - lines = f.readlines() - -doc = Document() -doc.styles['Normal'].font.name = '微软雅黑' -doc.styles['Normal'].font.size = Pt(11) - -def add_heading(text, level=1): - heading = doc.add_heading(text, level=level) - heading.alignment = WD_ALIGN_PARAGRAPH.LEFT - return heading - -for line in lines: - line = line.rstrip('\n') - - if line.startswith('# '): - add_heading(line[2:], level=1) - continue - if line.startswith('## '): - add_heading(line[3:], level=2) - continue - if line.startswith('### '): - add_heading(line[4:], level=3) - continue - if line.startswith('---'): - doc.add_paragraph('_' * 60) - continue - - # 图片 - if line.startswith('!['): - import re - m = re.match(r'!\[(.*?)\]\((images/.*?)\)', line) - if m: - alt, fname = m.groups() - img_path = os.path.join(IMAGES_DIR, os.path.basename(fname)) - if os.path.exists(img_path): - try: - doc.add_picture(img_path, width=Inches(6)) - last_para = doc.paragraphs[-1] - last_para.alignment = WD_ALIGN_PARAGRAPH.CENTER - except Exception as e: - doc.add_paragraph(f"[图片错误: {fname}]") - else: - doc.add_paragraph(f"[缺失图片: {fname}]") - continue - - # 空行 - if not line.strip(): - doc.add_paragraph() - continue - - # 普通段落,处理粗体斜体 - p = doc.add_paragraph() - parts = [] - tmp = line - while '**' in tmp: - parts.append(tmp[:tmp.find('**')]) - tmp = tmp[tmp.find('**')+2:] - if '**' in tmp: - parts.append(('bold', tmp[:tmp.find('**')])) - tmp = tmp[tmp.find('**')+2:] - else: - parts.append(('bold', tmp)) - break - if not parts: - parts = [line] - - for part in parts: - if isinstance(part, tuple): - style, text = part - run = p.add_run(text) - run.bold = (style == 'bold') - else: - p.add_run(part) - -doc.save(OUTPUT_DOCX) -print(f"✅ Word 已生成: {OUTPUT_DOCX}") -print(f"📄 段落数: {len(doc.paragraphs)}") diff --git a/automation/generate_html_fixed.py b/automation/generate_html_fixed.py deleted file mode 100644 index 99976e5..0000000 --- a/automation/generate_html_fixed.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -""" -生成 HTML,图片使用相对路径 'images/xxx.png'(确保图片在发布目录的 images 子文件夹中) -""" - -import os -import re - -BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年" -MD_FILE = os.path.join(BASE_DIR, "final-article.md") -OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_可复制.html") - -with open(MD_FILE, "r", encoding="utf-8") as f: - content = f.read() - -# 替换图片为 HTML img 标签,保持相对路径 -def replace_img(match): - alt, path = match.groups() - return f'{alt}' - -content = re.sub(r'!\[(.*?)\]\((images/.*?)\)', replace_img, content) - -# 转换 Markdown 为 HTML -html_lines = [] -for line in content.split('\n'): - if line.startswith('# '): - html_lines.append(f'

{line[2:]}

') - elif line.startswith('## '): - html_lines.append(f'

{line[3:]}

') - elif line.startswith('### '): - html_lines.append(f'

{line[4:]}

') - elif line.startswith('---'): - html_lines.append('
') - elif line.startswith('> '): - html_lines.append(f'
{line[2:]}
') - elif re.match(r'^[-*] ', line): - html_lines.append(f'
  • {line[2:]}
  • ') - elif re.match(r'^\d+\. ', line): - html_lines.append(f'
  • {line[line.find(". ")+2:]}
  • ') - elif line.strip() == '': - html_lines.append('
    ') - else: - # 处理行内粗体斜体 - tmp = re.sub(r'\*\*(.*?)\*\*', r'\1', line) - tmp = re.sub(r'\*(.*?)\*', r'\1', tmp) - html_lines.append(f'

    {tmp}

    ') - -html = f''' - - - -上海阳台种菜一年 - - - -{chr(10).join(html_lines)} - -''' - -with open(OUT_HTML, "w", encoding="utf-8") as f: - f.write(html) - -print(f"✅ HTML 已生成: {OUT_HTML}") -print(f"📊 字符数: {len(content)}") -print(f"🖼️ 图片路径: images/ (需与 HTML 同目录的 images 文件夹)") diff --git a/automation/generate_html_inline.py b/automation/generate_html_inline.py deleted file mode 100644 index c6d6bd9..0000000 --- a/automation/generate_html_inline.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python3 -""" -生成图文混排的 HTML(图片内联为 base64),方便直接复制 -""" - -import os -import re -import base64 - -BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年" -MD_FILE = os.path.join(BASE_DIR, "final-article.md") -IMAGES_DIR = os.path.join(BASE_DIR, "images") # 使用发布目录内的 images -OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_内联.html") - -# 读取 Markdown -with open(MD_FILE, "r", encoding="utf-8") as f: - content = f.read() - -# 预加载图片并转为 base64 -image_cache = {} -for fname in os.listdir(IMAGES_DIR): - if fname.endswith('.png'): - path = os.path.join(IMAGES_DIR, fname) - with open(path, "rb") as imgf: - b64 = base64.b64encode(imgf.read()).decode('utf-8') - image_cache[fname] = b64 - -# 替换图片 -def replace_img(match): - alt = match.group(1) - fname = match.group(2) - key = os.path.basename(fname) - if key in image_cache: - return f'{alt}' - else: - return f'

    [图片缺失: {fname}]

    ' - -content = re.sub(r'!\[(.*?)\]\((images/.*?)\)', replace_img, content) - -# Markdown 转 HTML -html_lines = [] -for line in content.split('\n'): - if line.startswith('# '): - html_lines.append(f'

    {line[2:]}

    ') - elif line.startswith('## '): - html_lines.append(f'

    {line[3:]}

    ') - elif line.startswith('### '): - html_lines.append(f'

    {line[4:]}

    ') - elif line.startswith('---'): - html_lines.append('
    ') - elif line.startswith('> '): - html_lines.append(f'
    {line[2:]}
    ') - elif re.match(r'^[-*] ', line): - html_lines.append(f'
  • {line[2:]}
  • ') - elif re.match(r'^\d+\. ', line): - html_lines.append(f'
  • {line[line.find(". ")+2:]}
  • ') - elif line.strip() == '': - html_lines.append('
    ') - else: - tmp = re.sub(r'\*\*(.*?)\*\*', r'\1', line) - tmp = re.sub(r'\*(.*?)\*', r'\1', tmp) - html_lines.append(f'

    {tmp}

    ') - -html = f''' - - - -上海阳台种菜一年 - - - -{chr(10).join(html_lines)} - -''' - -with open(OUT_HTML, "w", encoding="utf-8") as f: - f.write(html) - -print(f"✅ HTML 已生成: {OUT_HTML}") -print(f"📊 字符数: {len(content)}") -print(f"🖼️ 内嵌图片: {len(image_cache)} 张") diff --git a/automation/generate_optimized_md.py b/automation/generate_optimized_md.py deleted file mode 100644 index 1e83d75..0000000 --- a/automation/generate_optimized_md.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -""" -对 article.md 进行内容优化: -- 去除具体 App 品牌名(花帮主、园艺助手) -- 隐去设备具体品牌(小米米家) -- 保留功能描述和用户价值 -- 保持中立、实用、无广告感 -""" - -import os -import re - -BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年" -MD_FILE = os.path.join(BASE_DIR, "final-article.md") -OUT_MD = os.path.join(BASE_DIR, "final-article-optimized.md") - -with open(MD_FILE, "r", encoding="utf-8") as f: - content = f.read() - -# 1. 替换具体 App 名称 -> 通用描述 -content = re.sub(r'花帮主', '一些第三方种植App', content) -content = re.sub(r'园艺助手', '另一些生活助手类App', content) -content = re.sub(r'(\*\*)花帮主(\*\*),AI识别病虫害,准确率85%', '**一些第三方种植App**,可以通过 AI 识别病虫害,准确率在 80% 以上', content) - -# 2. 替换设备品牌 -> 通用描述 -content = re.sub(r'小米米家灌溉套装', '智能灌溉套装', content) -content = re.sub(r'LED补光灯', 'LED 植物补光灯', content) - -# 3. 移除可能带有广告嫌疑的表述(如“效果最好”、“推荐”等),改为中性描述 -content = re.sub(r'强烈推荐(易种)', '适合新手(易种)', content) -content = re.sub(r'强烈推荐', '推荐', content) - -# 4. 图片描述调整(不影响图片本身,只调整 alt 文本和图片说明) -# 图片文件保留不变,只调整 Markdown 中的说明文字 -content = re.sub(r'!\[App截图\]', '[App功能截图]', content) -content = re.sub(r'App截图', 'App功能界面示意', content) - -# 5. 增加免责声明(在文末) -if "声明:" not in content: - content = content.rstrip() + "\n\n---\n\n> **声明**:本文提及的工具和设备仅为个人使用经验分享,不构成商业推荐。读者可根据自身需求选择类似产品。\n" - -with open(OUT_MD, "w", encoding="utf-8") as f: - f.write(content) - -print(f"✅ 优化完成: {OUT_MD}") -print("🔧 优化项:") -print(" - 去除具体 App 品牌名") -print(" - 隐去设备品牌") -print(" - 增加中立表述") -print(" - 添加免责声明") diff --git a/config/sources.yaml b/config/sources.yaml index c88de82..7001321 100644 --- a/config/sources.yaml +++ b/config/sources.yaml @@ -4,62 +4,33 @@ sustainability_sources: # 中文RSS源(国内媒体,可稳定访问) rss: - - name: "澎湃新闻-绿政" + - name: "36氪-最新" type: "rss" - url: "https://www.thepaper.cn/rolling_green_news.rss" + url: "https://36kr.com/feed" update_frequency: "daily" credibility: "high" - focus: "绿色政策、环境新闻" - keywords: - - "环保" - - "绿色" - - "碳" - - "生态" - - "可持续" - - name: "澎湃新闻-最新" - type: "rss" - url: "https://www.thepaper.cn/rss/rolling.xml" - update_frequency: "daily" - credibility: "high" - focus: "综合新闻" - keywords: - - "环保" - - "绿色" - - "碳中和" - - "新能源" - - "循环" - - "可持续" - - "低碳" - - "垃圾分类" - - name: "虎嗅" - type: "rss" - url: "https://www.huxiu.com/rss/0.xml" - update_frequency: "daily" - credibility: "medium" focus: "科技商业、绿色经济" keywords: - - "环保" - - "绿色" - - "碳中和" + - "AI" - "新能源" - "可持续" + - "环保" + - "绿色" - "低碳" - "ESG" - "循环" - - name: "中国新闻网" + - name: "少数派" type: "rss" - url: "https://www.chinanews.com.cn/rss/scroll-news.xml" + url: "https://sspai.com/feed" update_frequency: "daily" credibility: "medium" - focus: "综合新闻" + focus: "科技数码、效率工具" keywords: - - "环保" - - "绿色" - - "碳中和" - - "生态" - - "新能源" - - "垃圾分类" - - "低碳" + - "AI" + - "效率" + - "工具" + - "数字" + - "智能" # 搜索引擎采集(通过Bing中文搜索抓取热点) # 基于《2025中国可持续消费报告》《绿色低碳消费大数据报告》等权威调研得出的七大热点方向 diff --git a/scripts/collector.py b/scripts/collector.py index 82f1dc4..d18c392 100644 --- a/scripts/collector.py +++ b/scripts/collector.py @@ -59,7 +59,7 @@ class SustainabilityCase: """可持续性案例""" id: str country: str - category: str # 子领域:城市农业、零浪费生活等 + category: str # 子领域:零浪费生活、循环消费等 title: str core_idea: str data_facts: str @@ -254,7 +254,6 @@ class SustainabilityCollector: '低碳出行': '低碳出行', '循环消费': '循环消费', '环保科技': '环保科技产品', - '城市农业': '循环消费', } case_data['category'] = category_map.get(field, field[:4] if len(field) > 4 else field) @@ -378,57 +377,47 @@ class SustainabilityCollector: logger.warning(f"web_search失败 {source.name}: {e}") return [] - def _generate_topic_with_llm(self, search_results: List[Dict]) -> Optional[SustainabilityTopic]: - """用LLM从搜索结果中生成选题""" + def _generate_topic_with_llm(self, search_results: Optional[List[Dict]] = None) -> Optional[SustainabilityTopic]: + """用LLM生成选题(有搜索结果时参考,无结果时直接生成)""" try: from app.core.nvidia_client import call_llm except ImportError: logger.warning("LLM不可用,跳过AI选题生成") return None - if not search_results: - return None - - # 整理搜索结果摘要 - summaries = [] - for r in search_results[:6]: - summaries.append(f"- {r.get('title','')}: {r.get('content','')[:150]}") - search_text = "\n".join(summaries) - - # 获取已有选题做去重参考 existing = self._get_existing_titles() existing_hint = "" if existing: - existing_hint = f"\n以下选题已存在,请避免重复:\n" + "\n".join(f"- {t[:30]}" for t in existing[-10:]) + existing_hint = "\n已存在选题(避免重复):" + "、".join(t[:20] for t in existing[-8:]) - # 按日期选不同类别 categories = self.config.get("sustainability_categories", ["可持续生活"]) day_idx = datetime.datetime.now().timetuple().tm_yday % len(categories) target_category = categories[day_idx] - prompt = f"""你是一个内容策略师。基于以下搜索结果,生成一个有价值、适合中文互联网传播的选题。 + search_section = "" + if search_results: + summaries = [f"- {r.get('title','')}: {r.get('content','')[:120]}" for r in search_results[:4]] + search_section = "搜索结果参考:\n" + "\n".join(summaries) + "\n" + + prompt = f"""你是一个内容策略师。生成一个面向中国年轻读者、有价值、适合传播的选题。 目标类别:{target_category} - -搜索结果: -{search_text} +{search_section} {existing_hint} -请生成一个选题,输出JSON格式: -{{ - "title": "标题(20字内,有吸引力,含核心关键词)", +生成一个选题,直接输出JSON(不要其他文字): +{{{{ + "title": "标题(20字内,含核心关键词,避免「新趋势」「指南」这类烂尾词)", "core_concept": "核心观点(一句话说清独特价值)", - "audience_pain": "受众痛点(真实用户的困惑或需求)", - "unique_angle": "独特视角(差异化切入点)", + "audience_pain": "受众痛点(真实用户的困惑)", + "unique_angle": "差异化切入点", "format": "内容形式(趋势洞察/实操指南/对比分析/案例解读)" -}} +}}}} 要求: -- 标题要像人会搜索的,带领域关键词 -- 避免「新趋势」「指南」「攻略」这类同质化结尾 -- 切入点要具体,不要泛泛而谈 -- 优先考虑中国读者能实操的内容 -只输出JSON,不要其他文字。""" +- 标题像普通人会搜索的 +- 切入点具体,不泛泛而谈 +- 优先考虑中国读者能实操的内容""" try: resp = call_llm(prompt, temperature=0.7) @@ -797,10 +786,8 @@ class SustainabilityCollector: logger.info(f"RSS采集 {sum(1 for a in all_articles if a.get('source_name','') not in [s.name for s in self.sources if s.type=='web_search'])} 篇, " f"搜索采集 {len(web_search_results)} 篇") - # ---------------------- 第二阶段:尝试LLM选题生成 ---------------------- - llm_topic = None - if web_search_results: - llm_topic = self._generate_topic_with_llm(web_search_results) + # ---------------------- 第二阶段:LLM选题生成 ---------------------- + llm_topic = self._generate_topic_with_llm(web_search_results if web_search_results else None) if llm_topic and not self._is_duplicate_topic(llm_topic.title, existing_titles): llm_topic.created_at = datetime.datetime.now().isoformat() diff --git a/scripts/fix_collector.py b/scripts/fix_collector.py deleted file mode 100644 index 84757d0..0000000 --- a/scripts/fix_collector.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -""" -Collector 修复脚本 -解决 field 和 priority_score 参数问题 -""" - -import sys -import os -sys.path.insert(0, '/root/openclaw-workspace/projects/yu-zhi-ran/platform/backend') - -from app.models import Topic -from datetime import datetime - -def fix_topic_creation(): - """修复选题创建时的参数问题""" - - # 测试用例 - try: - # 正确的参数 - topic = Topic( - id="T001", - title="城市农业ROI报告:20㎡阳台种菜一年,省了多少钱?", - field="城市农业", - priority_score=10, - status="待处理", - compliance_score=100, - ready_at=None, - published_at=None, - platform_urls={}, - created_at=datetime.now(), - updated_at=datetime.now() - ) - print("✅ 选题创建成功") - return True - except Exception as e: - print(f"❌ 选题创建失败: {e}") - return False - -if __name__ == "__main__": - fix_topic_creation() \ No newline at end of file diff --git a/scripts/generate_images.py b/scripts/generate_images.py deleted file mode 100644 index 5739777..0000000 --- a/scripts/generate_images.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -""" -独立图片生成脚本 - 供定时任务调用 -用法: python3 generate_images.py [platform] -示例: python3 generate_images.py \"上海阳台种菜一年\" zhihu -""" - -import sys -from pathlib import Path - -PROJECT_ROOT = Path(__file__).parent.parent -sys.path.insert(0, str(PROJECT_ROOT)) - -from scripts.image_generator import ImageGenerator - -def main(): - if len(sys.argv) < 2: - print("用法: python3 generate_images.py [platform=zhihu]") - sys.exit(1) - - title = sys.argv[1] - platform = sys.argv[2] if len(sys.argv) > 2 else "zhihu" - - generator = ImageGenerator() - - print(f"开始生成图片...") - print(f"文章标题: {title}") - print(f"目标平台: {platform}") - print(f"输出目录: {generator.output_dir}") - - try: - files = generator.generate_all_placeholders(title, platform) - - print(f"\n✅ 成功生成 {len(files)} 张图片:") - for name, path in files.items(): - size_kb = path.stat().st_size // 1024 - print(f" - {name}: {path.name} ({size_kb}KB)") - - print(f"\n📁 图片保存在: {generator.output_dir}") - return 0 - except Exception as e: - print(f"\n❌ 图片生成失败: {e}") - import traceback - traceback.print_exc() - return 1 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/scripts/import_topics.py b/scripts/import_topics.py deleted file mode 100644 index 90bc8b9..0000000 --- a/scripts/import_topics.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python3 -""" -将 content/ideas/ 目录下的 Markdown 选题文件转换为并导入数据库 -""" - -import os -import sys -import json -import re -from pathlib import Path -from datetime import datetime - -PROJECT_ROOT = Path(__file__).parent.parent -sys.path.insert(0, str(PROJECT_ROOT)) - -# 数据库导入 -try: - from app.database import SessionLocal - from app.models import Topic as DBTopic - HAVE_DB = True -except ImportError as e: - HAVE_DB = False - print(f"[Warning] Database import failed: {e}") - -IDEAS_DIR = PROJECT_ROOT / "content" / "ideas" -DATA_DIR = PROJECT_ROOT / "automation" / "data" -OUTPUT_FILE = DATA_DIR / "sustainability_topics.json" # 仅备份,不再作为主数据源 - -def extract_field(content, field_name): - patterns = [ - rf"\*\*{re.escape(field_name)}\*\*\s*[::]\s*(.+?)(?:\n|$)", - rf"{re.escape(field_name)}\s*[::]\s*(.+?)(?:\n|$)", - ] - for pattern in patterns: - match = re.search(pattern, content, re.MULTILINE) - if match: - return match.group(1).strip() - return None - -def parse_evaluation_matrix(content): - scores = {} - lines = content.split('\n') - for line in lines: - if '|' in line and '---' not in line and '维度' not in line: - parts = [p.strip() for p in line.split('|')] - if len(parts) >= 3: - dimension = parts[1] - score_str = parts[2] - try: - score = int(score_str) - scores[dimension] = score - except: - pass - if '**总分**' in line: - total_match = re.search(r'\*\*总分\*\*\s*\|\s*\*\*(\d+)\*\*', line) - if total_match: - scores['总分'] = int(total_match.group(1)) - return scores - -def md_to_topic(md_path): - with open(md_path, 'r', encoding='utf-8') as f: - content = f.read() - - title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE) - title = title_match.group(1).strip() if title_match else md_path.stem - - field = extract_field(content, '领域') or '可持续生活系统' - format_type = extract_field(content, '形式') or '趋势洞察 + 实操指南' - core_concept = extract_field(content, '核心观点') or '' - audience_pain = extract_field(content, '受众痛点') or '' - unique_angle = extract_field(content, '独特角度') or '' - estimated_days = extract_field(content, '预估完成时间') - priority_str = extract_field(content, '优先级') or '中' - publish_date = extract_field(content, '预计发布时间') - status = extract_field(content, '状态') or '待处理' - - priority_map = {'高': 10, '中': 7, '低': 4} - priority_score = priority_map.get(priority_str, 5) - - evaluation = parse_evaluation_matrix(content) - total_score = evaluation.get('总分', 0) - - # 生成 ID:从文件名提取前缀数字,如果没有则使用标题哈希 - stem = md_path.stem # e.g., "001-上海阳台种菜一年" - m = re.match(r'^(\d{3})', stem) - if m: - num = m.group(1) - topic_id = f'M{num}' # M 系列表示手动导入 - else: - import hashlib - short = hashlib.md5(title.encode()).hexdigest()[:6].upper() - topic_id = f'M{short}' - - return { - "id": topic_id, - "title": title, - "field": field, - "format": format_type, - "core_concept": core_concept, - "audience_pain": audience_pain, - "unique_angle": unique_angle, - "priority": priority_str, - "priority_score": priority_score, - "total_score": total_score, - "status": status, - "cases": [], - "source_file": md_path.name, - "created_at": datetime.now().isoformat(), - "updated_at": datetime.now().isoformat(), - "ready_at": publish_date, - "published_at": None, - "compliance_score": 100, - "platform_urls": {} - } - -def save_to_db(topic_dict): - if not HAVE_DB: - print("数据库不可用,跳过入库") - return False - db = SessionLocal() - try: - existing = db.query(DBTopic).filter(DBTopic.id == topic_dict['id']).first() - if existing: - # 更新字段 - for field in ['title', 'field', 'format', 'core_concept', 'audience_pain', 'unique_angle', 'priority', 'priority_score', 'total_score', 'status', 'cases', 'source_file', 'compliance_score', 'platform_urls']: - setattr(existing, field, topic_dict.get(field, getattr(existing, field))) - if topic_dict.get('ready_at'): - try: - existing.ready_at = datetime.strptime(topic_dict['ready_at'], '%Y-%m-%d').date() - except: - pass - existing.updated_at = datetime.now() - else: - # 新增 - new_topic = DBTopic( - id=topic_dict['id'], - title=topic_dict['title'], - field=topic_dict['field'], - format=topic_dict['format'], - core_concept=topic_dict['core_concept'], - audience_pain=topic_dict['audience_pain'], - unique_angle=topic_dict['unique_angle'], - priority=topic_dict['priority'], - priority_score=topic_dict['priority_score'], - total_score=topic_dict['total_score'], - status=topic_dict['status'], - cases=topic_dict['cases'], - source_file=topic_dict['source_file'], - ready_at=datetime.strptime(topic_dict['ready_at'], '%Y-%m-%d').date() if topic_dict.get('ready_at') else None, - published_at=None, - compliance_score=topic_dict['compliance_score'], - platform_urls=topic_dict['platform_urls'], - created_at=datetime.now(), - updated_at=datetime.now() - ) - db.add(new_topic) - db.commit() - return True - except Exception as e: - db.rollback() - print(f"数据库保存失败: {e}") - return False - finally: - db.close() - -def main(): - if not IDEAS_DIR.exists(): - print(f"错误:选题目录不存在 {IDEAS_DIR}") - return - - md_files = [] - for f in IDEAS_DIR.glob("*.md"): - if f.name == "README.md": - continue - if f.name.endswith('-research.md') or f.name.endswith('-compliance.md'): - continue - if re.match(r'^\d{3}-.+\.md$', f.name): - md_files.append(f) - - if not md_files: - print("未找到选题文件") - return - - print(f"找到 {len(md_files)} 个选题文件,开始导入...") - - topics = [] - for md_file in sorted(md_files): - print(f" 处理: {md_file.name}") - topic = md_to_topic(md_file) - topics.append(topic) - print(f" 标题: {topic['title']}") - print(f" ID: {topic['id']}") - print(f" 总分: {topic['total_score']}") - print(f" 状态: {topic['status']}") - - # 保存 JSON 备份 - DATA_DIR.mkdir(parents=True, exist_ok=True) - with open(OUTPUT_FILE, 'w', encoding='utf-8') as f: - json.dump(topics, f, ensure_ascii=False, indent=2) - print(f"\n✅ 已备份选题到 {OUTPUT_FILE}") - - # 导入数据库 - if HAVE_DB: - success_count = 0 - for t in topics: - if save_to_db(t): - success_count += 1 - print(f"✅ 已导入 {success_count}/{len(topics)} 个选题到数据库") - else: - print("⚠️ 数据库不可用,仅生成了 JSON 备份") - - # 统计 - ready_topics = [t for t in topics if t['status'] != '已发布'] - if ready_topics: - avg_score = sum(t['total_score'] for t in ready_topics) / len(ready_topics) - print(f"📊 可用选题数: {len(ready_topics)}") - print(f"🎯 平均评分: {avg_score:.1f}") - -if __name__ == "__main__": - main() diff --git a/scripts/strategy_topics_to_json.py b/scripts/strategy_topics_to_json.py index 6c3ff1f..431f7d3 100644 --- a/scripts/strategy_topics_to_json.py +++ b/scripts/strategy_topics_to_json.py @@ -7,11 +7,9 @@ topics = [ {"id":"A03","title":"数字游民签证全解析:30个国家政策对比,中国护照能去哪些?","field":"未来工作方式","format":"对比分析 + 实操指南","core_concept":"分析爱沙尼亚/葡萄牙/巴厘岛等30国游民签证,结合中国护照限制,给出签证+保险+税务+社群的完整路线","audience_pain":"想地理套利但被签证和社保困扰","unique_angle":"不是简单列出签证,而是给出中国护照持有者的可行组合方案(如泰国+大马+巴厘岛)","priority":"高","priority_score":10,"total_score":51,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"A04","title":"一人公司实验:从创意到营收的365天日志","field":"未来工作方式","format":"实践日志 + 方法论","core_concept":"基于Indie Hackers案例,结合中国孤独创业现状,提供MVP设计、现金流管理、法律合规的一站式指南","audience_pain":"想单干但怕失败、缺启动资金、不懂营销","unique_angle":"真实日志形式,展示完整从0到营收的过程,不美化","priority":"高","priority_score":10,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"A05","title":"AI时代的技能组合:什么技能值得投入10年?","field":"未来工作方式","format":"趋势分析 + 个人规划","core_concept":"基于WEF未来技能报告,划分4个技能维度(AI强化型、AI无法替代、复合型、过时型),帮中国职场人识别护城河技能","audience_pain":"学什么都不放心,怕投入时间后AI又取代","unique_angle":"将全球宏观报告转化为个人技能地图,提供可视化工具","priority":"中","priority_score":7,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, - {"id":"B01","title":"城市农业ROI报告:20㎡阳台种菜一年,省了多少钱?","field":"可持续生活系统","format":"数据分析 + 实操指南","core_concept":"对比东京垂直农场与国内空间限制,精选高ROI蔬菜品种,智能设备自动灌溉,给出详细成本核算和品种推荐","audience_pain":"想种但怕麻烦、怕亏本、不知道种什么","unique_angle":"用财务思维算账(投入/产出/时间成本),打破'种菜必须有地'的思维","priority":"高","priority_score":10,"total_score":52,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"B02","title":"零浪费家庭实验:一年只产100L垃圾,可能吗?","field":"可持续生活系统","format":"实践实验 + 方法论","core_concept":"对比瑞典零浪费城市,针对中国垃圾分类困境,提供垃圾追踪表、替代方案数据库、社区互助网络","audience_pain":"想环保但觉得做不到、不知道从哪减","unique_angle":"极限实验(100L/年)+ 可执行步骤(从塑料减量开始),不理想化","priority":"高","priority_score":10,"total_score":51,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"B03","title":"低碳生活账单:用3年省了8万,碳足迹降了60%","field":"可持续生活系统","format":"数据分析 + 案例研究","core_concept":"对比欧洲碳税政策,从交通(电动车+共享)、饮食(植物为主)、消费(二手优先)三个维度,展示真实账单变化","audience_pain":"觉得低碳=更贵,不敢尝试","unique_angle":"用财务数据说话(省8万),打破'环保=烧钱'误解","priority":"高","priority_score":10,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"B04","title":"循环消费实战:10件物品,用3年省了2万","field":"可持续生活系统","format":"实操指南 + 案例清单","core_concept":"对比法国二手强制法与中国闲鱼文化,提供购买决策树(买新/二手/租)、延长寿命技巧、转卖策略","audience_pain":"想买二手但怕质量差、怕麻烦","unique_angle":"10件物品的具体交易记录和对比(手机、相机、家具等),可复制","priority":"中","priority_score":7,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, - {"id":"B05","title":"社区菜园指南:如何推动小区5户邻居共建共享","field":"可持续生活系统","format":"方法论 + 实操步骤","core_concept":"对比纽约社区花园政策与中国物业协调难题,提供法律风险(物权)、利益分配机制、技术方案(分区+智能)","audience_pain":"想组织但怕纠纷、不懂法律、协调不了邻居","unique_angle":"从1个友好小区试点开始,成功后复制,降低风险","priority":"高","priority_score":10,"total_score":49,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"C01","title":"第二大脑2.0:用DeepSeek+本地向量库建立私有知识系统","field":"个人知识工厂","format":"技术指南 + 实操案例","core_concept":"对比Obsidian+RAG海外实践,针对国内云服务担忧,提供数据主权、隐私保护、无缝检索、AI问答的本地化方案","audience_pain":"想系统化知识但担心云存储安全,怕复杂","unique_angle":"强调数据主权,从API调用到本地部署的渐进路线","priority":"中","priority_score":7,"total_score":52,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"C02","title":"PKM极简实践:PARA系统在Notion上的落地模板","field":"个人知识工厂","format":"模板分享 + 方法论","core_concept":"将Tiago Forte的PARA体系简化为3个核心文件夹,每周10分钟维护,AI辅助整理,让中国人真正用起来","audience_pain":"学了方法坚持不了,工具复杂难上手","unique_angle":"极简版(4个区)+ 每日5分钟习惯养成,降低门槛","priority":"中","priority_score":7,"total_score":51,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"C03","title":"费曼学习法AI增强:如何让AI帮你'教'懂一个概念","field":"个人知识工厂","format":"方法论 + 实践工具","core_concept":"结合经典费曼技巧与AI工具,三步法(AI简化→自我复述→Gap识别)+ 输出倒逼输入","audience_pain":"学东西记不住,自以为懂了但其实不会","unique_angle":"用AI当'测试官',验证你的理解深度,非被动接受知识","priority":"中","priority_score":7,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, @@ -21,7 +19,7 @@ topics = [ {"id":"D02","title":"数字排毒月:戒掉微信/抖音后,生活发生了什么","field":"科技人文交叉","format":"实践实验 + 效果分析","core_concept":"对比硅谷禅修热与中国'失联恐惧',采用渐进式戒断(无屏时段)+ 替代活动 + 社交边界管理","audience_pain":"想减少屏幕时间但又怕错过重要信息,自律困难","unique_angle":"真实实验记录(not理论),展示戒断前后的生活变化数据","priority":"中","priority_score":7,"total_score":50,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"D03","title":"银发科技报告:给爸妈装智能设备,学到的5个设计原则","field":"科技人文交叉","format":"设计原则 + 案例","core_concept":"对比日本适老化设计与国产'适老模式'鸡肋,提炼简化选项、物理反馈、容错设计、情感连接的具体方案","audience_pain":"给父母买智能设备但他们不用,功能复杂","unique_angle":"不是推荐产品,而是总结5个设计原则,让读者自己改造设备","priority":"中","priority_score":7,"total_score":49,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, {"id":"D04","title":"儿童数字素养课:10岁儿子的AI启蒙12周","field":"科技人文交叉","format":"教育日志 + 方法论","core_concept":"对比芬兰AI教育与国内家长'禁止接触'心态,通过每周1次'AI家庭时间',培养批判性思维和创造力","audience_pain":"不知如何让孩子正确认识AI,怕沉迷又怕脱节","unique_angle":"真实父子12周项目记录,提供可复制的课程大纲","priority":"中","priority_score":7,"total_score":48,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}, - {"id":"D05","title":"科技与自然共生:如何用AI让阳台农场更'自然'","field":"科技人文交叉","format":"理念 + 实操方案","core_concept":"对比荷兰智能温室与中国人'回归原始'误区,实现技术隐形化(传感器+提醒)+ 自然反馈闭环 + 人工仪式感","audience_pain":"想用科技但又怕失去'自然感',追求矛盾","unique_angle":"技术与情感连接的平衡方案,AI只做幕后,人工保留仪式","priority":"高","priority_score":10,"total_score":48,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()} + {"id":"D06","title":"AI时代的隐私悖论:便利与安全的平衡术","field":"科技人文交叉","format":"趋势分析 + 实用指南","core_concept":"分析AI工具便利性背后个人数据的流向,提供普通用户可操作的数据保护策略","audience_pain":"想用AI又担心隐私,不知道如何保护自己","unique_angle":"不是恐吓式说教,而是给出'能做的10件事'的清单","priority":"中","priority_score":7,"total_score":46,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()} ] with open(OUTPUT_FILE:= '/root/openclaw-workspace/projects/yu-zhi-ran/automation/data/sustainability_topics.json', 'w', encoding='utf-8') as f: diff --git a/scripts/test_image_gen.py b/scripts/test_image_gen.py deleted file mode 100644 index 56741f5..0000000 --- a/scripts/test_image_gen.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -"""测试图片生成器""" - -import sys -from pathlib import Path - -PROJECT_ROOT = Path(__file__).parent.parent -sys.path.insert(0, str(PROJECT_ROOT)) - -from scripts.image_generator import ImageGenerator - -def main(): - print("开始测试图片生成...") - generator = ImageGenerator() - print(f"输出目录: {generator.output_dir}") - - try: - files = generator.generate_all_placeholders("测试文章标题:上海阳台种菜一年", "zhihu") - print(f"✅ 成功生成 {len(files)} 张图片:") - for name, path in files.items(): - size_kb = path.stat().st_size // 1024 - print(f" - {name}: {path.name} ({size_kb}KB)") - print(f"图片保存在: {generator.output_dir}") - return 0 - except Exception as e: - print(f"❌ 生成失败: {e}") - import traceback - traceback.print_exc() - return 1 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file