Niravi Docs
npm ↗ Get a key ↗

Python SDK

A small hand-written transport (auth, retries, rate-limit, typed errors, pagination) over generated Pydantic models. The API is the single source of truth — the SDK never hand-encodes field shapes.

Install

Not on PyPI yet. Version 0.2.0 is built and has the same surface as the TypeScript SDK 0.2.0, but pip install niravi does not find it until it is published. Until then, install it from source: ask hello@niravi.io for the 0.2.0 wheel and run pip install niravi-0.2.0-py3-none-any.whl (Python 3.10+), or call the HTTP API directly.

Quickstart

import niravi

client = niravi.connect("nv_...")  # dashboard → Settings → Developer

# Semantic search: up to 3 moments per video
for hit in client.search("a person walking at sunset", limit=5, moments_per_video=3):
    print(hit.video_id, hit.timestamp, hit.score, hit.raw_score)

# Drill into one video
video = client.get_video(hit.video_id)
print(video.transcript())
print(video.recall_ask("what happens in this clip?"))

client.close()

connect() also works as a context manager:

with niravi.connect("nv_...", workspace="demo_newsroom") as client:
    hits = client.search("a reporter speaking to the camera")

API

MethodDescription
client.search(query, *, limit=None, video_id=None, engine=None, moments_per_video=None, workspace_ids=None, search_options=None, rerank=None)Semantic search → hits. engine is "arrow" or "classic" (omit for the workspace default); moments_per_video 1 to 10
client.search_response(query, ...)The same, returning the whole response (results, engine, engine_fallback, …)
client.magic_search(search_type, query, *, limit=None, video_id=None)Typed search (character/location/music/emotion)
client.chat(message, *, video_id=None, max_tokens=None)Conversational Q&A, with citations
client.videos(*, limit=50, all_pages=False)List videos
client.get_video(video_id)→ a Video
client.upload(file_path, *, filename=None, pipeline=None, options=None, language=None, content_type=None, timeout=None)Upload a video, photo or document (write scope; runs on Arrow). Streams from disk, no timeout unless you pass one
client.delete_video(video_id)Delete an asset your workspace owns (write scope)
client.download_nmap(video_id, path=None)The .nmap archive: bytes, or streamed to path
client.engines() / client.index_options()The search engines; the workspace’s index options
client.workspaces()The workspaces the key can reach
client.health() / client.rate_limitHealth / the last response’s limits: limit, remaining, reset, limit_minute, limit_day, remaining_minute (Rate limits)

Video: detail, transcript(), scenes(), shots(), faces(), characters(), speakers(), sounds(), sound_events(), audio_segments(audio_type=None), music_tracks(), regions(page=None, timestamp=None), screenplay(), storyboard(), subtitles(fmt, raw=False) (raw=True → the SRT/VTT text), frame(timestamp, jpeg=False) (jpeg=True → the JPEG bytes), nmap(), save_nmap(path), recall_ask(question), delete().

video = client.get_video(video_id)
srt = video.subtitles("srt", raw=True)
jpeg = video.frame(10, jpeg=True)
client.download_nmap(video_id, f"{video_id}.nmap")
client.upload("episode.mp4", options={"faces": False}, language="en")

Auth & options

niravi.connect(
    "nv_...",
    base_url="https://api.niravi.io",  # default
    timeout=60.0,                      # per request (default); uploads and downloads are not bound by it
    max_retries=3,
    auth_scheme="x-api-key",           # or "bearer"
    workspace=None,                    # sent as X-Workspace-Id; None = the key's home
)

A 429 is retried for any call, honouring Retry-After. A 5xx or transport error is retried only for idempotent calls (reads, search, chat, recall); an upload is never resent.

Errors

Raises typed errors built from the error envelope: AuthError (401/403), NotFoundError (404), ValidationError (422), RateLimitError (429, carries retry_after), ServerError (5xx, including 502 chat_unavailable), all subclasses of NiraviError, which carries code, status, request_id and the legacy detail. Other statuses (400, 409 not_ready) raise a plain NiraviError.

try:
    client.get_video("nope")
except niravi.NotFoundError as e:
    print(e.code, e.request_id)

Pages and People have no SDK helpers yet: call them over HTTP (reference). License Apache-2.0.