Skip to content

Commit 6c1617a

Browse files
committed
feat: iconik connector, metadata collections, and source metadata search (sync spec v0.7.11)
Regenerated from spec v0.7.11 (cloudglue/cloudglue-api-spec#105) and bumped to 0.7.18. NOTE: the working branch was rebuilt on top of origin/main — the previous local checkout was based 9 commits back (missing the v0.7.9/v0.7.10 syncs); the regenerated cloudglue/sdk tree was carried over intact. Generated (cloudglue/sdk): - IconikSourceMetadata model; SourceMetadata oneOf and the connector/ source enums now cover iconik - New sync_file_source_metadata endpoint (POST /files/{file_id}/sync) - include_metadata query param on describe/transcribe get+list, collection media-description/rich-transcript listings, and segmentation describes; Describe/Transcribe responses gain a file object - SearchFilter.source_metadata and the doc_lexical search modality - 'metadata' collection_type Wrapper (cloudglue/client + package): - files.sync_source_metadata(file_id) for the new endpoint - include_metadata plumbed through describe/transcribe/segmentations/ collections methods (9 endpoints) - Search.create_filter gains source_metadata_filters (SearchFilterCriteria) - collection_type docstrings cover 'metadata' (and fix a stale enum) - IconikSourceMetadata re-exported at top level - data-connectors docstrings: per-connector matrices include iconik Verified against the live API: 14/14 checks across iconik listing/lookup/ title_search, metadata-collection create+index of grain+iconik URLs, source-metadata refresh (isinstance checks), doc_lexical + source_metadata-filtered search, and the include_metadata toggle.
1 parent f76b30e commit 6c1617a

296 files changed

Lines changed: 1146 additions & 368 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cloudglue/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from cloudglue.sdk.models.google_drive_source_metadata import GoogleDriveSourceMetadata
2626
from cloudglue.sdk.models.dropbox_source_metadata import DropboxSourceMetadata
2727
from cloudglue.sdk.models.gong_source_metadata import GongSourceMetadata
28+
from cloudglue.sdk.models.iconik_source_metadata import IconikSourceMetadata
2829

2930
# Export key classes at the module level for clean imports
3031
__all__ = [
@@ -45,4 +46,5 @@
4546
"GoogleDriveSourceMetadata",
4647
"DropboxSourceMetadata",
4748
"GongSourceMetadata",
49+
"IconikSourceMetadata",
4850
]

cloudglue/client/resources/collections.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ def create(
4141
"""Create a new collection.
4242
4343
Args:
44-
collection_type: Type of collection ('entities', 'rich-transcripts', 'media-descriptions', 'face-analysis')
44+
collection_type: Type of collection ('entities', 'rich-transcripts', 'media-descriptions',
45+
'face-analysis', 'metadata'). 'metadata' collections index connector source metadata
46+
and user metadata into file-level search documents WITHOUT downloading or processing
47+
the media — free to index, no processing configs, supports google-drive, dropbox,
48+
zoom, gong, recall, grain, and iconik URLs.
4549
name: Name of the collection (must be unique)
4650
description: Optional description of the collection
4751
extract_config: Optional configuration for extraction processing
@@ -117,7 +121,8 @@ def list(
117121
offset: Number of collections to skip
118122
order: Field to sort by ('created_at'). Defaults to 'created_at'
119123
sort: Sort direction ('asc', 'desc'). Defaults to 'desc'
120-
collection_type: Filter by collection type ('video', 'audio', 'image', 'text')
124+
collection_type: Filter by collection type ('entities', 'rich-transcripts',
125+
'media-descriptions', 'face-analysis', 'metadata')
121126
122127
Returns:
123128
The typed CollectionList object with collections and metadata
@@ -415,6 +420,7 @@ def get_rich_transcripts(
415420
start_time_seconds: Optional[float] = None,
416421
end_time_seconds: Optional[float] = None,
417422
response_format: Optional[str] = None,
423+
include_metadata: Optional[bool] = None,
418424
):
419425
"""Get the rich transcript of a video in a collection.
420426
@@ -424,6 +430,8 @@ def get_rich_transcripts(
424430
start_time_seconds: The start time in seconds to filter the rich transcript
425431
end_time_seconds: The end time in seconds to filter the rich transcript
426432
response_format: The format of the response, one of 'json' or 'markdown' (json by default)
433+
include_metadata: When true, include the file's `metadata` and `source_metadata`
434+
on the response's `file` object.
427435
428436
Returns:
429437
The typed RichTranscript object with video rich transcript data
@@ -434,7 +442,7 @@ def get_rich_transcripts(
434442
try:
435443
# Use the standard method to get a properly typed object
436444
response = self.api.get_transcripts(
437-
collection_id=collection_id, file_id=file_id, start_time_seconds=start_time_seconds, end_time_seconds=end_time_seconds, response_format=response_format
445+
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
438446
)
439447
return response
440448
except ApiException as e:
@@ -543,6 +551,7 @@ def list_rich_transcripts(
543551
added_before: Optional[str] = None,
544552
added_after: Optional[str] = None,
545553
response_format: Optional[str] = None,
554+
include_metadata: Optional[bool] = None,
546555
):
547556
"""List all rich transcription data for files in a collection.
548557
@@ -557,6 +566,8 @@ def list_rich_transcripts(
557566
added_before: Filter files added before a specific date (YYYY-MM-DD format), in UTC timezone
558567
added_after: Filter files added after a specific date (YYYY-MM-DD format), in UTC timezone
559568
response_format: Format for the response
569+
include_metadata: When true, include each file's `metadata` and `source_metadata`
570+
on the `file` object of each entry.
560571
561572
Returns:
562573
Collection rich transcripts list response
@@ -574,6 +585,7 @@ def list_rich_transcripts(
574585
added_before=added_before,
575586
added_after=added_after,
576587
response_format=response_format,
588+
include_metadata=include_metadata,
577589
)
578590
return response
579591
except ApiException as e:
@@ -594,6 +606,7 @@ def get_media_descriptions(
594606
include_word_timestamps: Optional[bool] = None,
595607
include_chapters: Optional[bool] = None,
596608
include_shots: Optional[bool] = None,
609+
include_metadata: Optional[bool] = None,
597610
):
598611
"""Get the media descriptions of a video in a collection.
599612
@@ -607,6 +620,8 @@ def get_media_descriptions(
607620
include_word_timestamps: When true, include word-level timestamps on speech entries. Not available for YouTube sources. Only applies when response_format=json.
608621
include_chapters: When true, include narrative chapters in the response (when segmentation strategy is 'narrative')
609622
include_shots: When true, include shot boundaries in the response (when segmentation strategy is 'shot-detector')
623+
include_metadata: When true, include the file's `metadata` and `source_metadata`
624+
on the response's `file` object.
610625
611626
Returns:
612627
The typed MediaDescription object with video media description data
@@ -617,7 +632,7 @@ def get_media_descriptions(
617632
try:
618633
# Use the standard method to get a properly typed object
619634
response = self.api.get_media_descriptions(
620-
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
635+
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
621636
)
622637
return response
623638
except ApiException as e:
@@ -635,6 +650,7 @@ def list_media_descriptions(
635650
added_before: Optional[str] = None,
636651
added_after: Optional[str] = None,
637652
response_format: Optional[str] = None,
653+
include_metadata: Optional[bool] = None,
638654
):
639655
"""List all media description data for files in a collection.
640656
@@ -649,6 +665,8 @@ def list_media_descriptions(
649665
added_before: Filter files added before a specific date (YYYY-MM-DD format), in UTC timezone
650666
added_after: Filter files added after a specific date (YYYY-MM-DD format), in UTC timezone
651667
response_format: Format for the response
668+
include_metadata: When true, include each file's `metadata` and `source_metadata`
669+
on the `file` object of each entry.
652670
653671
Returns:
654672
Collection media descriptions list response
@@ -666,6 +684,7 @@ def list_media_descriptions(
666684
added_before=added_before,
667685
added_after=added_after,
668686
response_format=response_format,
687+
include_metadata=include_metadata,
669688
)
670689
return response
671690
except ApiException as e:

cloudglue/client/resources/data_connectors.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,18 @@ def list_files(
7272
filter parameters they were issued under.
7373
var_from: Start date for filtering (YYYY-MM-DD, inclusive UTC day
7474
bound). Supported by Grain, Zoom, Recall, Google Drive,
75-
Dropbox, and Gong (Zoom and Gong default to a 6-month lookback
76-
when omitted); ignored for S3/GCS.
75+
Dropbox, Gong, and Iconik (Zoom and Gong default to a 6-month
76+
lookback when omitted); ignored for S3/GCS.
7777
to: End date for filtering (YYYY-MM-DD). Same per-connector
7878
support as `var_from`.
7979
folder_id: Google Drive folder ID to list contents of. Applies to Google Drive connectors only.
8080
path: Dropbox folder path to list contents of (default: root). Applies to Dropbox connectors only.
8181
bucket: Bucket name. Required for S3 and GCS connectors.
8282
prefix: Key prefix filter. Applies to S3 and GCS connectors only.
8383
title_search: Case-insensitive title filter. Supported by Grain,
84-
Zoom, Google Drive, Dropbox, and Gong; ignored for Recall (no
85-
title is available when listing) and S3/GCS.
84+
Zoom, Google Drive, Dropbox, Gong, and Iconik (full-text title
85+
search); ignored for Recall (no title is available when
86+
listing) and S3/GCS.
8687
team: Team filter. Applies to Grain connectors only. See the [Grain documentation](https://developers.grain.com/#recording-filter) for more details.
8788
meeting_type: Meeting type filter. Applies to Grain connectors only. See the [Grain documentation](https://developers.grain.com/#recording-filter) for more details.
8889
@@ -118,8 +119,8 @@ def get_source_metadata(self, connector_id: str, url: str):
118119
Returns provider-specific metadata (recording/call/file details) for a
119120
single file in a connected data source, without importing it.
120121
121-
Supported for Grain, Zoom, Recall, Google Drive, Dropbox, and Gong
122-
connectors. S3/GCS raise a CloudglueError with status 501 (plain
122+
Supported for Grain, Zoom, Recall, Google Drive, Dropbox, Gong, and
123+
Iconik connectors. S3/GCS raise a CloudglueError with status 501 (plain
123124
object stores have no richer metadata); a 502 is raised when the
124125
upstream provider's response can't be validated.
125126
@@ -151,12 +152,13 @@ def sync_file(self, connector_id: str, url: str):
151152
Imports the file at the given connector URI, returning the resulting
152153
Cloudglue file (creating it if it does not already exist). Idempotent:
153154
syncing the same URI returns the existing file. For Grain, Zoom,
154-
Recall, Google Drive, Dropbox, and Gong the file's `source_metadata`
155-
is populated from the provider.
155+
Recall, Google Drive, Dropbox, Gong, and Iconik the file's
156+
`source_metadata` is populated from the provider.
156157
157158
Besides the connector URIs emitted by `list_files()` (`s3://`,
158159
`gs://`, `gdrive://file/<id>`, `dropbox://<path>`, `zoom://`,
159-
`grain://recording/<id>`, ...), the server resolves these share links
160+
`grain://recording/<id>`, `iconik://asset/<id>`, ...), the server
161+
resolves these share links
160162
via the connector's OAuth:
161163
- Google Drive share links (`drive.google.com/file/d/<id>`,
162164
`/open?id=<id>`)

cloudglue/client/resources/describe.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def get(
121121
include_word_timestamps: Optional[bool] = None,
122122
include_chapters: Optional[bool] = None,
123123
include_shots: Optional[bool] = None,
124+
include_metadata: Optional[bool] = None,
124125
):
125126
"""Get the status and data of a media description job.
126127
@@ -137,6 +138,8 @@ def get(
137138
include_word_timestamps: When true, include word-level timestamps on speech entries. Not available for YouTube sources. Only applies when response_format=json.
138139
include_chapters: When true, include narrative chapters in the response (when segmentation strategy is 'narrative')
139140
include_shots: When true, include shot boundaries in the response (when segmentation strategy is 'shot-detector')
141+
include_metadata: When true, include the file's `metadata` and `source_metadata`
142+
on the response's `file` object.
140143
141144
Returns:
142145
The typed Describe job object with current status and data (if completed).
@@ -156,6 +159,7 @@ def get(
156159
include_word_timestamps=include_word_timestamps,
157160
include_chapters=include_chapters,
158161
include_shots=include_shots,
162+
include_metadata=include_metadata,
159163
)
160164
return response
161165
except ApiException as e:
@@ -173,6 +177,7 @@ def list(
173177
response_format: Optional[str] = None,
174178
url: Optional[str] = None,
175179
include_data: Optional[bool] = None,
180+
include_metadata: Optional[bool] = None,
176181
):
177182
"""List all media description jobs with optional filtering.
178183
@@ -186,6 +191,8 @@ def list(
186191
url: Filter description jobs by the input URL used for description.
187192
include_data: Include the data in the response. If false, the response will only include
188193
the job information and not the data to minimize the response size.
194+
include_metadata: When true, include each file's `metadata` and `source_metadata`
195+
on the `file` object of each job.
189196
190197
Returns:
191198
The typed DescribeList object with array of describe jobs.
@@ -204,6 +211,7 @@ def list(
204211
response_format=response_format,
205212
url=url,
206213
include_data=include_data,
214+
include_metadata=include_metadata,
207215
)
208216
return response
209217
except ApiException as e:

cloudglue/client/resources/files.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,34 @@ def get(self, file_id: str):
423423
except Exception as e:
424424
raise CloudglueError(str(e))
425425

426+
def sync_source_metadata(self, file_id: str):
427+
"""Refresh a connector file's source metadata.
428+
429+
Re-fetches the file's `source_metadata` live from its data connector
430+
(google-drive, dropbox, zoom, gong, recall, grain, or iconik) and
431+
updates the stored value. If the file belongs to any metadata
432+
collections, their search documents are re-indexed with the refreshed
433+
metadata. Works for both metadata-only and fully ingested connector
434+
files. Free — no media is downloaded or processed.
435+
436+
Args:
437+
file_id: The ID of the connector-backed file to refresh.
438+
439+
Returns:
440+
The file object with refreshed `source_metadata`.
441+
442+
Raises:
443+
CloudglueError: If the file has no connector URI, the source does
444+
not support metadata lookup, or the account has no connector
445+
of that type (400), or the file is not found (404).
446+
"""
447+
try:
448+
return self.api.sync_file_source_metadata(file_id=file_id)
449+
except ApiException as e:
450+
raise CloudglueError(str(e), e.status, e.data, e.headers, e.reason)
451+
except Exception as e:
452+
raise CloudglueError(str(e))
453+
426454
def delete(self, file_id: str):
427455
"""Delete a file.
428456

cloudglue/client/resources/search.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from cloudglue.sdk.models.search_request import SearchRequest
99
from cloudglue.sdk.models.search_filter import SearchFilter
10+
from cloudglue.sdk.models.search_filter_criteria import SearchFilterCriteria
1011
from cloudglue.sdk.models.search_filter_metadata_inner import SearchFilterMetadataInner
1112
from cloudglue.sdk.models.search_filter_file_inner import SearchFilterFileInner
1213
from cloudglue.sdk.models.search_filter_video_info_inner import SearchFilterVideoInfoInner
@@ -117,6 +118,7 @@ def create_filter(
117118
metadata_filters: Optional[List[Dict[str, Any]]] = None,
118119
video_info_filters: Optional[List[Dict[str, Any]]] = None,
119120
file_filters: Optional[List[Dict[str, Any]]] = None,
121+
source_metadata_filters: Optional[List[Dict[str, Any]]] = None,
120122
) -> SearchFilter:
121123
"""Create a search filter using simple dictionaries.
122124
@@ -133,7 +135,15 @@ def create_filter(
133135
video_info_filters: List of video info filter dictionaries. Same structure as metadata_filters,
134136
plus optional 'scope' ('file' or 'segment'). Defaults to 'file'.
135137
file_filters: List of file filter dictionaries (same structure, without scope)
136-
138+
source_metadata_filters: List of connector source-metadata filter dictionaries
139+
(same structure, without scope — file scope only). Paths address the
140+
connector-provided `source_metadata` object, e.g. 'topic' (zoom),
141+
'title' (gong/grain/iconik), 'participants.name' (grain),
142+
'parties.email' (gong), 'name' (google-drive/dropbox),
143+
'media_type' (iconik), or 'iconik_metadata.<FieldName>' (iconik
144+
custom metadata-view fields, use ContainsAny for list fields).
145+
Paths through arrays of objects match when ANY element matches.
146+
137147
Returns:
138148
SearchFilter object
139149
@@ -166,11 +176,18 @@ def create_filter(
166176
file_objs = [
167177
SearchFilterFileInner(**f) for f in file_filters
168178
]
169-
179+
180+
source_metadata_objs = None
181+
if source_metadata_filters:
182+
source_metadata_objs = [
183+
SearchFilterCriteria(**f) for f in source_metadata_filters
184+
]
185+
170186
return SearchFilter(
171187
metadata=metadata_objs,
172188
video_info=video_info_objs,
173189
file=file_objs,
190+
source_metadata=source_metadata_objs,
174191
)
175192

176193
def search(

cloudglue/client/resources/segmentations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ def list_describes(
392392
response_format: Optional[str] = None,
393393
limit: Optional[int] = None,
394394
offset: Optional[int] = None,
395+
include_metadata: Optional[bool] = None,
395396
):
396397
"""List describe jobs for a segmentation.
397398
@@ -404,6 +405,8 @@ def list_describes(
404405
response_format: Output format for the describe data ('json' or 'markdown')
405406
limit: Number of items to return (max 100)
406407
offset: Offset from the start of the list
408+
include_metadata: When true, include each file's `metadata` and `source_metadata`
409+
on the `file` object of each job.
407410
408411
Returns:
409412
DescribeList containing describe jobs for the segmentation
@@ -418,6 +421,7 @@ def list_describes(
418421
response_format=response_format,
419422
limit=limit,
420423
offset=offset,
424+
include_metadata=include_metadata,
421425
)
422426
return response
423427
except ApiException as e:

0 commit comments

Comments
 (0)