Video Reader — 给大模型配的一副"看视频的眼镜"
SkillFiles & storageLets video-incapable LLMs "watch videos". Use this skill when the user gives you a video file (.mp4/.mov/.gif, etc.) and wants you to understand what happens in it, especially for debugging app scrolling/interaction issues, reproducing bugs, analyzing user screen recordings, observing dynamic process
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Video Reader — 给大模型配的一副"看视频的眼镜" skill
What this skill tells your AI
The instructions your AI receives, as published by job-yang/jobyang-ai-skills in skills/video-reader/SKILL.md and read by ahel’s review.
这个 skill 解决什么问题
你(大模型)能看图,但看不了视频。视频本质就是一串按时间排好的图片。 本 skill 的脚本帮你做两件你做不了或做不好的事:
- 初筛:用帧差(相邻帧像素差异,纯数学,不花 token)算出"哪几秒画面在动", 自动跳过静止段。用户经常从"盘古开天辟地"开始录,前面几十秒对着桌子没动—— 这些会被整段折叠,一帧都不喂给你。
- 智能抽帧:只在有动作的地方抽帧,而且支持"先粗后细"两轮下钻,既不漏关键帧, 又不会把上下文撑爆。
重要边界:这个 skill 不含任何业务逻辑。 它不懂"卡顿""面板""跟手""中间态"是什么。 它只负责把视频变成"你能消化的帧 + 时间线"。看懂画面、判断对错、定位 bug——那是你的活。
四个子命令,按需要选(别只会 scan)
本 skill 有四个能力,接到视频任务先想清楚要哪个,不要永远只用 scan:
| 子命令 | 什么时候用 | 一句话 |
|---|---|---|
scan | 默认起点;要定位"哪几秒在动/出问题" | 帧差初筛+运动时间线+稀疏抽帧 |
zoom | 已知可疑区间,要看那几秒的细节 | 指定区间高密度抽帧 |
grid | 想先要个全片概览、一张图看节奏,或视频较长先扫一眼 | 均匀取帧拼成九宫格大图,一次 Read 看全片 |
transcribe | 画面看不出、需要听(旁白/口述/报错语音/"他说了啥") | 语音转文字(带时间戳,可选,需 ffmpeg+whisper) |
常见组合:长视频/不确定从哪看 → 先 grid 看全片节奏 → scan 看运动时间线 → zoom 下钻可疑段;涉及"说了什么" → 加 transcribe 与画面时间线对齐。 用户即使没点名,你也应根据意图主动选对子命令并告诉他你用了哪个、为什么。
核心工作流:粗扫 → 下钻(由你驱动)
不要一上来就把整段视频高密度抽帧,那样既慢又炸上下文。标准打法是两步,你来决定抽哪、抽多细:
第1步 scan(粗扫)
└─ 脚本输出:运动时间线(文字) + 活动段稀疏抽的几帧
└─ 你看时间线 + 帧,判断"问题大概在 X-Y 秒"
↓
第2步 zoom(下钻)
└─ 脚本在 X-Y 秒密集抽帧
└─ 你看细节;若还不够,继续在更小区间 zoom(可多轮)
关键心法:先读时间线,再决定要不要看帧、看哪段的帧。 很多时候 scan 的运动时间线 (纯文字)就足够让你判断该往哪下钻,这是最省 token 的方式。
上传被拦怎么办(很多平台禁视频格式,务必知道)
很多平台(如 Mira 等)在上传时直接禁掉视频/音频格式,用户传 .mp4/.mov 会被提示
"不支持的文件类型",根本传不进来。这不是死路,有两个绕过办法,你必须主动告诉用户:
- 改后缀:把
xxx.mp4重命名成平台允许的后缀(如xxx.txt/xxx.bin)再上传。 你拿到后不要被后缀骗了——它本质还是视频,先把它改回.mp4(或直接用原始路径)再喂给脚本即可。 OpenCV 按文件内容解码,不认后缀,所以哪怕后缀是.txt,只要内容是视频就能读; 实在不放心就cp 那个文件 /tmp/v.mp4再处理。 - 压成 zip:把视频压成
.zip上传(zip 通常不被拦)。你收到后先解压拿到里面的视频文件, 再喂给脚本。解压是你(大模型)调用解压能力完成的,脚本本身不处理 zip。
一句话:平台拦的是"后缀/格式",不是"内容"。改后缀或套个 zip 壳就能绕过, 拿到真身后照常 scan/zoom。遇到"视频传不上去"先想到这两招,别让用户卡在上传这一步。
怎么调用
脚本路径(用绝对路径调用):
<SKILL_DIR>/scripts/video_frames.py
依赖:Python3 + opencv-python-headless + numpy(matplotlib 仅 --debug 画曲线图时用)。OpenCV 自带视频解码,不依赖系统 ffmpeg。
脚本会自动检测并安装缺失依赖(pip install --user --break-system-packages,不污染系统),无需手动准备;只有自动安装失败时才会打印一条人话提示让你手动装。
脚本每次启动都会在 stderr 先自报家门(当前解释器路径 / 版本 / user-site)。若遇到"依赖装了却 import 不到",99% 是机器上多个 python3 错配(装包用解释器 A、跑脚本命中解释器 B,而 pip --user 按版本号分目录存包)。这时看启动打印的 python: 那行,把跑脚本的解释器对齐到装了包那个(用绝对路径,或建 venv)即可。报错提示里也会带上当前解释器路径,照着做不用手敲 which -a 排查。
scan —— 粗扫全片
python3 <SKILL_DIR>/scripts/video_frames.py scan <视频路径>
输出:stdout 是结构化 JSON(含 timeline、active_segments、frames 列表及每帧路径), stderr 是给你看的运动时间线概要。先读 timeline 决定下一步。
常用参数:
--start <秒> --end <秒>:只扫某段(用户给了大概范围时用)。--density <N>:活动段每秒抽几帧,默认 2(粗扫够用)。--max-width <px>:帧最大宽度,默认 900(省 token);要看清小字可调大。
zoom —— 对可疑区间高密度抽帧
python3 <SKILL_DIR>/scripts/video_frames.py zoom <视频路径> --start 10.0 --end 12.0 --density 8
--density 默认 8(每秒 8 帧),要看某个瞬间(如手指抬起那一刻)可加到 12~15,
区间也尽量收窄(如 10.5–11.0)。
grid —— 九宫格概览(一张图看全片节奏)
全片(或区间)均匀取帧拼成一张大图,每格左上角标秒数。一次 Read 一张图就能把握整段视频的节奏/概貌,省 token、好定位;看完再用 zoom 对可疑那一格的时间段下钻。
python3 <SKILL_DIR>/scripts/video_frames.py grid <视频路径>
python3 <SKILL_DIR>/scripts/video_frames.py grid <视频路径> --rows 4 --cols 4 --start 0 --end 30
--rows/--cols:网格行列,默认 3×3=9 格;长视频可加大(如 4×4)。--cell-width每格宽,默认 320。- 输出:JSON 里
grid_path是拼好的大图路径,cells[]是每格的t(秒)/行列号。Read 这张grid_path即可,按"从左到右、从上到下"读,每格角上的秒数就是它在视频里的时间。 - 和 scan 互补:scan 的运动时间线擅长"哪几秒在动",grid 擅长"整段长啥样"。不确定从哪看、或视频较长时,先 grid 毛估再 scan/zoom。
transcribe —— (可选)语音转写,补画面看不到的信息
画面只告诉你"看到什么",但旁白、客诉口述、报错语音提示这些只能听到的信息,靠这个子命令补。它是可选软能力,缺依赖只提示并跳过,不影响 scan/zoom:
python3 <SKILL_DIR>/scripts/video_frames.py transcribe <视频路径> --model turbo
- 依赖:系统
ffmpeg(抽音轨) +openai-whisper(pip,带 torch 较重,脚本会"用到才按需装")。任一缺失会打印安装方法并以退出码 4 跳过,你据此降级到只看画面即可。 --model:whisper 模型,默认turbo(快且准);要更准可用medium/large。--language zh/en可指定语言,默认自动检测。- 输出:stdout 是 JSON(
text全文 +segments带时间戳分段),stderr 是带时间戳的逐段文字。 - 用法心法:把转写的时间戳和
scan的画面运动时间线对齐,就能说出"第 X 秒画面在做什么、同时说了什么",定位更准。无音轨的纯录屏会自动跳过。
--debug —— 调试模式(默认关闭)
平时不用开。调试技能本身、或想搞清楚"为什么这段被判成静止/运动"时加上 --debug:
python3 <SKILL_DIR>/scripts/video_frames.py scan <视频路径> --debug
开了之后:
- 帧不再进随机临时目录,而是存到 当前目录的
video_reader_debug/<视频名>_<模式>/,稳定可复查。 - 额外产出
_debug/motion_data.json(每个采样点的时间+运动分、阈值、分段)和_debug/motion_curve.png(帧差曲线图,带阈值线和活动段底纹)。看这张图就能一眼判断 阈值定得对不对、该不该的段有没有被漏掉或误判,据此调--threshold。
看帧
JSON 里 frames[].path 是每帧的绝对路径,frames[].t 是它在视频里的秒数。
用 Read 工具读这些帧时,务必在心里(或回复里)把每张图和它的 t 时间戳绑定,
这样你才能说出"第几秒发生了什么"。读完即弃,不必保留。
怎么把帧"讲"给自己和用户
你的产出不是"我看到一个面板",而是带时间线的客观叙述,例如:
3.1s 面板在底部,处于全屏列表态
3.5s 面板开始向上滑动(用户在拖动)
3.8s 手指离开,面板停在约半屏位置
4.5s 面板没有继续吸附,停在中途不动 —— 与"应锚定半屏/全屏"的预期不符
如果用户给了上下文(同事的吐槽、预期行为),把它当作对照的参照系: 先客观描述实际发生了什么,再指出哪一帧/哪一秒和预期不一致。 如果用户没说用户干了啥,就别瞎猜对错,只做客观复述,把"事实时间线"摆出来, 让用户结合业务去判断。
几条实战经验(为什么这么设计)
- 静止段为什么要折叠:截图是不会"卡"的,静止段对排查交互问题没信息量, 只会浪费你的注意力和上下文。让代码把它们扔掉,你只看有动作的部分。
- 为什么时间戳用文字绑定而不是烧进画面:你读文字是 100% 准的,而认画面里烧的字 可能糊、可能挡画面、可能读错。所以脚本把时间放在文件名/JSON 里,你 Read 时对应上即可。
- 翻拍视频(带手、反光、抖动)怎么办:帧差用了"缩小+模糊+分块"来吸收噪点和轻微抖动, 所以翻拍视频也能大致定位到运动段。但手指位置这类细节,翻拍下精度有限,只能定性看方向, 必要时在回复里说明"这是翻拍视频,手指位置为估计"。
- GIF / 无音轨 / 元数据缺失:脚本对 fps 异常做了兜底(默认按 30fps),GIF 也能读。
不要做的事
- 不要把整段长视频一次性高密度抽帧再全部 Read —— 这就是上下文爆炸的根源。永远先 scan。
- 不要在 skill 里写死任何业务判断(什么算"正常滑动")。判断交给你和用户,skill 只供帧。
- 不要依赖"屏幕录制小白点"才能工作 —— 大多数视频没有,有就当福利,没有也得能干活。
Signals
- GitHub stars
- 79
- Forks
- 3
- Last commit
- Sep 2026
ahel review
K1binfo
installs-packagesK1binfo
installs-packages (in scripts/video_frames.py)K1binfo
installs-packages (in README.md)K1binfo
installs-packages (in README.zh-CN.md)
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
video-reader- Source
- github.com/job-yang/jobyang-ai-skills