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 niravidoes not find it until it is published. Until then, install it from source: ask hello@niravi.io for the 0.2.0 wheel and runpip 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
| Method | Description |
|---|---|
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_limit | Health / 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.