微信公众号 AI 热点自动发布工具
完整链路
1. 询问用户配置(主题、风格、配图数量)
↓
2. Exa/Tavily 搜索采集 AI 热点资料
↓
3. 撰写文章(Markdown 格式)
↓
4. 调用 nanobanana API 生成配图
↓
5. 上传图片到微信服务器(获取 mmbiz URL)
↓
6. 转换为 HTML 并发布到公众号草稿箱
↓
7. 提示用户去微信公众号后台检查文章
配置信息
微信公众号 API
- AppID:
WECHAT_APPID(通过环境变量配置) - AppSecret:
WECHAT_SECRET(通过环境变量配置)
图片生成 API
- 模型:
google/nano-banana-pro(通过 Replicate) - 脚本:
~/.codex/skills/article-illustrator/scripts/generate_image.py(也可能是~/.claude/skills/...或~/.gemini/skills/...,以你的工具为准)
配置方法见
README.md(本仓库已移除所有硬编码密钥/Token/本地路径)。
图片配字语言规则
重要:根据文章语言决定图片中的文字语言!
| 文章语言 | 图片 Prompt 语言 | 示例 |
|---|---|---|
| 中文文章 | 中文配字 | "流程图展示:搜索新闻 → 撰写文章 → 生成配图 → 发布,中文标注" |
| 英文文章 | 英文配字 | "Flowchart: Search → Write → Generate → Publish, English labels" |
Prompt 编写规则:
- 中文文章:在 prompt 末尾加
,中文标注,简体中文文字 - 英文文章:在 prompt 末尾加
, English text labels
执行流程详解
Step 1: 询问用户配置
设计思路:不同主题、风格、配图数量会影响后续所有步骤,所以先收集用户偏好。
如果是交互式运行,可以询问用户;如果是定时任务/自动运行(比如 OpenClaw Cron),则不要提问,直接从触发消息里解析参数或使用默认值。
默认配置(建议固定一套)
- 主题:AI工具
- 风格:github
- 配图:封面 + 3 张
- 作者:田威 AI(环境变量
WECHAT_AUTHOR默认值)
支持的参数(建议写在触发语句中):
主题:例如AI工具/大模型/AI Agent风格:例如purple/orangeheart/github配图:例如仅封面/封面+2张/封面+3张作者:例如田威 AI(会映射到环境变量WECHAT_AUTHOR)
覆盖规则(让用户“诉说”即可)
- 如果用户/定时任务消息里出现
主题=.../风格=.../配图=.../作者=...,则覆盖默认值。 - 其余自然语言描述(例如“写得更科普一些”“多强调边界和风险”“更偏护理视角”)视为写作约束,AI 可以自由调整结构与措辞以提升可读性。
- 冲突时以用户指令为准;不确定就保守处理(不编造数据、不夸大结论)。
交互式询问(可选):
问题 1 - 文章主题:
- AI Agent
- 大模型
- AI 工具
- 行业动态
- 自定义
问题 2 - CSS 风格:
- 紫色经典 purple(推荐)
- 橙心暖色 orangeheart
- GitHub风格 github
- 其他...
问题 3 - 配图数量:
- 仅封面图
- 封面 + 2张配图
- 封面 + 3张配图(推荐)
Step 2: 搜索采集 AI 热点(两阶段深度采集)
问题:简单搜索只返回标题和 200 字摘要,内容太浅,写不出有深度的文章。
解决方案:两阶段采集
阶段 1:广度搜索(发现)
↓ 筛选 3-5 篇高质量文章
阶段 2:深度抓取(提取)
↓ 获取完整原文内容
阶段 1:广度搜索(发现相关文章)
设计思路:
- 为什么用 Tavily/Exa? 专为 AI 优化,返回结构化数据
- 为什么搜 3 天? 太短没素材,太长不新鲜
- 为什么要 10 条? 足够筛选,但不会太多
Tavily vs Exa 选择:
| 场景 | 推荐 | 原因 |
|---|---|---|
| 新闻热点 | Tavily | topic="news" 专门优化新闻搜索 |
| 技术文档 | Exa | 对技术内容索引更全面 |
| 综合搜索 | 两者并用 | 互补,覆盖更广 |
# Tavily 搜索(适合新闻热点)
mcp__tavily__tavily-search(
query="AI artificial intelligence news {主题}",
topic="news",
days=3,
max_results=10,
search_depth="advanced" # 使用高级搜索
)
# Exa 搜索(适合技术内容)
mcp__exa__web_search_exa(
query="AI {主题} latest news tutorial",
numResults=10
)
筛选标准(从 10 条中选 3-5 条):
- 相关性:与主题直接相关,不是泛泛而谈
- 深度:有具体案例、数据、代码,不是纯新闻稿
- 新鲜度:优先最近 3 天的内容
- 来源质量:优先技术博客、官方文档、知名媒体
阶段 2:深度抓取(获取完整原文)
关键:使用 tavily-extract 抓取完整文章内容!
# 深度抓取选中的文章(返回完整原文,可达 2 万字)
mcp__tavily__tavily-extract(
urls=[
"https://example.com/article1",
"https://example.com/article2",
"https://example.com/article3"
],
extract_depth="advanced" # 高级提取,获取更多内容
)
对比效果:
| 方法 | 返回内容 | 适用场景 |
|---|---|---|
tavily-search | 标题 + 200字摘要 | 发现文章 |
tavily-extract | 完整原文(可达2万字) | 深度阅读 |
exa web_search | 标题 + 摘要 + 部分正文 | 快速了解 |
为什么要深度抓取?
- 摘要只有观点,没有论据
- 完整原文有案例、数据、代码
- 深度内容才能写出有价值的文章
素材整理模板
抓取完成后,整理成以下格式:
## 素材 1:[文章标题]
- **来源**:[URL]
- **核心观点**:[1-2 句话总结]
- **关键数据/案例**:
- [具体数据点 1]
- [具体案例 1]
- [代码片段(如有)]
- **可引用的金句**:[原文中的精彩表述]
## 素材 2:[文章标题]
...
## 素材 3:[文章标题]
...
整理要点:
- 提取具体数据(数字、百分比、对比)
- 提取真实案例(谁用了、怎么用、效果如何)
- 提取代码片段(如果是技术文章)
- 记录可引用的原文表述(增加可信度)
完整采集流程示例
# 1. 广度搜索
search_results = mcp__tavily__tavily-search(
query="Claude Code Skills tutorial 2025",
topic="general",
max_results=10,
search_depth="advanced"
)
# 2. 筛选高质量文章(人工或自动)
selected_urls = [
"https://huggingface.co/blog/...",
"https://www.siddharthbharath.com/claude-skills/",
"https://www.youngleaders.tech/p/..."
]
# 3. 深度抓取
full_content = mcp__tavily__tavily-extract(
urls=selected_urls,
extract_depth="advanced"
)
# 4. 整理素材(见上方模板)
Step 3: 撰写文章
设计思路:
- 为什么用 Markdown? 结构清晰,易于转换为 HTML,支持代码块
- 为什么标记配图位置? 让后续步骤知道在哪里插入图片,以及图片应该表达什么
- 为什么用科普/护理/科技风格? 准确克制、步骤清晰、强调边界与可落地性
参考示例文章:examples/nursing-tech-article.md
文章结构设计:
引子(钩子开头,抛出问题或观点)
↓
核心内容(3-5 个分点,每点配一张图)
↓
价值总结(明确结论)
↓
行动号召(引导读者下一步)
输出格式:Markdown,用注释标记配图位置和描述
# 文章标题
开头段落(钩子,吸引读者继续阅读)...
## 第一部分
内容...
<!-- IMAGE_1: 图片描述(根据文章语言决定中英文) -->
<!-- 图片应该可视化这部分的核心概念 -->
## 第二部分
内容...
<!-- IMAGE_2: 图片描述 -->
## 第三部分
内容...
<!-- IMAGE_3: 图片描述 -->
## 总结
结尾(明确结论 + 行动号召)...
配图位置选择原则:
- 前 1/3:可视化核心概念或问题
- 中间 1/3:展示流程、对比或数据
- 后 1/3:总结图或行动引导
Step 4: 调用 nanobanana 生成配图
设计思路:
- 为什么用 nanobanana? Google 的 Imagen 3 模型,生成质量高,支持中文
- 为什么封面用 16:9? 公众号封面最佳比例,在列表中显示效果好
- 为什么配图用 4:3? 文章内图片的标准比例,阅读体验好
- 为什么要中文配字? 中文文章配中文图,视觉一致性更好
必须使用 article-illustrator 的脚本(通过环境变量配置 API Key):
# 生成封面图(16:9,横版,适合列表展示)
python3 ~/.codex/skills/article-illustrator/scripts/generate_image.py \
--prompt "封面图描述,中文标注" \
--output "/tmp/wechat_cover.png" \
--aspect-ratio "16:9"
# 生成配图(4:3,适合文章内嵌)
python3 ~/.codex/skills/article-illustrator/scripts/generate_image.py \
--prompt "配图描述,中文标注" \
--output "/tmp/wechat_img1.png" \
--aspect-ratio "4:3"
Prompt 编写技巧:
[主题] + [具体内容] + [视觉风格] + [颜色调性] + [语言标注]
Prompt 示例(中文文章):
- 封面:"AI 自动化工作流程图,展示从命令到发布的完整链路,科技感蓝色调,简洁扁平设计,中文标注"
- 配图1:"开发者配置 API 的界面示意图,显示 AppID 输入框,深色主题 UI,中文标注"
- 配图2:"Python 代码编辑器截图风格,显示图片生成函数,VS Code 深色主题"
- 配图3:"微信公众号后台草稿箱界面,显示文章列表,绿色微信品牌色,中文标注"
常见问题:
- 图片没有中文?→ 确保 prompt 末尾加",中文标注,简体中文文字"
- 图片风格不一致?→ 所有图片使用相同的风格描述词
Step 5: 上传图片到微信服务器
设计思路:
- 为什么还要上传到微信? 公众号文章只能显示
mmbiz.qpic.cn域名的图片,外部图片会被过滤 - 为什么有两个接口? 封面图和文章内图片的处理方式不同
- 为什么 access_token 要每次获取? 有效期只有 2 小时,不能缓存
重要:公众号文章只能显示微信域名的图片!
import os
import requests
# 1. 获取 access_token(有效期 2 小时)
token_resp = requests.get(
"https://api.weixin.qq.com/cgi-bin/token",
params={
"grant_type": "client_credential",
"appid": os.environ["WECHAT_APPID"],
"secret": os.environ["WECHAT_SECRET"]
}
)
access_token = token_resp.json()["access_token"]
# 2. 上传封面图(永久素材接口,返回 media_id)
# 用于草稿的 thumb_media_id 字段
with open("/tmp/wechat_cover.png", "rb") as f:
thumb_resp = requests.post(
f"https://api.weixin.qq.com/cgi-bin/material/add_material"
f"?access_token={access_token}&type=image",
files={"media": ("cover.png", f, "image/png")}
)
thumb_media_id = thumb_resp.json()["media_id"]
# 3. 上传文章内配图(图文消息内图片接口,返回 URL)
# 返回的 URL 可以直接嵌入 HTML
with open("/tmp/wechat_img1.png", "rb") as f:
img_resp = requests.post(
f"https://api.weixin.qq.com/cgi-bin/media/uploadimg"
f"?access_token={access_token}",
files={"media": ("img1.png", f, "image/png")}
)
img1_url = img_resp.json()["url"]
# 返回: http://mmbiz.qpic.cn/sz_mmbiz_png/...
两个接口的区别:
| 接口 | 用途 | 返回值 | 使用场景 |
|---|---|---|---|
/material/add_material | 永久素材 | media_id | 封面图(thumb_media_id) |
/media/uploadimg | 图文消息内图片 | mmbiz URL | 文章内嵌图片 |
为什么这样设计?
- 封面图需要 media_id 是因为草稿 API 要求用 ID 引用
- 文章内图片需要 URL 是因为 HTML 里用
<img src="">引用
Step 6: 转换 HTML 并发布草稿
设计思路:
- 为什么要转 HTML? 公众号不支持 Markdown,只接受 HTML
- 为什么用内联 CSS? 公众号会过滤
<style>标签,只有内联样式才生效 - 为什么 ensure_ascii=False? 否则中文会变成
\uXXXX编码,微信无法正确显示
import json
# 1. 构建 HTML(使用微信返回的图片 URL)
# 所有样式必须内联,不能用 class
html_content = f'''
<section style="font-family: -apple-system, sans-serif; line-height: 1.8; color: #333; padding: 15px;">
<p style="margin-bottom: 20px;">段落内容</p>
<h2 style="border-bottom: 1px solid #eee; padding-bottom: 8px;">标题</h2>
<p style="text-align: center; margin: 25px 0;">
<img src="{img1_url}" style="max-width: 100%; border-radius: 6px;">
</p>
<blockquote style="background: #f6f8fa; border-left: 4px solid #ddd; padding: 12px 16px;">
引用内容
</blockquote>
</section>
'''
# 2. 构建草稿数据
draft_data = {
"articles": [{
"title": "文章标题(不超过21个中文字符)",
"digest": "文章摘要(会显示在分享卡片上)",
"content": html_content,
"thumb_media_id": thumb_media_id, # 封面图 ID
"need_open_comment": 1, # 开启评论
"only_fans_can_comment": 0 # 所有人可评论
}]
}
# 3. 发布草稿(关键:ensure_ascii=False)
response = requests.post(
f"https://api.weixin.qq.com/cgi-bin/draft/add?access_token={access_token}",
data=json.dumps(draft_data, ensure_ascii=False).encode('utf-8'),
headers={"Content-Type": "application/json; charset=utf-8"}
)
result = response.json()
# 成功返回: {"media_id": "草稿ID"}
HTML 样式要点:
- 所有样式必须内联(
style="...") - 图片加
max-width: 100%防止溢出 - 使用系统字体栈保证跨平台一致性
- 行高 1.8-2.0 提升阅读体验
常见错误:
- 中文乱码?→ 检查
ensure_ascii=False - 样式不生效?→ 检查是否用了内联样式
- 图片不显示?→ 检查是否用了微信返回的 URL
Step 7: 提示用户检查
设计思路:
- 为什么要提示检查? 自动发布的是草稿,需要人工确认后才能正式发布
- 为什么要输出 R2 链接? 方便用户在其他平台复用图片
- 为什么要输出草稿 ID? 方便后续通过 API 操作(如删除、修改)
发布完成后,输出:
✅ 发布完成!
📝 文章信息
- 标题:xxx
- 摘要:xxx
- 风格:xxx
📤 公众号
- 草稿 ID:xxx
- 请前往微信公众号后台检查文章:https://mp.weixin.qq.com
⚠️ 检查要点:
1. 图片是否正常显示
2. 排版是否正确
3. 标题和摘要是否合适
4. 确认无误后点击"发布"
CSS 风格配置
| 风格 ID | 名称 | 标题色 | 正文色 | 引用背景 |
|---|---|---|---|---|
purple | 紫色经典 | #8064a9 | #444444 | #f4f2f9 |
orangeheart | 橙心暖色 | #ef7060 | #000000 | #fff5f5 |
github | GitHub风格 | #333333 | #333333 | #f6f8fa |
详细配置见 styles.json
注意事项
- 图片语言:中文文章用中文配字,英文文章用英文配字
- 图片域名:公众号只能显示 mmbiz.qpic.cn 域名的图片
- 中文编码:JSON 必须用
ensure_ascii=False - 标题长度:最多 64 字节(约 21 个中文字符)
- access_token:有效期 2 小时,每次需重新获取
- 定时任务:自动运行时不要提问,直接按参数/默认值执行