跳转至

VideoDB 技能

面向视频、直播流和桌面会话的感知 + 记忆 + 行动。

用例

桌面感知

  • 启动/停止桌面会话,并捕获屏幕、麦克风和系统音频
  • 流式传输实时上下文,并保存分段会话记忆
  • 针对所说内容和屏幕上发生的事情执行实时警报/触发器
  • 生成会话摘要、可搜索时间线和可播放证据链接

视频摄取 + 流式传输

  • 摄取文件或 URL,并返回可播放的 Web 流链接
  • 转码/规范化:编解码器、比特率、帧率、分辨率、宽高比

索引 + 搜索(时间戳 + 证据)

  • 构建视觉、音频、关键词索引
  • 使用时间戳和可播放证据搜索并返回精确时刻
  • 从搜索结果自动创建剪辑

时间线编辑 + 生成

  • 字幕:生成、翻译、烧录
  • 叠加层:文本/图像/品牌标志、动态字幕
  • 音频:背景音乐、旁白、配音
  • 通过时间线操作进行程序化合成和导出

直播流(RTSP)+ 监控

  • 连接 RTSP/直播流
  • 执行实时视觉和音频理解,并为监控工作流发出事件/警报

工作原理

通用输入

  • 本地文件路径、公开URL 或 RTSP URL
  • 桌面捕获请求:开始 / 停止 / 创建会话摘要
  • 目标操作:获取理解上下文、转码规格、索引规格、搜索查询、剪辑范围、时间线编辑、警报规则

通用输出

  • 流 URL
  • 带有时间戳和证据链接的搜索结果
  • 生成的资产:字幕、音频、图像、剪辑
  • 面向直播流的事件/警报载荷
  • 桌面会话摘要和记忆条目

运行 Python 代码

在运行 VideoDB 代码之前,请切换到项目目录并加载环境变量:

from dotenv import load_dotenv
load_dotenv(".env")

import videodb
conn = videodb.connect()

这将从以下位置加载 VIDEO_DB_API_KEY:

  1. 环境变量(如果已导出)
  2. 项目当前目录中的 .env 文件

如果缺少密钥,videodb.connect() 会自动引发 AuthenticationError。

如果简短的内联命令足够,就不要编写脚本文件。

编写内联 Python(python -c "...")时,始终使用格式良好的代码——用分号分隔语句,使其易于阅读。如果超过约 3 条语句,请使用 heredoc:

python << 'EOF'
from dotenv import load_dotenv
load_dotenv(".env")

import videodb
conn = videodb.connect()
coll = conn.get_collection()
print(f"Videos: {len(coll.get_videos())}")
EOF

设置

如果用户要求“设置 videodb”等:

1. 安装 SDK

pip install "videodb[capture]" python-dotenv

如果在 Linux 上 videodb[capture] 失败,请不带捕获扩展安装:

pip install videodb python-dotenv

2. 配置 API 密钥

用户需要通过任一方法设置 VIDEO_DB_API_KEY:

  • 在终端中导出(在启动 Claude 之前):export VIDEO_DB_API_KEY=your-key
  • 项目中的 .env 文件:将 VIDEO_DB_API_KEY=your-key 保存到项目的 .env 文件中

要免费获取 API 密钥,请访问 console.videodb.io(无需信用卡,可免费上传 50 次)。

不要自行读取、写入或处理 API 密钥。始终让用户进行设置。

快速参考

上传媒体

# URL
video = coll.upload(url="https://example.com/video.mp4")

# YouTube
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")

# Local file
video = coll.upload(file_path="/path/to/video.mp4")

转录 + 字幕

# force=True skips the error if the video is already indexed
video.index_spoken_words(force=True)
text = video.get_transcript_text()
stream_url = video.add_subtitle()
from videodb.exceptions import InvalidRequestError

video.index_spoken_words(force=True)

# search() raises InvalidRequestError when no results are found.
# Always wrap in try/except and treat "No results found" as empty.
try:
    results = video.search("product demo")
    shots = results.get_shots()
    stream_url = results.compile()
except InvalidRequestError as e:
    if "No results found" in str(e):
        shots = []
    else:
        raise
import re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError

# index_scenes() has no force parameter — it raises an error if a scene
# index already exists. Extract the existing index ID from the error.
try:
    scene_index_id = video.index_scenes(
        extraction_type=SceneExtractionType.shot_based,
        prompt="Describe the visual content in this scene.",
    )
except Exception as e:
    match = re.search(r"id\s+([a-f0-9]+)", str(e))
    if match:
        scene_index_id = match.group(1)
    else:
        raise

# Use score_threshold to filter low-relevance noise (recommended: 0.3+)
try:
    results = video.search(
        query="person writing on a whiteboard",
        search_type=SearchType.semantic,
        index_type=IndexType.scene,
        scene_index_id=scene_index_id,
        score_threshold=0.3,
    )
    shots = results.get_shots()
    stream_url = results.compile()
except InvalidRequestError as e:
    if "No results found" in str(e):
        shots = []
    else:
        raise

时间线编辑

重要: 在构建时间线之前,务必验证时间戳:

  • start 必须 >= 0(负值会被静默接受,但会生成损坏的输出)
  • start 必须小于 end
  • end 必须 <= video.length
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle

timeline = Timeline(conn)
timeline.add_inline(VideoAsset(asset_id=video.id, start=10, end=30))
timeline.add_overlay(0, TextAsset(text="The End", duration=3, style=TextStyle(fontsize=36)))
stream_url = timeline.generate_stream()

视频转码(分辨率/质量变更)

from videodb import TranscodeMode, VideoConfig, AudioConfig

