mutonby/skill-autoshorts

GitHub: mutonby/skill-autoshorts

一个自动化视频剪辑管道,每日从长视频中提取并发布病毒式短视频片段。

Stars: 64 | Forks: 12

# lish. 其核心思路是维护一个较小的长视频待处理列表,每次录制新视频时将其转发给你的智能体。智能体(Hermes / Openclaw 或你正在运行的任何其他)会自动将其保存到输入文件夹中 —— 你无需手动管理路径,只需在聊天中发送视频即可。该技能每天从该文件夹中选取一个视频(优先处理最新的未处理视频,因此你刚发送的视频会排在队列前面),识别出值得剪辑的片段,进行剪切,叠加一个吸引人的钩子文本,并在同一个聊天频道中询问你希望发布哪些片段。你回复片段 ID 后,它会通过 [Upload-Post](https://upload-post.com) 在 TikTok / Instagram / YouTube 上进行定时发布。 **输入视频应已为 9:16 竖屏格式**(理想尺寸为 1080×1920),并且是准备好在社交媒体上发布——如果你需要字幕,也应已烧录在视频中。该技能不会重新格式化、裁剪或烧录字幕。它只负责剪切和添加钩子文本叠加层。将输入文件夹视为“近乎最终的长视频素材”,而不是原始的摄像机转储。 这与 Opus Clip / Vizard 销售的工作流相同,但你拥有其中的每一部分,并且你能够掌握实际发布的内容。 ## 设置提示 粘贴到 Claude Code、Codex、Hermes、Openclaw 或任何具有 shell 访问权限的智能体中: ``` ┌─────────────────┐ │ long video.mp4 │ └────────┬────────┘ │ ├──────────────► Whisper (medium, local) │ ─ word-level timestamps │ ─ language auto-detect │ ─ outputs transcript.json │ └──────────────► Gemini 3 Flash (multimodal, cloud) ─ receives the FULL VIDEO + the transcript ─ sees laughter, gestures, scene changes ─ MUST snap clip start/end to word boundaries from the transcript ─ outputs clips.json with {start, end, hook_text, reason, score} │ ▼ ffmpeg cut + Pillow hook overlay │ ▼ Upload-Post API ↳ TikTok (draft) ↳ Instagram Reels ↳ YouTube Shorts ``` ## 安装 当智能体读到本节时,它应遵循以下完整安装协议: 1. 克隆或 `git pull` 此仓库到 `~/Documents/skill-autoshorts/`(或用户偏好的其他路径)。 2. 确保已安装 `ffmpeg`(macOS 上使用 `brew install ffmpeg`,Linux 上使用 `apt install ffmpeg`)。通过 `ffmpeg -version` 验证。 3. 创建虚拟环境并安装 Python 依赖:`python3 -m venv venv && ./venv/bin/pip install -r requirements.txt`。 4. 向正在运行的智能体框架注册 `SKILL.md`。对于 Claude Code,将其复制或符号链接到 `~/.claude/skills/autoshorts/SKILL.md`。对于 Hermes / Openclaw,请遵循其技能注册文档。 5. 根据 `.env.example` 创建 `.env` 文件,并请求用户粘贴所需的值: - `GEMINI_API_KEY` — https://aistudio.google.com/apikey (免费层级即可)。 - `UPLOAD_POST_API_KEY` 和 `UPLOAD_POST_PROFILE` — https://app.upload-post.com → 设置 → API 密钥 + 管理用户(提供免费层级,无需信用卡)。 - 将默认的 `INPUT_FOLDER` 和 `OUTPUT_FOLDER` 设置为 `~/Documents/skill-autoshorts/input` 和 `.../output`,除非用户另有说明。默认 `WHISPER_MODEL=medium` 和 `TIMEZONE=Europe/Madrid`(如果用户处于其他时区,请覆盖)。 6. 验证 Upload-Post 密钥是否有效:`curl -s -H "Authorization: Apikey $UPLOAD_POST_API_KEY" https://api.upload-post.com/api/uploadposts/users` 应返回用户的个人资料和连接的平台。突出显示任何显示 `reauth_required: true` 的平台,以便用户在首次发布前修复。 7. 端到端阅读 `SKILL.md`。这是规范的日常工作流——可视化 QA、每周 `learn`、所有操作规则。 **安装后,无需执行其他操作。** 不要转录,不要调用 Gemini,不要发布。告知用户一切已就绪,总结 Upload-Post 上连接的内容,然后等待。此后,用户将在聊天中转发视频给你——你的工作是将每个视频保存到 `INPUT_FOLDER`,并在他们要求时调用该技能(`/autoshorts` 或等效命令)。 ### 安装期间给用户的注意事项 - 首次转录调用会下载 Whisper `medium` 模型(约 1.5 GB)。后续运行是即时的。 - Upload-Post 平台要求:**TikTok** 任何账户均可 · **Instagram** 必须是已关联 Facebook 主页的商业或创作者账户 · **YouTube** 任何 Google 账户 · LinkedIn / Reddit / Threads / X 同样受支持。 - `UPLOAD_POST_PROFILE` 值是你在 Upload-Post → 管理用户中创建的**配置文件名称**,而不是你的社交媒体用户名。 ## 有趣的环节:如何挑选片段 大多数“自动剪辑”工具要么 (a) 仅基于文本工作,错失了使某个时刻变得有趣/紧张/可分享的视觉线索;要么 (b) 仅基于视频工作,产生在词中截断的粗糙剪切。我们避开了这两种方式。 ``` ┌─────────────────┐ │ long video.mp4 │ └────────┬────────┘ │ ├──────────────► Whisper (medium, local) │ ─ word-level timestamps │ ─ language auto-detect │ ─ outputs transcript.json │ └──────────────► Gemini 3 Flash (multimodal, cloud) ─ receives the FULL VIDEO + the transcript ─ sees laughter, gestures, scene changes ─ MUST snap clip start/end to word boundaries from the transcript ─ outputs clips.json with {start, end, hook_text, reason, score} │ ▼ ffmpeg cut + Pillow hook overlay │ ▼ Upload-Post API ↳ TikTok (draft) ↳ Instagram Reels ↳ YouTube Shorts ``` **为何此组合有效:** 1. **Whisper 是计时器。** 词级时间戳意味着每次剪切都在清晰的单词边界上开始和结束。没有音节中间的截断,没有半口气的断点。 2. **Gemini Flash 是编辑器。** 它是多模态的——我们通过 Files API 发送实际的视频文件以及转录文本。它能看到笑点落地,听到笑声,注意到场景变化,对屏幕上的图表做出反应。关键是,提示词强制它使用 Whisper 转录文本中的时间戳,因此它无法凭空想象“20.5秒”而错失一个音节。 3. **流水线由人把关。** 模型提出方案;你做决定。每个候选片段在你看到之前都已剪切和渲染完毕,因此你审阅的是实际最终视频,而不是描述。你可以用手机回复。 ## 用法 ### 在智能体框架内运行(推荐 — Hermes / Openclaw / 类似工具) 这是该技能的构建目的。VPS 上的智能体框架运行每日定时任务,通过你的即时通讯工具提醒你(“这是今天的候选片段,我发布哪些?”),捕获你的回复,并完成闭环。你只需在录制新视频时在聊天中转发;你每天会收到片段候选的推送;你用手机回复 ID。安装后即可无需干预。 该技能本身不与 Telegram / WhatsApp / 等直接交互——由智能体框架负责。该技能只负责运行流水线并呈现候选片段表格;框架将其转发到你的即时通讯工具并将你的回复传递回来。 对于调用,框架要么在每日定时任务中触发 `/autoshorts`,要么在其自身的技能系统中调用等效命令。SKILL.md 是约定规范。 ### 作为独立 CLI 使用 ``` source venv/bin/activate # - MEDIA_UPLOAD: Technical term, keep in English. python autoshorts.py pick # - source video: 'source' might be translated, but in context, it's fine to translate. The instruction says to keep technical jargon in English, but 'source video' is common in video processing, so I'll translate it. However, in the examples, 'Kubernetes Setup' has 'Kubernetes' in English but 'Setup' translated. So, I should translate the common words but keep proper nouns and specific terms. python autoshorts.py transcribe input/your-video.mp4 # Re-evaluating: The instruction says "Keep all professional terms, proper nouns, tool/library/framework names, and technical jargon in their original English form." So: python autoshorts.py analyze input/your-video.mp4 # - autoshorts: Likely a tool name, so keep in English. python autoshorts.py extract input/your-video.mp4 \ --start 12.34 --end 45.67 \ --output output/your-video/clip_1.mp4 python autoshorts.py hook output/your-video/clip_1.mp4 \ --text "Tu hook aquí" --duration 3 \ --output output/your-video/clip_1_final.mp4 # - output//transcript.json: This is a file path with technical terms; might be a variable, so keep entire path in English. python autoshorts.py publish output/your-video/clip_1_final.mp4 \ --platforms tiktok,instagram,youtube \ --title "general title" \ --description "general description" \ --tiktok-title "TikTok-specific (max 90 chars, can have emojis + hashtags)" \ --instagram-title "Instagram caption (long-form, 500-800 chars + 20-30 hashtags)" \ --youtube-title "YouTube title (~40-60 chars, SEO-friendly)" \ --schedule "2026-05-01T10:00:00" \ --timezone "Europe/Madrid" \ --tiktok-mode draft # - Gemini: Tool or model name, keep in English. python autoshorts.py mark-processed input/your-video.mp4 \ --clips-generated 5 --clips-published 3 ``` ### 作为每日循环 整个系统设计为持续运行,每天一个视频: - 只要有新的长视频,你随时将其放入 `INPUT_FOLDER`。 - 定时任务 / systemd / openclaw 调度每天触发 `/autoshorts`。 - `pick` 命令总是选择**最新的未处理**视频。新素材会优先处理。旧的未处理视频仍会随时间逐渐处理。 - `state/processed.json`(以 sha256 为键)是运行之间的唯一记忆——它防止同一视频被重复剪辑。 - 如果你拒绝所有候选片段(回复“none”),该视频仍被标记为已消费。要重试,请手动从 `state/processed.json` 中删除其条目。 ## 如何学习 该流水线会随着你发布的每个片段而变得更智能。参与度数据从 Upload-Post 分析回流到选择明天片段的 Gemini 提示中。 ``` publish ─────► Upload-Post │ │ ▼ ▼ post-history.jsonl real platform metrics (clip → request_id, (views, likes, comments, hook, score, …) shares, saves) │ │ └───────┬────────┘ │ ▼ (weekly) learn subcommand ─ z-score per platform ─ composite = 0.6·views + 0.4·engagement_rate ─ top 20% = winners ─ bottom 20% = losers │ ▼ Gemini Flash "Here are winners and losers, plus the current HOT.md. Output an updated HOT.md (≤80 lines of patterns)." │ ▼ learnings/HOT.md │ ▼ (every analyze call, automatically) prepended to Gemini's analyze prompt │ ▼ tomorrow's clips reflect what worked ``` ### 三个 CLI 命令驱动此循环 | 命令 | 频率 | 作用 | |---|---|---| | `publish`(附带 `--clip-id --hook-text --viral-score --reason --video-source`) | 每个已批准的片段 | 将片段的完整上下文记录到 `learnings/post-history.jsonl`,以便后续与指标关联 | | `learn` | 每周 | 拉取最新分析数据,找出成功/失败案例,要求 Gemini 刷新 `HOT.md` | | `reflect`(可选) | 任何你需要时 | 快速定性分析——比较你批准 vs 拒绝的候选片段,无需指标 | ### 复合指标 `learn` 使用加权 z 分数对片段进行排名: ``` composite = 0.6 × z(total_views) + 0.4 × z(engagement_rate) where engagement_rate = (likes + comments + shares + saves) / total_views ``` 两个权重都是可配置的标志(`--weight-views`, `--weight-engagement`)——如果你更注重质量而非覆盖面,可调高参与度权重;如果追求纯数量,则调低。 ### 沉淀窗口 `learn --soak-days 7`(默认值):发布时间不足 7 天的片段被排除——参与度指标需要时间成熟,每日学习会追逐噪音。超过 90 天的片段 = 过时,同样被忽略。 如果你只有少于大约 5 个成功和 5 个失败案例,`learn` 会跳过综合分析,并向 `learnings/runs/learn-YYYY-MM-DD.md` 写入“数据不足”的说明。继续发布即可。 ### 可审计性 每次 `learn` 运行都会向 `learnings/runs/learn-YYYY-MM-DD.md` 写入完整审计日志:哪些片段被判定为成功,及其分数、先前的 HOT.md 和新的 HOT.md 并排显示。先前的 HOT.md 也会备份为 `HOT.YYYYMMDD-HHMMSS.md.bak`。如果 Gemini 综合出无用内容,你可以回滚。 ### Reflect(无指标定性分析) `reflect --window-days 30` 是一种更快的分析方式,无需等待参与度数据。它比较 Gemini **提供**的片段与你**批准**的片段,并要求 Gemini 提取定性模式(“批准包含具体数字的钩子,拒绝提问形式的钩子”)。输出到 `learnings/runs/reflect-...md`,并且**不会**自动提升到 HOT.md——这是供你阅读和整理的笔记。 ### 为何我们不自动提升所有内容 `learn` 仅基于指标覆盖 `HOT.md`——这是安全的,因为数据是真实的。`reflect` 是观察性的,可能会固化你过去的偏见(“我总是拒绝提问式钩子”),而非实际有效的内容。因此 reflect 输出保留在 `runs/` 中供人工审查。 ## 文件布局 ``` skill-autoshorts/ ├── README.md ← you are here ├── autoshorts.py ← CLI: pick / transcribe / analyze / extract / hook / publish / mark-processed ├── requirements.txt ├── .env ← secrets (gitignored) ├── .env.example ├── input/ ← drop long videos here ├── output/ │ └── / │ ├── transcript.json ← Whisper output (segments + word timestamps) │ ├── clips.json ← Gemini's clip selections │ ├── clip_1.mp4 ← raw cut │ ├── clip_1_final.mp4 ← cut + hook overlay │ └── … ├── state/ │ └── processed.json ← sha256s of videos already processed └── learnings/ ├── HOT.md ← auto-managed by `learn`, prepended to every analyze prompt ├── post-history.jsonl ← every clip we published (request_id, hook, score, …) ├── candidate-history.jsonl ← every candidate Gemini offered (so reflect can compare) ├── metrics.jsonl ← analytics snapshots from Upload-Post ├── insights/ ← MANUAL notes (not used by the pipeline) └── runs/ ├── learn-YYYY-MM-DD.md └── reflect-YYYY-MM-DD-HHMM.md ``` ## 各平台文案指南 发布助手接受一个通用的 `--title` / `--description`,外加各平台的覆盖参数。长度要求不对称: | 平台 | 字段 | 实际最佳长度 | 硬性限制 | 风格 | |---|---|---|---|---| | YouTube Shorts | `--youtube-title` | **40–60 字符** | 100 | 简短,包含关键词,利于 SEO。移动端过长会被截断。 | | TikTok | `--tiktok-title` | 70–85 字符 | 90 | 有力,1–2 个表情符号,标签置于末尾。 | | Instagram Reels | `--instagram-title` | 500–800 字符 | 2200 | 长篇叙事:钩子行,2–4 个短段落,行动号召,然后 20–30 个标签。 | 不要跨平台复用同一段文案。YouTube 需要精简;Instagram 需要深度。 ## 为何选择这些技术 - **Whisper `medium`** — 在消费级硬件(CPU `int8`)上精度与速度的平衡点。`small` 速度是两倍,但在专业词汇上表现较差;`large-v3` 明显更好但慢约 3 倍。 - **Gemini 3 Flash Preview (multimodal)** — 有免费层级,可通过 Files API 接受视频,通过 `response_mime_type=application/json` 返回严格 JSON,且运行成本足够低,可每日运行。关键是它能*观看*视频,而不仅仅是阅读转录文本。 - **Pillow + ffmpeg overlay** 用于钩子文本——替代方案(ffmpeg 的 `drawtext` 滤镜)需要 `libfreetype`,而许多 Homebrew 的 ffmpeg 构建缺少它。使用 PIL 将钩子渲染为透明 PNG,然后与始终可用的 `overlay` 滤镜合成,更具可移植性,并且能提供更好的文本渲染(抗锯齿、自动换行、多行布局)。钩子本身使用 TikTok 风格的**每行文本后的黑色药丸背景**(78% 不透明度,圆角),无论底下是什么——纯白帧、纯黑帧或复杂的屏幕共享——都能保持清晰可读,无需逐帧分析。 - **Upload-Post** — 一个 API 适用于约 10 个平台,在其仪表板中处理 OAuth,支持定时发布和平台特定标题。免费层级(每月 10 次上传)足以验证流水线;付费计划适用于生产量级。 ## 局限性 / 需知事项 - **配额**:Upload-Post 免费层级 = 每月 10 次上传,其中向 3 个平台发布一次计为 3 次。提供付费计划。 - **TikTok 草稿模式(默认)**:使用 `--tiktok-mode draft` 时,片段会进入你的 TikTok 收件箱(`post_mode=MEDIA_UPLOAD`)——你需要在 TikTok 应用中完成编辑后再发布。如果你想立即发布,使用 `--tiktok-mode direct`。 - **Whisper 首次运行下载**:首次转录约 1.5 GB;之后缓存。 - **Gemini Files API 处理**:一个 9 分钟的视频在 Google 端需要约 30–60 秒的处理时间才能查询。脚本会轮询并等待。 - **速率限制**:每日循环的设计部分是为了友好地遵守 TikTok / Instagram 的限制——一次性批量发布积压内容比每天发一个更可能被标记。 - **最新优先排序**:如果你每天都持续放入新视频,旧的可能会无限期地留在队列中。这是有意设计的(新鲜内容 > 旧积压),但如果你想要严格的先进先出,请修改 `cmd_pick` 中的排序方式。
标签:9:16视频格式, AI模型, AI视频处理, AI辅助编辑, ffmpeg, Instagram, Python编程, TikTok, YouTube, 上传API, 内容创作, 内容管理系统, 发布调度, 工作流自动化, 平台集成, 数据学习, 数据驱动优化, 用户交互, 病毒式内容, 短视频制作, 社交媒体营销, 视频剪辑, 语音识别, 逆向工具, 钩子文本叠加