Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 cloudglue/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from cloudglue.sdk.models.google_drive_source_metadata import GoogleDriveSourceMetadata
from cloudglue.sdk.models.dropbox_source_metadata import DropboxSourceMetadata
from cloudglue.sdk.models.gong_source_metadata import GongSourceMetadata
from cloudglue.sdk.models.iconik_source_metadata import IconikSourceMetadata

# Export key classes at the module level for clean imports
__all__ = [
Expand All @@ -45,4 +46,5 @@
"GoogleDriveSourceMetadata",
"DropboxSourceMetadata",
"GongSourceMetadata",
"IconikSourceMetadata",
]
27 changes: 23 additions & 4 deletions cloudglue/client/resources/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ def create(
"""Create a new collection.

Args:
collection_type: Type of collection ('entities', 'rich-transcripts', 'media-descriptions', 'face-analysis')
collection_type: Type of collection ('entities', 'rich-transcripts', 'media-descriptions',
'face-analysis', 'metadata'). 'metadata' collections index connector source metadata
and user metadata into file-level search documents WITHOUT downloading or processing
the media — free to index, no processing configs, supports google-drive, dropbox,
zoom, gong, recall, grain, and iconik URLs.
name: Name of the collection (must be unique)
description: Optional description of the collection
extract_config: Optional configuration for extraction processing
Expand Down Expand Up @@ -117,7 +121,8 @@ def list(
offset: Number of collections to skip
order: Field to sort by ('created_at'). Defaults to 'created_at'
sort: Sort direction ('asc', 'desc'). Defaults to 'desc'
collection_type: Filter by collection type ('video', 'audio', 'image', 'text')
collection_type: Filter by collection type ('entities', 'rich-transcripts',
'media-descriptions', 'face-analysis', 'metadata')

Returns:
The typed CollectionList object with collections and metadata
Expand Down Expand Up @@ -415,6 +420,7 @@ def get_rich_transcripts(
start_time_seconds: Optional[float] = None,
end_time_seconds: Optional[float] = None,
response_format: Optional[str] = None,
include_metadata: Optional[bool] = None,
):
"""Get the rich transcript of a video in a collection.

Expand All @@ -424,6 +430,8 @@ def get_rich_transcripts(
start_time_seconds: The start time in seconds to filter the rich transcript
end_time_seconds: The end time in seconds to filter the rich transcript
response_format: The format of the response, one of 'json' or 'markdown' (json by default)
include_metadata: When true, include the file's `metadata` and `source_metadata`
on the response's `file` object.

Returns:
The typed RichTranscript object with video rich transcript data
Expand All @@ -434,7 +442,7 @@ def get_rich_transcripts(
try:
# Use the standard method to get a properly typed object
response = self.api.get_transcripts(
collection_id=collection_id, file_id=file_id, start_time_seconds=start_time_seconds, end_time_seconds=end_time_seconds, response_format=response_format
collection_id=collection_id, file_id=file_id, start_time_seconds=start_time_seconds, end_time_seconds=end_time_seconds, response_format=response_format, include_metadata=include_metadata
)
return response
except ApiException as e:
Expand Down Expand Up @@ -543,6 +551,7 @@ def list_rich_transcripts(
added_before: Optional[str] = None,
added_after: Optional[str] = None,
response_format: Optional[str] = None,
include_metadata: Optional[bool] = None,
):
"""List all rich transcription data for files in a collection.

Expand All @@ -557,6 +566,8 @@ def list_rich_transcripts(
added_before: Filter files added before a specific date (YYYY-MM-DD format), in UTC timezone
added_after: Filter files added after a specific date (YYYY-MM-DD format), in UTC timezone
response_format: Format for the response
include_metadata: When true, include each file's `metadata` and `source_metadata`
on the `file` object of each entry.

Returns:
Collection rich transcripts list response
Expand All @@ -574,6 +585,7 @@ def list_rich_transcripts(
added_before=added_before,
added_after=added_after,
response_format=response_format,
include_metadata=include_metadata,
)
return response
except ApiException as e:
Expand All @@ -594,6 +606,7 @@ def get_media_descriptions(
include_word_timestamps: Optional[bool] = None,
include_chapters: Optional[bool] = None,
include_shots: Optional[bool] = None,
include_metadata: Optional[bool] = None,
):
"""Get the media descriptions of a video in a collection.

Expand All @@ -607,6 +620,8 @@ def get_media_descriptions(
include_word_timestamps: When true, include word-level timestamps on speech entries. Not available for YouTube sources. Only applies when response_format=json.
include_chapters: When true, include narrative chapters in the response (when segmentation strategy is 'narrative')
include_shots: When true, include shot boundaries in the response (when segmentation strategy is 'shot-detector')
include_metadata: When true, include the file's `metadata` and `source_metadata`
on the response's `file` object.

Returns:
The typed MediaDescription object with video media description data
Expand All @@ -617,7 +632,7 @@ def get_media_descriptions(
try:
# Use the standard method to get a properly typed object
response = self.api.get_media_descriptions(
collection_id=collection_id, file_id=file_id, start_time_seconds=start_time_seconds, end_time_seconds=end_time_seconds, response_format=response_format, include_thumbnails=include_thumbnails, include_word_timestamps=include_word_timestamps, include_chapters=include_chapters, include_shots=include_shots
collection_id=collection_id, file_id=file_id, start_time_seconds=start_time_seconds, end_time_seconds=end_time_seconds, response_format=response_format, include_thumbnails=include_thumbnails, include_word_timestamps=include_word_timestamps, include_chapters=include_chapters, include_shots=include_shots, include_metadata=include_metadata
)
return response
except ApiException as e:
Expand All @@ -635,6 +650,7 @@ def list_media_descriptions(
added_before: Optional[str] = None,
added_after: Optional[str] = None,
response_format: Optional[str] = None,
include_metadata: Optional[bool] = None,
):
"""List all media description data for files in a collection.

Expand All @@ -649,6 +665,8 @@ def list_media_descriptions(
added_before: Filter files added before a specific date (YYYY-MM-DD format), in UTC timezone
added_after: Filter files added after a specific date (YYYY-MM-DD format), in UTC timezone
response_format: Format for the response
include_metadata: When true, include each file's `metadata` and `source_metadata`
on the `file` object of each entry.

Returns:
Collection media descriptions list response
Expand All @@ -666,6 +684,7 @@ def list_media_descriptions(
added_before=added_before,
added_after=added_after,
response_format=response_format,
include_metadata=include_metadata,
)
return response
except ApiException as e:
Expand Down
20 changes: 11 additions & 9 deletions cloudglue/client/resources/data_connectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,18 @@ def list_files(
filter parameters they were issued under.
var_from: Start date for filtering (YYYY-MM-DD, inclusive UTC day
bound). Supported by Grain, Zoom, Recall, Google Drive,
Dropbox, and Gong (Zoom and Gong default to a 6-month lookback
when omitted); ignored for S3/GCS.
Dropbox, Gong, and Iconik (Zoom and Gong default to a 6-month
lookback when omitted); ignored for S3/GCS.
to: End date for filtering (YYYY-MM-DD). Same per-connector
support as `var_from`.
folder_id: Google Drive folder ID to list contents of. Applies to Google Drive connectors only.
path: Dropbox folder path to list contents of (default: root). Applies to Dropbox connectors only.
bucket: Bucket name. Required for S3 and GCS connectors.
prefix: Key prefix filter. Applies to S3 and GCS connectors only.
title_search: Case-insensitive title filter. Supported by Grain,
Zoom, Google Drive, Dropbox, and Gong; ignored for Recall (no
title is available when listing) and S3/GCS.
Zoom, Google Drive, Dropbox, Gong, and Iconik (full-text title
search); ignored for Recall (no title is available when
listing) and S3/GCS.
team: Team filter. Applies to Grain connectors only. See the [Grain documentation](https://developers.grain.com/#recording-filter) for more details.
meeting_type: Meeting type filter. Applies to Grain connectors only. See the [Grain documentation](https://developers.grain.com/#recording-filter) for more details.

Expand Down Expand Up @@ -118,8 +119,8 @@ def get_source_metadata(self, connector_id: str, url: str):
Returns provider-specific metadata (recording/call/file details) for a
single file in a connected data source, without importing it.

Supported for Grain, Zoom, Recall, Google Drive, Dropbox, and Gong
connectors. S3/GCS raise a CloudglueError with status 501 (plain
Supported for Grain, Zoom, Recall, Google Drive, Dropbox, Gong, and
Iconik connectors. S3/GCS raise a CloudglueError with status 501 (plain
object stores have no richer metadata); a 502 is raised when the
upstream provider's response can't be validated.

Expand Down Expand Up @@ -151,12 +152,13 @@ def sync_file(self, connector_id: str, url: str):
Imports the file at the given connector URI, returning the resulting
Cloudglue file (creating it if it does not already exist). Idempotent:
syncing the same URI returns the existing file. For Grain, Zoom,
Recall, Google Drive, Dropbox, and Gong the file's `source_metadata`
is populated from the provider.
Recall, Google Drive, Dropbox, Gong, and Iconik the file's
`source_metadata` is populated from the provider.

Besides the connector URIs emitted by `list_files()` (`s3://`,
`gs://`, `gdrive://file/<id>`, `dropbox://<path>`, `zoom://`,
`grain://recording/<id>`, ...), the server resolves these share links
`grain://recording/<id>`, `iconik://asset/<id>`, ...), the server
resolves these share links
via the connector's OAuth:
- Google Drive share links (`drive.google.com/file/d/<id>`,
`/open?id=<id>`)
Expand Down
8 changes: 8 additions & 0 deletions cloudglue/client/resources/describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def get(
include_word_timestamps: Optional[bool] = None,
include_chapters: Optional[bool] = None,
include_shots: Optional[bool] = None,
include_metadata: Optional[bool] = None,
):
"""Get the status and data of a media description job.

Expand All @@ -137,6 +138,8 @@ def get(
include_word_timestamps: When true, include word-level timestamps on speech entries. Not available for YouTube sources. Only applies when response_format=json.
include_chapters: When true, include narrative chapters in the response (when segmentation strategy is 'narrative')
include_shots: When true, include shot boundaries in the response (when segmentation strategy is 'shot-detector')
include_metadata: When true, include the file's `metadata` and `source_metadata`
on the response's `file` object.

Returns:
The typed Describe job object with current status and data (if completed).
Expand All @@ -156,6 +159,7 @@ def get(
include_word_timestamps=include_word_timestamps,
include_chapters=include_chapters,
include_shots=include_shots,
include_metadata=include_metadata,
)
return response
except ApiException as e:
Expand All @@ -173,6 +177,7 @@ def list(
response_format: Optional[str] = None,
url: Optional[str] = None,
include_data: Optional[bool] = None,
include_metadata: Optional[bool] = None,
):
"""List all media description jobs with optional filtering.

Expand All @@ -186,6 +191,8 @@ def list(
url: Filter description jobs by the input URL used for description.
include_data: Include the data in the response. If false, the response will only include
the job information and not the data to minimize the response size.
include_metadata: When true, include each file's `metadata` and `source_metadata`
on the `file` object of each job.

Returns:
The typed DescribeList object with array of describe jobs.
Expand All @@ -204,6 +211,7 @@ def list(
response_format=response_format,
url=url,
include_data=include_data,
include_metadata=include_metadata,
)
return response
except ApiException as e:
Expand Down
28 changes: 28 additions & 0 deletions cloudglue/client/resources/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,34 @@ def get(self, file_id: str):
except Exception as e:
raise CloudglueError(str(e))

def sync_source_metadata(self, file_id: str):
"""Refresh a connector file's source metadata.

Re-fetches the file's `source_metadata` live from its data connector
(google-drive, dropbox, zoom, gong, recall, grain, or iconik) and
updates the stored value. If the file belongs to any metadata
collections, their search documents are re-indexed with the refreshed
metadata. Works for both metadata-only and fully ingested connector
files. Free — no media is downloaded or processed.

Args:
file_id: The ID of the connector-backed file to refresh.

Returns:
The file object with refreshed `source_metadata`.

Raises:
CloudglueError: If the file has no connector URI, the source does
not support metadata lookup, or the account has no connector
of that type (400), or the file is not found (404).
"""
try:
return self.api.sync_file_source_metadata(file_id=file_id)
except ApiException as e:
raise CloudglueError(str(e), e.status, e.data, e.headers, e.reason)
except Exception as e:
raise CloudglueError(str(e))

def delete(self, file_id: str):
"""Delete a file.

Expand Down
21 changes: 19 additions & 2 deletions cloudglue/client/resources/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from cloudglue.sdk.models.search_request import SearchRequest
from cloudglue.sdk.models.search_filter import SearchFilter
from cloudglue.sdk.models.search_filter_criteria import SearchFilterCriteria
from cloudglue.sdk.models.search_filter_metadata_inner import SearchFilterMetadataInner
from cloudglue.sdk.models.search_filter_file_inner import SearchFilterFileInner
from cloudglue.sdk.models.search_filter_video_info_inner import SearchFilterVideoInfoInner
Expand Down Expand Up @@ -117,6 +118,7 @@ def create_filter(
metadata_filters: Optional[List[Dict[str, Any]]] = None,
video_info_filters: Optional[List[Dict[str, Any]]] = None,
file_filters: Optional[List[Dict[str, Any]]] = None,
source_metadata_filters: Optional[List[Dict[str, Any]]] = None,
) -> SearchFilter:
"""Create a search filter using simple dictionaries.

Expand All @@ -133,7 +135,15 @@ def create_filter(
video_info_filters: List of video info filter dictionaries. Same structure as metadata_filters,
plus optional 'scope' ('file' or 'segment'). Defaults to 'file'.
file_filters: List of file filter dictionaries (same structure, without scope)

source_metadata_filters: List of connector source-metadata filter dictionaries
(same structure, without scope — file scope only). Paths address the
connector-provided `source_metadata` object, e.g. 'topic' (zoom),
'title' (gong/grain/iconik), 'participants.name' (grain),
'parties.email' (gong), 'name' (google-drive/dropbox),
'media_type' (iconik), or 'iconik_metadata.<FieldName>' (iconik
custom metadata-view fields, use ContainsAny for list fields).
Paths through arrays of objects match when ANY element matches.

Returns:
SearchFilter object

Expand Down Expand Up @@ -166,11 +176,18 @@ def create_filter(
file_objs = [
SearchFilterFileInner(**f) for f in file_filters
]


source_metadata_objs = None
if source_metadata_filters:
source_metadata_objs = [
SearchFilterCriteria(**f) for f in source_metadata_filters
]

return SearchFilter(
metadata=metadata_objs,
video_info=video_info_objs,
file=file_objs,
source_metadata=source_metadata_objs,
)

def search(
Expand Down
4 changes: 4 additions & 0 deletions cloudglue/client/resources/segmentations.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ def list_describes(
response_format: Optional[str] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
include_metadata: Optional[bool] = None,
):
"""List describe jobs for a segmentation.

Expand All @@ -404,6 +405,8 @@ def list_describes(
response_format: Output format for the describe data ('json' or 'markdown')
limit: Number of items to return (max 100)
offset: Offset from the start of the list
include_metadata: When true, include each file's `metadata` and `source_metadata`
on the `file` object of each job.

Returns:
DescribeList containing describe jobs for the segmentation
Expand All @@ -418,6 +421,7 @@ def list_describes(
response_format=response_format,
limit=limit,
offset=offset,
include_metadata=include_metadata,
)
return response
except ApiException as e:
Expand Down
Loading