Skip to content

Commit 39d63d3

Browse files
committed
Merge branch 'main' into ankit/add-rtstream
2 parents 0ee6e65 + d185e9a commit 39d63d3

File tree

11 files changed

+789
-32
lines changed

11 files changed

+789
-32
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Trigger Agent Toolkit Update
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
7+
jobs:
8+
trigger-videodb-helper-update:
9+
if: ${{ github.event.pull_request.merged && github.event.pull_request.base.ref == 'main' }}
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Trigger Agent Toolkit Update workflow via repository_dispatch
13+
run: |
14+
curl -X POST -H "Accept: application/vnd.github+json" \
15+
-H "Authorization: Bearer ${{ secrets.AGENT_TOOLKIT_TOKEN }}" \
16+
-H "X-GitHub-Api-Version: 2022-11-28" \
17+
https://api.github.com/repos/video-db/agent-toolkit/dispatches \
18+
-d '{"event_type": "sdk-context-update", "client_payload": {"pr_number": ${{ github.event.pull_request.number }}}}'
19+

videodb/_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Constants used in the videodb package."""
2+
23
from typing import Union
34
from dataclasses import dataclass
45

@@ -74,6 +75,11 @@ class ApiPath:
7475
status = "status"
7576
event = "event"
7677
alert = "alert"
78+
generate_url = "generate_url"
79+
generate = "generate"
80+
web = "web"
81+
translate = "translate"
82+
dub = "dub"
7783

7884

7985
class Status:

videodb/audio.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@
44

55

66
class Audio:
7-
def __init__(self, _connection, id: str, collection_id: str, **kwargs) -> None:
7+
"""Audio class to interact with the Audio
8+
9+
:ivar str id: Unique identifier for the audio
10+
:ivar str collection_id: ID of the collection this audio belongs to
11+
:ivar str name: Name of the audio file
12+
:ivar float length: Duration of the audio in seconds
13+
"""
14+
15+
def __init__(
16+
self, _connection, id: str, collection_id: str, **kwargs
17+
) -> None:
818
self._connection = _connection
919
self.id = id
1020
self.collection_id = collection_id
@@ -20,5 +30,24 @@ def __repr__(self) -> str:
2030
f"length={self.length})"
2131
)
2232

33+
def generate_url(self) -> str:
34+
"""Generate the signed url of the audio.
35+
36+
:raises InvalidRequestError: If the get_url fails
37+
:return: The signed url of the audio
38+
:rtype: str
39+
"""
40+
url_data = self._connection.post(
41+
path=f"{ApiPath.audio}/{self.id}/{ApiPath.generate_url}",
42+
params={"collection_id": self.collection_id},
43+
)
44+
return url_data.get("signed_url", None)
45+
2346
def delete(self) -> None:
47+
"""Delete the audio.
48+
49+
:raises InvalidRequestError: If the delete fails
50+
:return: None if the delete is successful
51+
:rtype: None
52+
"""
2453
self._connection.delete(f"{ApiPath.audio}/{self.id}")

videodb/client.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,77 @@
2424

2525

2626
class Connection(HttpClient):
27-
def __init__(self, api_key: str, base_url: str) -> None:
27+
"""Connection class to interact with the VideoDB"""
28+
29+
def __init__(self, api_key: str, base_url: str) -> "Connection":
30+
"""Initializes a new instance of the Connection class with specified API credentials.
31+
32+
Note: Users should not initialize this class directly.
33+
Instead use :meth:`videodb.connect() <videodb.connect>`
34+
35+
:param str api_key: API key for authentication
36+
:param str base_url: Base URL of the VideoDB API
37+
:raise ValueError: If the API key is not provided
38+
:return: :class:`Connection <Connection>` object, to interact with the VideoDB
39+
:rtype: :class:`videodb.client.Connection`
40+
"""
2841
self.api_key = api_key
2942
self.base_url = base_url
3043
self.collection_id = "default"
3144
super().__init__(api_key=api_key, base_url=base_url, version=__version__)
3245

3346
def get_collection(self, collection_id: Optional[str] = "default") -> Collection:
47+
"""Get a collection object by its ID.
48+
49+
:param str collection_id: ID of the collection (optional, default: "default")
50+
:return: :class:`Collection <Collection>` object
51+
:rtype: :class:`videodb.collection.Collection`
52+
"""
3453
collection_data = self.get(path=f"{ApiPath.collection}/{collection_id}")
3554
self.collection_id = collection_data.get("id", "default")
3655
return Collection(
3756
self,
3857
self.collection_id,
3958
collection_data.get("name"),
4059
collection_data.get("description"),
60+
collection_data.get("is_public", False),
4161
)
4262

4363
def get_collections(self) -> List[Collection]:
64+
"""Get a list of all collections.
65+
66+
:return: List of :class:`Collection <Collection>` objects
67+
:rtype: list[:class:`videodb.collection.Collection`]
68+
"""
4469
collections_data = self.get(path=ApiPath.collection)
4570
return [
4671
Collection(
4772
self,
4873
collection.get("id"),
4974
collection.get("name"),
5075
collection.get("description"),
76+
collection.get("is_public", False),
5177
)
5278
for collection in collections_data.get("collections")
5379
]
5480

55-
def create_collection(self, name: str, description: str) -> Collection:
81+
def create_collection(
82+
self, name: str, description: str, is_public: bool = False
83+
) -> Collection:
84+
"""Create a new collection.
85+
86+
:param str name: Name of the collection
87+
:param str description: Description of the collection
88+
:param bool is_public: Make collection public (optional, default: False)
89+
:return: :class:`Collection <Collection>` object
90+
:rtype: :class:`videodb.collection.Collection`
91+
"""
5692
collection_data = self.post(
5793
path=ApiPath.collection,
5894
data={
5995
"name": name,
6096
"description": description,
97+
"is_public": is_public,
6198
},
6299
)
63100
self.collection_id = collection_data.get("id", "default")
@@ -66,9 +103,18 @@ def create_collection(self, name: str, description: str) -> Collection:
66103
collection_data.get("id"),
67104
collection_data.get("name"),
68105
collection_data.get("description"),
106+
collection_data.get("is_public", False),
69107
)
70108

71109
def update_collection(self, id: str, name: str, description: str) -> Collection:
110+
"""Update an existing collection.
111+
112+
:param str id: ID of the collection
113+
:param str name: Name of the collection
114+
:param str description: Description of the collection
115+
:return: :class:`Collection <Collection>` object
116+
:rtype: :class:`videodb.collection.Collection`
117+
"""
72118
collection_data = self.patch(
73119
path=f"{ApiPath.collection}/{id}",
74120
data={
@@ -82,12 +128,23 @@ def update_collection(self, id: str, name: str, description: str) -> Collection:
82128
collection_data.get("id"),
83129
collection_data.get("name"),
84130
collection_data.get("description"),
131+
collection_data.get("is_public", False),
85132
)
86133

87134
def check_usage(self) -> dict:
135+
"""Check the usage.
136+
137+
:return: Usage data
138+
:rtype: dict
139+
"""
88140
return self.get(path=f"{ApiPath.billing}/{ApiPath.usage}")
89141

90142
def get_invoices(self) -> List[dict]:
143+
"""Get a list of all invoices.
144+
145+
:return: List of invoices
146+
:rtype: list[dict]
147+
"""
91148
return self.get(path=f"{ApiPath.billing}/{ApiPath.invoices}")
92149

93150
def create_event(self, event_prompt: str, label: str):
@@ -103,6 +160,13 @@ def list_events(self):
103160
return event_data.get("events", [])
104161

105162
def download(self, stream_link: str, name: str) -> dict:
163+
"""Download a file from a stream link.
164+
165+
:param stream_link: URL of the stream to download
166+
:param name: Name to save the downloaded file as
167+
:return: Download response data
168+
:rtype: dict
169+
"""
106170
return self.post(
107171
path=f"{ApiPath.download}",
108172
data={
@@ -111,6 +175,31 @@ def download(self, stream_link: str, name: str) -> dict:
111175
},
112176
)
113177

178+
def youtube_search(
179+
self,
180+
query: str,
181+
result_threshold: Optional[int] = 10,
182+
duration: str = "medium",
183+
) -> List[dict]:
184+
"""Search for a query on YouTube.
185+
186+
:param str query: Query to search for
187+
:param int result_threshold: Number of results to return (optional)
188+
:param str duration: Duration of the video (optional)
189+
:return: List of YouTube search results
190+
:rtype: List[dict]
191+
"""
192+
search_data = self.post(
193+
path=f"{ApiPath.collection}/{self.collection_id}/{ApiPath.search}/{ApiPath.web}",
194+
data={
195+
"query": query,
196+
"result_threshold": result_threshold,
197+
"platform": "youtube",
198+
"duration": duration,
199+
},
200+
)
201+
return search_data.get("results")
202+
114203
def upload(
115204
self,
116205
file_path: str = None,
@@ -120,6 +209,17 @@ def upload(
120209
description: Optional[str] = None,
121210
callback_url: Optional[str] = None,
122211
) -> Union[Video, Audio, Image, None]:
212+
"""Upload a file.
213+
214+
:param str file_path: Path to the file to upload (optional)
215+
:param str url: URL of the file to upload (optional)
216+
:param MediaType media_type: MediaType object (optional)
217+
:param str name: Name of the file (optional)
218+
:param str description: Description of the file (optional)
219+
:param str callback_url: URL to receive the callback (optional)
220+
:return: :class:`Video <Video>`, or :class:`Audio <Audio>`, or :class:`Image <Image>` object
221+
:rtype: Union[ :class:`videodb.video.Video`, :class:`videodb.audio.Audio`, :class:`videodb.image.Image`]
222+
"""
123223
upload_data = upload(
124224
self,
125225
file_path,

0 commit comments

Comments
 (0)