From c38f4d8078753110e9a2409787ce4dc0a0d1d84b Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sun, 1 Dec 2024 07:28:03 +0530 Subject: [PATCH 01/18] feat: add rstream --- videodb/__about__.py | 2 +- videodb/_constants.py | 1 + videodb/collection.py | 16 ++++++++++++++++ videodb/rtstream.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 videodb/rtstream.py diff --git a/videodb/__about__.py b/videodb/__about__.py index 4189509..8791897 100644 --- a/videodb/__about__.py +++ b/videodb/__about__.py @@ -1,7 +1,7 @@ """ About information for videodb sdk""" -__version__ = "0.2.6" +__version__ = "0.2.7" __title__ = "videodb" __author__ = "videodb" __email__ = "contact@videodb.io" diff --git a/videodb/_constants.py b/videodb/_constants.py index b5eab1c..99177f9 100644 --- a/videodb/_constants.py +++ b/videodb/_constants.py @@ -70,6 +70,7 @@ class ApiPath: storage = "storage" download = "download" title = "title" + rtstream = "rtstream" class Status: diff --git a/videodb/collection.py b/videodb/collection.py index db45f24..0c66102 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -16,6 +16,7 @@ from videodb.video import Video from videodb.audio import Audio from videodb.image import Image +from videodb.rtstream import RtStream from videodb.search import SearchFactory, SearchResult logger = logging.getLogger(__name__) @@ -97,6 +98,21 @@ def delete_image(self, image_id: str) -> None: path=f"{ApiPath.image}/{image_id}", params={"collection_id": self.id} ) + def get_rtstream(self, id: str) -> RtStream: + rtstream_data = self._connection.get( + path=f"{ApiPath.rtstream}/{id}", + ) + return RtStream(self._connection, **rtstream_data) + + def list_rtstreams(self) -> List[RtStream]: + rtstreams_data = self._connection.get( + path=f"{ApiPath.rtstream}", + ) + return [ + RtStream(self._connection, **rtstream) + for rtstream in rtstreams_data.get("results") + ] + def search( self, query: str, diff --git a/videodb/rtstream.py b/videodb/rtstream.py new file mode 100644 index 0000000..84a0030 --- /dev/null +++ b/videodb/rtstream.py @@ -0,0 +1,32 @@ +from videodb._constants import ( + ApiPath, +) + + +class RtStream: + def __init__(self, _connection, id: str, **kwargs) -> None: + self._connection = _connection + self.id = id + self.name = kwargs.get("name", None) + self.collection_id = kwargs.get("collection_id", None) + self.created_at = kwargs.get("created_at", None) + self.sample_rate = kwargs.get("sample_rate", None) + self.status = kwargs.get("status", None) + + def __repr__(self) -> str: + return ( + f"RtStream(" + f"id={self.id}, " + f"name={self.name}, " + f"collection_id={self.collection_id}, " + f"created_at={self.created_at}, " + f"sample_rate={self.sample_rate}, " + f"status={self.status})" + ) + + def stream(self, start, end): + stream_data = self._connection.get( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.stream}", + params={"start": start, "end": end}, + ) + return stream_data.get("stream_url", None) From 88fb14a0a556d668d7fd79ac13c1f8d4d2bfa2eb Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Fri, 27 Dec 2024 21:46:55 +0530 Subject: [PATCH 02/18] feat: add rtstream scene index --- videodb/_constants.py | 1 + videodb/collection.py | 10 ++--- videodb/rtstream.py | 90 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/videodb/_constants.py b/videodb/_constants.py index 99177f9..e181dcf 100644 --- a/videodb/_constants.py +++ b/videodb/_constants.py @@ -71,6 +71,7 @@ class ApiPath: download = "download" title = "title" rtstream = "rtstream" + status = "status" class Status: diff --git a/videodb/collection.py b/videodb/collection.py index 0c66102..af42872 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -16,7 +16,7 @@ from videodb.video import Video from videodb.audio import Audio from videodb.image import Image -from videodb.rtstream import RtStream +from videodb.rtstream import RTStream from videodb.search import SearchFactory, SearchResult logger = logging.getLogger(__name__) @@ -98,18 +98,18 @@ def delete_image(self, image_id: str) -> None: path=f"{ApiPath.image}/{image_id}", params={"collection_id": self.id} ) - def get_rtstream(self, id: str) -> RtStream: + def get_rtstream(self, id: str) -> RTStream: rtstream_data = self._connection.get( path=f"{ApiPath.rtstream}/{id}", ) - return RtStream(self._connection, **rtstream_data) + return RTStream(self._connection, **rtstream_data) - def list_rtstreams(self) -> List[RtStream]: + def list_rtstreams(self) -> List[RTStream]: rtstreams_data = self._connection.get( path=f"{ApiPath.rtstream}", ) return [ - RtStream(self._connection, **rtstream) + RTStream(self._connection, **rtstream) for rtstream in rtstreams_data.get("results") ] diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 84a0030..206c9ab 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -1,9 +1,50 @@ from videodb._constants import ( ApiPath, + SceneExtractionType, ) -class RtStream: +class RTStreamSceneIndex: + def __init__( + self, _connection, rtstream_index_id: str, rtstream_id, **kwargs + ) -> None: + self._connection = _connection + self.rtstream_index_id = rtstream_index_id + self.rtstream_id = rtstream_id + self.name = kwargs.get("name", None) + self.status = kwargs.get("status", None) + + def __repr__(self) -> str: + return ( + f"RTStreamSceneIndex(" + f"rtstream_index_id={self.rtstream_index_id}, " + f"rtstream_id={self.rtstream_id}, " + f"name={self.name}, " + f"status={self.status})" + ) + + def get_scene_index(self): + index_data = self._connection.get( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}" + ) + if not index_data: + return None + return index_data.get("scene_index_records", []) + + def start(self): + return self._connection.patch( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", + data={"status": "running"}, + ) + + def stop(self): + return self._connection.patch( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", + data={"status": "stopped"}, + ) + + +class RTStream: def __init__(self, _connection, id: str, **kwargs) -> None: self._connection = _connection self.id = id @@ -15,7 +56,7 @@ def __init__(self, _connection, id: str, **kwargs) -> None: def __repr__(self) -> str: return ( - f"RtStream(" + f"RTStream(" f"id={self.id}, " f"name={self.name}, " f"collection_id={self.collection_id}, " @@ -30,3 +71,48 @@ def stream(self, start, end): params={"start": start, "end": end}, ) return stream_data.get("stream_url", None) + + def index_scenes( + self, + extraction_type=SceneExtractionType.time_based, + extraction_config={"time": 2, "frame_count": 5}, + prompt="Describe the scene", + model_name="GPT4o", + model_config={}, + name=None, + ): + index_data = self._connection.post( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}", + data={ + "extraction_type": extraction_type, + "extraction_config": extraction_config, + "prompt": prompt, + "model_name": model_name, + "model_config": model_config, + "name": name, + }, + ) + if not index_data: + return None + return RTStreamSceneIndex( + _connection=self._connection, + rtstream_index_id=index_data.get("rtstream_index_id"), + rtstream_id=self.id, + name=index_data.get("name"), + status=index_data.get("status"), + ) + + def list_indexes(self): + index_data = self._connection.get( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}" + ) + return [ + RTStreamSceneIndex( + _connection=self._connection, + rtstream_index_id=index.get("rtstream_index_id"), + rtstream_id=self.id, + name=index.get("name"), + status=index.get("status"), + ) + for index in index_data.get("scene_indexes", []) + ] From 6de7a44ab18c5218c9afd01f6fa11fe36c4003f0 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 06:48:22 +0530 Subject: [PATCH 03/18] feat: add events --- videodb/_constants.py | 1 + videodb/collection.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/videodb/_constants.py b/videodb/_constants.py index e181dcf..04f195f 100644 --- a/videodb/_constants.py +++ b/videodb/_constants.py @@ -72,6 +72,7 @@ class ApiPath: title = "title" rtstream = "rtstream" status = "status" + event = "event" class Status: diff --git a/videodb/collection.py b/videodb/collection.py index af42872..5a73c0c 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -113,6 +113,24 @@ def list_rtstreams(self) -> List[RTStream]: for rtstream in rtstreams_data.get("results") ] + def create_event( + self, + event_prompt="Did someone fall from bed? Output yes or no", + label="fall_alert", + ): + event_data = self._connection.post( + f"{ApiPath.rtstream}/{ApiPath.collection}/{self.id}/{ApiPath.event}", + data={"event_prompt": event_prompt, "label": label}, + ) + + return event_data.get("event_id") + + def get_events(self): + event_data = self._connection.get( + f"{ApiPath.rtstream}/{ApiPath.collection}/{self.id}/{ApiPath.event}" + ) + return event_data.get("events", []) + def search( self, query: str, From eb9d3105805b3162b62756158babe279d978618f Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 19:14:33 +0530 Subject: [PATCH 04/18] fix: update method name --- videodb/rtstream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 206c9ab..8563495 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -102,7 +102,7 @@ def index_scenes( status=index_data.get("status"), ) - def list_indexes(self): + def list_scene_indexes(self): index_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}" ) From 4f3bf83f114b9d60c67dd640f3f7df51db88a350 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:28:07 +0530 Subject: [PATCH 05/18] feat: add get scene index --- videodb/client.py | 12 ++++++++++++ videodb/collection.py | 18 ------------------ videodb/rtstream.py | 18 ++++++++++++++++-- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/videodb/client.py b/videodb/client.py index 53e1db4..4fd5674 100644 --- a/videodb/client.py +++ b/videodb/client.py @@ -90,6 +90,18 @@ def check_usage(self) -> dict: def get_invoices(self) -> List[dict]: return self.get(path=f"{ApiPath.billing}/{ApiPath.invoices}") + def create_event(self, event_prompt: str, label: str): + event_data = self.post( + f"{ApiPath.rtstream}/{ApiPath.event}", + data={"event_prompt": event_prompt, "label": label}, + ) + + return event_data.get("event_id") + + def list_events(self): + event_data = self.get(f"{ApiPath.rtstream}/{ApiPath.event}") + return event_data.get("events", []) + def download(self, stream_link: str, name: str) -> dict: return self.post( path=f"{ApiPath.download}", diff --git a/videodb/collection.py b/videodb/collection.py index 5a73c0c..af42872 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -113,24 +113,6 @@ def list_rtstreams(self) -> List[RTStream]: for rtstream in rtstreams_data.get("results") ] - def create_event( - self, - event_prompt="Did someone fall from bed? Output yes or no", - label="fall_alert", - ): - event_data = self._connection.post( - f"{ApiPath.rtstream}/{ApiPath.collection}/{self.id}/{ApiPath.event}", - data={"event_prompt": event_prompt, "label": label}, - ) - - return event_data.get("event_id") - - def get_events(self): - event_data = self._connection.get( - f"{ApiPath.rtstream}/{ApiPath.collection}/{self.id}/{ApiPath.event}" - ) - return event_data.get("events", []) - def search( self, query: str, diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 8563495..4db04b6 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -32,16 +32,18 @@ def get_scene_index(self): return index_data.get("scene_index_records", []) def start(self): - return self._connection.patch( + self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", data={"status": "running"}, ) + self.status = "running" def stop(self): - return self._connection.patch( + self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", data={"status": "stopped"}, ) + self.status = "stopped" class RTStream: @@ -116,3 +118,15 @@ def list_scene_indexes(self): ) for index in index_data.get("scene_indexes", []) ] + + def get_rtstream_scene_index(self, index_id: str) -> RTStreamSceneIndex: + index_data = self._connection.get( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}/{index_id}" + ) + return RTStreamSceneIndex( + _connection=self._connection, + rtstream_index_id=index_data.get("rtstream_index_id"), + rtstream_id=self.id, + name=index_data.get("name"), + status=index_data.get("status"), + ) From 098b50ad4b32610cba671b1c8248b4b48976bb85 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:57:59 +0530 Subject: [PATCH 06/18] fix: get scene index --- videodb/rtstream.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 4db04b6..4b65ac2 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -23,13 +23,18 @@ def __repr__(self) -> str: f"status={self.status})" ) - def get_scene_index(self): + def get_scene_index(self, page=1, page_size=100): index_data = self._connection.get( - f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}" + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}", + params={"page": page, "page_size": page_size}, ) + print(index_data) if not index_data: return None - return index_data.get("scene_index_records", []) + return { + "scenes": index_data.get("scene_index_records", []), + "next_page": index_data.get("next_page", False), + } def start(self): self._connection.patch( @@ -121,7 +126,7 @@ def list_scene_indexes(self): def get_rtstream_scene_index(self, index_id: str) -> RTStreamSceneIndex: index_data = self._connection.get( - f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}/{index_id}" + f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{index_id}" ) return RTStreamSceneIndex( _connection=self._connection, From c8449332e120065bc57ae34a7d5b0696eb6b5b58 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 22:35:33 +0530 Subject: [PATCH 07/18] fix: remove print --- videodb/rtstream.py | 1 - 1 file changed, 1 deletion(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 4b65ac2..07eac3d 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -28,7 +28,6 @@ def get_scene_index(self, page=1, page_size=100): f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}", params={"page": page, "page_size": page_size}, ) - print(index_data) if not index_data: return None return { From 034e2a60ad3cb5a8b7ac51fd8ac1f1c67f80c6ce Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sat, 28 Dec 2024 23:43:38 +0530 Subject: [PATCH 08/18] feat: add alerts --- videodb/_constants.py | 1 + videodb/rtstream.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/videodb/_constants.py b/videodb/_constants.py index 04f195f..bc95d24 100644 --- a/videodb/_constants.py +++ b/videodb/_constants.py @@ -73,6 +73,7 @@ class ApiPath: rtstream = "rtstream" status = "status" event = "event" + alert = "alert" class Status: diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 07eac3d..06992e1 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -49,6 +49,34 @@ def stop(self): ) self.status = "stopped" + def create_alert(self, event_id, callback_url) -> str: + alert_data = self._connection.post( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}", + data={ + "event_id": event_id, + "callback_url": callback_url, + }, + ) + return alert_data.get("alert_id", None) + + def list_alerts(self): + alert_data = self._connection.get( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}" + ) + return alert_data.get("alerts", []) + + def enable_alert(self, alert_id): + self._connection.patch( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", + data={"status": "enabled"}, + ) + + def disable_alert(self, alert_id): + self._connection.patch( + f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", + data={"status": "disabled"}, + ) + class RTStream: def __init__(self, _connection, id: str, **kwargs) -> None: From 596b1e751137938d1b9fb9a9324fd3ad24ee9bf1 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Sun, 29 Dec 2024 00:09:10 +0530 Subject: [PATCH 09/18] feat: add index config --- videodb/rtstream.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 06992e1..7fca74a 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -11,6 +11,9 @@ def __init__( self._connection = _connection self.rtstream_index_id = rtstream_index_id self.rtstream_id = rtstream_id + self.extraction_type = kwargs.get("extraction_type", None) + self.extraction_config = kwargs.get("extraction_config", None) + self.prompt = kwargs.get("prompt", None) self.name = kwargs.get("name", None) self.status = kwargs.get("status", None) @@ -19,6 +22,9 @@ def __repr__(self) -> str: f"RTStreamSceneIndex(" f"rtstream_index_id={self.rtstream_index_id}, " f"rtstream_id={self.rtstream_id}, " + f"extraction_type={self.extraction_type}, " + f"extraction_config={self.extraction_config}, " + f"prompt={self.prompt}, " f"name={self.name}, " f"status={self.status})" ) @@ -132,6 +138,9 @@ def index_scenes( _connection=self._connection, rtstream_index_id=index_data.get("rtstream_index_id"), rtstream_id=self.id, + extraction_type=index_data.get("extraction_type"), + extraction_config=index_data.get("extraction_config"), + prompt=index_data.get("prompt"), name=index_data.get("name"), status=index_data.get("status"), ) @@ -145,6 +154,9 @@ def list_scene_indexes(self): _connection=self._connection, rtstream_index_id=index.get("rtstream_index_id"), rtstream_id=self.id, + extraction_type=index.get("extraction_type"), + extraction_config=index.get("extraction_config"), + prompt=index.get("prompt"), name=index.get("name"), status=index.get("status"), ) @@ -159,6 +171,9 @@ def get_rtstream_scene_index(self, index_id: str) -> RTStreamSceneIndex: _connection=self._connection, rtstream_index_id=index_data.get("rtstream_index_id"), rtstream_id=self.id, + extraction_type=index_data.get("extraction_type"), + extraction_config=index_data.get("extraction_config"), + prompt=index_data.get("prompt"), name=index_data.get("name"), status=index_data.get("status"), ) From 087bfa758b415b954809bc96dfc2796c9ff039f9 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:43:58 +0530 Subject: [PATCH 10/18] refactor: rename methods --- videodb/rtstream.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 7fca74a..29d1b45 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -21,7 +21,6 @@ def __repr__(self) -> str: return ( f"RTStreamSceneIndex(" f"rtstream_index_id={self.rtstream_index_id}, " - f"rtstream_id={self.rtstream_id}, " f"extraction_type={self.extraction_type}, " f"extraction_config={self.extraction_config}, " f"prompt={self.prompt}, " @@ -29,7 +28,7 @@ def __repr__(self) -> str: f"status={self.status})" ) - def get_scene_index(self, page=1, page_size=100): + def get_scenes(self, page=1, page_size=100): index_data = self._connection.get( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}", params={"page": page, "page_size": page_size}, @@ -105,7 +104,7 @@ def __repr__(self) -> str: f"status={self.status})" ) - def stream(self, start, end): + def generate_stream(self, start, end): stream_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.stream}", params={"start": start, "end": end}, @@ -163,7 +162,7 @@ def list_scene_indexes(self): for index in index_data.get("scene_indexes", []) ] - def get_rtstream_scene_index(self, index_id: str) -> RTStreamSceneIndex: + def get_scene_index(self, index_id: str) -> RTStreamSceneIndex: index_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{index_id}" ) From 293479822087426812f8eeb0c7330ab54e204518 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:37:14 +0530 Subject: [PATCH 11/18] feat: add filter in get_scenes --- videodb/rtstream.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 29d1b45..f523b6d 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -28,10 +28,15 @@ def __repr__(self) -> str: f"status={self.status})" ) - def get_scenes(self, page=1, page_size=100): + def get_scenes(self, start: int = None, end: int = None, page=1, page_size=100): + params = {"page": page, "page_size": page_size} + if start and end: + params["start"] = start + params["end"] = end + index_data = self._connection.get( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}", - params={"page": page, "page_size": page_size}, + params=params, ) if not index_data: return None From a3c9b15bab2580e9b1e9d9c39ff6452b931333d5 Mon Sep 17 00:00:00 2001 From: ashish-spext Date: Wed, 12 Mar 2025 23:52:12 +0530 Subject: [PATCH 12/18] Add create rtstream --- videodb/collection.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/videodb/collection.py b/videodb/collection.py index af42872..1e3164f 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -98,6 +98,18 @@ def delete_image(self, image_id: str) -> None: path=f"{ApiPath.image}/{image_id}", params={"collection_id": self.id} ) + def connect_rtstream(self, url: str, name: str, sample_rate: int = 1) -> RTStream: + rtstream_data = self._connection.post( + path=f"{ApiPath.rtstream}", + data={ + "collection_id": self.id, + "url": url, + "name": name, + "sample_rate": sample_rate, + }, + ) + return RTStream(self._connection, **rtstream_data) + def get_rtstream(self, id: str) -> RTStream: rtstream_data = self._connection.get( path=f"{ApiPath.rtstream}/{id}", From c048b1583d6fafb99219fe7fd581fd26e0deb348 Mon Sep 17 00:00:00 2001 From: ashish-spext Date: Wed, 19 Mar 2025 23:59:08 +0530 Subject: [PATCH 13/18] Add start and stop camera, update status -> action in update status endpoints --- videodb/rtstream.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index f523b6d..2177574 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -48,14 +48,14 @@ def get_scenes(self, start: int = None, end: int = None, page=1, page_size=100): def start(self): self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", - data={"status": "running"}, + data={"action": "start"}, ) - self.status = "running" + self.status = "connected" def stop(self): self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", - data={"status": "stopped"}, + data={"action": "stop"}, ) self.status = "stopped" @@ -109,6 +109,20 @@ def __repr__(self) -> str: f"status={self.status})" ) + def start(self): + self._connection.patch( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.status}", + data={"action": "start"}, + ) + self.status = "connected" + + def stop(self): + self._connection.patch( + f"{ApiPath.rtstream}/{self.id}/{ApiPath.status}", + data={"action": "stop"}, + ) + self.status = "stopped" + def generate_stream(self, start, end): stream_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.stream}", From 089dfd942fdfb19651463e719de29c707c9c817f Mon Sep 17 00:00:00 2001 From: ashish-spext Date: Thu, 27 Mar 2025 23:56:55 +0530 Subject: [PATCH 14/18] Update action values for alerts and remove default model name --- videodb/rtstream.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index 2177574..b2fc3eb 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -78,13 +78,13 @@ def list_alerts(self): def enable_alert(self, alert_id): self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", - data={"status": "enabled"}, + data={"action": "enable"}, ) def disable_alert(self, alert_id): self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", - data={"status": "disabled"}, + data={"action": "disable"}, ) @@ -135,7 +135,7 @@ def index_scenes( extraction_type=SceneExtractionType.time_based, extraction_config={"time": 2, "frame_count": 5}, prompt="Describe the scene", - model_name="GPT4o", + model_name=None, model_config={}, name=None, ): From 0ee6e65274035abb80a1c6061911a4bbf6f0bdc3 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Wed, 28 May 2025 10:33:02 +0530 Subject: [PATCH 15/18] build: update sdk version --- videodb/__about__.py | 2 +- videodb/collection.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/videodb/__about__.py b/videodb/__about__.py index 8791897..90f7f66 100644 --- a/videodb/__about__.py +++ b/videodb/__about__.py @@ -1,7 +1,7 @@ """ About information for videodb sdk""" -__version__ = "0.2.7" +__version__ = "0.2.14" __title__ = "videodb" __author__ = "videodb" __email__ = "contact@videodb.io" diff --git a/videodb/collection.py b/videodb/collection.py index 1e3164f..3a005f3 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -98,7 +98,9 @@ def delete_image(self, image_id: str) -> None: path=f"{ApiPath.image}/{image_id}", params={"collection_id": self.id} ) - def connect_rtstream(self, url: str, name: str, sample_rate: int = 1) -> RTStream: + def connect_rtstream( + self, url: str, name: str, sample_rate: int = None + ) -> RTStream: rtstream_data = self._connection.post( path=f"{ApiPath.rtstream}", data={ From 53f9982f3cb7a1a39cb4c9faca1d929127b99eca Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Wed, 28 May 2025 11:08:01 +0530 Subject: [PATCH 16/18] docs: add docstrings --- videodb/client.py | 12 +++++ videodb/collection.py | 19 ++++++++ videodb/rtstream.py | 104 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/videodb/client.py b/videodb/client.py index a80ecbf..c4b511b 100644 --- a/videodb/client.py +++ b/videodb/client.py @@ -148,6 +148,13 @@ def get_invoices(self) -> List[dict]: return self.get(path=f"{ApiPath.billing}/{ApiPath.invoices}") def create_event(self, event_prompt: str, label: str): + """Create an rtstream event. + + :param str event_prompt: Prompt for the event + :param str label: Label for the event + :return: Event ID + :rtype: str + """ event_data = self.post( f"{ApiPath.rtstream}/{ApiPath.event}", data={"event_prompt": event_prompt, "label": label}, @@ -156,6 +163,11 @@ def create_event(self, event_prompt: str, label: str): return event_data.get("event_id") def list_events(self): + """List all rtstream events. + + :return: List of events + :rtype: list[dict] + """ event_data = self.get(f"{ApiPath.rtstream}/{ApiPath.event}") return event_data.get("events", []) diff --git a/videodb/collection.py b/videodb/collection.py index 3e75602..f048cf2 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -168,6 +168,13 @@ def delete_image(self, image_id: str) -> None: def connect_rtstream( self, url: str, name: str, sample_rate: int = None ) -> RTStream: + """Connect to an rtstream. + + :param str url: URL of the rtstream + :param str name: Name of the rtstream + :param int sample_rate: Sample rate of the rtstream default is 1fps + :return: :class:`RTStream ` object + """ rtstream_data = self._connection.post( path=f"{ApiPath.rtstream}", data={ @@ -180,12 +187,23 @@ def connect_rtstream( return RTStream(self._connection, **rtstream_data) def get_rtstream(self, id: str) -> RTStream: + """Get an rtstream by its ID. + + :param str id: ID of the rtstream + :return: :class:`RTStream ` object + :rtype: :class:`videodb.rtstream.RTStream` + """ rtstream_data = self._connection.get( path=f"{ApiPath.rtstream}/{id}", ) return RTStream(self._connection, **rtstream_data) def list_rtstreams(self) -> List[RTStream]: + """List all rtstreams in the collection. + + :return: List of :class:`RTStream ` objects + :rtype: List[:class:`videodb.rtstream.RTStream`] + """ rtstreams_data = self._connection.get( path=f"{ApiPath.rtstream}", ) @@ -193,6 +211,7 @@ def list_rtstreams(self) -> List[RTStream]: RTStream(self._connection, **rtstream) for rtstream in rtstreams_data.get("results") ] + def generate_image( self, prompt: str, diff --git a/videodb/rtstream.py b/videodb/rtstream.py index b2fc3eb..c6572c0 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -5,6 +5,17 @@ class RTStreamSceneIndex: + """RTStreamSceneIndex class to interact with the rtstream scene index + + :ivar str rtstream_index_id: Unique identifier for the rtstream scene index + :ivar str rtstream_id: ID of the rtstream this scene index belongs to + :ivar str extraction_type: Type of extraction + :ivar dict extraction_config: Configuration for extraction + :ivar str prompt: Prompt for scene extraction + :ivar str name: Name of the scene index + :ivar str status: Status of the scene index + """ + def __init__( self, _connection, rtstream_index_id: str, rtstream_id, **kwargs ) -> None: @@ -21,6 +32,7 @@ def __repr__(self) -> str: return ( f"RTStreamSceneIndex(" f"rtstream_index_id={self.rtstream_index_id}, " + f"rtstream_id={self.rtstream_id}, " f"extraction_type={self.extraction_type}, " f"extraction_config={self.extraction_config}, " f"prompt={self.prompt}, " @@ -29,6 +41,15 @@ def __repr__(self) -> str: ) def get_scenes(self, start: int = None, end: int = None, page=1, page_size=100): + """Get rtstream scene index scenes. + + :param int start: Start time of the scenes + :param int end: End time of the scenes + :param int page: Page number + :param int page_size: Number of scenes per page + :return: List of scenes + :rtype: List[dict] + """ params = {"page": page, "page_size": page_size} if start and end: params["start"] = start @@ -46,6 +67,11 @@ def get_scenes(self, start: int = None, end: int = None, page=1, page_size=100): } def start(self): + """Start the scene index. + + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", data={"action": "start"}, @@ -53,6 +79,11 @@ def start(self): self.status = "connected" def stop(self): + """Stop the scene index. + + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{ApiPath.scene}/{self.rtstream_index_id}/{ApiPath.status}", data={"action": "stop"}, @@ -60,6 +91,13 @@ def stop(self): self.status = "stopped" def create_alert(self, event_id, callback_url) -> str: + """Create an event alert. + + :param str event_id: ID of the event + :param str callback_url: URL to receive the alert callback + :return: Alert ID + :rtype: str + """ alert_data = self._connection.post( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}", data={ @@ -70,18 +108,35 @@ def create_alert(self, event_id, callback_url) -> str: return alert_data.get("alert_id", None) def list_alerts(self): + """List all alerts for the rtstream scene index. + + :return: List of alerts + :rtype: List[dict] + """ alert_data = self._connection.get( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}" ) return alert_data.get("alerts", []) def enable_alert(self, alert_id): + """Enable an alert. + + :param str alert_id: ID of the alert + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", data={"action": "enable"}, ) def disable_alert(self, alert_id): + """Disable an alert. + + :param str alert_id: ID of the alert + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.rtstream_id}/{ApiPath.index}/{self.rtstream_index_id}/{ApiPath.alert}/{alert_id}/{ApiPath.status}", data={"action": "disable"}, @@ -89,6 +144,16 @@ def disable_alert(self, alert_id): class RTStream: + """RTStream class to interact with the RTStream + + :ivar str id: Unique identifier for the rtstream + :ivar str name: Name of the rtstream + :ivar str collection_id: ID of the collection this rtstream belongs to + :ivar str created_at: Timestamp of the rtstream creation + :ivar int sample_rate: Sample rate of the rtstream + :ivar str status: Status of the rtstream + """ + def __init__(self, _connection, id: str, **kwargs) -> None: self._connection = _connection self.id = id @@ -110,6 +175,11 @@ def __repr__(self) -> str: ) def start(self): + """Connect to the rtstream. + + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.id}/{ApiPath.status}", data={"action": "start"}, @@ -117,6 +187,11 @@ def start(self): self.status = "connected" def stop(self): + """Disconnect from the rtstream. + + :return: None + :rtype: None + """ self._connection.patch( f"{ApiPath.rtstream}/{self.id}/{ApiPath.status}", data={"action": "stop"}, @@ -124,6 +199,13 @@ def stop(self): self.status = "stopped" def generate_stream(self, start, end): + """Generate a stream from the rtstream. + + :param int start: Start time of the stream + :param int end: End time of the stream + :return: Stream URL + :rtype: str + """ stream_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.stream}", params={"start": start, "end": end}, @@ -139,6 +221,17 @@ def index_scenes( model_config={}, name=None, ): + """Index scenes from the rtstream. + + :param str extraction_type: Type of extraction + :param dict extraction_config: Configuration for extraction + :param str prompt: Prompt for scene extraction + :param str model_name: Name of the model + :param dict model_config: Configuration for the model + :param str name: Name of the scene index + :return: Scene index, :class:`RTStreamSceneIndex ` object + :rtype: :class:`videodb.rtstream.RTStreamSceneIndex` + """ index_data = self._connection.post( f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}", data={ @@ -164,6 +257,11 @@ def index_scenes( ) def list_scene_indexes(self): + """List all scene indexes for the rtstream. + + :return: List of :class:`RTStreamSceneIndex ` objects + :rtype: List[:class:`videodb.rtstream.RTStreamSceneIndex`] + """ index_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{ApiPath.scene}" ) @@ -182,6 +280,12 @@ def list_scene_indexes(self): ] def get_scene_index(self, index_id: str) -> RTStreamSceneIndex: + """Get a scene index by its ID. + + :param str index_id: ID of the scene index + :return: Scene index, :class:`RTStreamSceneIndex ` object + :rtype: :class:`videodb.rtstream.RTStreamSceneIndex` + """ index_data = self._connection.get( f"{ApiPath.rtstream}/{self.id}/{ApiPath.index}/{index_id}" ) From 568bc1a12c677560e1436b05ad87dff8c32f30a0 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Wed, 28 May 2025 11:15:38 +0530 Subject: [PATCH 17/18] fix: docstrings --- videodb/rtstream.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/videodb/rtstream.py b/videodb/rtstream.py index c6572c0..4be4a8c 100644 --- a/videodb/rtstream.py +++ b/videodb/rtstream.py @@ -201,8 +201,8 @@ def stop(self): def generate_stream(self, start, end): """Generate a stream from the rtstream. - :param int start: Start time of the stream - :param int end: End time of the stream + :param int start: Start time of the stream in Unix timestamp format + :param int end: End time of the stream in Unix timestamp format :return: Stream URL :rtype: str """ From 3a2b8faecc2d7dc9bb869f1706346ec0d0541f34 Mon Sep 17 00:00:00 2001 From: Ankit raj <113342181+ankit-v2-3@users.noreply.github.com> Date: Wed, 28 May 2025 11:18:11 +0530 Subject: [PATCH 18/18] fix: docstring --- videodb/collection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/videodb/collection.py b/videodb/collection.py index f048cf2..e941cf4 100644 --- a/videodb/collection.py +++ b/videodb/collection.py @@ -172,7 +172,7 @@ def connect_rtstream( :param str url: URL of the rtstream :param str name: Name of the rtstream - :param int sample_rate: Sample rate of the rtstream default is 1fps + :param int sample_rate: Sample rate of the rtstream (optional) :return: :class:`RTStream ` object """ rtstream_data = self._connection.post(