Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
705c7f5
indexing: add understand, indexing and face store support
0xrohitgarg Apr 10, 2026
94674ce
configurable polling args for long running jobs
0xrohitgarg Apr 10, 2026
fa63876
make understand and index functions async
0xrohitgarg Apr 10, 2026
71aee12
indexing: add config support in understanding module
0xrohitgarg Apr 10, 2026
14da214
indexing: proper cast for float and int types in face data
0xrohitgarg Apr 10, 2026
810a229
Add prompt_url fallback for large generate_text payloads
ashish-spext Apr 16, 2026
222feec
Merge pull request #73 from video-db/investigate-generate-text-payload
ashish-spext Apr 16, 2026
e20831e
feat: make text gen. async
ankit-v2-3 Apr 17, 2026
a1967b9
fix: remove print
ankit-v2-3 Apr 17, 2026
bb40ba6
Merge pull request #74 from video-db/ankit/fix-text-gen
ashish-spext Apr 17, 2026
40f6130
feat: add async generation job support
0xrohitgarg May 5, 2026
7175107
add support for sandbox
0xrohitgarg May 14, 2026
b111387
Add sandbox model enum and GenAI sandbox options
0xrohitgarg May 15, 2026
a5ed81b
Remove unsupported large sandbox model
0xrohitgarg May 15, 2026
0b905a2
Remove internal FP8 sandbox model enums
0xrohitgarg May 15, 2026
eb00aaf
Use canonical sandbox model names
0xrohitgarg May 15, 2026
75bbc64
add support for sandbox id in rtstream scene index
0xrohitgarg May 16, 2026
afcc0c1
add voice clone interface
0xrohitgarg May 26, 2026
0a2497d
Merge branch 'indexing-v2' into hackathon
0xrohitgarg Jun 5, 2026
bf46719
Merge pull request #76 from video-db/hackathon
0xrohitgarg Jun 5, 2026
d264322
Merge pull request #90 from video-db/indexing-v2
ankit-v2-3 Jul 22, 2026
78d20ed
Revert sandbox and compute SDK changes
0xrohitgarg Jul 22, 2026
a06da10
Remove face store SDK support
0xrohitgarg Jul 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions videodb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from videodb.websocket_client import WebSocketConnection
from videodb.capture import CaptureClient, Channel, AudioChannel, VideoChannel, Channels, ChannelList

from videodb.index import IndexResult
from videodb.exceptions import (
VideodbError,
AuthenticationError,
Expand All @@ -53,6 +54,7 @@
"AuthenticationError",
"InvalidRequestError",
"IndexType",
"IndexResult",
"SearchError",
"play_stream",
"build_iframe_embed_code",
Expand Down
3 changes: 3 additions & 0 deletions videodb/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class ApiPath:
token = "token"
websocket = "websocket"
export = "export"
understand = "understand"
indexes = "indexes"
async_response = "async-response"


class Status:
Expand Down
37 changes: 37 additions & 0 deletions videodb/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class IndexResult:
"""Result of a ``video.index()`` call."""

def __init__(
self,
_connection=None,
index_id=None,
video_id=None,
collection_id=None,
name=None,
type=None,
status=None,
source=None,
config=None,
use_for=None,
output_url=None,
created_at=None,
**kwargs,
):
self._connection = _connection
self.id = index_id
self.video_id = video_id
self.collection_id = collection_id
self.name = name
self.type = type
self.status = status
self.source = source or {}
self.config = config or {}
self.use_for = use_for or []
self.output_url = output_url
self.created_at = created_at

def __repr__(self):
return (
f"IndexResult(id={self.id}, type={self.type}, "
f"status={self.status}, name={self.name})"
)
117 changes: 117 additions & 0 deletions videodb/understanding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
class FaceDetection:
"""A single detected face occurrence in a frame."""

def __init__(self, bbox, confidence, face_detection_id=None, timestamp_ms=None, **kwargs):
self.face_detection_id = face_detection_id
self.bbox = bbox
self.confidence = float(confidence) if confidence is not None else None
self.timestamp_ms = int(timestamp_ms) if timestamp_ms is not None else None

def __repr__(self):
return f"FaceDetection(bbox={self.bbox}, confidence={self.confidence})"


class SegmentResult:
"""Detection results for a single time segment / frame."""

def __init__(self, timestamp_ms=None, frame_url=None, detections=None, **kwargs):
self.timestamp_ms = int(timestamp_ms) if timestamp_ms is not None else None
self.frame_url = frame_url
self.detections = [
FaceDetection(**d) if isinstance(d, dict) else d
for d in (detections or [])
]

def __repr__(self):
return f"SegmentResult(timestamp_ms={self.timestamp_ms}, faces={len(self.detections)})"


class UnderstandingResult:
"""Result of a video.understand() call."""

def __init__(
self,
_connection=None,
understanding_id=None,
video_id=None,
collection_id=None,
extract=None,
status=None,
store=None,
config=None,
results=None,
**kwargs,
):
self._connection = _connection
self.id = understanding_id
self.video_id = video_id
self.collection_id = collection_id
self.extract = extract or []
self.status = status
self.store = store
self.config = config or {}
self.results_raw = results or {}
self.results = self._parse_results(results)

@staticmethod
def _parse_results(results):
"""Parse results from either dict format (get) or list format (create).

Server get_understanding returns:
{"faces": {"status": "done", "data": [segment dicts]}}
Server create/understand returns:
[segment dicts]
"""
if results is None:
return []

# Dict format from get_understanding: {extract_type: {status, data}}
if isinstance(results, dict):
segments = []
for extract_type, extract_data in results.items():
if isinstance(extract_data, dict):
data = extract_data.get("data")
if isinstance(data, list):
segments.extend(data)
elif isinstance(extract_data, list):
segments.extend(extract_data)
return [
SegmentResult(**s) if isinstance(s, dict) else s
for s in segments
]

# List format from create understanding
if isinstance(results, list):
return [
SegmentResult(**r) if isinstance(r, dict) else r
for r in results
]

return []

def to_source_dict(self) -> dict:
"""Serialize detection data for passing to video.index(source=...)."""
return {
"type": "faces",
"detections": [
{
"timestamp_ms": seg.timestamp_ms,
"frame_url": seg.frame_url,
"detections": [
{
"face_detection_id": d.face_detection_id,
"bbox": d.bbox,
"confidence": d.confidence,
}
for d in seg.detections
],
}
for seg in self.results
],
}

def __repr__(self):
return (
f"UnderstandingResult(id={self.id}, status={self.status}, "
f"segments={len(self.results)})"
)
Loading
Loading