Stateful, multi-turn video retrieval with a production-grade indexing pipeline built on VideoDB.
Explore the docs »
Quick Start
·
Features
·
How It Works
·
Python Integration
·
LLM Routing
·
Report Bug
Traditional video search often collapses complex intent into one embedding query.
DeepSearch improves relevance by combining:
- Indexing orchestration (scene extraction, transcript, object detection, multimodal enrichment, summary indexes)
- Retrieval orchestration (LLM-planned multi-index search, validator loop, reranking, and follow-up refinement)
- Stateful retrieval memory (context-aware refinement across conversational turns)
- Index from a public video URL or an existing VideoDB media ID
- Structured indexing telemetry via event callbacks for progress visibility
- Multi-turn search sessions with
search,followup,resume_session - Explainable clip results (primary subquery, primary index, supporting subqueries)
- Robust conversational continuity with persisted session state across turns
- Pluggable stores with SQLite defaults for sessions, index records, metadata, and artifacts
- Configurable model routing and per-stage model overrides
- Vision-aware enrichment for stronger multimodal retrieval quality
DeepSearch has two connected runtimes:
- Indexing runtime builds semantic indexes from scenes, transcript, and optional object signals.
- Retrieval runtime runs a stateful LangGraph loop that plans queries, validates candidates, reranks clips, and supports follow-up turns.
For each user query, DeepSearch returns ranked clips with explainability fields so you can see why each clip matched.
- Python 3.10+
- uv 0.8+
- VideoDB API key (console.videodb.io)
- OpenAI-compatible API key for configured LLM route
Recommended install (best retrieval quality):
uv sync --extra detectionDeepSearch uses object detection during indexing to add object-level visual signals (for example: person, laptop, car, traffic sign) into scene metadata. Retrieval then uses those signals during ranking and refinement, which improves results for object-centric queries.
If you want a lighter setup without local detector dependencies, you can still run DeepSearch by installing base deps only and disabling detection in config.
Base-only install:
uv syncThen set indexing.object_detection.mode to a non-local value in deepsearch_config.yaml to skip detection:
indexing:
object_detection:
mode: offcp .env.sample .envSet at minimum:
VIDEO_DB_API_KEYOPENAI_API_KEY
Optional:
DEEPSEARCH_DB_PATHDEEPSEARCH_CONFIG(defaults todeepsearch_config.yaml)
If you use a different LLM route:
- OpenRouter route: set
OPENROUTER_API_KEY - Vercel AI Gateway route: set
VERCEL_AI_GATEWAY_API_KEYand optionallyVERCEL_AI_GATEWAY_BASE_URL
--collection-id is optional. If you already have a VideoDB collection, pass its ID. If you leave it empty, DeepSearch falls back to your account default collection via the SDK.
uv run python index_video.py \
[--collection-id <collection_id>] \
--video-url <public_video_url>Or index an existing VideoDB media object:
uv run python index_video.py \
[--collection-id <collection_id>] \
--media-id <media_id>If your source video is local, upload it to VideoDB first, copy the returned media_id, then run indexing with --media-id.
import videodb
conn = videodb.connect(api_key="YOUR_VIDEO_DB_API_KEY")
collection = conn.get_collection() # or conn.get_collection("<collection_id>")
# Upload local media file
video = collection.upload(file_path="./videos/my_video.mp4", name="My Local Video")
print("media_id:", video.id)Then index it with DeepSearch:
uv run python index_video.py \
[--collection-id <collection_id>] \
--media-id <media_id>uv run python run_deepsearch.py \
[--collection-id <collection_id>] \
--query "rainy night scenes with emotional dialogue"Interactive commands:
/morefor next page/helpfor command help/exitto end and printsession_id
If you are integrating DeepSearch directly inside your app, use DeepSearchClient:
from deepsearch import DeepSearchClient
client = DeepSearchClient(config="deepsearch_config.yaml")
# Index from a public URL
manifest = client.index_video(
collection_id="c-...",
video_url="https://example.com/video.mp4",
)
# Or index an existing VideoDB media
# manifest = client.index_video(collection_id="c-...", media_id="m-...")
session = client.start_session(collection_id="c-...", page_size=5)
first = session.search("find product demo moments")
next_page = session.followup(ui_event={"type": "show_more"})
refined = session.followup(text="only include scenes with pricing discussion")DeepSearch supports typed config, dict config, and YAML-file config.
- Default config file:
deepsearch_config.yaml - Config schema:
deepsearch/config/schema.py - Environment overrides via
DeepSearchConfig.from_env()withDEEPSEARCH_prefix and nested keys using double underscores
Example:
export DEEPSEARCH_RETRIEVAL__PAGE_SIZE=20DeepSearch uses one configured LLM route for a run (OpenAI-compatible, OpenRouter, or Vercel AI Gateway), while still letting you set different models per indexing/retrieval node.
llm:
route: openrouter
provider_mode: openrouter
openrouter:
enabled: true
api_key_env: OPENROUTER_API_KEYllm:
route: vercel_ai_sdk_python
provider_mode: directllm:
models:
indexing:
scene_enrichment: openai/o3
subplot_summary: openai/o3-mini
final_summary: openai/o3
retrieval:
planner: openai/o3
paraphrase: openai/gpt-4o-mini
validator: openai/o3-mini
none_analyzer: openai/o3-mini
interpreter: openai/o3
reranker: openai/o3Use model IDs valid for your selected route/provider.
deepsearch/
├── client.py # Public client/session entrypoints
├── indexing/ # Indexing pipeline + stage contracts
├── retrieval/ # LangGraph retrieval graph + nodes
├── providers/ # LLM and detector provider adapters
├── stores/ # Session/metadata/index record stores
├── config/ # Typed config schema and defaults
├── telemetry/ # Logging utilities
└── errors/ # Error taxonomy and typed errors
index_video.py # CLI script for indexing
run_deepsearch.py # Interactive retrieval script
sample_end_user_usage.py # End-user API walkthrough
deepsearch_config.yaml # Example config
docs/PRD.md # Product requirements draft
docs/specs.md # Technical specs draft
If detection stage raises missing modules (torch, transformers, etc.), either install detection extras or disable local detection mode in config.
uv sync --extra detectionIf indexing fails after upload/extract, rerun index_video with the printed media_id (and optionally --force-reindex) to continue from persisted artifacts.
- Docs: docs.videodb.io
- Issues: GitHub Issues
- Discord: Join community
- Console: Get API key
Made with ❤️ by the VideoDB team