yuanflow-cli 0.1.34 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/yuanflow-skill/README.md +13 -0
- package/skills/yuanflow-skill/SKILL.md +31 -3
- package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/SKILL.md +27 -11
- package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/references/wechat-official-api.md +16 -0
- package/skills/yuanflow-skill//345/205/254/344/274/227/345/217/267/347/224/237/346/210/220/344/270/216/345/217/221/345/270/203/scripts/wechat_draft.py +73 -23
- package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/344/270/216/345/217/221/345/270/203/SKILL.md +147 -0
- package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/344/270/216/345/217/221/345/270/203/references/commands.md +39 -0
- package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/344/270/216/345/217/221/345/270/203/references/interaction-policy.md +20 -0
- package/skills/yuanflow-skill//345/260/217/347/272/242/344/271/246/350/277/220/350/220/245/344/270/216/345/217/221/345/270/203/references/publishing-policy.md +34 -0
package/package.json
CHANGED
|
@@ -9,6 +9,8 @@ YuanFlow Skill 是 `yuanflow-cli` 的 Agent Skill 仓库,用于把社媒平台
|
|
|
9
9
|
- `自媒体知识库/`:自媒体知识库渐进查询 Skill,走 `yuanflow-cli knowledge`。
|
|
10
10
|
- `OSS文件中转工具/`:OSS 临时上传、签名链接、对象复制 Skill,走 `yuanflow-cli oss`。
|
|
11
11
|
- `生图技能/`:图片生成与编辑 Skill,优先走 YuanFlow 内置 `yuanflow_image_request`。
|
|
12
|
+
- `公众号生成与发布/`:公众号文章创作、主题预览、微信内联 HTML 排版、正文图片上传和草稿箱推送 Skill。
|
|
13
|
+
- `小红书运营与发布/`:小红书选题调研、笔记搜索、账号分析、评论采集、文案创作、图文/视频发布和互动操作 Skill。
|
|
12
14
|
- `HTML报告生成/`:单页 HTML 报告生成 Skill,内置 9 种米色留白报告模板。
|
|
13
15
|
- `本地音视频转文字/`:本地 SenseVoice 音视频转文字 Skill,首次明确使用时按需下载模型。
|
|
14
16
|
- `音视频在线转文字/`:通过 YuanFlow 在线 ASR 接口把音频或视频转成干净文本,视频会先抽取音频并通过 OSS 中转。
|
|
@@ -32,6 +34,8 @@ YuanFlow Skill 是 `yuanflow-cli` 的 Agent Skill 仓库,用于把社媒平台
|
|
|
32
34
|
- 上传文件到临时 OSS、生成签名链接或复制 OSS 对象。
|
|
33
35
|
- 生成图片、编辑图片,并缓存返回 URL 或 base64 图片。生成图片必填 `prompt`,可选 `size / quality / style / n / response_format`;编辑图片必须通过 multipart 上传本地图片。
|
|
34
36
|
- 把自媒体分析、数据复盘、文案方案、账号监控、知识梳理和执行计划生成可直接打开的单页 HTML 报告。
|
|
37
|
+
- 生成或改写公众号文章,进入主题选择预览后导出微信公众号编辑器可粘贴 HTML,或推送到公众号草稿箱。
|
|
38
|
+
- 处理小红书单段或全流程任务,例如只写文案、只采集笔记、只分析账号、只采集评论、只做点赞收藏评论回复,或完整执行图文/视频发布流程;每轮开始前必须明确任务边界。
|
|
35
39
|
- 在用户明确要求本地转写时,把本地音频或视频转成文字;视频会先抽取音频,模型和缓存都保存在 Skill 自己目录下。
|
|
36
40
|
- 在用户要求在线转写、云端转写或 doubao-asr 时,把本地音频或视频经 OSS 中转后提交在线 ASR,默认只返回干净文本。
|
|
37
41
|
- 在用户要求自媒体平台浏览器自动化、账号登录态隔离、Cookie/profile 保存、平台页面采集或作品发布时,使用专用自媒体浏览器自动化 Skill;普通网页浏览和搜索仍使用通用浏览器能力。
|
|
@@ -99,6 +103,15 @@ yuanflow-skill list-skills
|
|
|
99
103
|
│ └─ SKILL.md
|
|
100
104
|
├─ 生图技能
|
|
101
105
|
│ └─ SKILL.md
|
|
106
|
+
├─ 公众号生成与发布
|
|
107
|
+
│ ├─ SKILL.md
|
|
108
|
+
│ ├─ scripts/
|
|
109
|
+
│ ├─ themes/
|
|
110
|
+
│ ├─ references/
|
|
111
|
+
│ └─ tests/
|
|
112
|
+
├─ 小红书运营与发布
|
|
113
|
+
│ ├─ SKILL.md
|
|
114
|
+
│ └─ references/
|
|
102
115
|
├─ HTML报告生成
|
|
103
116
|
│ ├─ SKILL.md
|
|
104
117
|
│ ├─ templates/
|
|
@@ -21,6 +21,8 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
|
|
|
21
21
|
- `自媒体知识库/`
|
|
22
22
|
- `OSS文件中转工具/`
|
|
23
23
|
- `生图技能/`
|
|
24
|
+
- `公众号生成与发布/`
|
|
25
|
+
- `小红书运营与发布/`
|
|
24
26
|
- `HTML报告生成/`
|
|
25
27
|
- `本地音视频转文字/`
|
|
26
28
|
- `音视频在线转文字/`
|
|
@@ -219,7 +221,33 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
|
|
|
219
221
|
|
|
220
222
|
- `HTML报告生成`
|
|
221
223
|
|
|
222
|
-
### 14. 走
|
|
224
|
+
### 14. 走 `公众号生成与发布`
|
|
225
|
+
|
|
226
|
+
遇到下面这些需求,优先进入这个子 Skill:
|
|
227
|
+
|
|
228
|
+
- 公众号文章创作、改写、润色、排版、主题预览或导出 HTML。
|
|
229
|
+
- 用户要求把 Markdown 转成微信公众号编辑器可粘贴的内联样式 HTML。
|
|
230
|
+
- 用户要求上传正文图片、生成封面建议,或推送到微信公众号草稿箱。
|
|
231
|
+
|
|
232
|
+
子 Skill 名称:
|
|
233
|
+
|
|
234
|
+
- `公众号生成与发布`
|
|
235
|
+
|
|
236
|
+
### 15. 走 `小红书运营与发布`
|
|
237
|
+
|
|
238
|
+
遇到下面这些需求,优先进入这个子 Skill:
|
|
239
|
+
|
|
240
|
+
- 小红书选题调研、笔记搜索、账号分析、评论采集、图文或视频发布。
|
|
241
|
+
- 用户要求写小红书文案、准备发布笔记、检查素材、生成话题标签。
|
|
242
|
+
- 用户要求对小红书笔记点赞、收藏、评论或回复。
|
|
243
|
+
|
|
244
|
+
它可以执行完整流程,也可以只做部分能力。每次开始前必须先明确用户本轮任务边界:只写文案、只采集、只分析、只互动、只发布,还是完整流程。
|
|
245
|
+
|
|
246
|
+
子 Skill 名称:
|
|
247
|
+
|
|
248
|
+
- `小红书运营与发布`
|
|
249
|
+
|
|
250
|
+
### 16. 走 `个人创作库`
|
|
223
251
|
|
|
224
252
|
遇到下面这些需求,优先进入这个子 Skill:
|
|
225
253
|
|
|
@@ -233,7 +261,7 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
|
|
|
233
261
|
|
|
234
262
|
- `个人创作库`
|
|
235
263
|
|
|
236
|
-
###
|
|
264
|
+
### 17. 走 `本地音视频转文字`
|
|
237
265
|
|
|
238
266
|
只有当用户明确要求使用本地音视频转文字、本地转写、本地 ASR、离线转写或本地模型把音频/视频转成文字时,才进入这个子 Skill。
|
|
239
267
|
|
|
@@ -243,7 +271,7 @@ description: 当用户需要处理自媒体平台接口工作流、平台数据
|
|
|
243
271
|
|
|
244
272
|
- `本地音视频转文字`
|
|
245
273
|
|
|
246
|
-
###
|
|
274
|
+
### 18. 走 `音视频在线转文字`
|
|
247
275
|
|
|
248
276
|
遇到下面这些需求,优先进入这个子 Skill:
|
|
249
277
|
|
|
@@ -5,7 +5,7 @@ description: 当用户需要公众号文章创作、文章改写、Markdown 排
|
|
|
5
5
|
|
|
6
6
|
# 公众号生成与发布
|
|
7
7
|
|
|
8
|
-
本 Skill 用于把公众号文章从“需求确认、内容生成、排版预览、导出 HTML
|
|
8
|
+
本 Skill 用于把公众号文章从“需求确认、内容生成、排版预览、导出 HTML、新增或更新草稿箱草稿”串成一个可控流程。它可以一次性完成全流程,也可以只做其中一段,例如只写文章、只生成封面建议、只做排版预览、只新增草稿或更新已有草稿。
|
|
9
9
|
|
|
10
10
|
## 分类
|
|
11
11
|
|
|
@@ -22,7 +22,7 @@ description: 当用户需要公众号文章创作、文章改写、Markdown 排
|
|
|
22
22
|
- 用户没有要求正文插图时:不要擅自生成插图;只处理文字正文和可选封面。
|
|
23
23
|
5. 排版结果使用 Markdown 还是 HTML。
|
|
24
24
|
- 如果选择 HTML,会把 Markdown 转成微信公众号编辑器可粘贴的内联样式 HTML。
|
|
25
|
-
6.
|
|
25
|
+
6. 是否需要写入微信公众号草稿箱,并确认是新增草稿还是更新已有草稿。更新已有草稿时必须先拿到目标草稿的 `media_id`,多图文还要确认更新第几篇,第一篇 `index=0`。草稿箱只负责生成或更新草稿,正式发布必须由用户自行在公众号后台确认。
|
|
26
26
|
|
|
27
27
|
## 内容创作流程
|
|
28
28
|
|
|
@@ -63,7 +63,7 @@ Agent 在排版前应做结构化增强,但不能改变事实:
|
|
|
63
63
|
- 用户要求生成插图:调用 `生图技能` 生成图片,使用工具返回的本地缓存路径插入 Markdown。
|
|
64
64
|
- 用户只要求封面:只生成或使用封面,不在正文里额外插图。
|
|
65
65
|
|
|
66
|
-
使用生图技能生成公众号封面或正文插图时,不能只凭当前文章主题临时想象一个空泛提示词。必须先查看 `生图技能`
|
|
66
|
+
使用生图技能生成公众号封面或正文插图时,不能只凭当前文章主题临时想象一个空泛提示词。必须先查看 `生图技能` 的提示词参考目录,优先根据参考文件的标题、目录或小节名判断有没有适合当前用户需求或间接相近方向的内容,例如知识卡、信息图、海报封面、科技商业插画、人物/场景图、产品图或编辑部视觉;发现相近方向后再进入对应小节阅读参考。不要求每次完整查看所有提示词,也不要机械逐篇浏览。读取后只借鉴其中的构图、镜头、版式、材质、灯光、信息层级、文字约束和负面提示写法,再结合当前公众号主题重写成新的高质量中文提示词;不要原样复制案例,不要带入无关品牌、人物、Logo、水印或英文占位字。若参考库没有完全匹配的方向,也要选择最接近的视觉类型作为结构参考,再生成更具体的画面规划。
|
|
67
67
|
|
|
68
68
|
生成公众号正文插图时必须遵守中文默认规则:
|
|
69
69
|
|
|
@@ -72,7 +72,9 @@ Agent 在排版前应做结构化增强,但不能改变事实:
|
|
|
72
72
|
- 如果文章段落确实需要图中文字,只允许使用与文章一致的简体中文短句,并明确列出具体中文文字。
|
|
73
73
|
- 除非用户明确要求英文或双语,不要在正文插图、封面图或预览图里生成英文。
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
写入草稿箱时使用 `scripts/wechat_draft.py`。
|
|
76
|
+
|
|
77
|
+
新增草稿示例:
|
|
76
78
|
|
|
77
79
|
```bash
|
|
78
80
|
python scripts/wechat_draft.py \
|
|
@@ -85,22 +87,36 @@ python scripts/wechat_draft.py \
|
|
|
85
87
|
--json
|
|
86
88
|
```
|
|
87
89
|
|
|
90
|
+
更新已有草稿示例:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python scripts/wechat_draft.py \
|
|
94
|
+
--credentials-file "D:\path\to\wechat-credentials.txt" \
|
|
95
|
+
--input article.md \
|
|
96
|
+
--theme newspaper \
|
|
97
|
+
--draft-media-id MEDIA_ID \
|
|
98
|
+
--draft-index 0 \
|
|
99
|
+
--output-dir dist \
|
|
100
|
+
--update-draft \
|
|
101
|
+
--json
|
|
102
|
+
```
|
|
103
|
+
|
|
88
104
|
执行顺序:
|
|
89
105
|
|
|
90
106
|
1. 读取或生成 Markdown 正文,确保正文里的本地图片路径真实存在。
|
|
91
107
|
2. 先用 `wechat_format.py` 完成主题排版和本地预览。
|
|
92
|
-
3.
|
|
108
|
+
3. 如果要新增或更新草稿箱,再用 `wechat_draft.py`:
|
|
93
109
|
- 获取 `access_token`。
|
|
94
110
|
- 上传正文图片到 `/cgi-bin/media/uploadimg`,替换正文图片地址。
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
4. 返回草稿 `media_id
|
|
111
|
+
- 新增草稿时必须上传或提供封面图 `thumb_media_id`,再调用 `/cgi-bin/draft/add` 创建草稿箱草稿。
|
|
112
|
+
- 更新已有草稿时必须提供 `--draft-media-id` 和 `--draft-index`,调用 `/cgi-bin/draft/update` 更新指定图文。更新接口不是局部 patch,需要按接口要求重新提交该篇文章的完整 `articles` 对象;如果只改正文且不换封面,可以不传封面。
|
|
113
|
+
4. 返回草稿 `media_id` 或更新结果、本地 `draft_payload.json`、`wechat.html`、`preview.html` 和图片上传映射。
|
|
98
114
|
|
|
99
115
|
接口细节需要确认时,读取 `references/wechat-official-api.md`,不要凭记忆改接口路径。
|
|
100
116
|
|
|
101
117
|
安全要求:
|
|
102
118
|
|
|
103
|
-
-
|
|
119
|
+
- 真实新增草稿必须显式传入 `--push-draft`;真实更新草稿必须显式传入 `--update-draft`、`--draft-media-id` 和 `--draft-index`。否则只生成本地 HTML 和草稿 payload。
|
|
104
120
|
- 不要在对话、工作台或日志里输出 AppSecret、access_token。
|
|
105
121
|
- 如果微信接口返回 IP 白名单、权限不足、未认证、额度不足等错误,要把错误原因原样归类说明,不要假装成功。
|
|
106
122
|
|
|
@@ -169,7 +185,7 @@ python scripts/wechat_format.py --input article.md --theme newspaper --output di
|
|
|
169
185
|
2. `option_grid`:主题卡片和文章预览结果。主题卡片必须带 `intent: select_wechat_theme`、`payload.theme` 和 `instruction`,让用户点击后形成待执行任务。
|
|
170
186
|
3. `preview_frame`:手机样式 HTML 预览。
|
|
171
187
|
4. `editor_panel`:Markdown 或 HTML 源码。
|
|
172
|
-
5. `action_bar`:导出 HTML
|
|
188
|
+
5. `action_bar`:导出 HTML、新增草稿、更新已有草稿、继续改写等动作。
|
|
173
189
|
|
|
174
190
|
## 公众号凭证
|
|
175
191
|
|
|
@@ -187,7 +203,7 @@ python scripts/wechat_format.py --input article.md --theme newspaper --output di
|
|
|
187
203
|
|
|
188
204
|
封面不使用第三方生成接口。需要封面时,使用 YuanFlow 内置生图技能生成。
|
|
189
205
|
|
|
190
|
-
|
|
206
|
+
生成封面前同样必须先查看 `生图技能/references/image-prompt-reference.md` 的标题、目录或小节名,选择与文章定位最接近的封面、海报、知识卡、商业科技视觉或信息图方向作为参考;只需进入相近方向阅读,不需要完整扫完所有提示词。封面提示词要把文章主题、目标读者、视觉主元素、构图层级、比例、中文文字规则和负面约束写清楚,避免只写“生成一张某主题封面图”这类空泛需求。
|
|
191
207
|
|
|
192
208
|
建议比例:
|
|
193
209
|
|
|
@@ -61,8 +61,24 @@ JSON:{"articles":[...]}
|
|
|
61
61
|
- `need_open_comment`
|
|
62
62
|
- `only_fans_can_comment`
|
|
63
63
|
|
|
64
|
+
5. 更新草稿
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
POST https://api.weixin.qq.com/cgi-bin/draft/update?access_token=ACCESS_TOKEN
|
|
68
|
+
JSON:{"media_id":"MEDIA_ID","index":0,"articles":{...}}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
核心字段:
|
|
72
|
+
|
|
73
|
+
- `media_id`:要修改的图文消息草稿 ID
|
|
74
|
+
- `index`:要更新的文章位置,第一篇为 `0`
|
|
75
|
+
- `articles`:新的图文信息对象,不是数组
|
|
76
|
+
|
|
77
|
+
更新草稿不是局部 patch。调用时应按官方字段重新提交指定 `index` 这一篇文章的完整内容对象。正文内图片仍必须先走 `/cgi-bin/media/uploadimg`,封面如需更新则传 `thumb_media_id`;如果只更新正文且不更换封面,可以不传新的封面。
|
|
78
|
+
|
|
64
79
|
## 执行约束
|
|
65
80
|
|
|
66
81
|
- 真实创建草稿必须显式使用 `--push-draft`。
|
|
82
|
+
- 真实更新草稿必须显式使用 `--update-draft`,并提供 `--draft-media-id` 和 `--draft-index`。
|
|
67
83
|
- 不要输出 AppSecret 或 access_token。
|
|
68
84
|
- 微信返回错误时保留 `errcode/errmsg`,并把错误归因到白名单、凭证、素材、草稿权限或额度。
|
|
@@ -18,6 +18,7 @@ WECHAT_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"
|
|
|
18
18
|
WECHAT_UPLOAD_ARTICLE_IMAGE_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"
|
|
19
19
|
WECHAT_ADD_MATERIAL_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material"
|
|
20
20
|
WECHAT_ADD_DRAFT_URL = "https://api.weixin.qq.com/cgi-bin/draft/add"
|
|
21
|
+
WECHAT_UPDATE_DRAFT_URL = "https://api.weixin.qq.com/cgi-bin/draft/update"
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class WechatApiError(RuntimeError):
|
|
@@ -171,29 +172,31 @@ def _truncate_utf8(value: str, max_bytes: int) -> str:
|
|
|
171
172
|
return encoded[:max_bytes].decode("utf-8", errors="ignore").rstrip()
|
|
172
173
|
|
|
173
174
|
|
|
174
|
-
def
|
|
175
|
+
def build_draft_article(
|
|
175
176
|
*,
|
|
176
177
|
title: str,
|
|
177
178
|
author: str,
|
|
178
179
|
digest: str,
|
|
179
180
|
content: str,
|
|
180
|
-
thumb_media_id: str,
|
|
181
|
+
thumb_media_id: str = "",
|
|
181
182
|
content_source_url: str = "",
|
|
182
183
|
) -> dict[str, Any]:
|
|
183
|
-
|
|
184
|
-
"
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"thumb_media_id": thumb_media_id,
|
|
192
|
-
"need_open_comment": 0,
|
|
193
|
-
"only_fans_can_comment": 0,
|
|
194
|
-
}
|
|
195
|
-
]
|
|
184
|
+
article = {
|
|
185
|
+
"title": _truncate_utf8(title, 64),
|
|
186
|
+
"author": author,
|
|
187
|
+
"digest": _truncate_utf8(digest, 54),
|
|
188
|
+
"content": content,
|
|
189
|
+
"content_source_url": content_source_url,
|
|
190
|
+
"need_open_comment": 0,
|
|
191
|
+
"only_fans_can_comment": 0,
|
|
196
192
|
}
|
|
193
|
+
if thumb_media_id:
|
|
194
|
+
article["thumb_media_id"] = thumb_media_id
|
|
195
|
+
return article
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def build_draft_payload(*, article: dict[str, Any]) -> dict[str, Any]:
|
|
199
|
+
return {"articles": [article]}
|
|
197
200
|
|
|
198
201
|
|
|
199
202
|
def add_draft(access_token: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -207,7 +210,36 @@ def add_draft(access_token: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
|
207
210
|
)
|
|
208
211
|
|
|
209
212
|
|
|
213
|
+
def update_draft(
|
|
214
|
+
access_token: str,
|
|
215
|
+
*,
|
|
216
|
+
media_id: str,
|
|
217
|
+
index: int,
|
|
218
|
+
article: dict[str, Any],
|
|
219
|
+
) -> dict[str, Any]:
|
|
220
|
+
if not media_id.strip():
|
|
221
|
+
raise WechatApiError("draft-media-id-missing", "更新草稿必须提供 --draft-media-id。")
|
|
222
|
+
body = json.dumps(
|
|
223
|
+
{
|
|
224
|
+
"media_id": media_id.strip(),
|
|
225
|
+
"index": index,
|
|
226
|
+
"articles": article,
|
|
227
|
+
},
|
|
228
|
+
ensure_ascii=False,
|
|
229
|
+
).encode("utf-8")
|
|
230
|
+
return _request_json(
|
|
231
|
+
"POST",
|
|
232
|
+
WECHAT_UPDATE_DRAFT_URL,
|
|
233
|
+
params={"access_token": access_token},
|
|
234
|
+
data=body,
|
|
235
|
+
headers={"Content-Type": "application/json; charset=utf-8"},
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
210
239
|
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
240
|
+
if args.push_draft and args.update_draft:
|
|
241
|
+
raise WechatApiError("draft-operation-conflict", "--push-draft 和 --update-draft 不能同时使用。")
|
|
242
|
+
|
|
211
243
|
input_path = Path(args.input).resolve()
|
|
212
244
|
output_dir = Path(args.output_dir).resolve()
|
|
213
245
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -222,14 +254,15 @@ def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
222
254
|
access_token_status = "skipped"
|
|
223
255
|
|
|
224
256
|
credentials = {"app_id": "", "app_secret": ""}
|
|
225
|
-
|
|
257
|
+
will_write_draft = bool(args.push_draft or args.update_draft)
|
|
258
|
+
if will_write_draft or args.credentials_file or args.app_id or args.app_secret:
|
|
226
259
|
credentials = _load_credentials(
|
|
227
260
|
Path(args.credentials_file).resolve() if args.credentials_file else None,
|
|
228
261
|
args.app_id,
|
|
229
262
|
args.app_secret,
|
|
230
263
|
)
|
|
231
264
|
|
|
232
|
-
if
|
|
265
|
+
if will_write_draft:
|
|
233
266
|
access_token = get_access_token(credentials["app_id"], credentials["app_secret"])
|
|
234
267
|
access_token_status = "ok"
|
|
235
268
|
markdown, image_uploads = upload_and_replace_markdown_images(markdown, input_path.parent, access_token)
|
|
@@ -245,10 +278,8 @@ def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
245
278
|
uploaded_markdown_path.write_text(markdown, encoding="utf-8")
|
|
246
279
|
|
|
247
280
|
cover_media_id = args.thumb_media_id.strip()
|
|
248
|
-
if
|
|
281
|
+
if will_write_draft and not cover_media_id and args.cover_image:
|
|
249
282
|
cover_image = Path(args.cover_image).resolve() if args.cover_image else None
|
|
250
|
-
if not cover_image:
|
|
251
|
-
raise WechatApiError("cover-image-required", "推送草稿箱必须提供 --cover-image 或 --thumb-media-id。")
|
|
252
283
|
if not cover_image.exists() or not cover_image.is_file():
|
|
253
284
|
raise WechatApiError("cover-image-not-found", f"封面图片不存在:{cover_image}")
|
|
254
285
|
try:
|
|
@@ -261,8 +292,11 @@ def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
261
292
|
cover_upload = {"source": str(cover_image), "media_id": cover_media_id}
|
|
262
293
|
|
|
263
294
|
draft_payload: dict[str, Any] | None = None
|
|
264
|
-
|
|
265
|
-
|
|
295
|
+
draft_article: dict[str, Any] | None = None
|
|
296
|
+
if args.push_draft and not cover_media_id:
|
|
297
|
+
raise WechatApiError("cover-image-required", "新增草稿必须提供 --cover-image 或 --thumb-media-id。")
|
|
298
|
+
if cover_media_id or args.update_draft:
|
|
299
|
+
draft_article = build_draft_article(
|
|
266
300
|
title=title,
|
|
267
301
|
author=author,
|
|
268
302
|
digest=args.digest.strip() or _plain_text_digest(markdown),
|
|
@@ -270,6 +304,9 @@ def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
270
304
|
content_source_url=args.content_source_url.strip(),
|
|
271
305
|
thumb_media_id=cover_media_id,
|
|
272
306
|
)
|
|
307
|
+
draft_payload = build_draft_payload(
|
|
308
|
+
article=draft_article,
|
|
309
|
+
)
|
|
273
310
|
draft_payload_path = output_dir / "draft_payload.json"
|
|
274
311
|
draft_payload_path.write_text(json.dumps(draft_payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
275
312
|
else:
|
|
@@ -279,10 +316,20 @@ def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
279
316
|
if not draft_payload:
|
|
280
317
|
raise WechatApiError("draft-payload-missing", "草稿 payload 未生成。")
|
|
281
318
|
draft_result = add_draft(access_token, draft_payload)
|
|
319
|
+
elif args.update_draft:
|
|
320
|
+
if not draft_article:
|
|
321
|
+
raise WechatApiError("draft-payload-missing", "草稿更新 payload 未生成。")
|
|
322
|
+
draft_result = update_draft(
|
|
323
|
+
access_token,
|
|
324
|
+
media_id=args.draft_media_id,
|
|
325
|
+
index=args.draft_index,
|
|
326
|
+
article=draft_article,
|
|
327
|
+
)
|
|
282
328
|
|
|
283
329
|
result = {
|
|
284
330
|
"ok": True,
|
|
285
|
-
"pushed":
|
|
331
|
+
"pushed": will_write_draft,
|
|
332
|
+
"operation": "update" if args.update_draft else ("add" if args.push_draft else "preview"),
|
|
286
333
|
"title": title,
|
|
287
334
|
"theme": args.theme,
|
|
288
335
|
"account": {
|
|
@@ -323,6 +370,9 @@ def main() -> int:
|
|
|
323
370
|
parser.add_argument("--app-id", default="", help="微信公众号 AppID")
|
|
324
371
|
parser.add_argument("--app-secret", default="", help="微信公众号 AppSecret")
|
|
325
372
|
parser.add_argument("--push-draft", action="store_true", help="显式创建草稿箱草稿;不传则只生成本地文件和 payload")
|
|
373
|
+
parser.add_argument("--update-draft", action="store_true", help="显式更新已有草稿;需同时提供 --draft-media-id")
|
|
374
|
+
parser.add_argument("--draft-media-id", default="", help="要更新的已有草稿 media_id")
|
|
375
|
+
parser.add_argument("--draft-index", type=int, default=0, help="要更新的图文位置,第一篇为 0")
|
|
326
376
|
parser.add_argument("--json", action="store_true", help="输出 JSON")
|
|
327
377
|
args = parser.parse_args()
|
|
328
378
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 小红书运营与发布
|
|
3
|
+
description: 当用户需要小红书选题调研、文案创作、笔记搜索、账号分析、评论采集、图文或视频发布、点赞收藏评论回复等小红书运营任务时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 小红书运营与发布
|
|
7
|
+
|
|
8
|
+
本 Skill 用于把小红书任务从“明确边界、采集分析、内容创作、素材检查、登录确认、发布执行、互动操作、结果回报”串成一个可控流程。它拥有完整能力,但用户可以只使用其中一部分,例如只写文案、只采集笔记、只分析账号、只采集评论、只做发布前检查,或一次性完成完整运营流程。
|
|
9
|
+
|
|
10
|
+
## 分类
|
|
11
|
+
|
|
12
|
+
自媒体技能区
|
|
13
|
+
|
|
14
|
+
## 开始前必须确认
|
|
15
|
+
|
|
16
|
+
1. 本轮任务边界:只做调研、只写文案、只采集、只分析账号、只互动、只发布,还是完整流程。
|
|
17
|
+
2. 目标对象:关键词、笔记链接、笔记 ID、账号主页、用户 ID、本地图片、本地视频或已有文案。
|
|
18
|
+
3. 是否需要真实执行写操作:发布、评论、回复、点赞、收藏都属于写操作。
|
|
19
|
+
4. 发布确认策略:
|
|
20
|
+
- 默认每次真实发布前必须向用户确认。
|
|
21
|
+
- 如果用户明确说“后续都自动直接发布”“这个账号以后不用重复问”,可以把该偏好作为用户记忆;后续同类任务不重复确认,但仍需在执行结果里说明已按用户记忆自动执行。
|
|
22
|
+
5. 评论和回复默认必须确认;点赞、收藏可按用户明确指令直接执行。
|
|
23
|
+
6. 登录态使用 YuanFlow 独立浏览器配置,不要求用户复用默认 Chrome,不读取用户默认浏览器 Cookie。
|
|
24
|
+
|
|
25
|
+
## 能力分流
|
|
26
|
+
|
|
27
|
+
| 用户意图 | 优先流程 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| 搜索笔记、找素材、查热点 | 使用小红书搜索能力,必要时读取笔记详情 |
|
|
30
|
+
| 账号分析、竞品分析 | 搜索用户或读取用户主页,再采集近期笔记 |
|
|
31
|
+
| 评论采集、用户反馈分析 | 使用评论采集能力,必要时继续采集二级评论 |
|
|
32
|
+
| 写小红书文案 | 先确认产品、受众、风格、字数、是否需要图片,再创作文案 |
|
|
33
|
+
| 发布图文笔记 | 检查标题、正文、图片、话题、可见性、账号登录态,再发布 |
|
|
34
|
+
| 发布视频笔记 | 检查标题、正文、视频、封面、话题、可见性、账号登录态,再发布 |
|
|
35
|
+
| 点赞、收藏、评论、回复 | 先确认目标笔记和动作,评论/回复需确认具体文本 |
|
|
36
|
+
|
|
37
|
+
## YuanFlow 调用优先级
|
|
38
|
+
|
|
39
|
+
1. 当前在 YuanFlow 内时,优先使用受控工具 `yuanflow_cli_call`,不要让用户手动安装 npm,也不要暴露 token。
|
|
40
|
+
2. 数据读取优先使用 `yuanflow-cli` 已有小红书接口和通用自媒体 Skill。
|
|
41
|
+
3. 登录、发布、浏览器任务优先使用 YuanFlow 独立浏览器配置和自媒体浏览器自动化能力。
|
|
42
|
+
4. 当前环境没有受控工具但本地存在 `yuanflow-cli` 时,再使用本地 CLI。
|
|
43
|
+
5. 不使用独立小红书 MCP,不要求用户配置 MCP server。
|
|
44
|
+
|
|
45
|
+
## 常用 CLI 映射
|
|
46
|
+
|
|
47
|
+
数据读取优先使用这些稳定能力:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
yuanflow-cli xiaohongshu web-v3 fetch-search-notes --keyword "关键词" --format agent-json
|
|
51
|
+
yuanflow-cli xiaohongshu web-v3 fetch-search-users --keyword "关键词" --format agent-json
|
|
52
|
+
yuanflow-cli xiaohongshu web-v3 fetch-note-detail --note_id "笔记ID" --format agent-json
|
|
53
|
+
yuanflow-cli xiaohongshu web-v3 fetch-note-comments --note_id "笔记ID" --format agent-json
|
|
54
|
+
yuanflow-cli xiaohongshu web-v3 fetch-user-notes --user_id "用户ID" --format agent-json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
也可以按任务使用通用命令:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
yuanflow-cli search content --platform xiaohongshu --keyword "关键词" --format agent-json
|
|
61
|
+
yuanflow-cli search users --platform xiaohongshu --keyword "关键词" --format agent-json
|
|
62
|
+
yuanflow-cli works detail --platform xiaohongshu --target "笔记链接或笔记ID" --format agent-json
|
|
63
|
+
yuanflow-cli comments collect --platform xiaohongshu --target "笔记链接或笔记ID" --format agent-json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
浏览器登录和发布前检查使用:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
yuanflow-cli browser session-init --platform xiaohongshu --account main --format agent-json
|
|
70
|
+
yuanflow-cli browser profile-path --platform xiaohongshu --account main --format agent-json
|
|
71
|
+
yuanflow-cli browser task-plan --platform xiaohongshu --task login --format agent-json
|
|
72
|
+
yuanflow-cli browser dry-run --platform xiaohongshu --task publish --title "标题" --caption "正文" --file "D:\path\image.png" --format agent-json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 调研与采集流程
|
|
76
|
+
|
|
77
|
+
1. 先确认关键词、目标人群、调研目的和结果格式。
|
|
78
|
+
2. 搜索笔记时优先返回标题、作者、发布时间、互动数据、封面/图片、链接或 note_id。
|
|
79
|
+
3. 用户要求“完整分析”时,不只返回列表,要继续读取代表性笔记详情。
|
|
80
|
+
4. 评论采集需要明确采集范围:只采集一级评论、是否采集回复、数量上限、是否导出。
|
|
81
|
+
5. 输出分析时必须区分“数据事实”和“运营判断”,不要把推测写成事实。
|
|
82
|
+
|
|
83
|
+
## 文案创作流程
|
|
84
|
+
|
|
85
|
+
1. 先确认任务边界:只写标题、只写正文、标题+正文、发布版笔记、种草文案、测评文案、探店文案、合集文案或完整发布流程。
|
|
86
|
+
2. 确认账号定位、目标用户、产品/主题、语气风格、禁忌表达、字数范围、是否需要话题标签。
|
|
87
|
+
3. 如果用户要求参考平台趋势,先采集或搜索同类笔记,再创作。
|
|
88
|
+
4. 输出小红书文案时默认包含:
|
|
89
|
+
- 标题候选
|
|
90
|
+
- 正文
|
|
91
|
+
- 话题标签
|
|
92
|
+
- 配图建议
|
|
93
|
+
- 发布注意事项
|
|
94
|
+
5. 用户只要求“写文案”时,不擅自进入发布流程。
|
|
95
|
+
|
|
96
|
+
## 发布流程
|
|
97
|
+
|
|
98
|
+
### 图文笔记
|
|
99
|
+
|
|
100
|
+
1. 检查标题、正文、图片列表、话题、可见性、发布时间和目标账号。
|
|
101
|
+
2. 图片必须是本地可访问路径或 YuanFlow 资源路径。
|
|
102
|
+
3. 标题应符合小红书长度限制,过长时先给用户改写建议。
|
|
103
|
+
4. 默认发布前确认;用户已明确授权自动发布时,可直接执行。
|
|
104
|
+
5. 发布失败时报告失败阶段:未登录、素材不存在、上传失败、页面元素变化、提交失败或平台风控。
|
|
105
|
+
|
|
106
|
+
### 视频笔记
|
|
107
|
+
|
|
108
|
+
1. 检查标题、正文、视频路径、封面、话题、可见性、发布时间和目标账号。
|
|
109
|
+
2. 视频路径必须是本地可访问文件。
|
|
110
|
+
3. 不要把图文和视频混成一个发布任务。
|
|
111
|
+
4. 默认发布前确认;用户已明确授权自动发布时,可直接执行。
|
|
112
|
+
|
|
113
|
+
## 互动流程
|
|
114
|
+
|
|
115
|
+
点赞、收藏、评论、回复都需要先定位目标笔记。
|
|
116
|
+
|
|
117
|
+
- 点赞:用户明确要求后可直接执行。
|
|
118
|
+
- 收藏:用户明确要求后可直接执行。
|
|
119
|
+
- 评论:必须确认评论文本,除非用户已经给出明确文本。
|
|
120
|
+
- 回复:必须确认评论 ID 或目标评论内容,并确认回复文本。
|
|
121
|
+
|
|
122
|
+
执行后必须返回:
|
|
123
|
+
|
|
124
|
+
- 动作类型
|
|
125
|
+
- 目标笔记或评论
|
|
126
|
+
- 执行结果
|
|
127
|
+
- 失败原因
|
|
128
|
+
- 是否使用了用户记忆中的自动执行偏好
|
|
129
|
+
|
|
130
|
+
## 输出要求
|
|
131
|
+
|
|
132
|
+
1. 不要只贴原始接口 JSON;必须整理成用户能读懂的结果。
|
|
133
|
+
2. 数据采集类任务要输出关键字段、数量、失败项和下一步建议。
|
|
134
|
+
3. 创作类任务要输出可直接使用的内容,不要只给方法论。
|
|
135
|
+
4. 发布类任务要输出发布状态、目标账号、素材清单和失败原因。
|
|
136
|
+
5. 若任务产生产物文件,说明文件绝对路径。
|
|
137
|
+
6. 不暴露 token、Cookie、Authorization、x-s、x-t 或任何登录敏感信息。
|
|
138
|
+
|
|
139
|
+
## 常见错误
|
|
140
|
+
|
|
141
|
+
- 用户只想写文案,却直接尝试发布。
|
|
142
|
+
- 采集任务没有确认关键词、数量或目标笔记。
|
|
143
|
+
- 发布前没有检查图片/视频路径是否存在。
|
|
144
|
+
- 把小红书 MCP 当成独立安装项使用。
|
|
145
|
+
- 未经确认就评论或回复。
|
|
146
|
+
- 采集结果直接粘 JSON,没有做归纳。
|
|
147
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# 小红书命令参考
|
|
2
|
+
|
|
3
|
+
本文件只记录 YuanFlow 里推荐的命令映射。执行时优先使用 `yuanflow_cli_call`,没有受控工具时才使用本地 `yuanflow-cli`。
|
|
4
|
+
|
|
5
|
+
## 搜索和采集
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
yuanflow-cli search content --platform xiaohongshu --keyword "关键词" --format agent-json
|
|
9
|
+
yuanflow-cli search users --platform xiaohongshu --keyword "关键词" --format agent-json
|
|
10
|
+
yuanflow-cli works detail --platform xiaohongshu --target "笔记链接或笔记ID" --format agent-json
|
|
11
|
+
yuanflow-cli comments collect --platform xiaohongshu --target "笔记链接或笔记ID" --format agent-json
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 原子接口
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
yuanflow-cli xiaohongshu web-v3 fetch-search-notes --keyword "关键词" --format agent-json
|
|
18
|
+
yuanflow-cli xiaohongshu web-v3 fetch-search-users --keyword "关键词" --format agent-json
|
|
19
|
+
yuanflow-cli xiaohongshu web-v3 fetch-note-detail --note_id "笔记ID" --format agent-json
|
|
20
|
+
yuanflow-cli xiaohongshu web-v3 fetch-note-comments --note_id "笔记ID" --format agent-json
|
|
21
|
+
yuanflow-cli xiaohongshu web-v3 fetch-user-notes --user_id "用户ID" --format agent-json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 浏览器配置和发布前检查
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yuanflow-cli browser session-init --platform xiaohongshu --account main --format agent-json
|
|
28
|
+
yuanflow-cli browser profile-path --platform xiaohongshu --account main --format agent-json
|
|
29
|
+
yuanflow-cli browser task-plan --platform xiaohongshu --task login --format agent-json
|
|
30
|
+
yuanflow-cli browser dry-run --platform xiaohongshu --task publish --title "标题" --caption "正文" --file "D:\path\asset.png" --format agent-json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 写操作边界
|
|
34
|
+
|
|
35
|
+
- 发布:默认确认,用户明确记忆自动发布后可跳过重复确认。
|
|
36
|
+
- 点赞和收藏:用户明确要求后可执行。
|
|
37
|
+
- 评论和回复:默认确认文本和目标。
|
|
38
|
+
- 所有失败必须报告失败阶段,不能伪造成功。
|
|
39
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 互动策略
|
|
2
|
+
|
|
3
|
+
## 点赞和收藏
|
|
4
|
+
|
|
5
|
+
用户明确要求对某篇笔记点赞或收藏时,可以执行。执行前需要确认目标笔记能唯一定位。
|
|
6
|
+
|
|
7
|
+
## 评论
|
|
8
|
+
|
|
9
|
+
评论属于公开写操作,默认必须确认评论文本。用户已经给出明确评论内容时,可以视为已确认文本,但仍要确认目标笔记是否唯一。
|
|
10
|
+
|
|
11
|
+
## 回复
|
|
12
|
+
|
|
13
|
+
回复必须确认目标评论或评论 ID,并确认回复文本。不能只凭模糊描述随意回复。
|
|
14
|
+
|
|
15
|
+
## 安全边界
|
|
16
|
+
|
|
17
|
+
- 不发布骚扰、冒充、虚假承诺、违法营销或引导违规交易的内容。
|
|
18
|
+
- 不泄露 Cookie、token、x-s、x-t、Authorization。
|
|
19
|
+
- 不伪造执行成功;平台失败、风控、登录失效都要如实说明。
|
|
20
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 发布策略
|
|
2
|
+
|
|
3
|
+
## 默认确认
|
|
4
|
+
|
|
5
|
+
小红书真实发布默认需要用户确认。用户只说“帮我写”“帮我准备”“帮我生成笔记”时,只输出内容和发布前检查,不直接发布。
|
|
6
|
+
|
|
7
|
+
## 自动发布偏好
|
|
8
|
+
|
|
9
|
+
当用户明确表达“后续都自动发布”“这个账号以后不用重复问”“确认,以后同类任务直接发”时,Agent 可以记录偏好。之后同类任务执行时要说明“已按用户记忆自动发布”,但仍要检查素材、标题和登录态。
|
|
10
|
+
|
|
11
|
+
## 图文笔记
|
|
12
|
+
|
|
13
|
+
- 必须有标题、正文和至少一张图片。
|
|
14
|
+
- 图片必须是本地可访问路径或 YuanFlow 资源路径。
|
|
15
|
+
- 话题标签可以由 Agent 建议,但不能虚构活动、品牌授权或官方背书。
|
|
16
|
+
|
|
17
|
+
## 视频笔记
|
|
18
|
+
|
|
19
|
+
- 必须有标题、正文和本地视频路径。
|
|
20
|
+
- 可选封面图。
|
|
21
|
+
- 视频和图文不要混发。
|
|
22
|
+
|
|
23
|
+
## 失败回报
|
|
24
|
+
|
|
25
|
+
失败时按阶段回报:
|
|
26
|
+
|
|
27
|
+
1. 登录态缺失。
|
|
28
|
+
2. 素材路径不存在。
|
|
29
|
+
3. 页面打开失败。
|
|
30
|
+
4. 上传失败。
|
|
31
|
+
5. 平台页面元素变化。
|
|
32
|
+
6. 提交失败。
|
|
33
|
+
7. 平台风控或限制。
|
|
34
|
+
|