Skip to main content

OpenSceneSense

Turn video into structured, timestamped scene intelligence without installing a local ML stack.

OpenSceneSense samples the most useful frames, transcribes optional audio, analyzes visual content with OpenAI or OpenRouter, and returns summaries, events, metadata, timing, and usage information. It is designed for applications, batch pipelines, dataset tooling, and anything that needs a dependable JSON result rather than a demo-only paragraph.

Looking for private, local inference? Use OpenSceneSense Ollama. The two packages share the v1.2 result contract but intentionally do not share a dependency graph.

Why v1.2

  • Modern OpenAI Responses API support with image input and strict JSON Schema output.
  • OpenRouter support through an explicit Chat Completions adapter.
  • One structured summary request produces the detailed summary, brief summary, and events.
  • Budget-bounded scene selection: scene density changes which frames win, never the configured cost ceiling.
  • Reduced-rate scene scanning on downscaled frames instead of analyzing every decoded frame.
  • JPEG preprocessing with a configurable size and quality ceiling.
  • Optional, replaceable audio transcription with no local audio-decoding stack.
  • Typed results, a checked-in JSON Schema, legacy dictionary compatibility, usage telemetry, progress events, strict mode, and resumable stage caches.
  • No import-time FFmpeg process, console output, or global logging configuration.

Install

OpenSceneSense supports Python 3.10+ and requires the FFmpeg and FFprobe executables.

pip install openscenesense

Install FFmpeg with your platform package manager:

# Ubuntu/Debian
sudo apt-get install ffmpeg

# macOS
brew install ffmpeg

Verify the local requirement:

openscenesense check

The default package remains API-focused. It does not install Torch, Transformers, Ollama, librosa, or soundfile.

Python quick start

Set OPENAI_API_KEY, then choose model IDs explicitly so deployments do not depend on changing aliases or README defaults:

from openscenesense import ModelConfig, VideoAnalyzer

analyzer = VideoAnalyzer(
    model_config=ModelConfig(
        vision_model="gpt-5.6-luna",
        text_model="gpt-5.6-luna",
        audio_model="whisper-1",
    ),
    min_frames=8,
    max_frames=32,
    frames_per_minute=4,
)

result = analyzer.analyze_video_structured("video.mp4")

print(result.summary.brief)
for event in result.timeline:
    print(event.start_time, event.description)

analyze_video_structured() is the preferred v1.2 API. Existing code can continue using analyze_video(), which returns the v1.1 dictionary shape with additive metadata:

legacy = analyzer.analyze_video("video.mp4")
print(legacy["brief_summary"])
print(legacy["frame_analyses"])

CLI quick start

API keys are read from environment variables and are never accepted as CLI arguments.

export OPENAI_API_KEY="..."

openscenesense analyze video.mp4 \
  --provider openai \
  --vision-model gpt-5.6-luna \
  --summary-model gpt-5.6-luna \
  --structured-output \
  --output result.json

Useful controls:

--provider openai|openrouter
--frame-selector dynamic|uniform
--min-frames / --max-frames / --frames-per-minute
--scene-change-threshold / --scene-scan-fps / --min-scene-gap
--max-image-dimension / --jpeg-quality
--no-audio
--api-mode responses|chat_completions|auto
--timeout / --max-workers
--strict / --max-frame-failure-ratio
--cache-dir / --resume / --force
--structured-output

Print the result schema with:

openscenesense schema

OpenRouter

OpenRouter handles frame and summary inference; OpenAI audio transcription remains independent and can be disabled or replaced.

import os

from openscenesense import ModelConfig, OpenRouterAnalyzer

analyzer = OpenRouterAnalyzer(
    openrouter_key=os.environ["OPENROUTER_API_KEY"],
    openai_key=os.environ.get("OPENAI_API_KEY"),
    model_config=ModelConfig(
        vision_model="your-vision-capable-openrouter-model",
        text_model="your-structured-output-model",
        audio_model="whisper-1",
    ),
    enable_audio=False,
)

result = analyzer.analyze_video_structured("video.mp4")

OpenAI defaults to the Responses API. OpenRouter defaults to Chat Completions. api_mode="auto" only falls back when an endpoint is genuinely unsupported; authentication, model, rate-limit, and malformed-response failures are never retried through a second endpoint.

Data boundary

Metadata probing and frame selection happen locally. The package sends only the selected, size-bounded JPEG frames to the chosen vision provider; it does not upload the original video as one file. When built-in audio is enabled, a temporary mono WAV is sent to OpenAI transcription. The resulting frame descriptions and transcript are sent to the configured summary provider.

