VideoDB スキル
ビデオ、ライブストリーム、デスクトップセッションのための認識 + 記憶 + アクション。
使用するタイミング
デスクトップ認識
- 画面、マイク、システムオーディオをキャプチャするデスクトップセッションの開始/停止
- ライブコンテキストのストリーミングとエピソード的セッション記憶の保存
- 画面上で話されている内容や発生しているイベントに対するリアルタイムアラート/トリガーの実行
- セッションサマリー、検索可能なタイムライン、再生可能な証拠リンクの生成
ビデオ取り込み + ストリーム
- ファイルまたはURLから取り込み、再生可能なWebストリームリンクを返す
- トランスコード/正規化: コーデック、ビットレート、fps、解像度、アスペクト比
インデックス + 検索(タイムスタンプ + 証拠)
- 視覚、音声、キーワードインデックスの構築
- 検索して正確な瞬間をタイムスタンプと再生可能な証拠とともに返す
- 検索結果からクリップを自動生成
タイムライン編集 + 生成
- 字幕: 生成、翻訳、焼き込み
- オーバーレイ: テキスト/画像/ブランディング、モーションキャプション
- オーディオ: 背景音楽、ナレーション、吹き替え
- タイムライン操作によるプログラム的な合成とエクスポート
ライブストリーム (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 が以下の場所から読み取られます:
- 環境変数(すでにエクスポートされている場合)
- 現在のディレクトリのプロジェクト
.envファイル
キーがない場合、videodb.connect() は自動的に AuthenticationError を発生させます。
短いインラインコマンドで済む場合は、スクリプトファイルを作成しないでください。
インラインPython(python -c "...")を記述する場合は、常に適切にフォーマットされたコードを使用してください — セミコロンを使用してステートメントを区切り、読みやすく保ちます。約3ステートメントを超える場合は、代わりにヒアドキュメントを使用してください:
python << 'EOF'
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
coll = conn.get_collection()
print(f"動画数: {len(coll.get_videos())}")
EOF
セットアップ
ユーザーが「videodbをセットアップする」などと要求した場合:
1. SDKのインストール
pip install "videodb[capture]" python-dotenv
videodb[capture] がLinuxで失敗した場合は、capture拡張なしでインストールしてください:
pip install videodb python-dotenv
2. APIキーの設定
ユーザーは以下のいずれかの方法で VIDEO_DB_API_KEY を設定する必要があります:
- ターミナルにエクスポート(Claude起動前):
export VIDEO_DB_API_KEY=your-key - プロジェクトの
.envファイル: プロジェクトの.envファイルにVIDEO_DB_API_KEY=your-keyを保存
無料の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")
# ローカルファイル
video = coll.upload(file_path="/path/to/video.mp4")
文字起こし + 字幕
# force=True は、動画がすでにインデックスされている場合のエラーをスキップします
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() は結果が見つからない場合に InvalidRequestError を送出します。
# 常に try/except でラップし、「結果が見つかりません」を空として扱います。
try:
results = video.search("製品デモ")
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() には force パラメータがありません — シーン
# インデックスがすでに存在する場合、エラーが発生します。エラーから既存のインデックスIDを抽出します。
try:
scene_index_id = video.index_scenes(
extraction_type=SceneExtractionType.shot_based,
prompt="このシーンの視覚的な内容を説明してください。",
)
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
# score_threshold を使用して低関連性ノイズをフィルタリング(推奨: 0.3以上)
try:
results = video.search(
query="ホワイトボードに書いている人",
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="終わり", duration=3, style=TextStyle(fontsize=36)))
stream_url = timeline.generate_stream()
動画のトランスコード(解像度/品質の変更)
from videodb import TranscodeMode, VideoConfig, AudioConfig
# サーバー側で解像度、品質、アスペクト比を変更
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
# 常に短いセグメントをリフレームすることを推奨:
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
# フルレングス動画の非同期リフレーム(None を返し、結果は webhook 経由):
video.reframe(target="vertical", callback_url="https://example.com/webhook")
# プリセット: "vertical" (9:16), "square" (1:1), "landscape" (16:9)
reframed = video.reframe(start=0, end=60, target="square")
# カスタム寸法
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})
生成メディア
image = coll.generate_image(
prompt="夕日が山に沈む様子",
aspect_ratio="16:9",
)
エラーハンドリング
from videodb.exceptions import AuthenticationError, InvalidRequestError
try:
conn = videodb.connect()
except AuthenticationError:
print("VIDEO_DB_API_KEY を確認してください")
try:
video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
print(f"アップロードに失敗しました: {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 | プランで制限された機能 — ユーザーにプラン制限について通知 |
例
代表的なプロンプト
- 「デスクトップキャプチャを開始し、パスワードフィールドが表示されたらアラートを出してください。」
- 「セッションを録画し、終了時に実用的なサマリーを生成してください。」
- 「このファイルを取り込んで、再生可能なストリームリンクを返してください。」
- 「このフォルダをインデックスして、人がいるすべてのシーンを見つけ、タイムスタンプを返してください。」
- 「字幕を生成し、焼き込んで、軽い背景音楽を追加してください。」
- 「このRTSP URLに接続し、人がゾーンに入ったらアラートを出してください。」
画面録画(デスクトップキャプチャ)
録画セッション中にWebSocketイベントをキャプチャするには ws_listener.py を使用します。デスクトップキャプチャは macOS のみをサポートしています。
クイックスタート
- 状態ディレクトリを選択:
STATE_DIR="${VIDEODB_EVENTS_DIR:-$HOME/.local/state/videodb}" - リスナーを起動:
VIDEODB_EVENTS_DIR="$STATE_DIR" python scripts/ws_listener.py --clear "$STATE_DIR" & - WebSocket IDを取得:
cat "$STATE_DIR/videodb_ws_id" - キャプチャコードを実行(完全なワークフローについては reference/capture.md を参照)
- イベントが書き込まれる場所:
$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ツールを使用して見つけてください。
- reference/api-reference.md - 完全なVideoDB Python SDK APIリファレンス
- reference/search.md - ビデオ検索(音声単語およびシーンベース)の詳細ガイド
- reference/editor.md - タイムライン編集、アセット、および合成
- reference/streaming.md - HLSストリーミングとインスタント再生
- reference/generative.md - AIによるメディア生成(画像、動画、音声)
- reference/rtstream.md - ライブストリーム取り込みワークフロー(RTSP/RTMP)
- reference/rtstream-reference.md - RTStream SDKメソッドとAIパイプライン
- reference/capture.md - デスクトップキャプチャワークフロー
- reference/capture-reference.md - キャプチャSDKとWebSocketイベント
- reference/use-cases.md - 一般的な動画処理パターンと例
VideoDBが操作をサポートしている場合は、ffmpeg、moviepy、またはローカルのエンコードツールを使用しないでください。 以下はすべてVideoDBによってサーバーサイドで処理されます — トリミング、クリップの結合、オーディオまたは音楽のオーバーレイ、字幕の追加、テキスト/画像オーバーレイ、トランスコード、解像度変更、アスペクト比変換、プラットフォーム要件に合わせたリサイズ、文字起こし、メディア生成。reference/editor.md の制限事項(トランジション、速度変更、クロップ/ズーム、カラーグレーディング、音量ミキシング)にリストされている操作についてのみ、ローカルツールにフォールバックしてください。
何をいつ使うか
| 問題 | VideoDBの解決策 |
|---|---|
| プラットフォームが動画のアスペクト比または解像度を拒否 | video.reframe() または VideoConfig を使用した 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/ の下にローカルにベンダリングされています。実行時に外部のリポジトリリンクをたどる代わりに、上記のローカルコピーを使用してください。