用 Claude 反推视频提示词:ffmpeg 抽帧 + Opus 5.5 看图
把一段视频交给 Claude Opus 5.5,拿到可以直接用于 Sora、Veo、可灵、Seedance 等视频模型的中英文提示词。一段 10 秒的视频,约 30 秒出结果,费用约 0.05~0.07 美元。
验证说明:2026-10-28 在 macOS 上使用 Python 3.13、Anthropic Python SDK 2.3.0 和 ffmpeg 9.0,对一段 10 秒、3 个镜头的程序生成测试视频抽 8 张画面,通过本站实际调用
claude-opus-5-5两次:输入均为 6,640 Token,输出分别为 2,107 和 1,458 Token,控制台记录 US$0.0653 和 US$0.0529,每次耗时约 30 秒。实际用量随画面数、视频内容和模型版本变化。
1. 原理:先抽画面,再让 Claude 看图
Claude 不能直接读取视频文件,也听不到声音。做法是先用 ffmpeg 从视频里截取若干张关键画面,按时间顺序连同时间点一起发给 Claude,让它逐个镜头分析,再写出提示词。
| 步骤 | 做什么 | 用到 |
|---|---|---|
| 抽帧 | 在视频里均匀取 8~24 个时间点,各截一张长边不超过 1024 像素的 JPEG | ffmpeg |
| 看图分析 | 图片和时间点放进同一条消息,要求逐镜头描述主体、动作、运镜、光线和风格 | Claude 原生接口、claude-opus-5-5 |
| 输出 | 只返回 JSON:分镜表、整体风格、中英文提示词和负面提示词 | Python 解析后保存 |
只分析你有权使用的视频。生成的提示词用于描述画面风格,不代表可以复制他人作品中受保护的内容。
2. 准备
需要三样东西:ffmpeg、Anthropic 官方 Python SDK 和 302API 的 Key。
# 安装 ffmpeg(任选其一)
brew install ffmpeg # macOS
winget install Gyan.FFmpeg # Windows
sudo apt install ffmpeg # Ubuntu / Debian
# 安装 SDK
pip install anthropic在 302API 控制台创建 Key,保存为环境变量 API302_KEY。不要写进代码或发到聊天里。
export API302_KEY="你的 Key" # macOS / Linux
$env:API302_KEY = "你的 Key" # Windows PowerShell3. 最小可运行脚本
保存为 video2prompt.py。脚本不到 100 行:抽帧、发给 Claude、解析结果、打印费用。
"""用 Claude 反推视频提示词:ffmpeg 均匀抽取关键画面,Claude Opus 5.5 看图写出可复用的提示词。
用法:python video2prompt.py 视频.mp4 [--frames 12]
准备:安装 ffmpeg;pip install anthropic;设置环境变量 API302_KEY(在 302API 控制台创建)。
结果:打印中英文提示词和本次费用,并把完整结果保存为“视频名.prompt.json”。
"""
import argparse
import base64
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
import anthropic
MODEL = "claude-opus-5-5"
PRICE_INPUT, PRICE_OUTPUT = 3.8, 19.0 # 本站价,美元 / 百万 Token;以 302api.com/models 为准
SYSTEM = """你是专业的视频分析师和 AI 视频提示词工程师。用户会按时间顺序给你一段视频的若干关键画面。
请先逐个镜头分析主体、动作、场景、景别与运镜、光线色调和画面风格,再写出能让 AI 视频模型生成类似视频的提示词。
只描述画面中看得到的内容;看不清或无法判断的地方写“无法判断”,不要编造。
严格只输出一个 JSON 对象,不要任何其他文字,结构如下:
{"shots":[{"start":"00:00","end":"00:03","subject":"","action":"","scene":"","camera":"","lighting":"","style":""}],
"overall_style":"",
"prompt":{"zh":"","en":""},
"negative_prompt":{"zh":"","en":""}}"""
def run(*args):
return subprocess.run(args, check=True, capture_output=True, text=True).stdout
def duration_of(video):
return float(run("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "csv=p=0", str(video)))
def extract_frames(video, count, folder):
"""在视频里均匀取 count 个时间点,各截一张长边不超过 1024 像素的 JPEG。"""
total = duration_of(video)
frames = []
for i in range(count):
at = total * (i + 0.5) / count
out = Path(folder) / f"frame_{i:02d}.jpg"
run("ffmpeg", "-v", "error", "-y", "-ss", f"{at:.2f}", "-i", str(video), "-frames:v", "1",
"-vf", "scale='min(1024,iw)':-2", "-q:v", "4", str(out))
frames.append((at, out))
return total, frames
def main():
parser = argparse.ArgumentParser(description="用 Claude 反推视频提示词")
parser.add_argument("video", type=Path)
parser.add_argument("--frames", type=int, default=12, help="抽取的画面数,默认 12,最多 24")
args = parser.parse_args()
if not os.environ.get("API302_KEY"):
sys.exit("请先设置环境变量 API302_KEY")
with tempfile.TemporaryDirectory() as folder:
total, frames = extract_frames(args.video, max(1, min(args.frames, 24)), folder)
content = []
for i, (at, path) in enumerate(frames, 1):
content.append({"type": "text", "text": f"画面 {i},{int(at // 60):02d}:{at % 60:04.1f}"})
content.append({"type": "image", "source": {"type": "base64", "media_type": "image/jpeg",
"data": base64.b64encode(path.read_bytes()).decode()}})
content.append({"type": "text", "text": f"视频总时长 {total:.1f} 秒。请按要求输出 JSON。"})
client = anthropic.Anthropic(api_key=os.environ["API302_KEY"], base_url="https://api.302api.com",
timeout=600, max_retries=3)
# 流式接收,长回复也不会因为等待太久而断开
with client.messages.stream(model=MODEL, max_tokens=4000, system=SYSTEM,
messages=[{"role": "user", "content": content}]) as stream:
message = stream.get_final_message()
text = "".join(block.text for block in message.content if block.type == "text").strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0]
result = json.loads(text)
out = args.video.with_suffix(".prompt.json")
out.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
usage = message.usage
cost = (usage.input_tokens * PRICE_INPUT + usage.output_tokens * PRICE_OUTPUT) / 1e6
print("中文提示词:\n" + result["prompt"]["zh"] + "\n")
print("English prompt:\n" + result["prompt"]["en"] + "\n")
print(f"共 {len(result['shots'])} 个镜头,完整结果已保存到 {out}")
print(f"用量:输入 {usage.input_tokens} Token,输出 {usage.output_tokens} Token,约 ${cost:.4f}(以控制台账单为准)")
if __name__ == "__main__":
main()
新旧版本的 Anthropic SDK 都可以直接使用,不需要额外设置请求头。
4. 运行并查看结果
python video2prompt.py 我的视频.mp4 --frames 8下面是验证时的实际输出(测试视频依次为分形缓慢放大、生命游戏元胞演化和旋转的渐变色)。中文提示词:
程序化生成艺术短片,三段硬切。第一段:曼德博集合分形,主心形和圆形内部呈红橙绿放射状渐变,边缘布满蓝橙绿细密分形枝杈,背景为粉紫色并带绿蓝光晕,画面缓慢平稳放大。第二段:纯黑背景上的康威生命游戏像素细胞自动机,青绿色像素组成十字、菱形、环形和成团结构,逐帧演化并留下暗蓝色残影,固定俯视画面。第三段:橙色与蓝色的平滑双色渐变,中间过渡为紫粉色,渐变分界从垂直方向缓慢旋转为斜向。二维平面、高饱和、干净锐利的数字图形,无实拍元素。
English prompt:
A procedural generative-art montage with three hard cuts. Shot 1: a Mandelbrot set fractal, the main cardioid and bulbs filled with radial red, orange and green gradients, edges covered in fine blue-orange-green fractal filaments, on a pink-violet background with a green and blue glow, slowly and smoothly zooming in. Shot 2: a Conway's Game of Life style pixel cellular automaton on pure black, cyan-green pixels forming crosses, diamonds, rings and clustered structures that evolve frame by frame and leave dark blue trails, static top-down flat view. Shot 3: a smooth orange-to-blue two-color gradient with a purple-pink blend in the middle, the dividing line slowly rotating from vertical to diagonal. Flat 2D, highly saturated, clean and crisp digital graphics, no live-action elements.
命令行最后两行:
共 3 个镜头,完整结果已保存到 sample.prompt.json
用量:输入 6640 Token,输出 1458 Token,约 $0.0529(以控制台账单为准)完整结果保存在同名的 .prompt.json 文件里,包含每个镜头的起止时间、主体、动作、运镜、光线和风格,可以挑出单个镜头的描述单独使用。
最后到控制台的调用记录核对:模型为 claude-opus-5-5,输入、输出 Token 和金额与脚本打印的一致,才说明请求确实经过本站并已结算。
5. 费用估算
本站 claude-opus-5-5 价格为输入 $3.8、输出 $19(美元 / 百万 Token),实时价格见模型与价格。一张 1024×576 的画面约 750 个输入 Token,分析结果通常在 2,000 个输出 Token 左右。
| 抽取画面数 | 输入 Token(约) | 输出 Token(约) | 单次费用(约) |
|---|---|---|---|
| 8 张(实测两次) | 6,640 | 1,458~2,107 | $0.053~0.065 |
| 12 张 | 9,700 | 2,100 | $0.077 |
| 24 张 | 18,800 | 2,100 | $0.11 |
12 张和 24 张为按实测结果推算的估计值,实际扣费以控制台账单为准。画面越多,细节越准,但费用也越高;镜头变化少的视频 8~12 张通常就够用。
6. 让 Codex 帮你写完整版工具
最小脚本适合试用。需要镜头切换检测、按目标模型(Sora、可灵等)调整写法、批量处理、本地缓存和费用统计时,可以把下面这段指令交给 Codex、Claude Code 等 AI 编程工具,让它从零写一个完整的命令行工具。
展开完整指令(可直接复制)
请帮我从零写一个“视频反推提示词”工具:输入一个视频文件,输出可直接用于 AI 视频生成模型的提示词。模型通过 302API 调用 Claude Opus 5.5。302API的接入文档:https://302api.com/docs
## 一、接口信息(必须照此实现)
- 动手前先阅读本站接入文档 https://302api.com/docs (Anthropic 格式示例、`max_tokens` 预扣费、错误码都在里面)和错误排查页 https://302api.com/guides/api-errors/ 。接口地址、参数和报错处理以文档为准;如果文档与本指令不一致,按文档实现,并在完成时告诉我哪里不一致。
- 使用 Anthropic 官方 Python SDK(`anthropic`),走 Anthropic 原生格式 `/v1/messages`。
- `base_url` 固定为 `https://api.302api.com`(不要带 `/v1`,SDK 会自动拼接)。
- 模型名:`claude-opus-5-5`。
- API Key 只从环境变量 `API302_KEY` 读取,不得写进代码、配置文件或日志;提供 `.env.example`,并把 `.env` 加入 `.gitignore`。
- 客户端超时设为 600 秒,开启 SDK 自带重试(max_retries=3);遇到 429 或 5xx 时按 `Retry-After` 退避。
- 使用流式输出(`client.messages.stream`),避免长回复超时。
- `max_tokens` 默认 8000,可通过 `--max-tokens` 调整。网关会按这个上限预扣费用,设得过大时余额不足会被拒绝。
## 二、关键限制
- Claude 不能直接读取视频,也听不到音频。必须先把视频转成若干张关键画面(JPEG),以 base64 图片的形式放进同一条 user 消息里,并在每张图前附一段文字标注它的时间点,例如“画面 3,00:07.5”。
- 每次请求最多发送 24 张画面;画面长边缩放到 1024 像素以内,JPEG 质量 80;单张图片不超过 5MB。
## 三、功能要求
1. 命令行用法:`python -m video2prompt 输入视频.mp4 [选项]`
- `--frames N`:最多取多少张画面,默认 16,上限 24。
- `--target`:目标视频模型风格,可选 `general`(默认)、`sora`、`veo`、`kling`、`seedance`、`runway`,不同目标的提示词写法放在独立的模板文件里,方便后续增改。
- `--lang`:输出语言,`zh`、`en` 或 `both`(默认 both)。
- `--out`:输出目录,默认与视频同目录。
2. 抽帧:调用系统里的 ffmpeg / ffprobe(启动时检查是否已安装,没有就给出中文安装提示)。
- 先用镜头切换检测(`select='gt(scene,0.3)'`)找出镜头变化点;
- 镜头数不足时按时长均匀补帧,超过上限时均匀抽样;
- 始终包含第一帧和最后一帧;
- 记录每张画面的时间点和所属镜头序号。
3. 可选字幕或对白:如果视频带字幕轨,用 ffmpeg 提取成文本一并发给模型;没有就跳过。不要自行接入语音识别。
4. 发给模型的系统提示词要求它:
- 先逐个镜头分析:主体、动作、场景、光线、色调、景别、机位与运镜(推拉摇移跟、手持、航拍等)、转场、节奏、画面风格(写实、动画、胶片感等)、时长;
- 再给出整体风格总结;
- 最后按 `--target` 对应模板写出最终提示词:一段完整的整体提示词 + 每个镜头一段分镜提示词 + 负面提示词;
- 只描述画面里看得到的内容,看不清的地方明确写“无法判断”,不要编造;
- 严格只输出 JSON,结构见下。
5. 输出 JSON 结构(用 pydantic 定义并校验,校验失败时把错误信息发回模型重试一次):
```
{
"video": {"file": "", "duration_sec": 0, "shots": 0},
"shots": [{"index": 1, "start": "00:00.0", "end": "00:03.2", "subject": "", "action": "", "scene": "", "camera": "", "lighting": "", "style": ""}],
"overall_style": "",
"prompt": {"zh": "", "en": ""},
"shot_prompts": [{"index": 1, "zh": "", "en": ""}],
"negative_prompt": {"zh": "", "en": ""}
}
```
同时生成一份便于阅读的 Markdown 报告(附带抽出的画面缩略图)。
6. 用量与费用:从响应的 `usage` 读取输入、输出 Token,按每百万 Token 输入 3.8 美元、输出 19 美元估算本次费用,在命令行末尾打印。价格写成配置项,不要写死在逻辑里。
7. 缓存:以“视频文件哈希 + 参数”为键,把抽帧结果和模型结果缓存到本地 `.cache/`,同一视频同一参数不重复调用接口;提供 `--no-cache` 跳过缓存。
8. 批量:支持传入文件夹,逐个处理,单个失败不影响其他文件,最后汇总成功和失败清单。
## 四、工程要求
- Python 3.10+,依赖写进 `requirements.txt`(anthropic、pydantic、python-dotenv 等,尽量少)。
- 代码结构:抽帧、调用模型、提示词模板、输出写入分别放在独立模块。
- 所有给用户看的提示和报错用简体中文。
- 写单元测试:抽帧逻辑用一段用 ffmpeg 现场生成的测试视频;模型调用部分用假客户端,不真实请求接口。
- README(中文)写清:安装 ffmpeg、配置 `API302_KEY`、使用示例、费用估算方法、常见错误(401 是 Key 不对;402 是余额不足以预扣本次费用,需要充值或调小 `--max-tokens`;429 是请求太快)。
完成后先用一个 10 秒左右的视频、`--frames 8` 实际跑一次,确认图片能正常发送并返回合规 JSON,再告诉我结果。常见问题
401 / 认证失败
检查环境变量 API302_KEY 在当前终端是否可见、Key 是否已在控制台停用。
402 / 余额不足
请求前会按 max_tokens 上限临时冻结费用,余额不够时返回 402。充值,或把脚本里的 max_tokens 调小。
413 / 请求太大
减少 --frames 数量,或把截图的长边从 1024 像素再调小。
描述不准或漏掉镜头
均匀抽帧可能错过很短的镜头。增加画面数,或改用第 6 节完整版里的镜头切换检测。
能识别对白和背景音乐吗?
不能,Claude 只看画面。视频自带字幕轨时,可以用 ffmpeg 把字幕提取成文本一起发送。
参考与下一步
Claude 原生接口说明 · Claude 模型价格 · 报错排查 · 提示缓存省钱指南 · ffmpeg 官方文档