Disable audio or supply your own transcriber when that boundary is too broad. Provider retention and training policies remain the provider's responsibility, so review them for sensitive workloads. Opt-in caches stay on the machine running OpenSceneSense.

Structured result contract

Both OpenSceneSense distributions emit schema version 1.2:

AnalysisResult
├── schema_version
├── summary
│   ├── detailed
│   └── brief
├── timeline[]
├── frame_analyses[]
├── audio_segments[]
├── metadata
│   ├── video
│   ├── selection
│   ├── models
│   ├── performance
│   └── usage
├── warnings[]
└── errors[]

The source schema is Docs/analysis_result.schema.json. Regenerate it after contract changes:

python scripts/export_schema.py

Frame selection

DynamicFrameSelector builds one predictable frame budget:

from openscenesense import DynamicFrameSelector, VideoAnalyzer

selector = DynamicFrameSelector(
    scene_change_threshold=0.18,
    scene_scan_fps=2.0,
    min_scene_gap=0.75,
)

analyzer = VideoAnalyzer(
    frame_selector=selector,
    min_frames=8,
    max_frames=32,
    frames_per_minute=4,
)

The opening and closing frames are retained, strong scene-change peaks receive up to 60% of the remaining budget, and unused positions fill the largest temporal gaps. Selected frames record selection_reason and a normalized difference_score.

Use UniformFrameSelector when deterministic spacing is more important than scene changes.

Audio is replaceable

Disable audio without changing the visual pipeline:

analyzer = VideoAnalyzer(enable_audio=False)

Or provide an object with transcribe(video_path) -> list[AudioSegment]:

import os

from openscenesense import AudioSegment, VideoAnalyzer


class ExistingTranscript:
    def transcribe(self, video_path):
        return [AudioSegment("Already transcribed", 0.0, 2.0, 1.0)]


analyzer = VideoAnalyzer(
    audio_transcriber=ExistingTranscript(),
    api_key=os.environ["OPENAI_API_KEY"],
)

The built-in OpenAI transcriber extracts a temporary mono 16 kHz WAV through FFmpeg. Extraction failures become warnings in normal mode and exceptions in strict mode.

Reliability controls

def progress(event):
    print(event.stage, event.current, event.total, event.message)


analyzer = VideoAnalyzer(
    strict=False,
    max_frame_failure_ratio=0.25,
    on_progress=progress,
    timeout=120,
    max_workers=5,
)

Authentication, missing-model, and rate-limit failures stop immediately. In normal mode, isolated frame, transcription, or summary-validation failures are returned as warnings with deterministic fallbacks. strict=True converts partial failures into exceptions.

Cache and resume

Caching is opt-in because results can contain sensitive descriptions and transcripts.

analyzer = VideoAnalyzer(
    cache_dir=".openscenesense-cache",
    resume=True,
)

The key incorporates the video edge hash, size, modification nanoseconds, provider, models, prompts, selection settings, preprocessing settings, and transcription configuration. Manifests, metadata, transcripts, frame analyses, and final results are written atomically in separate stages.

Development

git clone https://github.com/ymrohit/openscenesense.git
cd openscenesense
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check openscenesense tests scripts benchmarks Examples
python -m build

CI tests minimum-supported and latest-compatible dependencies across supported Python versions. The bounded live integration under scripts/ runs only through manual dispatch with provider credentials.

More detail:

License and support

OpenSceneSense is released under the MIT License. Report bugs and request features through GitHub Issues.

Metadata

Release files for openscenesense 1.2.0

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

Source distribution (sdist)

Source distribution for openscenesense 1.2.0
File Size Uploaded
openscenesense-1.2.0.tar.gz 49.7 kB Details

Built distribution (wheel)

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

Total release size: 84.5 kB

Release files / openscenesense-1.2.0.tar.gz

Download URL openscenesense-1.2.0.tar.gz
Size 49.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e71eccce00ed1cff0e4341a78fc4895ce5f3de518dec5d8f4707a1224b8a9a46
BLAKE2b-256 checksum
How to use checksums
a9f835a56ceeb96995152fc74d359dd085a373669e70ee4c4ea5d17a6e4f4cf0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / openscenesense-1.2.0-py3-none-any.whl

Download URL openscenesense-1.2.0-py3-none-any.whl
Size 34.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fa3a22aa067be1bffb1ac9f7120c524cf3cbbeba65eb756e0c8d837768dfc4b6
BLAKE2b-256 checksum
How to use checksums
bcd1b4e84cc619aa7ea38e71b2375b84b14eba3dd5c9e348d4f1a68f751382aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.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