sentrysearch README

The project's README from github.com/ssrajadh/sentrysearch. As one markdown file: README.md.

SentrySearch

Semantic search over video footage. Type what you're looking for, get a trimmed clip back.

[!IMPORTANT] Official source: github.com/ssrajadh/sentrysearch is the only official home of SentrySearch. Other sites republishing or mirroring this project are not affiliated with or endorsed by the maintainer, always download from this repository.

Languages: English · 简体中文

New: SentrySearch codebase walkthrough video

The Pipeline:

  1. SentrySearch (find an event in your footage)
  2. SentryMerge (auto-cut the multi-cam footage into one video that follows the subject across cameras)
  3. SentryBlur (auto-redact sensitive information)

Table of Contents

How it works

SentrySearch splits your videos into overlapping chunks, embeds each chunk as video using Google's Gemini Embedding API, Alibaba DashScope (qwen-cloud), or a local Qwen3-VL model, and stores the vectors in a local ChromaDB database. When you search, your text query (or image, see search by image) is embedded into the same vector space and matched against the stored video embeddings. The top match is automatically trimmed from the original file and saved as a clip.

Getting Started

  1. Install uv (if you don't have it):

macOS/Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh

Windows:

powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
  1. Clone and install:
git clone https://github.com/ssrajadh/sentrysearch.git
cd sentrysearch
uv tool install .

Requires Python 3.11 or 3.12 (PyTorch wheels don't yet support 3.13+). If your default Python is newer, install a managed 3.12 and pin the tool install:

uv python install 3.12
uv tool install --python 3.12 .
  1. Set up your API key (or use a local model instead) — only needed for the default Gemini backend; skip if you use --backend local or --backend qwen-cloud with DASHSCOPE_API_KEY in .env.
sentrysearch init

This prompts for your Gemini API key, writes it to .env, and validates it with a test embedding.

  1. Index your footage:
sentrysearch index /path/to/footage
  1. Search:
sentrysearch search "red truck running a stop sign"

ffmpeg is required for video chunking and trimming. If you don't have it system-wide, the bundled imageio-ffmpeg is used automatically.

Manual setup: If you prefer not to use sentrysearch init, you can copy .env.example to .env and add your key from aistudio.google.com/apikey manually.

Usage

Init

$ sentrysearch init
Enter your Gemini API key (get one at https://aistudio.google.com/apikey): ****
Validating API key...
Setup complete. You're ready to go — run `sentrysearch index <directory>` to get started.

If a key is already configured, you'll be asked whether to overwrite it.

Tip: Set a spending limit at aistudio.google.com/billing to prevent accidental overspending.

Index footage

$ sentrysearch index /path/to/video/footage
Indexing file 1/3: front_2024-01-15_14-30.mp4 [chunk 1/4]
Indexing file 1/3: front_2024-01-15_14-30.mp4 [chunk 2/4]
...
Indexed 12 new chunks from 3 files. Total: 12 chunks from 3 files.

Options:

$ sentrysearch search "red truck running a stop sign"
  #1 [0.87] front_2024-01-15_14-30.mp4 @ 02:15-02:45
  #2 [0.74] left_2024-01-15_14-30.mp4 @ 02:10-02:40
  #3 [0.61] front_2024-01-20_09-15.mp4 @ 00:30-01:00

Saved clip: ./match_front_2024-01-15_14-30_02m15s-02m45s.mp4

If the best result's similarity score is below the confidence threshold (default 0.41), you'll be prompted before trimming:

No confident match found (best score: 0.28). Show results anyway? [y/N]:

With --no-trim, low-confidence results are shown with a note instead of a prompt.

Options: --results N, --output-dir DIR, --no-trim to skip auto-trimming, --threshold 0.5 to adjust the confidence cutoff, --save-top N to save the top N clips instead of just the best match, --dedupe to drop results too similar to a higher-ranked pick (prevents near-duplicate chunks of the same event from filling the list), and --rerank to ask a VLM to re-rank the returned candidates before trimming. Backend and model are auto-detected from the index — pass --backend or --model only to override.

# Save top 5 clips, dropping near-duplicates
sentrysearch search "red truck" --save-top 5 --dedupe 0.9

# Re-rank the top 10 embedding matches with a VLM before trimming
sentrysearch search "pedestrian crossing behind the car" --rerank --results 10

The --dedupe value is a cosine similarity ceiling (0–1). Any result whose similarity to an already-kept higher-ranked result exceeds this value is dropped. Lower values are stricter: 0.8 requires results to be very distinct, 0.95 only removes near-identical chunks. 0.9 is a good default.

--rerank extracts each returned candidate clip, sends it to a VLM with the query, and sorts likely visual matches ahead of embedding-only results. Gemini and qwen-cloud searches use Gemini 2.5 Flash for reranking; local searches use a local Qwen3-VL Instruct reranker. If reranking cannot run or a candidate cannot be scored, SentrySearch keeps the embedding-ranked results instead of failing the search.

Search by image

Use a reference image as the query — useful for "find clips that look like this" when describing the scene in words is awkward (a screenshot of a specific car, a reference frame from another video, etc.).

$ sentrysearch img ~/Downloads/image.jpg
  #1 [0.72] 2026-03-12_10-44-17-left_repeater.mp4 @ 00:00-00:30
  #2 [0.69] 2026-03-12_10-44-17-left_repeater.mp4 @ 00:25-00:55
  #3 [0.67] 2026-02-12_20-02-15-front.mp4 @ 00:00-00:18

Saved clip: ./match_2026-03-12_10-44-17-left_repeater_00m00s-00m30s.mp4

The image is embedded into the same vector space as the indexed video chunks and ranked by cosine similarity. Image search supports --results, --threshold, --save-top, --dedupe, --overlay, --no-trim, --backend, and --model.

Supported formats: JPG, PNG, WEBP, GIF, HEIC/HEIF on the Gemini backend; the local backend additionally accepts anything PIL can decode (BMP, TIFF, etc.).

Note: Image search returns visually similar matches, not necessarily the same object. A red sedan query may surface other red sedans of similar shape — calibrate expectations accordingly.

Highlights

Don't know what to search for? sentrysearch highlights ranks the most anomalous clips in your index — chunks whose embeddings sit far from everything else — and trims them automatically. Good for skimming a fresh dump of footage.

$ sentrysearch highlights -n 3
  #1 [0.165] 2026-02-12_20-02-15-back.mp4 @ 00:00-00:18
  #2 [0.163] 2026-02-12_20-02-15-right_repeater.mp4 @ 00:00-00:18
  #3 [0.149] 2026-02-12_20-02-15-front.mp4 @ 00:00-00:18
...

Scoring methods (--method):

Refinement options:

Caveat: Statistically anomalous ≠ interesting. Sensor glitches, lens flare, night frames in a mostly-daytime index, and the lone garage clip all rank high. Use --exclude-baseline and --dedupe to filter the noise, or --against to constrain by topic.

Qwen Cloud (Alibaba DashScope)

Use the optional qwen-cloud backend for DashScope / Model Studio multimodal embeddings (default model qwen3-vl-embedding, overridable with --dashscope-model or DASHSCOPE_EMBEDDING_MODEL):

uv tool install ".[qwen-cloud]"
export DASHSCOPE_API_KEY=...
sentrysearch index /path/to/footage --backend qwen-cloud
sentrysearch search "your query" --backend qwen-cloud

Video uploads: local chunk files are sent to DashScope-managed temporary OSS by the official Python SDK before the API consumes them (the HTTP API expects a URL; the SDK handles upload for you).

Local Backend (no API key needed)

Index and search using a local Qwen3-VL-Embedding model instead of the Gemini API. Free, private, and runs entirely on your machine. For the best search quality, use the Gemini backend — the local 8B model is a solid alternative when you need offline/private search, and the 2B model is a fallback when hardware can't support 8B.

The model is auto-detected from your hardware — qwen8b for NVIDIA GPUs and Macs with 24 GB+ RAM, qwen2b for smaller Macs and CPU-only systems. You can override with --model qwen2b or --model qwen8b. Pick an install based on your hardware:

Hardware Install command Auto-detected model Notes
Apple Silicon, 24 GB+ RAM uv tool install ".[local]" qwen8b Full float16 via MPS
Apple Silicon, 16 GB RAM uv tool install ".[local]" qwen2b 8B won't fit; 2B uses ~6 GB
Apple Silicon, 8 GB RAM uv tool install ".[local]" qwen2b Tight — may swap under load; Gemini API recommended instead
NVIDIA, 18 GB+ VRAM uv tool install ".[local]" qwen8b Full bf16 precision (CUDA wheels pulled automatically on Linux/Windows)
NVIDIA, 8–16 GB VRAM uv tool install ".[local-quantized]" qwen8b 4-bit quantization (~6–8 GB)

Won't work well: Intel Macs and machines without a dedicated GPU. These fall back to CPU with float32 — too slow and memory-hungry for practical use. Use the Gemini API backend (the default) instead.

Not sure? On Mac, use ".[local]". On NVIDIA, use ".[local-quantized]" — 4-bit quantization works on the widest range of NVIDIA hardware with minimal quality loss. (bitsandbytes requires CUDA and does not work on Mac/MPS.)

Python version: PyTorch wheels lag behind new Python releases, so the local backend requires Python 3.11 or 3.12. If your default Python is 3.13+, install a managed 3.12 and pin the tool install to it:

uv python install 3.12
uv tool install --python 3.12 ".[local]"

Mac prerequisite: Install system FFmpeg (the local model's video processor requires it — the Gemini backend uses a bundled ffmpeg instead):

brew install ffmpeg

Index with --backend local and search — no extra flags needed:

sentrysearch index /path/to/footage --backend local
sentrysearch search "car running a red light"

The search command auto-detects the backend and model from whatever you indexed with. You can also use --model as a shorthand — it implies --backend local:

sentrysearch index /path/to/footage --model qwen2b   # same as --backend local --model qwen2b
sentrysearch search "car running a red light"          # auto-detects local/qwen2b from index

Options:

Notes:

Why the local model is fast

The local backend stays fast and memory-efficient through a few techniques that compound:

With all of this, expect ~2-5s per chunk on an A100 and ~3-8s on a T4. On a 4090, the 8B model in bf16 should be in the low single digits per chunk.

Tesla Metadata Overlay

Burn speed, location, and time onto trimmed clips:

sentrysearch search "car cutting me off" --overlay

This extracts telemetry embedded in Tesla dashcam files (speed, GPS) and renders a HUD overlay. The overlay shows:

tesla overlay

Requirements:

Install with Tesla overlay support:

uv tool install ".[tesla]"

Without geopy, the overlay still works but omits the city/road name.

Source: teslamotors/dashcam

Stitch with SentryMerge

SentryMerge is a sibling tool that auto-cuts a single cross-camera video of one event from a SentrySearch result. Every time sentrysearch search runs, it caches the result list to ~/.sentrysearch/last_search.json; SentryMerge picks that up via --last, picks the best multi-camera clip-set, asks a VLM for sub-second visibility ranges per camera, and stitches one frame-accurate video that follows the subject across cameras:

sentrysearch search "<query>"
sentrymerge --last                      # → merge.mp4

--last works without re-running search; sentrymerge --query "..." re-runs search under the hood. See the SentryMerge README for install instructions, VLM backend options (Gemini / OpenAI / local Qwen), and the modular cam-config system for non-Tesla dashcams.

Redact with SentryBlur

SentryBlur is a sibling tool for local face, license plate, and natural-language redaction of video. Every time sentrysearch search saves a clip, it caches the path to ~/.sentrysearch/last_clip.json; SentryBlur picks that up via --last, so search-then-redact is two commands and no path-passing:

sentrysearch search "car cuts me off"
sentryblur prompt --last "road signs"   # → match_<...>_blurred.mp4

sentryblur faces --last and sentryblur plates --last work the same way. Pick faces or plates for fast CPU detectors; use prompt "<text>" for arbitrary objects (phone screens, monitors, name tags) — prompt requires an NVIDIA GPU or Apple Silicon. See the SentryBlur README for install instructions and hardware notes.

Managing the index

# Show index info (files marked [missing] no longer exist on disk)
sentrysearch stats

# Remove specific files by path substring
sentrysearch remove path/to/footage

# Wipe the entire index
sentrysearch reset

Failed chunks and retrying

If a chunk cannot be embedded after retries, SentrySearch records it in a dead-letter queue (DLQ) at ~/.sentrysearch/dlq.json and continues indexing the rest of your footage. Chunks usually land there because of repeated transient API/backend failures, decoder errors for a specific file, missing files, or out-of-memory errors. Permanent-looking failures such as missing files, decode errors, and OOM are recorded immediately because retrying the same chunk with the same settings is unlikely to help.

Inspect failed chunks:

sentrysearch dlq list

Retry them on the next index run

sentrysearch (ssrajadh/sentrysearch)

Searching Database…

What is this?SentrySearch is a CLI tool that lets you semantically search through video footage (like Tesla dashcam clips) by typing what you're looking for and getting back a trimmed clip of the matching moment.
How does the search actually work under the hood?It splits videos into overlapping chunks, embeds each chunk using Gemini Embedding, Alibaba DashScope, or a local Qwen3-VL model, stores the vectors in a local ChromaDB database, and matches your text or image query against those embeddings to find and trim the best clip.
How do I get it running?Install uv, clone the repo and install the tool, set up a Gemini API key (or skip for a local/offline backend), then index your footage and run a search query.
Do I need a Gemini API key to use this?Only if you use the default Gemini backend; you can skip it entirely by running with --backend local or --backend qwen-cloud with a DashScope API key instead.
Any install pitfalls I should know about?It requires Python 3.11 or 3.12 specifically, since PyTorch wheels for the local backend don't yet support 3.13+; you may need to install a managed 3.12 if your default Python is newer.
Does the offline local backend work on any Mac or PC?It runs well on Apple Silicon Macs with enough RAM and on NVIDIA GPUs (full precision or 4-bit quantized depending on VRAM), but Intel Macs and machines without a dedicated GPU fall back to slow CPU inference and should use the Gemini API instead.
Can I keep my footage from ever leaving my machine?Yes, the local Qwen3-VL backend runs entirely on-device, so no footage or query data is sent to any API.
What are SentryMerge and SentryBlur?They're companion tools in the same pipeline: SentryMerge auto-cuts multi-camera footage into one video following the subject across cameras, and SentryBlur auto-redacts sensitive information.
Can I search using an image instead of typing a query?Yes, you can pass a reference image and it will be embedded into the same vector space as the indexed clips and matched by visual similarity, which is useful when describing a scene in words is hard.
What does the Tesla Metadata Overlay do?It burns speed, location, and time data onto the trimmed clips, which is handy for Tesla dashcam footage that carries this metadata.
What does the --rerank option do?It sends each candidate clip and the query to a vision-language model (Gemini 2.5 Flash or a local Qwen3-VL Instruct model) to re-sort likely visual matches ahead of purely embedding-ranked results.
Creator
ssrajadh
Size
36.6 MB
Stars
4.6K
Updated
CommitOct 17
Age
7mo
Commits · 90 Days