Skip to main content

Cinematlas

Ask a question. Get the second in the video that answers it.

pip install "cinematlas[whisper]"
cinematlas doctor
cinematlas ingest "www.b.com/keynote.mp4"
cinematlas search "when do they announce pricing?"
 1. vid_3f2a…#12 @    7:11  Pricing starts at ten dollars a seat.
    https://www.b.com/keynote.mp4#t=431

The finding: fuse in the embedding, not in the ranking

Video search has two kinds of question. "How many medals has his beer won?" is about what was said. "The one with the girl on hay bales" is about what was shown.

The standard design indexes speech and pictures separately, retrieves from each, and merges the ranked lists. That fails, because the lists disagree on every question that's about only one of the two, and merging averages the disagreement away. Cinematlas embeds each scene's keyframe and its transcript into one vector, so there's nothing to reconcile.

Same signals, fused… Said Shown Mean Hit@1
after retrieval (rank fusion, tuned weights, reranked) 0.80 0.50 0.65
inside one joint image+speech vector 0.73 0.93 0.83

On the questions where the two disagree, the joint vector wins 14 and loses 3 (exact McNemar p = 0.013).

It isn't reading the subtitles. Every frame in the benchmark has burned-in captions, so we cropped them off and re-embedded. Keyframes alone dropped on speech questions (0.53 → 0.40), because the pixels had been reading the subtitles. The joint vector didn't drop (0.73 → 0.77): the speech is in the embedding, not painted on the frame.

The router we built to fix rank fusion is now optional. Routing each question to a specialist recovers late fusion to 0.82, statistically tied with the joint vector alone (p = 1.0). The joint vector finds the scene in one query (~80 ms). search() adds a sentence reranker on top to return the exact second.

60 questions over 6 videos from one program, written by the authors. The paired test is how we tell signal from noise. Full results, caption ablation and limits.


Quickstart

export MONGODB_URI="mongodb+srv://…"     # MDB_URI also works
export VOYAGE_API_KEY="pa-…"
from cinematlas import Cinematlas

engine = Cinematlas()
engine.ensure_indexes()                                  # once; idempotent

engine.ingest("https://www.youtube.com/watch?v=5NhYvbMdbBU")
engine.ingest("lecture.mov")                             # or a URL, bytes, file object, web upload

results = engine.search("how loud is a sonic boom?")     # the scene, down to the second
results.top.link                                         # 'https://…#t=34'
results.top.text                                         # 'Sonic booms are about 110 decibels.'
results.top.explain()                                    # rank per source, relevance, score

engine.search_scene_vector("a baby's hand holding a finger")   # joint vector only: the scene, ~80 ms

Results are plain dicts underneath (json.dumps works). Cinematlas doesn't pick an LLM for you; results.to_context() gives you numbered, citable excerpts to pass to one.


How it works

 ingest(video)
   ├─ scenes ── PySceneDetect cuts, ≤30 s each
   ├─ said ──── faster-whisper → timestamped sentences, aligned to scenes
   ├─ shown ─── the middle keyframe of each scene
   └─ Voyage ── one joint keyframe+transcript vector per scene (plus keyframe-only and transcript vectors)
                → one MongoDB Atlas document per scene

 search(question)
   ├─ $rankFusion over scene, keyframe, transcript and BM25 retrieval       one query
   ├─ $rerank over candidate sentences                                      picks the second
   └─ routing by reranker confidence                                        said vs shown
Need Call
The scene and the exact second (default) search(q)
The scene, fastest search_scene_vector(q)
Speech only search(q, sources=("transcript", "text"))
Your own blend search(q, weights={"scene": 2, "transcript": 1, "rerank": 1})
One source search_transcript · search_text · search_visual_vector · search_scene_vector

All of them accept video_id=. Every hit carries moment ({start, end, text}), moment_link (YouTube ?t=431s, files #t=431), ranks, relevance and the scene's fields.

ingest() accepts a URL (YouTube or any file link, scheme optional), a path, bytes, a file object, or a FastAPI UploadFile / Flask FileStorage. Remote URLs are treated as untrusted: private addresses are refused, downloads are capped, and signed-URL credentials are stripped before storage. Re-ingesting a video replaces it without a gap.


CLI

cinematlas doctor                        # checks the deployment and prints the exact fix for each problem
cinematlas setup [--update]              # create indexes; --update upgrades them in place
cinematlas ingest <url|path|->           # progress on stderr, JSON on stdout
cinematlas search "<question>" [-k 5] [--by hybrid|transcript|visual|text] [--format table|json|context]

Global options: --uri, --db, --collection, --transcript-mode, -v.

Atlas features used

$rankFusion (8.0+) for one-query hybrid retrieval, $rerank (8.3+) for in-database sentence reranking, Automated Embedding for transcripts, Atlas Search for BM25, scalar quantization and BSON float32 vectors. Each has an equivalent fallback, and cinematlas doctor tells you which path is in use.

Development

uv sync
uv run pytest -m "not integration and not media"    # unit, offline (~9 s)
uv run pytest -m media                               # real ffmpeg / Whisper on a committed NASA fixture
uv run pytest -m integration                         # live Atlas + Docker Atlas Local (reads .env)
uv run python bench/ingest.py && uv run python bench/ingest.py --no-captions && uv run python bench/run.py

MIT license. Test and benchmark media: NASA, public domain.

Release files for cinematlas 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cinematlas 0.4.3
File Size Uploaded
cinematlas-0.4.3.tar.gz 931.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cinematlas 0.4.3
File Interpreter ABI Platform
cinematlas-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 975.2 kB

Release files / cinematlas-0.4.3.tar.gz

Download URL cinematlas-0.4.3.tar.gz
Size 931.9 kB
Tags Source
SHA-256 checksum
How to use checksums
809874e399496fbfb5a2afbe3b46358fd60bb05c45a6e1250673d01c4ee2bae9
BLAKE2b-256 checksum
How to use checksums
6bd75435dcd1cef553f3294b910b97e6bce2885910f394dda91f31888349b49e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / cinematlas-0.4.3-py3-none-any.whl

Download URL cinematlas-0.4.3-py3-none-any.whl
Size 43.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dfac652d64526aae74be392ab7e5a5bf423e3d2920f39e0e8be6d99f4e87c1c5
BLAKE2b-256 checksum
How to use checksums
8fd83186712ebbc6e7657228fb5fb4f1131945300d2bddbf451a3b5ca471d143
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.5

2 release files

0.4.4

2 release files

This release

0.4.3 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page