# Change resolution, quality, or aspect ratio server-side
job_id = conn.transcode(
    source="https://example.com/video.mp4",
    callback_url="https://example.com/webhook",
    mode=TranscodeMode.economy,
    video_config=VideoConfig(resolution=720, quality=23, aspect_ratio="16:9"),
    audio_config=AudioConfig(mute=False),
)

调整宽高比(面向社交平台)

警告: reframe() 是低速的服务器端操作。对于长视频可能需要几分钟,并可能超时。最佳实践:

  • 尽可能使用 start/end 限制为短片段
  • 对于完整长度视频,使用 callback_url 进行异步处理
  • 首先使用 Timeline 裁剪视频,然后调整较短结果的宽高比
from videodb import ReframeMode

# Always prefer reframing a short segment:
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)

# Async reframe for full-length videos (returns None, result via webhook):
video.reframe(target="vertical", callback_url="https://example.com/webhook")

# Presets: "vertical" (9:16), "square" (1:1), "landscape" (16:9)
reframed = video.reframe(start=0, end=60, target="square")

# Custom dimensions
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})

生成媒体

image = coll.generate_image(
    prompt="a sunset over mountains",
    aspect_ratio="16:9",
)

错误处理

from videodb.exceptions import AuthenticationError, InvalidRequestError

try:
    conn = videodb.connect()
except AuthenticationError:
    print("Check your VIDEO_DB_API_KEY")

try:
    video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
    print(f"Upload failed: {e}")

常见问题

场景 错误消息 解决方案
为已索引的视频创建索引 Spoken word index for video already exists 使用 video.index_spoken_words(force=True) 跳过已索引项
场景索引已存在 Scene index with id XXXX already exists 使用 re.search(r"id\s+([a-f0-9]+)", str(e)) 从错误中提取现有的 scene_index_id
无搜索结果 InvalidRequestError: No results found 捕获异常并将其作为空结果处理(shots = [])
宽高比调整超时 长视频会无限期阻塞 使用 start/end 限制片段,或为异步处理传递 callback_url
时间轴上的负时间戳 静默生成损坏的流 在创建 VideoAsset 之前始终验证 start >= 0
generate_video() / create_collection() 失败 Operation not allowed 或 maximum limit 受套餐限制的功能——通知用户套餐限制

示例

标准 Prompt

  • “开始桌面捕获,并在显示密码字段时发出警报。”
  • “记录会话,并在结束时生成可执行的摘要。”
  • “导入此文件并返回可播放的流链接。”
  • “索引此文件夹,找到所有包含人物的场景,并返回时间戳。”
  • “生成字幕并烧录,添加轻背景音乐。”
  • “连接此 RTSP URL,并在有人进入区域时发出警报。”

屏幕录制(桌面捕获)

使用 ws_listener.py 在录制会话期间捕获 WebSocket 事件。桌面捕获仅支持 macOS。

快速开始

  1. 选择状态目录:STATE_DIR="${VIDEODB_EVENTS_DIR:-$HOME/.local/state/videodb}"
  2. 启动监听器:VIDEODB_EVENTS_DIR="$STATE_DIR" python scripts/ws_listener.py --clear "$STATE_DIR" &
  3. 获取 WebSocket ID:cat "$STATE_DIR/videodb_ws_id"
  4. 运行捕获代码(完整工作流参见 reference/capture.md)
  5. 事件写入位置:$STATE_DIR/videodb_events.jsonl

每次开始新的捕获运行时,始终使用 --clear,以避免旧转录和视觉事件泄漏到新会话中。

事件查询

import json
import os
import time
from pathlib import Path

events_dir = Path(os.environ.get("VIDEODB_EVENTS_DIR", Path.home() / ".local" / "state" / "videodb"))
events_file = events_dir / "videodb_events.jsonl"
events = []

if events_file.exists():
    with events_file.open(encoding="utf-8") as handle:
        for line in handle:
            try:
                events.append(json.loads(line))
            except json.JSONDecodeError:
                continue

transcripts = [e["data"]["text"] for e in events if e.get("channel") == "transcript"]
cutoff = time.time() - 300
recent_visual = [
    e for e in events
    if e.get("channel") == "visual_index" and e["unix_ts"] > cutoff
]

附加文档

参考文档位于与 SKILL.md 文件相同目录下的 reference/ 目录中。必要时使用 Glob 工具查找。

当 VideoDB 支持该操作时,不要使用 ffmpeg、moviepy 或本地编码工具。 以下所有操作均由 VideoDB 在服务器端处理——裁剪、合并片段、叠加音频或音乐、添加字幕、文本/图像叠加、转码、更改分辨率、转换宽高比、调整大小以满足平台要求、转录、媒体生成。仅当涉及 reference/editor.md 中“限制”部分列出的操作(转场、变速、裁剪/缩放、调色、音量混音)时,才回退到本地工具。

应该使用什么

问题 VideoDB 解决方案
平台拒绝视频的宽高比或分辨率 使用 VideoConfig 的 video.reframe() 或 conn.transcode()
需要为 Twitter/Instagram/TikTok 调整视频大小 video.reframe(target="vertical") 或 target="square"
需要更改分辨率(例如:1080p → 720p) 使用 VideoConfig(resolution=720) 的 conn.transcode()
需要为视频叠加音频/音乐 在 Timeline 中使用 AudioAsset
需要添加字幕 video.add_subtitle() 或 CaptionAsset
需要合并/裁剪片段 在 Timeline 中使用 VideoAsset
需要生成旁白、音乐、音效 coll.generate_voice()、generate_music()、generate_sound_effect()

来源

此技能的参考资料在 skills/videodb/reference/ 下本地提供。 运行时不要跟踪外部仓库链接,而是使用上述本地副本。

维护者: VideoDB

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC