🔄 卡若AI 同步 2026-03-26 18:14 | 更新:Cursor规则、金仓、水溪整理归档、卡木、火炬、总索引与入口、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 12 个
This commit is contained in:
@@ -27,7 +27,7 @@ alwaysApply: true
|
||||
|
||||
## 强制复盘(每次对话结束)
|
||||
|
||||
**每次对话的最后一条回复,必须以完整复盘块收尾。** 格式严格按 `运营中枢/参考资料/卡若复盘格式_固定规则.md`,包含 🎯📌💡📝▶ 五块,带具体日期+时间(YYYY-MM-DD HH:mm)。**🎯 内须写达成率数值%**;**🎯 块全部写完后须单独一行「➡️ 🎯 块后达成率复述:XX%」**;**▶ 块全部写完后须单独一行「📊 复盘结束达成率复述:XX%」**(两处 XX% 须与 🎯 达成率一致)。**项目开发类**(写代码/改仓库/开发文档 1~10/部署/命中火炬「全栈开发」「前端开发」「全栈测试」「项目开发占卜术」等)须在 **➡️ 🎯 行之后、📌 之前** 增加 **☯ 奇门 Q门 3.0(项目盘)** 叠层:含 **盘势总完成度 XX%**、**八门各 YY%+🟢🟡🔴+一句**、**➡️ ☯ 块后盘势复述 XX%**(与盘势总完成度一致);细则与模板见同文件「奇门 Q门 3.0 叠层」节。非开发类可一行简写「八门不起」且盘势与 🎯 同源。不可省略、不可用简版。即使是简单任务也必须复盘。
|
||||
**每次对话的最后一条回复,必须以完整复盘块收尾。** 格式严格按 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**:**🎯📌💡📝▶** 五块,标题带日期+时间(YYYY-MM-DD HH:mm)。**🎯 仅一行一句话、≤50 字(含标点)**,句内包含 **达成率数值(%)**(**可为负**),目标/结果/原奇门体感**全部揉进该句**。**达成率**须与**本回合主交付验收**一致(**视频号等分发**以 **成功条数÷计划条数** 为主口径,见真源文件)。**禁止**:`➡️ 🎯 块后达成率复述`、`📊 复盘结束达成率复述`、标准复盘内**独立** ☯/奇门/八门段;用户**点名起盘**时八门见 `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`,**附在五块之后**。即使是简单任务也必须复盘。速查:`.cursor/skills/karuo-recap-format/SKILL.md`。
|
||||
|
||||
## Soul 创业派对子项目(多根工作区)
|
||||
|
||||
|
||||
19
.cursor/skills/karuo-recap-format/SKILL.md
Normal file
19
.cursor/skills/karuo-recap-format/SKILL.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: karuo-recap-format
|
||||
description: 卡若AI 对话收尾复盘格式 v5.0(🎯 单行一句 ≤50 字、分发达成率、禁复述与标准☯)。触发:复盘格式、卡若复盘、达成率怎么写、视频号分发复盘。
|
||||
---
|
||||
|
||||
# 卡若复盘格式(Cursor Skill · v5.0)
|
||||
|
||||
**真源**:`运营中枢/参考资料/卡若复盘格式_固定规则.md`(须与之一致)。
|
||||
|
||||
## 强制
|
||||
|
||||
- 每轮回复**最后**为完整 **[卡若复盘](YYYY-MM-DD HH:mm)**,含 **🎯📌💡📝▶** 五块;复盘块内**不用表格**。
|
||||
- **🎯 目标·结果·达成率**:**仅一行一句话**,**≤50 字(含标点)**,句内包含 **达成率 %**(**可为负**);目标、结果、原奇门体感**全部揉进这一句**,不单列。
|
||||
- **达成率口径**:以**本回合主交付可验收结果**计;**视频号/多平台分发**以 **实际发表成功条数 ÷ 本批计划条数 ×100%**(去重判定「已在平台」计成功);与交付无关的百分比**禁止**。
|
||||
- **禁止**:`➡️ 🎯 块后达成率复述`、`📊 复盘结束达成率复述`、标准复盘内的 **☯/奇门/八门** 独立段(用户**点名起盘**时按 `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md` **附在五块之后**)。
|
||||
|
||||
## 📌 过程
|
||||
|
||||
须写清**可验收数字**(如 29/29 已发、0 条新发、脚本 exit 等),与 🎯 中达成率**对齐**。
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: 项目开发占卜术(Cursor 入口)
|
||||
description: 卡若AI 火炬 F01c。奇门 Q门 3.0 八门项目盘;用户点名起盘时输出,附在复盘 v4.0 五块之后。触发:项目开发占卜术、Q门3.0、八门复盘、起盘、盘势。
|
||||
description: 卡若AI 火炬 F01c。奇门 Q门 3.0 八门项目盘;用户点名起盘时输出,附在复盘 v5.0 五块之后。触发:项目开发占卜术、Q门3.0、八门复盘、起盘、盘势。
|
||||
---
|
||||
|
||||
# 项目开发占卜术 · Cursor 入口
|
||||
@@ -9,4 +9,4 @@ description: 卡若AI 火炬 F01c。奇门 Q门 3.0 八门项目盘;用户点
|
||||
|
||||
`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`
|
||||
|
||||
**标准对话复盘**(不含八门):`运营中枢/参考资料/卡若复盘格式_固定规则.md` **v4.0**(仅 🎯📌💡📝▶)。
|
||||
**标准对话复盘**(不含八门):`运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**(仅 🎯📌💡📝▶;🎯 单行一句)。
|
||||
|
||||
@@ -1,13 +1,69 @@
|
||||
{
|
||||
"updated": "2026-03-25T21:16:36.209864+00:00",
|
||||
"updated": "2026-03-26T10:12:28.441527+00:00",
|
||||
"conversations": [
|
||||
{
|
||||
"对话ID": "b81e7cbc-274d-4740-9218-a2b3b6cb96bb",
|
||||
"名称": "运行过程讨论",
|
||||
"项目": "未分类",
|
||||
"首条消息": "运行",
|
||||
"创建时间": "2026-03-26T10:11:15.730000+00:00",
|
||||
"消息数量": 33
|
||||
},
|
||||
{
|
||||
"对话ID": "b1ffcd15-47aa-4c86-b099-89a4381c6a29",
|
||||
"名称": "Gitea账号权限设置",
|
||||
"项目": "工具维护",
|
||||
"首条消息": "帮我把这两个账号加到gitea 获得所有项目的上传和下载的权限\n用户1:fsmecx@gmail.com qwre125800.\n\n用户2:1069948207@qq.com wong123321",
|
||||
"创建时间": "2026-03-26T09:53:55.844000+00:00",
|
||||
"消息数量": 42
|
||||
},
|
||||
{
|
||||
"对话ID": "8a294233-3297-4b43-9326-f6746ce9c695",
|
||||
"名称": "Mbti 小程序的 app security",
|
||||
"项目": "开发",
|
||||
"首条消息": "告诉我mbti 小程序的 app sercurt",
|
||||
"创建时间": "2026-03-26T04:18:22.015000+00:00",
|
||||
"消息数量": 17
|
||||
},
|
||||
{
|
||||
"对话ID": "d7e6077a-cae8-4198-b2bc-1f372f0a6d1a",
|
||||
"名称": "Health experiences and cherishing life",
|
||||
"项目": "工具维护",
|
||||
"首条消息": "这个真的一定要注意身体,我真的是24年的3月20号,直接那个几个病,五病同发病症一起来,然后直接进到 ICU 里面,就,然后成为了当当去的那个医院的最严重的,一年来最严重的一个案例之一。然后那个今天看到的那个叫啥?张雪峰嘎了,我跟他同一同年,就差一个月,都是属老鼠的,我感觉这个两年前同样经过这个命运还是后怕,要是没有我老婆的话,这个就不存在这个世界了,所以要珍爱生命。帮我写一条朋友圈,符合卡洛的风格,不超过150个字",
|
||||
"创建时间": "2026-03-26T03:40:59.437000+00:00",
|
||||
"消息数量": 6
|
||||
},
|
||||
{
|
||||
"对话ID": "04b4524a-293f-459f-a363-153524cc0989",
|
||||
"名称": "Service delivery plan and pricing",
|
||||
"项目": "Soul创业",
|
||||
"首条消息": "2万,我们交付的东西有几个?就第一个它的一个流量,第二个那个名片就是上面我们的那个个人介绍给他链接流量进去,对吧?嗯,第三个的话我们是会给他的房间帮他组织一个那个根据他的项目,或者但是要跟我们有关的项目,或者我们给他的一个项目的一些赋能,然后把这个团队给他拉起来,再收上,拉起来那第四个的话给他授上去去解决一些流量的一些问题吗?至少能保证就是差不多200~600个人每场。那自己他自己弄的话应该也能做到100~200个一场,但他能清晰的知道一些主题,让他知道清晰的知道他要做什么,就刚刚说的他要做什么,怎么组建人,怎么分配,然后接下来底部怎么去走,我们给他做这一些的一些交付,就有硬件的。硬件手机流量的交付以及方法论的方交付,以及团队孵化的交付,就做这几个东西。这个我们,那我们基本的收费可能会收到5万到10万之间,只是前期会2万块的一个定金。可以设计成那个可退的吗?可能他一场到两场,他觉得不 OK,直接就退给他了。这些都直接献上千个合同就可以了,就防止一些法律风险。写这个2-5万",
|
||||
"创建时间": "2026-03-25T22:24:14.237000+00:00",
|
||||
"消息数量": 35
|
||||
},
|
||||
{
|
||||
"对话ID": "4540146b-c2ef-400c-8fb5-9defcc316df8",
|
||||
"名称": "身份证相关文件夹查找",
|
||||
"项目": "未分类",
|
||||
"首条消息": "那个查找这台电脑关于身份证的相关的文件夹",
|
||||
"创建时间": "2026-03-25T21:51:56.719000+00:00",
|
||||
"消息数量": 38
|
||||
},
|
||||
{
|
||||
"对话ID": "84ad8880-00c1-4c62-b8ea-d819301c02d2",
|
||||
"名称": "Personal analysis and financial advice",
|
||||
"项目": "Soul创业",
|
||||
"首条消息": "/Users/karuo/Documents/聊天记录\n/Users/karuo/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄\n/Users/karuo/Documents/聊天记录/soul\n/Users/karuo/Documents/聊天记录/soul\n@1、卡若:本人 ,结合这个聊天的所有的那个。所有的聊天记录以及这个。陆逊这里的所有的聊天记录,然后那个。还有 so 上面的聊天记录,你是深度的去阅读像这些内容,然后帮我看一下这个卡洛,它卡洛就我本人经常描述这个人的综合一些东西,然后来看一下那个我最,我应该做什么事情,然后那个华司马那样的钱做什么?赚什么样的钱?嗯,以及投产比整体的分析一下,给我一个我的个人建议",
|
||||
"创建时间": "2026-03-25T21:24:48.262000+00:00",
|
||||
"消息数量": 30
|
||||
},
|
||||
{
|
||||
"对话ID": "118a4821-a10b-44c2-aa04-aecf7164e173",
|
||||
"名称": "项目-升级",
|
||||
"项目": "工具维护",
|
||||
"首条消息": "你这个思路,不是“奇怪”。\n\n本质上是绝大多数人根本没进入的一个层级。\n\n我给你拆干净一点,你这套东西核心就五个字:结构性赚钱模型。\n\n而不是“预测涨跌”。\n\n⸻\n\n一、你不是在赌方向,你是在做“概率套利”\n\n市场上99%的人在干嘛?\n\n就是在赌:\n\t•\t明天涨还是跌\n\t•\t哪个热点更猛\n\t•\t哪个消息更刺激\n\n这叫:方向交易。\n\n而你在干的,是另一件事:\n\n👉 不依赖方向,也能赚钱\n\n你自己其实已经说出来了:\n\t•\t胜率53%已经顶级\n\t•\t没人能预测明天\n\t•\t热点追逐一定亏钱\n\n所以你直接跳过了“预测”这件事。\n\n你干的是:\n\n👉 利用波动本身赚钱\n\n核心就是你说的:\n\t•\t暴跌 → 隐含波动率高\n\t•\t双卖期权 → 收时间价值\n\t•\t持续降低成本\n\n这其实就是典型的:\n\n👉 卖波动率(Short Volatility)策略\n\n⸻\n\n二、你的“99%胜率”,本质是定义问题\n\n你说你胜率99%。\n\n这句话外行听不懂,内行会警惕。\n\n为什么?\n\n因为你把“胜率”定义成了:\n\n👉 只要最终不亏 or 还能继续滚动,就算赢\n\n而不是:\n\n👉 每一笔交易的涨跌\n\n这就非常关键了。\n\n你做的",
|
||||
"创建时间": "2026-03-25T21:10:26.078000+00:00",
|
||||
"消息数量": 24
|
||||
"消息数量": 89
|
||||
},
|
||||
{
|
||||
"对话ID": "8d2eec2c-6213-405f-a482-7fbb10b11084",
|
||||
|
||||
@@ -1 +1 @@
|
||||
2026-03-25
|
||||
2026-03-26
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"updated": "2026-03-25 21:07:35",
|
||||
"date": "2026-03-25",
|
||||
"updated": "2026-03-26 18:11:53",
|
||||
"date": "2026-03-26",
|
||||
"scan_total": 0,
|
||||
"copied_new": 0,
|
||||
"skipped_idempotent": 0,
|
||||
|
||||
@@ -1533,3 +1533,15 @@
|
||||
{"platform": "视频号", "video_path": "/private/tmp/soul_channels_127_128_bundle/说个案例你就懂.mp4", "title": "说个案例你就懂", "success": false, "status": "error", "message": "localStorage 缺少 finder_raw(rawKeyBuff),post_create 会报 300002。请运行: python3 视频号发布/", "elapsed_sec": 0.0, "timestamp": "2026-03-25 14:41:38"}
|
||||
{"platform": "视频号", "video_path": "/private/tmp/soul_channels_127_128_bundle/链接要落到具体事.mp4", "title": "链接要落到具体事", "success": false, "status": "error", "message": "localStorage 缺少 finder_raw(rawKeyBuff),post_create 会报 300002。请运行: python3 视频号发布/", "elapsed_sec": 0.0, "timestamp": "2026-03-25 14:41:43"}
|
||||
{"platform": "视频号", "video_path": "/tmp/soul_channels_127_128_bundle/我之前抖音就这么做.mp4", "title": "我之前抖音就这么做", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=我之前抖音就这么做 | createTime=2026-03-25 14:45 | 无tips)", "screenshot": "/tmp/channels_ss/我之前抖音就这么做_5_before_close.png", "elapsed_sec": 47.91404128074646, "timestamp": "2026-03-25 14:45:28"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第129场_20260320_output/成片/七千店复制拿投资月流水五十万.mp4", "title": "七千店复制拿投资月流水五十万", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=七千店复制拿投资月流水五十万 | createTime=2026-03-26 05:47 | 无tips)", "screenshot": "/tmp/channels_ss/七千店复制拿投资月流水五十万_5_before_close.png", "elapsed_sec": 46.52436590194702, "timestamp": "2026-03-26 05:47:23"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_01_我看你不太好 你不太好 你不太好 你.mp4", "title": "我看你不太好 你不太好 你不太好 你", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=我看你不太好 你不太好 你不太好 你 | createTime=2026-03-26 05:48 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_01_我看你不太好 你不太好 你不太好 你_5_before_close.png", "elapsed_sec": 45.15270709991455, "timestamp": "2026-03-26 05:48:14"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_02_你不太好 你不太好 你不太好 你不太.mp4", "title": "你不太好 你不太好 你不太好 你不太", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=你不太好 你不太好 你不太好 你不太 | createTime=2026-03-26 05:48 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_02_你不太好 你不太好 你不太好 你不太_5_before_close.png", "elapsed_sec": 45.62456488609314, "timestamp": "2026-03-26 05:49:00"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_03_内容库是要干嘛的 前面后面 我跟你说.mp4", "title": "内容库是要干嘛的 前面后面 我跟你说", "success": false, "status": "error", "message": "post_create errCode=300002 request failed", "elapsed_sec": 98.34439396858215, "timestamp": "2026-03-26 05:52:23"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_03_内容库是要干嘛的 前面后面 我跟你说.mp4", "title": "内容库是要干嘛的 前面后面 我跟你说", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=内容库是要干嘛的 前面后面 我跟你说 | createTime=2026-03-26 09:24 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_03_内容库是要干嘛的 前面后面 我跟你说_5_before_close.png", "elapsed_sec": 48.238685846328735, "timestamp": "2026-03-26 09:24:28"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_04_需要优化的点 第一个是 介面优化 第.mp4", "title": "需要优化的点 第一个是 介面优化 第", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=需要优化的点 第一个是 介面优化 第 | createTime=2026-03-26 09:25 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_04_需要优化的点 第一个是 介面优化 第_5_before_close.png", "elapsed_sec": 46.28265976905823, "timestamp": "2026-03-26 09:25:14"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_05_你看关于这块 同步这块 我这里的话是.mp4", "title": "你看关于这块 同步这块 我这里的话是", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=你看关于这块 同步这块 我这里的话是 | createTime=2026-03-26 09:25 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_05_你看关于这块 同步这块 我这里的话是_5_before_close.png", "elapsed_sec": 46.61995196342468, "timestamp": "2026-03-26 09:26:01"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_06_这里搜索 选择要同步 要同步的人 要.mp4", "title": "这里搜索 选择要同步 要同步的人 要", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=这里搜索 选择要同步 要同步的人 要 | createTime=2026-03-26 09:26 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_06_这里搜索 选择要同步 要同步的人 要_5_before_close.png", "elapsed_sec": 45.655829668045044, "timestamp": "2026-03-26 09:26:47"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_07_这样会比较能性化一点 但是活儿是很乱.mp4", "title": "这样会比较能性化一点 但是活儿是很乱", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=这样会比较能性化一点 但是活儿是很乱 | createTime=2026-03-26 09:27 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_07_这样会比较能性化一点 但是活儿是很乱_5_before_close.png", "elapsed_sec": 46.68155598640442, "timestamp": "2026-03-26 09:27:33"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_08_你想是多少好友来干嘛 我才知道 我要.mp4", "title": "你想是多少好友来干嘛 我才知道 我要", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=你想是多少好友来干嘛 我才知道 我要 | createTime=2026-03-26 09:28 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_08_你想是多少好友来干嘛 我才知道 我要_5_before_close.png", "elapsed_sec": 47.47290658950806, "timestamp": "2026-03-26 09:28:21"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_09_看直播的分论 啥意思呢 我们进入 进.mp4", "title": "看直播的分论 啥意思呢 我们进入 进", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=看直播的分论 啥意思呢 我们进入 进 | createTime=2026-03-26 09:28 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_09_看直播的分论 啥意思呢 我们进入 进_5_before_close.png", "elapsed_sec": 46.84691596031189, "timestamp": "2026-03-26 09:29:08"}
|
||||
{"platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_10_我带ID我是知道 当天的总销售 是随.mp4", "title": "我带ID我是知道 当天的总销售 是随", "success": true, "status": "published", "message": "✓ API+列表API (列表第8条命中 | kw=我带ID我是知道 当天的总销售 是随 | createTime=2026-03-26 09:29 | 无tips)", "screenshot": "/tmp/channels_ss/soul130_10_我带ID我是知道 当天的总销售 是随_5_before_close.png", "elapsed_sec": 47.1520562171936, "timestamp": "2026-03-26 09:29:55"}
|
||||
|
||||
@@ -34,3 +34,14 @@
|
||||
{"timestamp": "2026-03-24 21:38:24", "platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片_大师版/疗愈师配AI助手能收多少钱 一个小团队5万到10万.mp4", "video_signature": "疗愈师配AI助手能收多少钱 一个小团队5万到10万.mp4|24461141", "status": "likely_published"}
|
||||
{"timestamp": "2026-03-24 21:38:24", "platform": "小红书", "video_path": "/Users/karuo/Movies/soul视频/soul 派对 120场 20260320_output/成片_大师版/赚钱没那么复杂,自信心才是核心问题.mp4", "video_signature": "赚钱没那么复杂,自信心才是核心问题.mp4|22996736", "status": "likely_published"}
|
||||
{"timestamp": "2026-03-25 14:45:28", "platform": "视频号", "video_path": "/tmp/soul_channels_127_128_bundle/我之前抖音就这么做.mp4", "video_signature": "我之前抖音就这么做.mp4|5229367", "status": "published"}
|
||||
{"timestamp": "2026-03-26 05:47:23", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第129场_20260320_output/成片/七千店复制拿投资月流水五十万.mp4", "video_signature": "七千店复制拿投资月流水五十万.mp4|9583735", "status": "published"}
|
||||
{"timestamp": "2026-03-26 05:48:14", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_01_我看你不太好 你不太好 你不太好 你.mp4", "video_signature": "soul130_01_我看你不太好 你不太好 你不太好 你.mp4|14525846", "status": "published"}
|
||||
{"timestamp": "2026-03-26 05:49:00", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_02_你不太好 你不太好 你不太好 你不太.mp4", "video_signature": "soul130_02_你不太好 你不太好 你不太好 你不太.mp4|24950550", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:24:28", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_03_内容库是要干嘛的 前面后面 我跟你说.mp4", "video_signature": "soul130_03_内容库是要干嘛的 前面后面 我跟你说.mp4|50252357", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:25:14", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_04_需要优化的点 第一个是 介面优化 第.mp4", "video_signature": "soul130_04_需要优化的点 第一个是 介面优化 第.mp4|14508469", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:26:01", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_05_你看关于这块 同步这块 我这里的话是.mp4", "video_signature": "soul130_05_你看关于这块 同步这块 我这里的话是.mp4|55088468", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:26:47", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_06_这里搜索 选择要同步 要同步的人 要.mp4", "video_signature": "soul130_06_这里搜索 选择要同步 要同步的人 要.mp4|53061133", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:27:34", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_07_这样会比较能性化一点 但是活儿是很乱.mp4", "video_signature": "soul130_07_这样会比较能性化一点 但是活儿是很乱.mp4|49605178", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:28:21", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_08_你想是多少好友来干嘛 我才知道 我要.mp4", "video_signature": "soul130_08_你想是多少好友来干嘛 我才知道 我要.mp4|54366732", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:29:08", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_09_看直播的分论 啥意思呢 我们进入 进.mp4", "video_signature": "soul130_09_看直播的分论 啥意思呢 我们进入 进.mp4|48160664", "status": "published"}
|
||||
{"timestamp": "2026-03-26 09:29:55", "platform": "视频号", "video_path": "/Users/karuo/Movies/soul视频/第130场_20260324_output/切片/soul130_10_我带ID我是知道 当天的总销售 是随.mp4", "video_signature": "soul130_10_我带ID我是知道 当天的总销售 是随.mp4|58372629", "status": "published"}
|
||||
|
||||
52
03_卡木(木)/木叶_视频内容/视频切片/Soul剪辑取向分析_SKILL.md
Normal file
52
03_卡木(木)/木叶_视频内容/视频切片/Soul剪辑取向分析_SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: Soul剪辑取向分析
|
||||
description: 在按高光剪 Soul/飞书录屏**之前**,自动分析画面主内容区宽度占比与左右留白,**判断更适合竖屏塑形还是横屏全幅**,并输出**标注截图 + Markdown 报告**;与 `analyze_feishu_ui_crop` 同源几何算法。
|
||||
triggers: 剪辑取向、竖屏还是横屏、先分析再剪、取向分析、横竖判断、录屏适合哪种比例、suggest_clip_orientation
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.0"
|
||||
updated: "2026-03-26"
|
||||
---
|
||||
|
||||
# Soul 剪辑取向分析 · Skill
|
||||
|
||||
## 一、何时执行
|
||||
|
||||
在 **`batch_clip` 之后、`soul_enhance` 之前**(或拿到代表 mp4 后立刻执行)。同一场次只需跑一次(可用首条切片或原片)。
|
||||
|
||||
## 二、命令
|
||||
|
||||
脚本:`03_卡木(木)/木叶_视频内容/视频切片/脚本/suggest_clip_orientation.py`
|
||||
|
||||
```bash
|
||||
cd 脚本
|
||||
python3 suggest_clip_orientation.py "/path/to/代表.mp4" \
|
||||
--at 0.12 --at 0.22 --at 0.35 --at 0.5 \
|
||||
--save-dir "/path/to/场次_output/裁剪检查"
|
||||
```
|
||||
|
||||
- 多 `--at`:沿时间轴多点取样,减少「刚好卡在转场」误判。
|
||||
- `--save-dir`:生成 `*_取向标注_t*.png`(绿框=算法认定的主内容包络)与 `*_剪辑取向分析.md`。
|
||||
|
||||
## 三、判定逻辑(摘要)
|
||||
|
||||
- 计算深色主内容包络宽度 `W_band` 与整幅宽 `W` 的比 `r = W_band/W`,及左右留白比例。
|
||||
- **r 较小**且两侧留白大 → **竖屏优先**(裁条发抖音等)。
|
||||
- **r 较大**且左右边窄 → **横屏全幅优先**(`--horizontal-full`,无黑边)。
|
||||
- 中间带 → **灰区**,以标注图人工拍板。
|
||||
|
||||
具体阈值见脚本内 `_recommend_one`。
|
||||
|
||||
## 四、读后动作
|
||||
|
||||
打开报告中的 Markdown,按「综合建议」:
|
||||
|
||||
| 建议 | 下一步 Skill / 参数 |
|
||||
|------|---------------------|
|
||||
| 竖屏优先 | `Soul竖屏切片_SKILL.md` + `analyze_feishu_ui_crop` + `soul_enhance --vertical --crop-vf …` |
|
||||
| 横屏全幅优先 | `Soul横屏全幅高光_SKILL.md` + `soul_enhance --horizontal-full --title-only` |
|
||||
|
||||
## 五、相关文件
|
||||
|
||||
- `analyze_feishu_ui_crop.py`:输出精确 `CROP_VF`(竖屏必跑)。
|
||||
- `soul_enhance.py`:`--horizontal-full` / `--horizontal-center-pad` / `--vertical`。
|
||||
74
03_卡木(木)/木叶_视频内容/视频切片/Soul横屏全幅高光_SKILL.md
Normal file
74
03_卡木(木)/木叶_视频内容/视频切片/Soul横屏全幅高光_SKILL.md
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
name: Soul横屏全幅高光
|
||||
description: Soul 派对飞书录屏→**横屏 1920×1080 高光成片**,**整幅画面无左右黑边**;与 `Soul竖屏切片_SKILL.md` **共用同一份 highlights / hook / 字幕规则**,差别仅在于**不裁竖条**、封面与字幕按**全幅 16:9** 绘制。可选 legacy:`--horizontal-center-pad`(中间一条+黑边)见文末。
|
||||
triggers: Soul横屏全幅、横屏高光、横屏无黑边、视频号横屏、16比9全画面、横屏成片、整幅横屏
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "2.0"
|
||||
updated: "2026-03-26"
|
||||
---
|
||||
|
||||
# Soul 横屏全幅高光 · Skill
|
||||
|
||||
> **必须先做取向分析**:`脚本/suggest_clip_orientation.py`(或 `Soul剪辑取向分析_SKILL.md`),根据包络宽度占比判断本场用**竖屏**还是**本 Skill(横屏全幅)**,再成片。
|
||||
|
||||
---
|
||||
|
||||
## 一、成片定义
|
||||
|
||||
| 项 | 要求 |
|
||||
|----|------|
|
||||
| 分辨率 | 与源切片一致,常见 **1920×1080** |
|
||||
| 画面 | **整幅**录屏内容,**无**为适配而加的左右黑边 |
|
||||
| 高光 / 文案 | 与竖屏 Skill **同一份** `highlights.json`、简体、片尾规则 |
|
||||
| 禁止混淆 | 本 Skill **不是**抖音竖条;**不是**「双路视频横拼」 |
|
||||
|
||||
---
|
||||
|
||||
## 二、与竖屏的边界
|
||||
|
||||
- **竖屏**:主内容仅占画面中间窄条、两侧大白 → 用 `analyze_feishu_ui_crop` + `--vertical --crop-vf …`
|
||||
- **横屏全幅**(本 Skill):主内容已占大部分宽度 → `soul_enhance --horizontal-full`,**不要** `--crop-vf`
|
||||
|
||||
---
|
||||
|
||||
## 三、成片命令
|
||||
|
||||
目录:`03_卡木(木)/木叶_视频内容/视频切片/脚本/`
|
||||
|
||||
```bash
|
||||
python3 soul_enhance.py \
|
||||
--clips "/path/to/场次_output/切片" \
|
||||
--highlights "/path/to/场次_output/highlights.json" \
|
||||
--transcript "/path/to/场次_output/transcript.srt" \
|
||||
-o "/path/to/场次_output/成片_横屏全幅" \
|
||||
--horizontal-full --title-only \
|
||||
--no-trim-silence \
|
||||
--force-burn-subs \
|
||||
--typewriter-subs
|
||||
```
|
||||
|
||||
- **`--horizontal-full`**:关闭竖条裁剪;`--title-only` **不再**偷偷打开 `--vertical`。
|
||||
- **不要**同时传 `--vertical`、`--crop-vf`、`--horizontal-center-pad`。
|
||||
|
||||
---
|
||||
|
||||
## 四、可选:横屏单中屏 + 左右黑边(legacy)
|
||||
|
||||
若平台必须 16:9 但只想突出中间一条(会出现黑边):
|
||||
|
||||
```bash
|
||||
python3 soul_enhance.py ... --vertical --title-only \
|
||||
--crop-vf "crop=宽:1080:左:0" --overlay-x 左 \
|
||||
--horizontal-center-pad ...
|
||||
```
|
||||
|
||||
详见脚本 `--help`。日常优先按取向报告选「全幅」或「竖条」。
|
||||
|
||||
---
|
||||
|
||||
## 五、验收
|
||||
|
||||
- [ ] 成片无 **pad 出来的左右黑边**(全幅模式)
|
||||
- [ ] `ffprobe` 宽高与源切片一致
|
||||
- [ ] 字幕、hook、CTA 与竖屏 Skill 一致
|
||||
@@ -12,6 +12,8 @@ updated: "2026-03-24"
|
||||
|
||||
> 专门切 Soul 派对视频为**竖屏成片**,用于抖音/首页。**主链路两文件夹**:横版切片 → 成片;另设 **`裁剪检查/`** 仅放 analyze 标定图与 txt(不占「成片」逻辑)。
|
||||
|
||||
**横屏全幅(整幅 16:9、无左右黑边)**:先跑 **`Soul剪辑取向分析_SKILL.md`**,再按报告选 **`Soul横屏全幅高光_SKILL.md`**(`--horizontal-full`)。若必须中间一条+黑边:`soul_enhance --horizontal-center-pad`。
|
||||
|
||||
---
|
||||
|
||||
## 一、文件夹结构(主:切片 → 成片)
|
||||
|
||||
@@ -64,6 +64,82 @@ def load_frame(path: Path, at_ratio: float | None) -> np.ndarray:
|
||||
return np.asarray(Image.open(BytesIO(raw)).convert("RGB"), dtype=np.float32)
|
||||
|
||||
|
||||
def compute_feishu_band(arr: np.ndarray, strict_core: bool = False) -> dict:
|
||||
"""
|
||||
从 RGB float32 帧估计飞书会议深色主内容区包络 [L, L+W_band)。
|
||||
失败时抛出 ValueError(消息给人读)。
|
||||
"""
|
||||
h, w, _ = arr.shape
|
||||
gray = 0.299 * arr[:, :, 0] + 0.587 * arr[:, :, 1] + 0.114 * arr[:, :, 2]
|
||||
col_mean = gray.mean(axis=0)
|
||||
|
||||
win = 31
|
||||
pad = win // 2
|
||||
kernel = np.ones(win) / win
|
||||
smooth = np.convolve(np.pad(col_mean, (pad, pad), mode="edge"), kernel, mode="valid")
|
||||
|
||||
dark = smooth < 105
|
||||
best = (0, 0)
|
||||
i = 0
|
||||
while i < w:
|
||||
if not dark[i]:
|
||||
i += 1
|
||||
continue
|
||||
j = i
|
||||
while j < w and dark[j]:
|
||||
j += 1
|
||||
if j - i > best[1] - best[0]:
|
||||
best = (i, j)
|
||||
i = j
|
||||
L0, R0 = best
|
||||
if R0 - L0 < 200:
|
||||
raise ValueError("未找到足够宽的深色带,请换一帧或检查分辨率")
|
||||
|
||||
right = R0
|
||||
for x in range(R0, min(R0 + 500, w)):
|
||||
if smooth[x] > 195 and col_mean[x] > 200 and x + 5 < w and smooth[x : x + 5].min() > 185:
|
||||
right = x
|
||||
break
|
||||
|
||||
if strict_core:
|
||||
L = max(0, L0)
|
||||
W_band = R0 - L0
|
||||
else:
|
||||
white_mean = 248.0
|
||||
white_smooth = 228.0
|
||||
|
||||
def col_is_desktop_white(x: int) -> bool:
|
||||
if x < 0 or x >= w:
|
||||
return True
|
||||
return col_mean[x] >= white_mean and smooth[x] >= white_smooth
|
||||
|
||||
L = L0
|
||||
while L > 0 and not col_is_desktop_white(L - 1):
|
||||
L -= 1
|
||||
|
||||
R = R0
|
||||
while R < w and not col_is_desktop_white(R):
|
||||
R += 1
|
||||
|
||||
W_band = R - L
|
||||
if W_band < 200:
|
||||
L, W_band = max(0, L0), R0 - L0
|
||||
|
||||
if W_band < 200:
|
||||
raise ValueError(f"可用宽度 {W_band} 过窄,请换一帧")
|
||||
|
||||
return {
|
||||
"w": w,
|
||||
"h": h,
|
||||
"L0": L0,
|
||||
"R0": R0,
|
||||
"L": L,
|
||||
"W_band": W_band,
|
||||
"right": right,
|
||||
"arr": arr,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("input", type=Path, help="全画面截图 jpg/png 或视频 mp4")
|
||||
@@ -92,73 +168,15 @@ def main():
|
||||
args = ap.parse_args()
|
||||
|
||||
arr = load_frame(args.input, args.at)
|
||||
h, w, _ = arr.shape
|
||||
gray = 0.299 * arr[:, :, 0] + 0.587 * arr[:, :, 1] + 0.114 * arr[:, :, 2]
|
||||
col_mean = gray.mean(axis=0)
|
||||
|
||||
win = 31
|
||||
pad = win // 2
|
||||
kernel = np.ones(win) / win
|
||||
smooth = np.convolve(np.pad(col_mean, (pad, pad), mode="edge"), kernel, mode="valid")
|
||||
|
||||
# 第一步:找最深色连续区作为「核心」,避免误选整屏平均
|
||||
dark = smooth < 105
|
||||
best = (0, 0)
|
||||
i = 0
|
||||
while i < w:
|
||||
if not dark[i]:
|
||||
i += 1
|
||||
continue
|
||||
j = i
|
||||
while j < w and dark[j]:
|
||||
j += 1
|
||||
if j - i > best[1] - best[0]:
|
||||
best = (i, j)
|
||||
i = j
|
||||
L0, R0 = best
|
||||
if R0 - L0 < 200:
|
||||
print("未找到足够宽的深色带,请换一帧或检查分辨率", file=sys.stderr)
|
||||
try:
|
||||
geo = compute_feishu_band(arr, strict_core=args.strict_core)
|
||||
except ValueError as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 右缘参考:深色带之后持续高亮(白底)从哪列起
|
||||
right = R0
|
||||
for x in range(R0, min(R0 + 500, w)):
|
||||
if smooth[x] > 195 and col_mean[x] > 200 and x + 5 < w and smooth[x : x + 5].min() > 185:
|
||||
right = x
|
||||
break
|
||||
|
||||
if args.strict_core:
|
||||
L = max(0, L0)
|
||||
W_band = R0 - L0
|
||||
else:
|
||||
# 第二步:从核心向左右扩到「桌面大白」边界(阈值略放宽,避免把浅灰边栏判成「已到边」而过窄)
|
||||
white_mean = 248.0
|
||||
white_smooth = 228.0
|
||||
|
||||
def col_is_desktop_white(x: int) -> bool:
|
||||
if x < 0 or x >= w:
|
||||
return True
|
||||
return col_mean[x] >= white_mean and smooth[x] >= white_smooth
|
||||
|
||||
L = L0
|
||||
while L > 0 and not col_is_desktop_white(L - 1):
|
||||
L -= 1
|
||||
|
||||
R = R0
|
||||
while R < w and not col_is_desktop_white(R):
|
||||
R += 1
|
||||
|
||||
W_band = R - L
|
||||
if W_band < 200:
|
||||
print(
|
||||
f"扩边后宽度 {W_band} 过窄,回退为深色核心 [{L0},{R0})",
|
||||
file=sys.stderr,
|
||||
)
|
||||
L, W_band = max(0, L0), R0 - L0
|
||||
|
||||
if W_band < 200:
|
||||
print(f"可用宽度 {W_band} 过窄,请换一帧", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
w, h = geo["w"], geo["h"]
|
||||
L0, R0 = geo["L0"], geo["R0"]
|
||||
L, W_band, right = geo["L"], geo["W_band"], geo["right"]
|
||||
|
||||
if args.squeeze_498 and args.center_in_band:
|
||||
print("同时指定 --squeeze-498 与 --center-in-band 时以 --center-in-band 为准", file=sys.stderr)
|
||||
|
||||
@@ -1930,13 +1930,19 @@ def _parse_clip_index(filename: str) -> int:
|
||||
return int(m.group(1)) if m else 0
|
||||
|
||||
|
||||
# 横屏单中屏:先按竖条塑形 crop,再左右 pad 到 16:9(整屏仅一条画面,非左右双视频拼屏)
|
||||
HORIZONTAL_CENTER_PAD_VF = "pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=black"
|
||||
|
||||
|
||||
def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_path,
|
||||
force_burn_subs=False, skip_subs=False, vertical=False,
|
||||
crop_vf=None, overlay_x=None, typewriter_subs=False,
|
||||
vertical_fit_full=False, trim_silence=True,
|
||||
subtitle_extra_delay=0.0, use_stickers=True):
|
||||
subtitle_extra_delay=0.0, use_stickers=True,
|
||||
horizontal_center_pad=False):
|
||||
"""增强单个切片。vertical=True 时输出竖条,宽由 --crop-vf 决定(原生包络常见 560~750×1080;旧 498 为两段裁或 scale)。
|
||||
vertical_fit_full:整幅 16:9 缩放入 498×1080 + 上下黑边。
|
||||
horizontal_center_pad:与竖条塑形相同链路(封面/字幕仍按竖条叠在横版上),最后输出 1920×1080,中间为裁切条、左右黑边。
|
||||
"""
|
||||
|
||||
print(f" 输入: {os.path.basename(clip_path)}", flush=True)
|
||||
@@ -2275,7 +2281,13 @@ def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_pa
|
||||
|
||||
# 5.4 输出:竖条(宽由 vf)或全画面 letterbox
|
||||
if vertical and not vertical_fit_full:
|
||||
print(f" [5/5] 竖屏输出({out_w}×{out_h})…", flush=True)
|
||||
if horizontal_center_pad:
|
||||
print(
|
||||
f" [5/5] 横屏单中屏(竖条 {out_w}×{out_h} → 1920×1080,左右黑边、单画面)…",
|
||||
flush=True,
|
||||
)
|
||||
else:
|
||||
print(f" [5/5] 竖屏输出({out_w}×{out_h})…", flush=True)
|
||||
elif vertical and vertical_fit_full:
|
||||
print(f" [5/5] 竖屏输出(全画面 letterbox)…", flush=True)
|
||||
else:
|
||||
@@ -2292,14 +2304,21 @@ def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_pa
|
||||
shutil.copy(current_video, output_path)
|
||||
print(f" ⚠ 已回退为未缩放版本", flush=True)
|
||||
elif vertical:
|
||||
vf_out = vf_use
|
||||
if horizontal_center_pad:
|
||||
vf_out = f"{vf_use},{HORIZONTAL_CENTER_PAD_VF}"
|
||||
r = subprocess.run([
|
||||
'ffmpeg', '-y', '-i', current_video,
|
||||
'-vf', vf_use, '-c:a', 'copy', output_path
|
||||
'-vf', vf_out, '-c:a', 'copy', output_path
|
||||
], capture_output=True, text=True)
|
||||
if r.returncode == 0 and os.path.exists(output_path):
|
||||
print(f" ✓ 竖屏竖条裁剪完成", flush=True)
|
||||
if horizontal_center_pad:
|
||||
print(f" ✓ 横屏单中屏输出完成(整屏仅一条画面)", flush=True)
|
||||
else:
|
||||
print(f" ✓ 竖屏竖条裁剪完成", flush=True)
|
||||
else:
|
||||
print(f" ❌ 竖屏裁剪失败: {(r.stderr or '')[:300]}", file=sys.stderr)
|
||||
tag = "横屏单中屏" if horizontal_center_pad else "竖屏裁剪"
|
||||
print(f" ❌ {tag}失败: {(r.stderr or '')[:300]}", file=sys.stderr)
|
||||
shutil.copy(current_video, output_path)
|
||||
print(f" ⚠ 已回退为未裁剪版本,请检查 FFmpeg", flush=True)
|
||||
else:
|
||||
@@ -2371,6 +2390,16 @@ def main():
|
||||
action="store_true",
|
||||
help="关闭表情贴片",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--horizontal-center-pad",
|
||||
action="store_true",
|
||||
help="横屏单中屏成片:与竖条塑形相同(封面/字幕/贴片),最后输出 1920×1080,中间一条画面、左右黑边;禁止与 --vertical-fit-full 同用",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--horizontal-full",
|
||||
action="store_true",
|
||||
help="横屏全幅成片:整幅 16:9(无左右黑边),高光/字幕/封面与竖屏 Skill 同源;不要与 --vertical / --crop-vf / --horizontal-center-pad 同用",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
clips_dir = Path(args.clips) if args.clips else CLIPS_DIR
|
||||
@@ -2395,8 +2424,40 @@ def main():
|
||||
overlay_x_arg = None if overlay_x_arg < 0 else overlay_x_arg
|
||||
typewriter = getattr(args, "typewriter_subs", False)
|
||||
vfit = getattr(args, "vertical_fit_full", False)
|
||||
hpad = getattr(args, "horizontal_center_pad", False)
|
||||
hfull = getattr(args, "horizontal_full", False)
|
||||
if hfull and getattr(args, "vertical", False):
|
||||
print("❌ --horizontal-full 与 --vertical 互斥", flush=True)
|
||||
return
|
||||
if hfull and hpad:
|
||||
print("❌ --horizontal-full 与 --horizontal-center-pad 互斥", flush=True)
|
||||
return
|
||||
if hfull and crop_vf_arg:
|
||||
print("⚠️ --horizontal-full 将忽略 --crop-vf(全幅 16:9 不裁竖条)", flush=True)
|
||||
crop_vf_arg = ""
|
||||
if hfull and vfit:
|
||||
print("⚠️ --horizontal-full 与 --vertical-fit-full 互斥,已关闭 letterbox 竖屏模式。", flush=True)
|
||||
vfit = False
|
||||
args.vertical_fit_full = False
|
||||
if hpad and vfit:
|
||||
print("⚠️ --horizontal-center-pad 与 --vertical-fit-full 互斥,已关闭全画面 letterbox。", flush=True)
|
||||
vfit = False
|
||||
args.vertical_fit_full = False
|
||||
# 横屏全幅:整幅叠字幕,成片 1920×1080,无左右黑边
|
||||
if hfull:
|
||||
vertical = False
|
||||
print("ℹ️ 横屏全幅成片:--title-only 仍生效,但不会强制竖屏。", flush=True)
|
||||
# 横屏单中屏必须先走竖条链路(叠字幕/封面),再 pad
|
||||
if hpad:
|
||||
vertical = True
|
||||
if not crop_vf_arg:
|
||||
print(
|
||||
"❌ --horizontal-center-pad 须配合 --crop-vf(或先跑 analyze_feishu_ui_crop 写入塑形参数)",
|
||||
flush=True,
|
||||
)
|
||||
return
|
||||
# Soul 成片:--title-only 或塑形相关参数时默认竖屏直出,避免只传 --crop-vf 却漏 --vertical 误出 1920×1080 横版
|
||||
if not vertical and (title_only or crop_vf_arg or vfit):
|
||||
if not vertical and not hfull and (title_only or crop_vf_arg or vfit):
|
||||
vertical = True
|
||||
print(
|
||||
"ℹ️ 已默认启用竖屏直出(因 --title-only 和/或 --crop-vf / --vertical-fit-full);"
|
||||
@@ -2404,12 +2465,19 @@ def main():
|
||||
flush=True,
|
||||
)
|
||||
print("="*60)
|
||||
print("🎬 Soul切片增强" + ("(成片竖屏直出)" if vertical else ""))
|
||||
print(
|
||||
"🎬 Soul切片增强"
|
||||
+ ("(成片竖屏直出)" if vertical and not hpad else "")
|
||||
+ ("(横屏单中屏 1920×1080)" if hpad else "")
|
||||
+ ("(横屏全幅 16:9 无黑边)" if hfull else "")
|
||||
)
|
||||
print("="*60)
|
||||
print(
|
||||
f"功能: 封面+字幕+加速10%+去语气词"
|
||||
+ ("+去长静音" if not getattr(args, "no_trim_silence", False) else "")
|
||||
+ ("+竖屏条(高1080宽随vf)" if vertical else "")
|
||||
+ ("+竖屏条(高1080宽随vf)" if vertical and not hpad else "")
|
||||
+ ("+横屏单中屏(竖条+左右黑边)" if hpad else "")
|
||||
+ ("+横屏全幅(整幅叠字幕)" if hfull else "")
|
||||
+ ("+全画面letterbox(不裁竖条)" if vertical and vfit else "")
|
||||
+ ("+逐字字幕" if typewriter else "")
|
||||
)
|
||||
@@ -2473,13 +2541,14 @@ def main():
|
||||
force_burn_subs=getattr(args, "force_burn_subs", False),
|
||||
skip_subs=getattr(args, "skip_subs", False),
|
||||
vertical=vertical,
|
||||
crop_vf=crop_vf_arg or None,
|
||||
crop_vf=(None if hfull else (crop_vf_arg or None)),
|
||||
overlay_x=overlay_x_arg,
|
||||
typewriter_subs=typewriter,
|
||||
vertical_fit_full=vfit,
|
||||
trim_silence=not getattr(args, "no_trim_silence", False),
|
||||
subtitle_extra_delay=float(getattr(args, "subtitle_extra_delay", 0.0) or 0.0),
|
||||
use_stickers=getattr(args, "stickers", True) and not getattr(args, "no_stickers", False),
|
||||
horizontal_center_pad=hpad,
|
||||
):
|
||||
success_count += 1
|
||||
finally:
|
||||
|
||||
206
03_卡木(木)/木叶_视频内容/视频切片/脚本/suggest_clip_orientation.py
Normal file
206
03_卡木(木)/木叶_视频内容/视频切片/脚本/suggest_clip_orientation.py
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Soul / 飞书录屏:在剪辑前判断更适合 **竖屏塑形** 还是 **横屏全幅(无黑边)**。
|
||||
|
||||
依据:与 analyze_feishu_ui_crop 相同的「深色主内容区包络」宽度占整幅比例、左右留白比例。
|
||||
输出:终端摘要 + 可选 --save-dir 下的标注截图与 Markdown 报告(含建议 soul_enhance 参数)。
|
||||
|
||||
用法:
|
||||
python3 suggest_clip_orientation.py /path/to/原片或切片.mp4
|
||||
python3 suggest_clip_orientation.py /path/to/原片.mp4 --at 0.15 --at 0.35 --at 0.5 --save-dir ./裁剪检查
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
from analyze_feishu_ui_crop import compute_feishu_band, load_frame
|
||||
|
||||
|
||||
def _recommend_one(r: float, ml: float, mr: float) -> tuple[str, str]:
|
||||
"""
|
||||
r = W_band/w, ml = L/w, mr = (w-L-W_band)/w
|
||||
返回 (标签, 理由短句)
|
||||
"""
|
||||
side_margin = ml + mr
|
||||
if r < 0.40 and side_margin > 0.18:
|
||||
return "竖屏优先", f"主内容宽约{r:.0%},左右留白合计约{side_margin:.0%},适合裁竖条发抖音等"
|
||||
if r < 0.44:
|
||||
return "竖屏优先", f"主内容宽约{r:.0%},偏窄条布局,竖屏信息密度更高"
|
||||
if r >= 0.68 and ml < 0.12 and mr < 0.12:
|
||||
return "横屏全幅优先", f"主内容宽约{r:.0%},左右边窄,全幅 16:9 无黑边更合适"
|
||||
if r >= 0.62:
|
||||
return "横屏全幅优先", f"主内容宽约{r:.0%},接近满宽,建议横屏全幅成片"
|
||||
if 0.44 <= r < 0.52 and side_margin > 0.28:
|
||||
return "竖屏倾向", f"中等宽度但留白仍明显({side_margin:.0%}),可竖屏;若更在意界面全貌则横屏"
|
||||
return "灰区·请对照截图", f"主内容宽约{r:.0%},建议对比标注图后人工定竖屏/横屏"
|
||||
|
||||
|
||||
def _draw_overlay(arr_f, L: int, W_band: int, caption: str) -> Image.Image:
|
||||
u8 = np.clip(arr_f, 0, 255).astype(np.uint8)
|
||||
im = Image.fromarray(u8).convert("RGB")
|
||||
dr = ImageDraw.Draw(im)
|
||||
y0, y1 = 0, im.height - 1
|
||||
x0, x1 = L, L + W_band - 1
|
||||
for off in range(3):
|
||||
dr.rectangle([x0 - off, y0 - off, x1 + off, y1 + off], outline=(0, 220, 90), width=2)
|
||||
bar_h = 36
|
||||
dr.rectangle([0, 0, im.width, bar_h], fill=(16, 16, 16))
|
||||
try:
|
||||
font = ImageFont.truetype("/System/Library/Fonts/PingFang.ttc", 22)
|
||||
except Exception:
|
||||
font = ImageFont.load_default()
|
||||
dr.text((8, 6), caption[:80], fill=(255, 255, 255), font=font)
|
||||
return im
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="判断 Soul 录屏更适合竖屏还是横屏成片")
|
||||
ap.add_argument("input", type=Path, help="mp4 或静态图")
|
||||
ap.add_argument(
|
||||
"--at",
|
||||
type=float,
|
||||
action="append",
|
||||
dest="at_list",
|
||||
help="视频取样时刻比例,可多次指定;默认 [0.12, 0.22, 0.35, 0.5]",
|
||||
)
|
||||
ap.add_argument("--strict-core", action="store_true", help="与 analyze 同义,仅用深色核心")
|
||||
ap.add_argument(
|
||||
"--save-dir",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="写入标注 PNG + 取向分析报告.md",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
|
||||
at_list = args.at_list if args.at_list else [0.12, 0.22, 0.35, 0.5]
|
||||
rows = []
|
||||
labels = []
|
||||
|
||||
for ratio in at_list:
|
||||
try:
|
||||
arr = load_frame(args.input, ratio)
|
||||
geo = compute_feishu_band(arr, strict_core=args.strict_core)
|
||||
except ValueError as e:
|
||||
print(f" ⚠️ t≈{ratio:.0%}:{e}", file=sys.stderr)
|
||||
continue
|
||||
w, h = geo["w"], geo["h"]
|
||||
L, Wb = geo["L"], geo["W_band"]
|
||||
r = Wb / w
|
||||
ml = L / w
|
||||
mr = (w - L - Wb) / w
|
||||
tag, reason = _recommend_one(r, ml, mr)
|
||||
labels.append(tag)
|
||||
rows.append(
|
||||
{
|
||||
"at": ratio,
|
||||
"w": w,
|
||||
"h": h,
|
||||
"L": L,
|
||||
"W_band": Wb,
|
||||
"r": r,
|
||||
"ml": ml,
|
||||
"mr": mr,
|
||||
"tag": tag,
|
||||
"reason": reason,
|
||||
"arr": geo["arr"],
|
||||
}
|
||||
)
|
||||
print(
|
||||
f" t≈{ratio:.0%} 包络宽={Wb}px ({r:.1%}) 左留白={ml:.1%} 右留白={mr:.1%} → {tag}"
|
||||
)
|
||||
|
||||
if not rows:
|
||||
print("❌ 所有取样均失败,无法判断", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 综合:数票 + 看最小 r(保守:若任一刻强烈竖屏则提示)
|
||||
from collections import Counter
|
||||
|
||||
c = Counter(labels)
|
||||
majority = c.most_common(1)[0][0]
|
||||
min_r_row = min(rows, key=lambda x: x["r"])
|
||||
max_r_row = max(rows, key=lambda x: x["r"])
|
||||
|
||||
if "竖屏优先" in c or "竖屏倾向" in c:
|
||||
if c["竖屏优先"] + c.get("竖屏倾向", 0) >= len(rows) * 0.5:
|
||||
final = "竖屏塑形(Soul竖屏切片 Skill)"
|
||||
elif min_r_row["r"] < 0.38:
|
||||
final = "竖屏塑形(存在明显窄条帧,建议竖屏)"
|
||||
else:
|
||||
final = f"综合偏 {majority},但样本有分歧,请对照截图"
|
||||
elif "横屏全幅优先" in c:
|
||||
if c["横屏全幅优先"] >= len(rows) * 0.5:
|
||||
final = "横屏全幅(Soul横屏全幅高光 Skill,无左右黑边)"
|
||||
else:
|
||||
final = f"综合偏 {majority},请对照截图"
|
||||
else:
|
||||
final = "灰区:请对照 save-dir 标注图人工选择"
|
||||
|
||||
print("\n──────── 综合建议 ────────")
|
||||
print(final)
|
||||
print("──────────────────────────")
|
||||
|
||||
vf = f"crop={rows[0]['W_band']}:1080:{rows[0]['L']}:0"
|
||||
ox = rows[0]["L"]
|
||||
print("\n若选竖屏(示例参数,请以 analyze_feishu_ui_crop --save-dir 为准):")
|
||||
print(f' --vertical --title-only --crop-vf "{vf}" --overlay-x {ox}')
|
||||
|
||||
print("\n若选横屏全幅(无黑边,整幅 1920×1080 叠字幕):")
|
||||
print(" --horizontal-full --title-only")
|
||||
print(" (不要带 --crop-vf / --vertical)")
|
||||
|
||||
if args.save_dir:
|
||||
sd = args.save_dir.resolve()
|
||||
sd.mkdir(parents=True, exist_ok=True)
|
||||
stem = args.input.stem.replace(" ", "_")[:36]
|
||||
md_lines = [
|
||||
"# 剪辑取向分析报告\n",
|
||||
f"- 源文件: `{args.input.name}`\n",
|
||||
f"- 取样点: {at_list}\n",
|
||||
f"- **综合建议**: {final}\n",
|
||||
"\n## 各取样点\n",
|
||||
"| t | 包络宽 | 占幅 | 左留白 | 右留白 | 判断 |\n",
|
||||
"|---|--------|------|--------|--------|------|\n",
|
||||
]
|
||||
for row in rows:
|
||||
caption = f"{row['tag']} 包络{row['W_band']}px={row['r']:.0%}"
|
||||
im = _draw_overlay(row["arr"], row["L"], row["W_band"], caption)
|
||||
png_name = f"{stem}_取向标注_t{int(row['at']*100)}.png"
|
||||
p = sd / png_name
|
||||
im.save(p, optimize=True)
|
||||
md_lines.append(
|
||||
f"| {row['at']:.0%} | {row['W_band']} | {row['r']:.1%} | {row['ml']:.1%} | {row['mr']:.1%} | {row['tag']} |\n"
|
||||
)
|
||||
md_lines.append(f"![t{row['at']:.0%}]({png_name})\n\n")
|
||||
|
||||
md_lines.extend(
|
||||
[
|
||||
"## 成片命令模板\n",
|
||||
"### 竖屏\n",
|
||||
"```bash\n",
|
||||
'python3 soul_enhance.py -c .../切片 -l .../highlights.json -t .../transcript.srt -o .../成片 \\\n',
|
||||
f' --vertical --title-only --crop-vf "{vf}" --overlay-x {ox} \\\n',
|
||||
" --no-trim-silence --force-burn-subs --typewriter-subs\n",
|
||||
"```\n",
|
||||
"### 横屏全幅(无黑边)\n",
|
||||
"```bash\n",
|
||||
"python3 soul_enhance.py -c .../切片 -l .../highlights.json -t .../transcript.srt -o .../成片_横屏全幅 \\\n",
|
||||
" --horizontal-full --title-only \\\n",
|
||||
" --no-trim-silence --force-burn-subs --typewriter-subs\n",
|
||||
"```\n",
|
||||
]
|
||||
)
|
||||
report = sd / f"{stem}_剪辑取向分析.md"
|
||||
report.write_text("".join(md_lines), encoding="utf-8")
|
||||
print(f"\n📁 已写: {report}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -90,13 +90,23 @@ updated: "2026-03-24"
|
||||
|
||||
## 三、一键命令
|
||||
|
||||
**优先(纯接口、无网页控件)**:`channels_api_publish.py` — 全 **httpx**,走 `helper_upload_params` → DFS 分片 → `post_clip_video` → `post_create`。Cookie 仍须由 `channels_login.py` 写入 `channels_storage_state.json`(**localStorage 须含 `finder_raw`**,否则 `post_create` 会 300002)。
|
||||
|
||||
```bash
|
||||
cd /Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容/视频号发布/脚本
|
||||
|
||||
# 1. 首次或 Cookie 过期:微信扫码登录
|
||||
python3 channels_login.py
|
||||
# 1. 首次或 Cookie 过期:微信扫码登录(建议进一次发表页以注入 rawKeyBuff)
|
||||
python3 channels_login.py --playwright-only
|
||||
|
||||
# 2. 批量发布(10-25 分钟真实间隔)
|
||||
# 2. 纯 API 批量发(推荐)
|
||||
python3 channels_api_publish.py --video-dir "/path/to/成片或切片目录"
|
||||
# 或环境变量:CHANNELS_VIDEO_DIR=/path/to/dir python3 channels_api_publish.py
|
||||
# 试跑前 2 条:python3 channels_api_publish.py --video-dir "..." --limit 2
|
||||
```
|
||||
|
||||
**备选(Playwright 点页面、F12 注入定时)**:需要页面控件或接口失败再排错时用:
|
||||
|
||||
```bash
|
||||
python3 channels_web_cli.py publish-dir \
|
||||
--video-dir "<视频目录>" \
|
||||
--min-gap 10 --max-gap 25 \
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
视频号纯 API 发布 v8 — 零 Playwright,全 httpx
|
||||
协议: helper_upload_params → DFS upload → post_clip_video → poll clip_result → post_create
|
||||
|
||||
CLI:
|
||||
python3 channels_api_publish.py --video-dir "/path/to/mp4目录"
|
||||
CHANNELS_VIDEO_DIR=/path/to/dir python3 channels_api_publish.py
|
||||
python3 channels_api_publish.py --video-dir ... --limit 3 # 只发前 3 条待发布
|
||||
|
||||
v8 修复 (2026-03-13):
|
||||
- 添加 post_clip_video 转码步骤(浏览器必需的中间步骤)
|
||||
- URL 改写: wxapp.tc.qq.com → finder.video.qq.com(与浏览器一致)
|
||||
@@ -11,6 +16,7 @@ v8 修复 (2026-03-13):
|
||||
- post_create 使用服务端返回的 clipKey/draftId
|
||||
- 去除 clientid(UUID4 格式触发设备验证 300001)
|
||||
"""
|
||||
import argparse
|
||||
import asyncio
|
||||
import hashlib
|
||||
import json
|
||||
@@ -28,7 +34,8 @@ import httpx
|
||||
|
||||
SCRIPT_DIR = Path(__file__).parent
|
||||
COOKIE_FILE = SCRIPT_DIR / "channels_storage_state.json"
|
||||
VIDEO_DIR = Path("/Users/karuo/Movies/soul视频/soul_派对_121场_20260311_output/成片")
|
||||
# 无 --video-dir 且无 CHANNELS_VIDEO_DIR 时的兼容默认(旧脚本直跑)
|
||||
_DEFAULT_VIDEO_DIR = Path("/Users/karuo/Movies/soul视频/soul_派对_121场_20260311_output/成片")
|
||||
|
||||
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
|
||||
from publish_result import PublishResult, is_published, save_results, print_summary
|
||||
@@ -823,6 +830,42 @@ def _maybe_login_then_retry() -> bool:
|
||||
return _run_login_then_retry()
|
||||
|
||||
|
||||
def _parse_cli_args():
|
||||
ap = argparse.ArgumentParser(
|
||||
description="视频号纯 API 批量发布(httpx,无浏览器控件;需 channels_storage_state.json 含 finder_raw)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--video-dir",
|
||||
type=str,
|
||||
default="",
|
||||
help="含 *.mp4 的目录;可改用环境变量 CHANNELS_VIDEO_DIR",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--limit",
|
||||
type=int,
|
||||
default=0,
|
||||
help="最多发布几条待发布条目,0 表示不限制",
|
||||
)
|
||||
return ap.parse_args()
|
||||
|
||||
|
||||
def _resolve_video_dir(arg_dir: str) -> Path | None:
|
||||
raw = (arg_dir or "").strip() or os.environ.get("CHANNELS_VIDEO_DIR", "").strip()
|
||||
p = Path(raw).expanduser() if raw else _DEFAULT_VIDEO_DIR
|
||||
p = p.resolve()
|
||||
if not p.is_dir():
|
||||
return None
|
||||
return p
|
||||
|
||||
|
||||
def _title_for_video(vp: Path) -> str:
|
||||
if vp.name in TITLES:
|
||||
return TITLES[vp.name]
|
||||
if VideoMeta is not None:
|
||||
return VideoMeta.from_filename(str(vp)).title("视频号")
|
||||
return f"{vp.stem} #Soul派对 #创业日记"
|
||||
|
||||
|
||||
def _gen_schedule_unix(count: int) -> list[int]:
|
||||
"""与 distribute_all 一致:智能错峰 datetime → 视频号定时 Unix;近未来视为立即(0)。"""
|
||||
if count <= 0:
|
||||
@@ -832,7 +875,18 @@ def _gen_schedule_unix(count: int) -> list[int]:
|
||||
|
||||
|
||||
async def main():
|
||||
args = _parse_cli_args()
|
||||
video_dir = _resolve_video_dir(args.video_dir)
|
||||
if video_dir is None:
|
||||
print(
|
||||
"[!] 视频目录无效。请传: python3 channels_api_publish.py --video-dir \"/path/to/mp4\""
|
||||
" 或设置 CHANNELS_VIDEO_DIR。",
|
||||
flush=True,
|
||||
)
|
||||
return 1
|
||||
|
||||
print("=== 视频号纯 API 发布 v8 (DFS + clip_video + post_create) ===\n", flush=True)
|
||||
print(f" [CLI] 目录: {video_dir}", flush=True)
|
||||
|
||||
state = load_state()
|
||||
if not state:
|
||||
@@ -892,13 +946,27 @@ async def main():
|
||||
uin = str(up_params["uin"])
|
||||
print(f" uin: {uin}", flush=True)
|
||||
|
||||
videos = sorted(VIDEO_DIR.glob("*.mp4"))
|
||||
finder_raw_main = pick_finder_raw_from_ls(ls)
|
||||
if not finder_raw_main:
|
||||
print(
|
||||
"[!] 纯 API 发表需要 localStorage 里的 finder_raw(rawKeyBuff),当前缺失 → post_create 会 300002。\n"
|
||||
" 请执行: python3 channels_login.py --playwright-only\n"
|
||||
" 登录后进入一次「创建/发表」页,等终端出现 Cookie 已保存后再跑本脚本。\n",
|
||||
flush=True,
|
||||
)
|
||||
return 1
|
||||
print(f" finder_raw: OK({len(finder_raw_main)} 字符)", flush=True)
|
||||
|
||||
videos = sorted(video_dir.glob("*.mp4"))
|
||||
if not videos:
|
||||
print("[!] 未找到视频", flush=True)
|
||||
return 1
|
||||
|
||||
need_pub = [v for v in videos if not is_published("视频号", str(v))]
|
||||
print(f"\n共 {len(videos)} 条视频,{len(need_pub)} 条待发布\n", flush=True)
|
||||
if args.limit > 0:
|
||||
need_pub = need_pub[: args.limit]
|
||||
_lim = f"本跑最多 {args.limit} 条" if args.limit > 0 else "条数不限制"
|
||||
print(f"\n共 {len(videos)} 条 mp4,待发布 {len(need_pub)} 条({_lim})\n", flush=True)
|
||||
if not need_pub:
|
||||
print("[OK] 全部已发布", flush=True)
|
||||
return 0
|
||||
@@ -909,11 +977,12 @@ async def main():
|
||||
consecutive_fail = 0
|
||||
|
||||
for i, vp in enumerate(need_pub):
|
||||
t = TITLES.get(vp.name, f"{vp.stem} #Soul派对 #创业日记")
|
||||
t = _title_for_video(vp)
|
||||
r = await publish_one(
|
||||
cookie_str, finder_id, uin, finger_print, aid,
|
||||
up_params, str(vp), t, i + 1, len(need_pub),
|
||||
scheduled_ts=schedule[i],
|
||||
finder_raw=finder_raw_main,
|
||||
)
|
||||
results.append(r)
|
||||
if r.status != "skipped":
|
||||
|
||||
177
03_卡木(木)/木叶_视频内容/视频号发布/脚本/channels_post_delete.py
Normal file
177
03_卡木(木)/木叶_视频内容/视频号发布/脚本/channels_post_delete.py
Normal file
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
视频号批量删除:按切片目录用 VideoMeta 标题关键词匹配 post_list 描述,
|
||||
再调用 mmfinderassistant-bin/post/post_delete(body: {"objectId": "export/..."})。
|
||||
|
||||
匹配规则与发布验收一致:描述须含 channels_publish.REQUIRED_DESC_FRAGMENTS。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
|
||||
|
||||
import httpx
|
||||
from video_metadata import VideoMeta
|
||||
|
||||
import channels_publish as ch
|
||||
|
||||
POST_DELETE_URL = "https://channels.weixin.qq.com/cgi-bin/mmfinderassistant-bin/post/post_delete"
|
||||
|
||||
|
||||
def _md5_file(path: Path) -> str:
|
||||
h = hashlib.md5()
|
||||
with path.open("rb") as f:
|
||||
for chunk in iter(lambda: f.read(1 << 20), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest().lower()
|
||||
|
||||
|
||||
def _media_md5s_from_item(it: dict) -> set[str]:
|
||||
out: set[str] = set()
|
||||
for med in (it.get("desc") or {}).get("media") or []:
|
||||
m = (med.get("md5sum") or "").strip().lower()
|
||||
if m:
|
||||
out.add(m)
|
||||
return out
|
||||
|
||||
|
||||
def match_posts_for_dir(
|
||||
video_dir: Path,
|
||||
items: list,
|
||||
glob_pat: str,
|
||||
required_frags: list[str] | None = None,
|
||||
md5_fallback: bool = True,
|
||||
) -> dict[str, tuple[str, str]]:
|
||||
"""
|
||||
每个 mp4 至多一条:{filename: (objectId, matched_keyword)}。
|
||||
关键词按长度降序,优先最长匹配;列表顺序与 post_list 返回一致(通常新在前)。
|
||||
"""
|
||||
if required_frags is None:
|
||||
required_frags = ch.REQUIRED_DESC_FRAGMENTS
|
||||
out: dict[str, tuple[str, str]] = {}
|
||||
paths = sorted(video_dir.glob(glob_pat))
|
||||
if not paths:
|
||||
paths = sorted(video_dir.glob("*.mp4"))
|
||||
for p in paths:
|
||||
meta = VideoMeta.from_filename(p.name)
|
||||
title = meta.title("视频号")
|
||||
kws = ch._title_keywords_for_list_check(title, str(p))
|
||||
kws_sorted = sorted({k for k in kws if (k or "").strip()}, key=len, reverse=True)
|
||||
for it in items:
|
||||
desc = (it.get("desc") or {}).get("description") or ""
|
||||
dl = desc.lower()
|
||||
if any((f or "").lower() not in dl for f in required_frags):
|
||||
continue
|
||||
hit_kw = None
|
||||
for kw in kws_sorted:
|
||||
if kw in desc:
|
||||
hit_kw = kw
|
||||
break
|
||||
if not hit_kw:
|
||||
continue
|
||||
oid = it.get("objectId")
|
||||
if not oid:
|
||||
continue
|
||||
out[p.name] = (str(oid), hit_kw)
|
||||
break
|
||||
if md5_fallback:
|
||||
paths = sorted(video_dir.glob(glob_pat)) or sorted(video_dir.glob("*.mp4"))
|
||||
for p in paths:
|
||||
if p.name in out:
|
||||
continue
|
||||
try:
|
||||
fmd5 = _md5_file(p)
|
||||
except OSError:
|
||||
continue
|
||||
for it in items:
|
||||
if fmd5 not in _media_md5s_from_item(it):
|
||||
continue
|
||||
oid = it.get("objectId")
|
||||
if not oid:
|
||||
continue
|
||||
out[p.name] = (str(oid), f"md5:{fmd5[:8]}…")
|
||||
break
|
||||
return out
|
||||
|
||||
|
||||
def post_delete_one(cookie_str: str, object_id: str) -> dict:
|
||||
r = httpx.post(
|
||||
POST_DELETE_URL,
|
||||
json={"objectId": object_id},
|
||||
headers={
|
||||
"Cookie": cookie_str,
|
||||
"User-Agent": ch.UA,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=httpx.Timeout(15.0, connect=5.0),
|
||||
)
|
||||
try:
|
||||
return r.json()
|
||||
except Exception:
|
||||
return {"errCode": -9, "errMsg": r.text[:200]}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="视频号:按目录匹配列表并 post_delete")
|
||||
ap.add_argument("--video-dir", type=Path, required=True, help="切片目录")
|
||||
ap.add_argument("--glob", default="*.mp4", help="匹配切片,如 soul130_*.mp4")
|
||||
ap.add_argument("--max-pages", type=int, default=35, help="post_list 最大翻页数")
|
||||
ap.add_argument("--dry-run", action="store_true", help="只打印将删条目,不调用删除")
|
||||
ap.add_argument(
|
||||
"--no-md5-fallback",
|
||||
action="store_true",
|
||||
help="禁用本地文件 MD5 与列表 media.md5sum 兜底匹配",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
d = args.video_dir.expanduser().resolve()
|
||||
if not d.is_dir():
|
||||
print(f"目录不存在: {d}", flush=True)
|
||||
return 1
|
||||
cs = ch._cookie_str_from_file()
|
||||
ok, msg, _ = ch.verify_session_cookie()
|
||||
if not ok:
|
||||
print(msg, flush=True)
|
||||
return 1
|
||||
items = ch._gather_post_list(cs, args.max_pages)
|
||||
matched = match_posts_for_dir(
|
||||
d, items, args.glob, md5_fallback=not args.no_md5_fallback
|
||||
)
|
||||
mp4s = sorted(d.glob(args.glob)) or sorted(d.glob("*.mp4"))
|
||||
# 同一 objectId 只删一次(避免误配两条文件名指向同一动态)
|
||||
by_oid: dict[str, tuple[str, str]] = {}
|
||||
for fname, (oid, kw) in matched.items():
|
||||
if oid in by_oid:
|
||||
print(f" [skip dup oid] {fname} same as {by_oid[oid][0]}", flush=True)
|
||||
continue
|
||||
by_oid[oid] = (fname, kw)
|
||||
|
||||
missing = [p.name for p in mp4s if p.name not in matched]
|
||||
print(f"目录 mp4: {len(mp4s)} | 匹配到动态: {len(by_oid)} | 未匹配文件: {len(missing)}", flush=True)
|
||||
for oid, (fname, kw) in by_oid.items():
|
||||
print(f" DEL? {fname} | kw={kw[:40]}… | {oid[:56]}…", flush=True)
|
||||
if missing:
|
||||
print(" 未匹配:", ", ".join(missing[:20]), ("…" if len(missing) > 20 else ""), flush=True)
|
||||
|
||||
if args.dry_run:
|
||||
return 2 if missing else 0
|
||||
|
||||
errs = 0
|
||||
for oid, (fname, _) in by_oid.items():
|
||||
data = post_delete_one(cs, oid)
|
||||
code = data.get("errCode")
|
||||
em = (data.get("errMsg") or "")[:120]
|
||||
print(f" {fname} errCode={code} {em}", flush=True)
|
||||
if code != 0:
|
||||
errs += 1
|
||||
time.sleep(0.35)
|
||||
return 1 if errs else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
File diff suppressed because one or more lines are too long
@@ -25,7 +25,7 @@ updated: "2026-03-26"
|
||||
- **1~10 目录**:需求 | 架构 | 原型 | 前端 | 接口 | 后端 | 数据库 | 部署 | 手册 | 项目管理。
|
||||
- **入口**:第一次用先读 `1、需求/卡若AI项目使用说明.md`(或该项目等价说明),再读 `10、项目管理/开发文档使用指引(卡若交互式).md`。
|
||||
- **手册**:使用手册**一律按卡若AI 使用手册结构**书写(书籍式:README 总目录 + 篇/章多文件 + 附录),并**图文并茂**。配图放 `9、手册/images/`,在章节内引用,并在 `images/README.md` 登记。详见 `开发模板/9、手册/使用手册生成规范_卡若AI结构.md`;入口可保留 `9、手册/使用手册(带图).md` 作导航或单页摘要。
|
||||
- **复盘**:迭代结尾用 `10、项目管理/迭代复盘模板.md`;**对话内复盘**一律遵守 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v4.0**(**仅** 🎯📌💡📝▶;🎯 目标/结果各一句 + 达成率%)。用户**点名**起盘/八门时,另见 **`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`**(F01c · 演门测机),**附在标准复盘后**输出。
|
||||
- **复盘**:迭代结尾用 `10、项目管理/迭代复盘模板.md`;**对话内复盘**一律遵守 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**(**仅** 🎯📌💡📝▶;🎯 **单行一句 ≤50 字**含达成率%,验收绑定可负)。用户**点名**起盘/八门时,另见 **`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`**(F01c · 演门测机),**附在标准复盘后**输出。
|
||||
|
||||
### 1.2 执行流程(调研 → 计划 → 执行 → 评审 → 复盘)
|
||||
|
||||
@@ -283,7 +283,7 @@ scripts/
|
||||
| **神射手 开发文档 4、前端** | 神射手项目内前端规范、核心组件代码、截图索引 |
|
||||
| **Superpowers与全栈开发对比与优化建议** | `运营中枢/参考资料/Superpowers与全栈开发对比与优化建议.md` — 计划粒度、TDD、两阶段评审、分支收尾等优化方向 |
|
||||
| **埋点统计与点击锚点(Soul 沉淀)** | 三层架构 + module/action/target 锚点约定 + `10、项目管理` 登记表;Soul 参考 `一场soul的创业实验-永平`;见本 Skill **§1.10**(2026-03-22 扩充) |
|
||||
| **火炬「项目开发占卜术」Skill(F01c · 演门测机)** | **奇门 Q门 3.0** 八门健康度;用户**点名起盘/占卜**时按该 Skill **单独输出**,附在标准复盘 v4.0 五块之后 |
|
||||
| **火炬「项目开发占卜术」Skill(F01c · 演门测机)** | **奇门 Q门 3.0** 八门健康度;用户**点名起盘/占卜**时按该 Skill **单独输出**,附在标准复盘 v5.0 五块之后 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: 项目开发占卜术
|
||||
description: 火炬 · 项目开发「起盘」— 用奇门 Q门 3.0 八门框架做迭代健康度与风险扫描(非玄学,可验收百分比);**用户点名**起盘/占卜/八门时执行;输出**附在**卡若标准复盘五块**之后**,不替代 v4.0 复盘。触发词:项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势、门迫。
|
||||
description: 火炬 · 项目开发「起盘」— 用奇门 Q门 3.0 八门框架做迭代健康度与风险扫描(非玄学,可验收百分比);**用户点名**起盘/占卜/八门时执行;输出**附在**卡若标准复盘五块**之后**,不替代 v5.0 复盘。触发词:项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势、门迫。
|
||||
triggers: 项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势、门迫、火炬占卜、项目盘
|
||||
owner: 火炬
|
||||
group: 火
|
||||
@@ -13,7 +13,7 @@ memory_palace_slot: 以八门扫项目健康,百分比对齐落地表
|
||||
# 项目开发占卜术(火炬 · 演门测机)
|
||||
|
||||
> **本质**:用 **奇门 Q门 3.0** 的**八门隐喻**做**项目维度的完成度/风险快照**,输出 **可对照验收的百分比 + 交通灯**。
|
||||
> **与 Cursor 每轮复盘的关系(v4.0)**:`运营中枢/参考资料/卡若复盘格式_固定规则.md` **不再**要求对话末尾写 ☯ 块;**仅当用户明确要求**「起盘 / 占卜术 / 八门 / Q门」时,按本 Skill 输出八门全文,并放在 **标准复盘五块(🎯📌💡📝▶)结束之后**。
|
||||
> **与 Cursor 每轮复盘的关系(v5.0)**:`运营中枢/参考资料/卡若复盘格式_固定规则.md` 要求 **🎯 单行一句**、**禁止**标准复盘内独立 ☯ 段;**仅当用户明确要求**「起盘 / 占卜术 / 八门 / Q门」时,按本 Skill 输出八门全文,并放在 **标准复盘五块(🎯📌💡📝▶)结束之后**。
|
||||
> **禁止**:当作命理预测;所有门线必须是**本迭代/本仓库/本对话可验证事实**的归纳。
|
||||
|
||||
---
|
||||
@@ -22,7 +22,7 @@ memory_palace_slot: 以八门扫项目健康,百分比对齐落地表
|
||||
|
||||
用户或上下文出现:**项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势**,或明确说「按占卜术收尾」「起个盘」时,读本 Skill 并执行 **第二节起盘清单**。
|
||||
|
||||
**未点名**时:**不要**自动追加八门段;对话收尾只写卡若复盘 **v4.0 五块**即可。
|
||||
**未点名**时:**不要**自动追加八门段;对话收尾只写卡若复盘 **v5.0 五块**即可。
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +39,7 @@ memory_palace_slot: 以八门扫项目健康,百分比对齐落地表
|
||||
- **景门**:文档、演示、日志、可观测、对接口头是否一致。
|
||||
- **死门**:僵死代码、废弃路由、冻结需求是否拖累。
|
||||
- **惊门**:风险、合规、告警、未知项(依赖未锁版本等)。
|
||||
4. **写输出**:在 **完整卡若复盘五块(v4.0)之后**,另起段落输出 **☯ 奇门 Q门 3.0(项目盘)**,骨架如下(复盘块内不用表格,用分行列表):
|
||||
4. **写输出**:在 **完整卡若复盘五块(v5.0)之后**,另起段落输出 **☯ 奇门 Q门 3.0(项目盘)**,骨架如下(复盘块内不用表格,用分行列表):
|
||||
|
||||
```markdown
|
||||
**☯ 奇门 Q门 3.0(项目盘)**
|
||||
@@ -64,12 +64,12 @@ memory_palace_slot: 以八门扫项目健康,百分比对齐落地表
|
||||
## 三、与「全栈开发」关系
|
||||
|
||||
- **全栈开发** Skill 负责 1~10、计划、评审、代码落地;**本 Skill** 负责 **按需**八门盘 + 百分比口径。
|
||||
- 两 Skill **同时命中**且用户要起盘时:先按全栈流程交付并写完 **v4.0 复盘五块**,再追加本 Skill **☯ 段**。
|
||||
- 两 Skill **同时命中**且用户要起盘时:先按全栈流程交付并写完 **v5.0 复盘五块**,再追加本 Skill **☯ 段**。
|
||||
|
||||
---
|
||||
|
||||
## 四、引用
|
||||
|
||||
- 标准复盘母体:`运营中枢/参考资料/卡若复盘格式_固定规则.md`(**v4.0**,仅五块)。
|
||||
- 标准复盘母体:`运营中枢/参考资料/卡若复盘格式_固定规则.md`(**v5.0**,仅五块;🎯 单行一句)。
|
||||
- Cursor 规则:`.cursor/rules/karuo-ai.mdc`(强制复盘五块)。
|
||||
- 登记:`SKILL_REGISTRY.md` **F01c**。
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
- **细粒度拆解**,执行计划带精确路径/命令/预期
|
||||
- **技能联动**:执行前检查联动子技能
|
||||
- **至少两轮验证**;不通过则回溯→搜索→再执行
|
||||
- **复盘五块齐全**(🎯📌💡📝▶),🎯 为「目标一句、结果一句、达成率%」;可带数据与引用;细则见 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v4.0**
|
||||
- **复盘五块齐全**(🎯📌💡📝▶),🎯 为**单行一句 ≤50 字**(含目标+结果+达成率%,可负);细则见 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**
|
||||
- **可拆任务 1~6 线程并行**:划界归域→独立处理→汇总。详见 `运营中枢/参考资料/多线程并行处理规范.md`
|
||||
|
||||
## 五、执行流程(强制)
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
**第四步:Mongo 对话留存 + 强制复盘**
|
||||
- **先**完成 Mongo 留存闭环(将本轮 Cursor 对话写入 `karuo_site`,不重复键):执行 `python3 01_卡资(金)/金仓_存储备份/聊天记录管理/脚本/realtime_chat_sync.py`;细则与顺序见 `运营中枢/参考资料/卡若AI_Mongo对话留存闭环.md` 与 `.cursor/rules/karuo-ai.mdc`。
|
||||
- **再**用复盘形式收尾(🎯📌💡📝▶),带日期+时间(YYYY-MM-DD HH:mm),🎯 内目标/结果各一句 + 达成率%。格式见 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v4.0**。
|
||||
- **再**用复盘形式收尾(🎯📌💡📝▶),带日期+时间(YYYY-MM-DD HH:mm),🎯 **单行一句**含达成率%(验收绑定,可负)。格式见 `运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**。
|
||||
|
||||
## 六、记忆
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|:---|:---|
|
||||
| 技能查找 | 热技能速查→未命中读 SKILL_REGISTRY.md→读 SKILL.md 执行 |
|
||||
| 常规操作 | 优先命令行 + 复用现成流程,不提问 |
|
||||
| 复盘 | 所有回复强制用完整复盘(🎯📌💡📝▶,v4.0) |
|
||||
| 复盘 | 所有回复强制用完整复盘(🎯📌💡📝▶,v5.0) |
|
||||
| 沉淀 | 写入 `水溪_整理归档/经验库/待沉淀/` |
|
||||
| 对话后优化 | 经验沉淀 + 技能变更更新 SKILL_REGISTRY + 使用手册。见 `运营中枢/使用手册/对话沉淀与优化规则.md` |
|
||||
| 基因胶囊 | 读 `土砖_技能复制/基因胶囊/SKILL.md` |
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 卡若AI 技能注册表(Skill Registry)
|
||||
|
||||
> **一张表查所有技能**。任何 AI 拿到这张表,就能按关键词找到对应技能的 SKILL.md 路径并执行。
|
||||
> 78 技能 + 3 卡路Cursor入口 | 15 成员 | 5 负责人
|
||||
> 版本:5.16 | 更新:2026-03-26
|
||||
> 79 技能 + 3 卡路Cursor入口 | 15 成员 | 5 负责人
|
||||
> 版本:5.17 | 更新:2026-03-26
|
||||
>
|
||||
> **技能配置、安装、删除、掌管人登记** → 见 **`运营中枢/工作台/01_技能控制台.md`**。
|
||||
|
||||
@@ -116,6 +116,8 @@
|
||||
| M01f | 小红书发布 | 木叶 | **小红书发布、发布到小红书、小红书登录、小红书上传、RED发布** | `03_卡木(木)/木叶_视频内容/小红书发布/SKILL.md` | 逆向 creator API 视频笔记发布,封面取第一帧 |
|
||||
| M01g | 快手发布 | 木叶 | **快手发布、发布到快手、快手登录、快手上传、kuaishou发布** | `03_卡木(木)/木叶_视频内容/快手发布/SKILL.md` | 逆向 cp.kuaishou.com API 视频发布 |
|
||||
| M01h | 多平台分发 | 木叶 | **多平台分发、一键分发、全平台发布、批量分发、视频分发** | `03_卡木(木)/木叶_视频内容/多平台分发/SKILL.md` | 一键分发到5平台(抖音/B站/视频号/小红书/快手),Cookie统一管理 |
|
||||
| M01i | **Soul横屏全幅高光** | 木叶 | **横屏全幅、横屏高光、横屏无黑边、视频号横屏、16比9全画面、整幅横屏** | `03_卡木(木)/木叶_视频内容/视频切片/Soul横屏全幅高光_SKILL.md` | 与竖屏共用 highlights;`soul_enhance --horizontal-full` 整幅 16:9、**无左右黑边**;可选 `--horizontal-center-pad` 单中屏+黑边 |
|
||||
| M01j | **Soul剪辑取向分析** | 木叶 | **剪辑取向、竖屏还是横屏、先分析再剪、取向分析、横竖判断、suggest_clip_orientation** | `03_卡木(木)/木叶_视频内容/视频切片/Soul剪辑取向分析_SKILL.md` | `suggest_clip_orientation.py` 多点取样+标注图+报告,再选竖屏或横屏全幅 |
|
||||
| M02 | 网站逆向分析 | 木根 | 逆向分析、模拟登录 | `03_卡木(木)/木根_逆向分析/网站逆向分析/SKILL.md` | 网站 API 分析、SDK 生成 |
|
||||
| M02a | **全网AI自动注册** | 木根 | **AI注册、自动注册、批量注册、API Key、注册账号、免费API、API池、key池、自动开号、Gemini注册** | `03_卡木(木)/木根_逆向分析/全网AI自动注册/SKILL.md` | OpenAI/Cursor/Gemini/Groq 等全网 AI API 自动注册+Key 池管理 |
|
||||
| M03 | 项目生成 | 木果 | 生成项目、五行模板 | `03_卡木(木)/木果_项目模板/项目生成/SKILL.md` | 按五行模板生成新项目 |
|
||||
@@ -132,7 +134,8 @@
|
||||
| F01 | 全栈开发 | 火炬 | 知己、RAG、分销、**卡若AI官网、官网开发、全站开发、开发文档、1~10**、**埋点、点击统计、用户行为、行为统计、数据统计、点击锚点、锚点、trackClick** | `04_卡火(火)/火炬_全栈消息/全栈开发/SKILL.md` | 全栈项目 + 官网/全站与开发文档 1~10;**§1.10 埋点与点击锚点全站强制** |
|
||||
| F01a | 前端开发 | 火炬 | **前端开发、毛玻璃、神射手风格、毛狐狸风格、前端标准、苹果毛玻璃**、**埋点、点击锚点、trackClick、用户行为** | `04_卡火(火)/火炬_全栈消息/前端开发/SKILL.md` | 毛玻璃 + 前端标准;**§五 用户行为与点击锚点**;详规见全栈 §1.10 |
|
||||
| F01b | 全栈测试 | 火炬 | **全栈测试、功能测试、回归测试、深度测试、E2E测试、API测试、发布测试、测试验收** | `04_卡火(火)/火炬_全栈消息/全栈开发/全栈测试/SKILL.md` | 功能开发后系统化验收:前端/后端/数据库/脚本/发布引擎五维测试;**每完成一个功能必须调用** |
|
||||
| F01c | **项目开发占卜术**(间名 **演门测机**) | 火炬 | **项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势、门迫** | `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md` | 奇门 Q门 3.0 八门框架扫项目健康度;**复盘 ☯ 块**与 `卡若复盘格式_固定规则.md` 强制对齐 |
|
||||
| F01c | **项目开发占卜术**(间名 **演门测机**) | 火炬 | **项目开发占卜术、开发占卜、Q门3.0、奇门项目盘、八门复盘、起盘、盘势、门迫** | `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md` | 奇门 Q门 3.0 八门健康度扫描;**仅用户点名起盘**时附在复盘 v5.0 五块**之后**,**不**写入标准 🎯 |
|
||||
| F01d | **卡若复盘格式** | 火炬 | **复盘格式、卡若复盘、达成率怎么写、复盘 v5、视频号分发复盘、负达成率** | `.cursor/skills/karuo-recap-format/SKILL.md` | v5.0:🎯 单行一句 ≤50 字、达成率绑定分发/验收(可负)、禁 ➡️/📊 复述与标准 ☯ |
|
||||
| F02 | 消息中枢 | 火炬 | WhatsApp、Telegram | `04_卡火(火)/火炬_全栈消息/消息中枢/SKILL.md` | 多平台消息聚合 |
|
||||
| F02a | **艾叶 IM Bridge** | 火炬 | **艾叶、IM、聊天对接、消息网关、微信对接、企业微信对接、飞书对接、WhatsApp对接、网页聊天、IM桥接、通道配置、艾叶IM** | `04_卡火(火)/火炬_全栈消息/艾叶/SKILL.md` | 多平台 IM 网关:个人微信/企业微信/飞书/WhatsApp/网页→卡若AI 对话 |
|
||||
| F03 | 读书笔记 | 火炬 | 拆解这本书、五行拆书 | `04_卡火(火)/火炬_全栈消息/读书笔记/SKILL.md` | 五行框架拆书 |
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
**卡若AI 所有对话的 AI 回复一律采用「复盘形式」**,只有一种格式:完整复盘,每轮/每步均以完整复盘块收尾。
|
||||
|
||||
**权威全文**:`运营中枢/参考资料/卡若复盘格式_固定规则.md` **v4.0**:**仅五块** 🎯📌💡📝▶;**🎯** 为 **目标一句、结果一句、达成率 XX%**(不把 Human 3.0、奇门八门**单独成段**;需要的信息**写进这三句里**)。用户**点名起盘/占卜**时,八门另见 `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`,**附在五块之后**。
|
||||
**权威全文**:`运营中枢/参考资料/卡若复盘格式_固定规则.md` **v5.0**:**仅五块** 🎯📌💡📝▶;**🎯** 为 **单行一句话 ≤50 字(含标点)**,句内含 **目标+结果+达成率(%)**(**可为负**);**不把** Human 3.0、奇门八门**单独成段**(点名起盘时八门**附在五块之后**)。**禁止** `➡️ 🎯 复述`、`📊 复盘复述`、标准复盘内独立 ☯。**分发类**达成率以 **视频号等实际成功÷计划** 为主口径。Cursor 速查:`.cursor/skills/karuo-recap-format/SKILL.md`。
|
||||
|
||||
## 13.2 五块结构(每块必带图标)
|
||||
|
||||
书写时**每块标题必须带图标 + 粗体**,例如:**🎯 目标·结果·达成率**、**📌 过程**、**💡 反思**、**📝 总结**、**▶ 下一步执行**。
|
||||
|
||||
- **🎯**:目标(一句)· 结果(一句)· 达成率(**XX%**)
|
||||
- **🎯**:**一行一句**(≤50 字)· 内含达成率 **XX%** 或 **-XX%**
|
||||
- **📌**:1、2、3 分点;复盘块内不用表格
|
||||
- **💡**:1~3 点反思
|
||||
- **📝**:一两句总结
|
||||
@@ -32,12 +32,10 @@
|
||||
**[卡若复盘](2026-03-26 16:00)**
|
||||
|
||||
**🎯 目标·结果·达成率**
|
||||
- **目标**:把第13章改成与复盘 v4.0 一致。
|
||||
- **结果**:已改写本章;要点已并入 🎯 三句口径。
|
||||
- **达成率**:**100%**
|
||||
第13章对齐复盘 v5.0 已写完,手册与真源一致,达成率 100%。
|
||||
|
||||
**📌 过程**
|
||||
1. 读固定规则 v4.0。
|
||||
1. 读 `卡若复盘格式_固定规则.md` v5.0。
|
||||
2. 重写本章结构与示例。
|
||||
3. 保存文件。
|
||||
|
||||
@@ -45,7 +43,7 @@
|
||||
1. 手册与固定规则应单源对齐,避免双口径。
|
||||
|
||||
**📝 总结**
|
||||
以后 Cursor 收尾只写五块即可。
|
||||
🎯 单行一句后,禁复述行与标准 ☯。
|
||||
|
||||
**▶ 下一步执行**
|
||||
无。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 卡若复盘格式(固定规则)
|
||||
|
||||
> **强制规则。** 卡若AI(卡路/卡罗拉同系)内**复盘格式永远只有一种**:完整复盘。**每一轮回复、每一个步骤结束**,均以**完整复盘块**收尾,不得使用简版或省略。**复盘块标题除日期外必须带时间**(YYYY-MM-DD HH:mm)。**复盘块内不用表格**,各块以**小图标 + 小标题**识别。
|
||||
> **v4.0(2026-03-26)**:**仅五块** 🎯📌💡📝▶,**不再**强制 **Human 3.0 复盘块**、**奇门 Q门 项目盘(☯)**、**达成率双复述(➡️/📊)**。原「本质/边界/证据、八门健康度」等若仍有关,**揉进 🎯 三句话里一句带过即可**,不另起块。用户**点名**要「起盘 / 占卜术 / 八门盘」时,按 `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md` **单独追加输出**,**不**计入标准复盘五块。
|
||||
> **强制规则。** 卡若AI(卡路/卡罗拉同系)内**复盘格式永远只有一种**:完整复盘。**每一轮回复、每一个步骤结束**,均以**完整复盘块**收尾。**复盘块标题除日期外必须带时间**(YYYY-MM-DD HH:mm)。**复盘块内不用表格**,各块以**小图标 + 小标题**识别。
|
||||
> **v5.1(2026-03-26)**:**仅五块** 🎯📌💡📝▶。**🎯 为单行一句话**(**整句 ≤50 字**,含标点),内嵌**目标+结果+达成率数值**;达成率 **只允许 0~100%**,表示**本阶段 / 本回合约定范围内的完成比例**(**禁止负数**;受阻或未闭环用 **0% 或较低百分比**,原因写在 📌)。**禁止** `➡️ 🎯 块后达成率复述`、`📊 复盘结束达成率复述`、**标准复盘内任何独立** ☯/奇门/八门段。原八门体感若仍需表达,**只作为短语写进这一句**,不单列。用户**点名**「起盘 / 占卜术 / 八门 / Q门」时,按 `04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md` **附在五块之后**追加,**不**计入 🎯 字数豁免。
|
||||
|
||||
---
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
| 顺序 | 图标 | 块标题 | 说明 |
|
||||
|:---:|:---:|:---|:---|
|
||||
| 1 | 🎯 | **目标·结果·达成率** | **共三句,每句一行**:**目标**(一句)·**结果**(一句,可含验收/依据)·**达成率**(**XX%** 单独一行)。不把 OKR 长文、八门、Human 3.0 **单独成段**;需要时信息**写进这三句里**。 |
|
||||
| 2 | 📌 | **过程** | 1、2、3 分点简述做了什么 |
|
||||
| 1 | 🎯 | **目标·结果·达成率** | **仅一行一句话**,**≤50 字(含标点)**:内嵌本回合**要做什么 / 实际怎样**,并给出 **达成率 0~100%**(**本阶段完成比例**,禁止负数;未做完用低值或 0%,**须在 📌 用条数/状态交代**)。 |
|
||||
| 2 | 📌 | **过程** | 1、2、3 分点简述做了什么;**含可验收数据**(尤其分发:成功条数/计划条数、脚本退出码要点) |
|
||||
| 3 | 💡 | **反思** | 1~3 点:做得好的 / 可改进的 |
|
||||
| 4 | 📝 | **总结** | 一两句结论或可复用经验 |
|
||||
| 5 | ▶ | **下一步执行** | 与本次任务、未完成项关联的下一步;无则写「无」 |
|
||||
@@ -21,10 +21,19 @@
|
||||
|
||||
---
|
||||
|
||||
## 达成率口径(验收绑定 · 强制)
|
||||
|
||||
- **取值**:**仅 0~100%**,**禁止负数**;语义为**本阶段 / 本回合约定范围内的完成比例**,不是「扣分」。
|
||||
- **默认**:达成率 **只反映本回合主交付的可验收结果**,**禁止**与交付无关的虚高百分比。
|
||||
- **多平台 / 视频号分发**:**round(本批已成功在平台条数 ÷ 本批计划条数 × 100)**,封顶 **100%**;**脚本判定已存在、去重跳过**计为已成功;登录失败、0 条成功则 **0%**(📌 写明原因与分子分母)。
|
||||
- **非分发任务**:**已完成子项 ÷ 本阶段计划子项 ×100%**,封顶 **100%**;未启动可 **0%**。
|
||||
|
||||
---
|
||||
|
||||
## 顺序总览(复盘块内 · 从上到下)
|
||||
|
||||
1. 标题行 **[卡若复盘](YYYY-MM-DD HH:mm)**
|
||||
2. **🎯 目标·结果·达成率**(目标一句、结果一句、达成率 **XX%**)
|
||||
2. **🎯 目标·结果·达成率**(**单行一句**,≤50 字,内含 **0~100%**)
|
||||
3. **📌 过程** → **💡 反思** → **📝 总结** → **▶ 下一步执行**
|
||||
|
||||
---
|
||||
@@ -39,12 +48,10 @@
|
||||
**[卡若复盘](YYYY-MM-DD HH:mm)**
|
||||
|
||||
**🎯 目标·结果·达成率**
|
||||
- **目标**:(本回合要达成什么,一句;可顺带点出对齐的诉求或范围。)
|
||||
- **结果**:(实际交付或状态,一句;可顺带点出依据/未覆盖处。)
|
||||
- **达成率**:**XX%**
|
||||
(一句话 ≤50 字:目标+结果+达成率 0~100%;本阶段完成比例,受阻时 📌 写清条数与原因。)
|
||||
|
||||
**📌 过程**
|
||||
1. 第一步做了什么。(一句)
|
||||
1. 第一步做了什么。(一句,可含条数/比例)
|
||||
2. 第二步做了什么。(一句)
|
||||
3. 第三步做了什么。(一句)
|
||||
|
||||
@@ -118,7 +125,7 @@
|
||||
🎯 · 📌 · 💡 · 📝 · ▶;不用表格。
|
||||
|
||||
- **🎯 目标·结果·达成率**
|
||||
**三行三句** + **达成率百分比一行**;**禁止**在标准复盘里再插 **🧠 Human 3.0**、**☯ 奇门项目盘**、**➡️/📊 达成率复述** 等独立段。若仍要表达「本质/边界/风险/八门体感」,**压缩进目标句或结果句**,不另起块。
|
||||
**严格一行一句、≤50 字(含标点)**,句内须出现 **达成率 0~100%**;**禁止**在标准复盘里写 **➡️/📊 复述行**、**独立 ☯/奇门/八门**(点名起盘时八门**另附**在五块之后)。
|
||||
|
||||
- **📌 过程 / 💡 反思**
|
||||
1 2 3 简短分行;中间可加流程图、示意图、图片。反思 1~3 点,每点一句;简洁、可执行、不空泛。
|
||||
@@ -133,7 +140,7 @@
|
||||
|
||||
## 强制执行
|
||||
|
||||
- **卡若AI 内所有对话**:AI 的回复**一律用复盘形式**。**复盘格式永远只有一种**:本文件中的完整复盘块(**仅** 🎯📌💡📝▶);**禁止在复盘块内使用表格**;复盘标题**除日期外必须带时间(YYYY-MM-DD HH:mm)**;**🎯 内须含达成率 XX%**;**禁止**把 Human 3.0、奇门八门、达成率双复述作为**强制固定段**塞进复盘。用户**明确要求起盘/占卜术**时,八门输出见 **`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`**,**附在标准复盘块之后**即可。
|
||||
- **卡若AI 内所有对话**:AI 的回复**一律用复盘形式**。**复盘格式永远只有一种**:本文件中的完整复盘块(**仅** 🎯📌💡📝▶);**禁止在复盘块内使用表格**;复盘标题**除日期外必须带时间(YYYY-MM-DD HH:mm)**;**🎯 须为单行一句 ≤50 字且含达成率 0~100%(禁止负数)**;**禁止** `➡️ 🎯 块后达成率复述`、`📊 复盘结束达成率复述`、**标准复盘内独立** ☯/奇门八门段。用户**明确要求起盘/占卜术**时,八门输出见 **`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`**,**附在标准复盘块之后**即可。
|
||||
- **唯一格式**:仅此一种;`.cursor/rules/karuo-ai.mdc` 与交互流程均引用本文件。
|
||||
|
||||
---
|
||||
@@ -141,6 +148,7 @@
|
||||
## 引用关系
|
||||
|
||||
- 规则:`.cursor/rules/karuo-ai.mdc` → 对话结束时强制本格式。
|
||||
- Cursor Skill:`.cursor/skills/karuo-recap-format/SKILL.md`(复盘 v5.0 速查)。
|
||||
- 交互流程:`卡若AI交互流程与强制执行条件.md` § 五 与本文件一致。
|
||||
- 执行流程:`卡若AI执行流程与对话全流程.md` 步骤 7 与本文件一致。
|
||||
- **奇门八门(非默认复盘)**:`04_卡火(火)/火炬_全栈消息/项目开发占卜术/SKILL.md`(F01c · 演门测机)。
|
||||
|
||||
@@ -438,3 +438,4 @@
|
||||
| 2026-03-24 09:50:31 | 🔄 卡若AI 同步 2026-03-24 09:49 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-26 05:02:47 | 🔄 卡若AI 同步 2026-03-26 05:02 | 更新:Cursor规则、总索引与入口、金仓、金盾、水桥平台对接、水溪整理归档、卡木、火炬、运营中枢、运营中枢参考资料等 | 排除 >20MB: 12 个 |
|
||||
| 2026-03-26 05:07:33 | 🔄 卡若AI 同步 2026-03-26 05:07 | 更新:Cursor规则、金仓、卡木、火炬、总索引与入口、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 12 个 |
|
||||
| 2026-03-26 05:17:53 | 🔄 卡若AI 同步 2026-03-26 05:17 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 12 个 |
|
||||
|
||||
@@ -441,3 +441,4 @@
|
||||
| 2026-03-24 09:50:31 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-24 09:49 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-26 05:02:47 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-26 05:02 | 更新:Cursor规则、总索引与入口、金仓、金盾、水桥平台对接、水溪整理归档、卡木、火炬、运营中枢、运营中枢参考资料等 | 排除 >20MB: 12 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-26 05:07:33 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-26 05:07 | 更新:Cursor规则、金仓、卡木、火炬、总索引与入口、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 12 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-26 05:17:53 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-26 05:17 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 12 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
|
||||
Reference in New Issue
Block a user