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…

这是什么?SentrySearch 是一个命令行工具,让你对视频素材(如 Tesla 行车记录仪片段)进行语义搜索:输入你想找的内容,就能得到裁剪好的对应时刻片段。
搜索在底层到底是怎么工作的?它把视频切分成有重叠的块,用 Gemini Embedding、阿里 DashScope 或本地 Qwen3-VL 模型对每一块做嵌入,把向量存进本地 ChromaDB 数据库,再用你的文字或图片查询与这些嵌入进行匹配,找出并裁剪出最佳片段。
怎么让它跑起来?安装 uv,克隆仓库并安装该工具,配置 Gemini API 密钥(或者跳过、改用本地/离线后端),然后为素材建立索引并运行搜索查询。
使用它必须有 Gemini API 密钥吗?只有使用默认的 Gemini 后端才需要;用 --backend local 运行即可完全绕开,或者改用 --backend qwen-cloud 并配合 DashScope API 密钥。
安装上有什么需要提前知道的坑吗?它明确要求 Python 3.11 或 3.12,因为本地后端的 PyTorch wheel 尚不支持 3.13+;如果你默认的 Python 版本更新,可能需要另外安装一个受管理的 3.12。
离线本地后端在任何 Mac 或 PC 上都能用吗?它在内存充足的 Apple Silicon Mac 和 NVIDIA GPU 上运行良好(视显存而定,可用全精度或 4-bit 量化),但 Intel Mac 和没有独立显卡的机器只能退回缓慢的 CPU 推理,应该改用 Gemini API。
我能保证素材永远不离开我的电脑吗?可以。本地 Qwen3-VL 后端完全在设备上运行,不会向任何 API 发送素材或查询数据。
SentryMerge 和 SentryBlur 是什么?它们是同一流水线中的配套工具:SentryMerge 会自动把多机位素材剪成一个跟随主体跨机位的视频,SentryBlur 则自动遮盖敏感信息。
可以不用打字,改用图片来搜索吗?可以。你可以传入一张参考图片,它会被嵌入到与已索引片段相同的向量空间中并按视觉相似度匹配,这在难以用文字描述场景时很有用。
Tesla Metadata Overlay 是做什么的?它把速度、位置和时间数据烧录到裁剪出的片段上,对带有这类元数据的 Tesla 行车记录仪素材非常实用。
--rerank 选项是做什么的?它把每个候选片段和查询一起发给一个视觉语言模型(Gemini 2.5 Flash 或本地 Qwen3-VL Instruct 模型),把可能的视觉匹配重新排到纯嵌入排序结果的前面。
Creator
ssrajadh
Size
36.7 MB
Stars
4.6K
Updated
CommitOct 18
Age
7mo
Commits · 90 Days