关于 video-search
这是用于定位视频片段并回答视频语音或画面内容问题的 VideoDB 技能。它指导 Agent 通过转录文本搜索,或使用 VideoDB 工具和 Python SDK 深入分析单个视频及视频集合。
主要功能
- 01搜索转录文本中的匹配片段
- 02针对视频内容提问
- 03跨视频集合搜索
- 04筛选或汇总检测到的物体
- 05根据匹配片段生成剪辑
适用场景
- 01查找视频中讨论某主题的位置
- 02回答有关场景和屏幕文字的问题
- 03搜索并比较视频库中的内容
MCP 相关
提供 VideoDB 连接器工具时,该技能指导 Agent 上传、分析和搜索视频及视频集合;也说明了连接器不可用时使用 Python SDK 的方式。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ video-db/ skills --skill video-search安装后在 Claude Code 中输入/video-search确认已加载。
详细介绍
查找片段,或向视频提问
选择路径
- 已提供 VideoDB 连接器工具(名称如
upload_media、search_video、ask_video、understand_video):使用这些工具。这是在 Claude 网页版、桌面版和移动版聊天,以及 Cowork 中使用的路径。无需安装任何内容,也不要索要 API 密钥。 - 没有 VideoDB 工具,但有 shell(Claude Code、Cowork,或任何能运行 Python 的 Agent):用一句友好的话索要 VideoDB API 密钥(可在 https://console.videodb.io 免费获取,含 $20 额度,无需银行卡)。用户通过聊天或其他方式提供密钥后,由你自行将其保存到项目的
.env文件中,变量名为VIDEO_DB_API_KEY;绝不要打印密钥,然后继续使用本文末尾的 Python SDK 路径。在 Claude Code 中,也可以使用/mcp,然后授权 videodb。 - 没有 VideoDB 工具,也没有 shell:你当前处于 Claude 聊天中。只回复以下内容,并根据请求调整措辞:“尚未连接 VideoDB。请打开 Settings → Connectors,找到 VideoDB,点击 Connect 并登录(免费,无需银行卡)。然后重新发送此请求,我会接手处理。”此处不要提及 API 密钥、
.env、shell、Claude Code 或/mcp;这些都不适用于聊天,而且在聊天中粘贴密钥也无法使用,因为这里不能运行代码。
与用户交流时:回复中绝不要使用“索引”“已索引”或“正在索引”。请说“可搜索”(“现在可以根据说了什么和画面中显示的内容进行搜索”),并使用“转录”,不要提及任务名称。每次只发送一行状态信息,然后给出结果。
长时间运行的任务会返回 status: processing。回复中会包含 output_url,并指出用于轮询的工具(poll_with,旧版服务则使用 retry_with)。使用该工具和 output_url 继续轮询,直到状态变为 done;连续多次返回 processing 属于正常情况(上传一个 10 分钟的 YouTube 视频大约需要五分钟),如果返回 done 但结果为空,请再轮询一次。绝不要重新运行写入操作,否则会启动第二个任务。
使用连接器工具
1. 获取视频。 首先调用 search_videos_by_title(query),并传入视频标题或链接中的文字;如果账号中已有该视频的 m- ID,则重复使用。否则,对于 YouTube 链接或公开 URL,调用 upload_media(url),轮询直到状态为 done,并记下 m- ID 和以秒为单位的 length。用户没有 URL,且文件在其电脑上:连接器无法接收本地文件;请引导他们前往 https://console.videodb.io 上传,然后继续使用 m- ID。
2. 选择快速路径或索引路径。
快速路径,默认用于回答关于视频中说了什么的一次性问题。 自行阅读转录文本并找到相关片段:
generate_transcript(media_id) # a job; poll until done (instant if already transcribed)
get_transcript(media_id, timestamped=true, segmenter="sentence") # sentence segments with start and end seconds
扫描各片段,找出用户描述的时刻,记下起止时间,然后转到步骤 4。无需建立索引。注意两个问题:转录任务的 done 结果包含文本和词语列表,但该列表会被截断,因此务必使用 get_transcript 读取;默认的分段器按词分段,最多 2000 个片段,因此请传入 segmenter="sentence"(可处理几小时的语音),或使用 start 和 end 指定时间窗口。如果工具截断的视频仍然过长,或者用户会持续询问该视频相关问题,就说明应该使用索引路径。
没有匹配项:直截了当地说明,不要把牵强的匹配说成用户询问的内容。YouTube 上传内容可能只是较长演讲的节选。可以提供最接近的片段,并明确标注;也可以请用户提供另一个视频。
索引路径。 如果问题涉及画面内容而非说话内容、用户需要计数或精确筛选条件、用户会针对同一视频或媒体库提出多个问题,或者转录文本过长而无法阅读,请使用此路径。先检查 list_indexes(video_id);如果没有可用索引:
understand_video(video_id, analyzers=[
{"type": "spoken_words", "name": "transcript"},
{"type": "vlm", "name": "scene", "config": {"prompt": "Describe the scene and any on-screen text."}}
])
轮询 get_understanding(video_id, understanding_id),直到每个分析器的状态都为 done,然后为每个分析器建立一个索引:
create_index(video_id, understanding_id, analyzer_name="transcript")
create_index(video_id, understanding_id, analyzer_name="scene")
只需处理语音内容(播客、通话):仅运行 spoken_words 分析器。涉及对象和计数(“有多少辆汽车”):添加 {"type": "object_detection"} 或 {"type": "activity_recognition"}。
3. 检索(索引路径)。
| 用户需求 | 调用 |
|---|---|
| 带时间戳的片段 | search_video(video_id, query, include_clip=true) |
| 带来源的书面回答 | ask_video(video_id, question, include_sources=true) |
| 搜索整个媒体库 | search_collection(query) 或 ask_collection(question) |
| 计数和分组(“哪些对象出现得最多”) | aggregate_index(video_id, index_name="objects", group_by="frames.detections.label") |
| 精确筛选条件(“标签 = car 的场景”) | query_index(video_id, index_name, filter) |
| 深入调查并进行后续提问 | search_video(..., mode="deepsearch"),然后在下次调用时传入 session_id |
4. 提供结果。 将片段的 start 到 end 时间以 mm:ss 格式给出,并附上匹配的文字(引用转录文本或每条搜索结果中的 text);如果设置了 include_clip,还要提供每个片段的 player_url。将匹配项剪辑成一个片段:调用 generate_clip(video_id, timeline=[[start, end], ...])(单位为秒,在每侧留出几秒余量会更便于阅读),轮询,然后分享 player_url。
使用 index_spoken_words 或 index_scenes(v1)建立索引的旧视频,需使用 legacy_search_video 和 legacy_search_collection 进行搜索。
使用 Python SDK(Claude Code)
如果 import videodb 失败,请先使用 /videodb:setup 进行设置。完整参考文档:${CLAUDE_PLUGIN_ROOT}/python/SKILL.md 和 ${CLAUDE_PLUGIN_ROOT}/python/reference/search.md。
from dotenv import load_dotenv; load_dotenv(".env")
import videodb, time
conn = videodb.connect(); coll = conn.get_collection()
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
u = video.understand(analyzers=[{"type": "spoken_words", "name": "transcript"},
{"type": "vlm", "name": "scene", "config": {"prompt": "Describe the scene."}}])
u.wait_until_complete()
for a in u.list_analyzers():
if a.is_successful: video.index(source=a, name=a.name).wait_until_complete()
r = video.search("the part about pricing")
for s in r.shots: print(f"[{s.start:.0f}s-{s.end:.0f}s] {s.text}")
print(r.compile()) # stream URL of the matches; player: https://console.videodb.io/player?url={STREAM_URL}