wechat-publish
Skill0 starsChanged 29 days agoMITView on GitHub
将 Notion 或 Markdown 文章排成可粘贴到微信公众号编辑器的富文本 HTML,并处理图片与本地预览。目标明确为公众号排版、Notion/MD 转微信时使用。竖版图片卡片由 wechat-slides 处理;一般文案、普通 Notion/MD 编辑和未明确平台的“发出去”不自动触发。
- Installs packages
Files
WeChat Publish — Markdown 到微信公众号发布工作流
把内容(Notion 页面或 Markdown 文件)转换成微信公众号编辑器可直接粘贴的 HTML。
输出浏览器预览页面(xxx_preview.html),打开后点「复制全文到微信」→ 微信公众号后台 Ctrl+V 粘贴。
排版规格详见 references/template-spec.md——记录了 706 编辑风格的 inline style 规范(颜色、标题、段落、图片、引用块)。
如果为自己的品牌使用,替换其中的颜色方案和字体即可。
环境配置(使用前必读)
1. 设置工作路径
skill 脚本需要知道两个根路径。在首次使用时告诉 LLM,或写入环境变量:
# 知识库根目录(Markdown 文件、Obsidian vault)
export VAULT_ROOT="$HOME/path/to/your/knowledge-vault"
# 媒体素材库根目录(可选,如果有 706-media 风格的素材库)
export MEDIA_VAULT="$HOME/path/to/your/media-vault"如果 MEDIA_VAULT 未设置,skill 会自动跳过媒体库检索,仅使用传统路径搜索。
706 项目当前使用的路径(供团队成员参考):
VAULT_ROOT = $706_CLOUD/706-knowledge/706知识库
MEDIA_VAULT = ~/Dev/706-local-os/706-media2. 需要的 LLM 能力
这个 skill 不绑定特定的 LLM。需要的最低能力集:
| 能力 | 用途 | 哪些 LLM 有 |
| 读文件 | 读取 MD 文件和图片 | Claude, GPT-4, Gemini |
| 运行 Python 脚本 | 图片处理、base64 编码、生成 HTML | Claude Code, Cursor, Codex, OpenCode |
| 写文件 | 输出 _preview.html | 同上 |
| 多模态看图(推荐) | 自动标注图片 caption | Claude, GPT-4V, Gemini |
| Web fetch(可选) | 从 Notion 获取内容 | Claude, Cursor + MCP |
LLM 适配说明:
- Claude Code / Claude Desktop:所有能力原生支持,直接按本 skill 执行
- Cursor / Codex / OpenCode:有文件读写和 Python 执行能力,可直接用。没有多模态的话,caption 走文本启发式规则
- ChatGPT / Gemini 网页版:可以对话方式完成大部分操作,但需要手动运行 Python 脚本和粘贴 HTML
- 纯 API 调用:按本 skill 的工作流描述写代码调用即可
3. Python 依赖
pip install Pillow # 图片处理(resize、格式转换、base64)输入来源
来源 A:Notion 页面
用户提供 Notion 页面链接或 ID,用 Notion API / MCP 获取内容。
来源 B:Markdown 文件
用户提供本地 .md 文件路径。参考实现:706-knowledge/by-project/2050/03-媒体区/md_to_wechat.py
先通读 MD 全文 → 识别结构 → 再写解析器。不要假设结构。
MD 结构灵活性(重要)
每篇文章的结构可能完全不同。必须识别:
| 元素 | 可能的形式 |
| 章节分隔 | ### N · 标题 / 裸数字 0, 1, 2 / ## 标题 |
| 章节标题 | ### 的内容 / 第一个斜体段落 / blockquote 首句 |
| 歌词引用 | > *斜体诗句* + > 作者,来源,年代 |
| 图片 | ![[path]] /  / ![[vault-relative/path]] |
| 脚注 | [^1] 正文引用 + [^1]: 定义 文末 |
原则:先通读全文 → 画出结构树 → 再写解析器。
工作流
Step 1: 确认输入和配置
- 来源:Notion 链接 还是 本地 MD 文件
- 颜色方案:默认 706 标准配色(见
references/template-spec.md),可按需替换为自定义品牌色 - 图片处理:MD 来源 → base64 内嵌;Notion 来源 → 已有公网 URL 或上传图床
Step 2: 获取内容 & 分析结构
Notion 来源:用 Notion API / MCP fetch 页面,解析 Markdown。
MD 来源:直接读取 .md 文件。
标准 MD 语法映射:
# h1:跳过(工作区标题)## h2:文章主标题 → 头部区块(栏目标签 + 38px 标题 + 英文副标题 + 装饰线)### N · 中文标题:章节 →01. ENGLISH [ 中文 ]标题行 + 20px 中文大标题#### 子标题:小节标题**加粗**、*斜体*、[链接](url):inline 格式> 引用块:带左边框的引用样式- 列表项:<ul><li>| 表格 |:inline styled<table>---:跳过![[path|caption]]:场景图(有 caption = 场景图,无 caption = 头像圆形裁切)
Step 3: 构建文章 HTML
必须先阅读 references/template-spec.md,按规格逐元素生成 inline-styled HTML。
关键结构(详见 template-spec.md):
- 外层用
<table>包裹,padding: 70px 30px 100px - 头部:栏目标签 → 38px 衬线主标题 → 英文副标题 → 30px×1px 装饰线
- 章节:
<section style="margin-bottom:60px">包裹,首章节加margin-top:80px - 正文:
<section>元素,15px,line-height:2,非首段margin-top:16px - 每个元素必须带
background-color
Step 4: 处理图片
4a. 媒体库优先检索(如果有 MEDIA_VAULT)
生成 HTML 之前,先查 MEDIA_VAULT/media-index.json 是否有可用素材:
import json, os
media_root = os.environ.get("MEDIA_VAULT")
if media_root and os.path.exists(os.path.join(media_root, "media-index.json")):
with open(os.path.join(media_root, "media-index.json")) as f:
index = json.load(f)
# 按场景检索:
# 空间场景 → category: "上海空间" (品牌自定义)
# 活动现场 → project + event 匹配
# 嘉宾头像 → category: "嘉宾"
# 文末底图 → category: "品牌素材"
# 二维码 → category: "品牌素材"媒体库命中 → 直接加载文件做 base64。未命中 → 走传统搜索。
4b. 图片路径多源搜索
SEARCH_DIRS = [
MD_DIR / "images", # 文章同级 images/ 子目录
MEDIA_VAULT, # 媒体素材库(如果设置了环境变量)
VAULT_ROOT / "media", # vault 根 media/ 目录
VAULT_ROOT, # vault 根
]文件名修正:空格 → 下划线;提取纯文件名。
4c. 图片尺寸与质量
MAX_WIDTH = 800 # 微信 feed 流约 600px,编辑器约 800px
JPEG_QUALITY = 75 # 清晰度和体积最佳平衡- 原图 > 800px 宽 → resize
- PNG → 转 JPEG
- 总 HTML < 10MB(微信粘贴上限)
- Base64 缓存到
_cache/目录
4d. 图片 Caption 检测
图片下方文本判断是 caption 还是独立段落:
- Lookahead:跳过空白行找到下一个有内容的行
- 排除规则(以下情况不作为 caption):
- 以
>开头(blockquote) - 以
*...*包裹(italic 段落) - 是章节标记(单数字
0-9) - 以
感谢、撰文、摄影等元信息开头
- 以
- 拆分规则:如果匹配行含
。!?,在第一句处拆分为 caption + 余段 - 短文本:无句号且 < 40 字符 → 整体作 caption
Step 5: 生成预览 HTML
预览框架(本地预览用,不进入微信):
- 深色背景(
#1a1a1a) - 375px 手机预览框,border-radius:12px
- sticky 顶部工具栏 + 「复制全文到微信」按钮
copyContent()用 Selection+Range 复制#article-content内容
<div class="phone-frame">
<div id="article-content">
<!-- 文章 HTML(全 inline style,会被复制到微信) -->
</div>
</div>Step 6: Pre-flight 校验(必做)
| 检查项 | 方法 | 通过条件 |
| 图片全量引用 | MD 中 
