WeChat Article Pipeline — 微信文章处理流水线
概述
收到用户提供的微信公众号文章链接(mp.weixin.qq.com)后,按以下步骤执行:
- 添加至 IMA 知识库 — 将文章 URL 添加到用户的 IMA 知识库
- 获取媒体信息 — 从知识库获取文章信息(URL、元数据)
- 抓取完整内容 — 用 WebFetch 获取文章正文和所有图片 URL
- 下载图片 — 下载文章内嵌图片到本地
- 清洗内容 — 去掉作者信息、公众号来源、广告、预览标签等无关内容
- 生成 HTML — 用系统中文 CSS 字体 + @font-face 构建排版 HTML
- 转换 PDF — 用 Playwright/Chromium 渲染为 A4 PDF
- 交付 — 将 PDF 交付给用户
🫸 新手上手指南(分享给首次使用的人看)
如果用户尚未配置过 IMA 和 Playwright,按以下顺序指导他完成设置。
1️⃣ 下载并安装 IMA 桌面客户端
IMA 是腾讯出品的 AI 知识库工具,本 skill 用它来存储和管理文章。
下载地址: https://ima.qq.com/
支持 Windows / macOS,下载对应版本安装即可。
安装后登录你的微信/QQ 账号。
2️⃣ 在 WorkBuddy 中安装 IMA 知识库 Skill
本 skill 依赖「腾讯 ima」skill 来调用 IMA API。在 WorkBuddy 中运行:
/skills
在技能市场搜索 IMA 或 腾讯ima,安装以下两个 skill:
腾讯ima:knowledge-base腾讯ima:notes
3️⃣ 配置 IMA API 凭证
IMA 知识库 API 需要 Client ID 和 API Key。获取方式:
- 打开 https://ima.qq.com/agent-interface
- 登录你的 IMA 账号
- 点击创建,获取你的 Client ID 和 API Key
- 在终端执行以下命令存储凭证:
mkdir -p ~/.config/ima
echo "你的ClientID" > ~/.config/ima/client_id
echo "你的APIKey" > ~/.config/ima/api_key
凭证只用于向
ima.qq.com发请求,不会泄露到其他地方。
4️⃣ 安装 Playwright + Chromium(用于 PDF 生成)
本 skill 用浏览器内核将 HTML 渲染为 PDF。只需在终端执行一次:
cd /tmp && npm install playwright && npx playwright install chromium
这条命令会下载约 90MB 的 Chromium 浏览器引擎,只需执行一次即可。
5️⃣ ✅ 完成后验证
# 检查 Playwright 是否安装成功
test -f /tmp/node_modules/playwright/index.js && echo "✅ Playwright OK"
# 检查 Chromium
ls ~/Library/Caches/ms-playwright/chromium_headless_shell-*/chrome-headless-shell-* 2>/dev/null && echo "✅ Chromium OK"
# 检查 IMA 凭证
test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key && echo "✅ IMA 凭证 OK"
三行都显示 ✅ 即配置完成,可以开始使用了。
🚀 执行流程(WorkBuddy 使用此 section)
以下指令供执行工作流时使用。WorkBuddy 每次调用 Bash 时 shell 状态不会持久,因此所有路径变量需由 WorkBuddy 在上下文中追踪,或在每个 Bash 调用中重新计算。
Step 0: 环境检查 & 定位路径
先定位本 skill 和 IMA skill 的路径。WorkBuddy 将以下两个路径记在上下文中:
# ── 本 skill 目录 ──
SKILL_DIR="$HOME/.workbuddy/skills/wechat-article-pipeline"
if [ ! -f "$SKILL_DIR/SKILL.md" ]; then
# 兜底搜索
SKILL_DIR=$(find "$HOME/.workbuddy/skills" -maxdepth 2 -name "SKILL.md" -path "*wechat*article*" 2>/dev/null | head -1 | xargs dirname)
fi
echo "SKILL_DIR=$SKILL_DIR"
# ── IMA skill 目录(查找 ima_api.cjs) ──
IMA_SKILL_DIR=""
for d in "$HOME/.workbuddy/skills/"*ima* "$HOME/.workbuddy/skills/"*IM* "$HOME/.workbuddy/skills/"*腾讯* "$HOME/.workbuddy/skills/"*tencent*; do
if [ -f "$d/ima_api.cjs" ]; then
IMA_SKILL_DIR="$d"
break
fi
done
# 兜底:全局搜索 ima_api.cjs
if [ -z "$IMA_SKILL_DIR" ]; then
IMA_SKILL_DIR=$(find "$HOME/.workbuddy/skills" -maxdepth 3 -name "ima_api.cjs" -type f 2>/dev/null | head -1 | xargs dirname 2>/dev/null)
fi
if [ -z "$IMA_SKILL_DIR" ]; then
echo 'MISSING_IMA_SKILL'
exit 1
fi
echo "IMA_SKILL_DIR=$IMA_SKILL_DIR"
# ── IMA 凭证 ──
if [ ! -f "$HOME/.config/ima/client_id" ] || [ ! -f "$HOME/.config/ima/api_key" ]; then
echo 'MISSING_IMA_CREDENTIALS'
exit 1
fi
输出 MISSING_IMA_SKILL 时,提示用户安装 IMA skill(参见「新手上手指南」第2步)。 输出 MISSING_IMA_CREDENTIALS 时,提示用户配置凭证(参见「新手上手指南」第3步)。
正常输出后,WorkBuddy 记下 SKILL_DIR 和 IMA_SKILL_DIR 的值,后续步骤直接引用。
Step 0b: 检查 Playwright
node -e "try{require('/tmp/node_modules/playwright');console.log('PW_OK')}catch(e){console.log('PW_MISSING')}"
输出 PW_MISSING 时提示用户安装(参见新手指南第4步)。
⚠️ 重要提示:WorkBuddy 每次调用 Bash 时 shell 状态不会持久。因此每个 Bash 调用中所需的变量(如
IMA_SKILL_DIR、OPTS等)都需要在调用内重新计算或由 WorkBuddy 以实际值替换。以下步骤中,
<IMA_SKILL_DIR>、<SKILL_DIR>、<WORK_DIR>、<kb_id>、<media_id>、<文章URL>等占位符由 WorkBuddy 在执行时代入实际值。OPTS 每次使用时都需要重新生成,格式固定为:
OPTS=$(printf '{"clientId":"%s","apiKey":"%s"}' "$(cat ~/.config/ima/client_id)" "$(cat ~/.config/ima/api_key)")
Step 1: 加载 IMA 技能指令
调用 Skill("ima-skills") 加载 IMA 操作指令,获取 import_urls、get_media_info 等接口的调用方式。
Step 2: 查找用户的知识库
OPTS=$(printf '{"clientId":"%s","apiKey":"%s"}' "$(cat ~/.config/ima/client_id)" "$(cat ~/.config/ima/api_key)")
node "<IMA_SKILL_DIR>/ima_api.cjs" "openapi/wiki/v1/search_knowledge_base" \
'{"query":"","cursor":"","limit":20}' "$OPTS"
从返回结果中选择一个知识库(如果用户没指定,选 content_count 最大的那个)。WorkBuddy 记下 kb_id。
Step 3: 添加文章 URL 到知识库
OPTS=$(printf '{"clientId":"%s","apiKey":"%s"}' "$(cat ~/.config/ima/client_id)" "$(cat ~/.config/ima/api_key)")
node "<IMA_SKILL_DIR>/ima_api.cjs" "openapi/wiki/v1/import_urls" '{
"knowledge_base_id": "<kb_id>",
"urls": ["<文章URL>"]
}' "$OPTS"
记录返回的 media_id。
Step 4: 获取媒体信息
OPTS=$(printf '{"clientId":"%s","apiKey":"%s"}' "$(cat ~/.config/ima/client_id)" "$(cat ~/.config/ima/api_key)")
node "<IMA_SKILL_DIR>/ima_api.cjs" "openapi/wiki/v1/get_media_info" \
'{"media_id": "<media_id>"}' "$OPTS"
从 url_info.url 提取文章的最终访问地址。
Step 5: 用 WebFetch 抓取文章全文
用 WebFetch 工具请求文章 URL,prompt 写明以下要求:
请完整提取这篇文章的全部内容,包括:
- 文章标题
- 所有正文文字内容,保持完整段落
- 所有图片的 URL(img 标签的 src 属性值)
- 列表、表格、代码块等格式信息
不要遗漏任何段落,给我最完整的内容。
Step 6: 下载图片到工作目录
WORK_DIR=$(mktemp -d)
echo "WORK_DIR=$WORK_DIR"
WorkBuddy 记下 WORK_DIR。然后用 curl 逐一下载 WebFetch 返回的所有图片:
for url in "<图片URL1>" "<图片URL2>"; do
ext="jpeg"
[[ "$url" == *.png* ]] && ext="png"
[[ "$url" == *.jpg* ]] && ext="jpg"
[[ "$url" == *.gif* ]] && ext="gif"
curl -sL -o "<WORK_DIR>/img${count}.${ext}" "$url"
echo "img${count}.${ext}: $(wc -c < "<WORK_DIR>/img${count}.${ext}") bytes"
count=$((count + 1))
done
如果图片下载后文件大小为 0 或极小(< 1KB),尝试带 Referer 重试:
curl -sL -e "https://mp.weixin.qq.com/" -o "<WORK_DIR>/img${count}.${ext}" "<图片URL>"
Step 7: 检测系统中文字体路径
WorkBuddy 执行以下检测,记下 CN_FONT_URL(URL 编码后的字体文件路径):
- macOS: 检测
/System/Library/Fonts/STHeiti Light.ttc→file:///System/Library/Fonts/STHeiti%20Light.ttc - macOS 备选:
/System/Library/Fonts/PingFang.ttc - Windows / WSL:
/mnt/c/Windows/Fonts/msyh.ttc - Windows (Git Bash):
/c/Windows/Fonts/msyh.ttc - Linux:
/usr/share/fonts/truetype/wqy/wqy-microhei.ttc或/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc - 找不到时:CN_FONT_URL 留空,HTML 中不插入
@font-face,使用sans-serif降级
Step 8: 构建 HTML 文件
WorkBuddy 根据文章内容和图片列表,生成一份完整的 HTML 文件。CSS 模板如下:
CN_FONT_RULE
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'CJKFont', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', sans-serif;
font-size: 12pt; line-height: 1.8; color: #333; padding: 40px 50px;
}
h1 { text-align: center; font-size: 22pt; color: #1a1a2e; margin-bottom: 6pt; }
h2 { font-size: 16pt; color: #16213e; margin-top: 24pt; margin-bottom: 12pt; border-left: 4px solid #0f3460; padding-left: 10pt; }
p { margin-bottom: 8pt; }
.bold { font-weight: bold; }
.note { background: #f0f4f8; padding: 10pt 14pt; margin: 10pt 0; border-radius: 4pt; font-size: 11pt; }
.bullet { padding-left: 20pt; margin-bottom: 4pt; }
img { display: block; max-width: 90%; margin: 12pt auto; border: 1px solid #ddd; border-radius: 4pt; }
.caption { text-align: center; font-size: 9pt; color: #888; margin-bottom: 16pt; }
table { width: 80%; margin: 10pt auto; border-collapse: collapse; font-size: 10pt; }
th { background: #0f3460; color: white; padding: 6pt 10pt; border: 1px solid #0f3460; }
td { padding: 5pt 10pt; border: 1px solid #ccc; text-align: center; }
.divider { text-align: center; color: #ccc; margin: 20pt 0 12pt; }
.center { text-align: center; font-weight: bold; font-size: 12pt; margin-bottom: 4pt; }
.star { padding-left: 12pt; font-size: 11pt; color: #444; margin-bottom: 4pt; }
其中 CN_FONT_RULE:
- 有 CN_FONT_URL 时:
@font-face { font-family: 'CJKFont'; src: url('CN_FONT_URL'); } - 无 CN_FONT_URL 时:留空
文章内容到 HTML 的映射规则:
| 文章元素 | HTML 输出 |
|---------|----------|
| 文章标题 | <h1> |
| 二级标题(##) | <h2> |
| 正文段落 | <p> |
| 粗体强调 | <p class="bold"> |
| 注意事项/提示框 | <div class="note"> |
| 列表项 | <p class="bullet">• 内容</p> |
| 图片 | <img src="file:///WORK_DIR/imgX.jpeg"> 使用绝对路径 |
| 图片说明 | <p class="caption">说明文字</p> |
| 表格 | <table><tr><th>/<td> |
| 分隔线 | <div class="divider">— — — —</div> |
| 结尾引导语 | <p class="star"> |
清洗规则:排除以下所有内容:
- 作者/公众号名称、原创声明、"修改于"
- "预览时标签不可点" 等无关标签
- 分享引导语、关注引导、小程序控件
- 广告、商业推广信息
HTML 文件保存路径:<WORK_DIR>/article.html
Step 9: 转换 HTML → PDF
node "<SKILL_DIR>/scripts/html2pdf.cjs" "<WORK_DIR>/article.html" "<WORK_DIR>/文章标题.pdf"
Step 10: 交付 PDF
用 deliver_attachments 将生成的 PDF 文件交付给用户。
注意事项
- IMA 技能更新:如果
ima_api.cjs返回code=-200(有新版),先按指引更新 skill 版本再继续 - 微信图片防盗链:如果
curl下载失败(文件极小),重试时添加-e "https://mp.weixin.qq.com/"Referer - Emoji 渲染:系统字体通常不支持彩色 emoji(⭐ ⚠️),用
*替代⭐,!替代⚠️ - PDF 文本提取:Chromium 生成的 PDF 使用 CID 编码,文本提取工具可能无法读取中文,但视觉渲染完全正常
微信扫一扫