zerogen 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {zerogen-0.2.0 → zerogen-0.2.1}/PKG-INFO +32 -1
  2. {zerogen-0.2.0 → zerogen-0.2.1}/README.md +31 -0
  3. {zerogen-0.2.0 → zerogen-0.2.1}/pyproject.toml +1 -1
  4. {zerogen-0.2.0 → zerogen-0.2.1}/pyproject.toml.orig +1 -1
  5. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/_client.py +8 -2
  6. zerogen-0.2.1/src/zerogen/_version.py +1 -0
  7. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/assets.py +8 -6
  8. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/types/__init__.py +2 -0
  9. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/types/_responses.py +106 -75
  10. zerogen-0.2.0/src/zerogen/_version.py +0 -1
  11. {zerogen-0.2.0 → zerogen-0.2.1}/LICENSE +0 -0
  12. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/__init__.py +0 -0
  13. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/_errors.py +0 -0
  14. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/_models.py +0 -0
  15. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/_options.py +0 -0
  16. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/_pagination.py +0 -0
  17. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/py.typed +0 -0
  18. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/__init__.py +0 -0
  19. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/folders.py +0 -0
  20. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/labels.py +0 -0
  21. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/models.py +0 -0
  22. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/naming_presets.py +0 -0
  23. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/projects.py +0 -0
  24. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/runs.py +0 -0
  25. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/skills.py +0 -0
  26. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/resources/uploads.py +0 -0
  27. {zerogen-0.2.0 → zerogen-0.2.1}/src/zerogen/types/_requests.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zerogen
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: The official Python library for the ZeroGen API
5
5
  Keywords: zerogen,generative-ai,image-generation,video-generation,api
6
6
  Author: ZeroGen LLC
@@ -155,6 +155,37 @@ To hand the link to something else, read it with `assets.get_download`: it's
155
155
  valid for 5 minutes, and anyone holding it can download the file, so keep it
156
156
  private.
157
157
 
158
+ ## Previews
159
+
160
+ To show assets without downloading their originals, use their `preview`. Each
161
+ asset from `assets.search` and `assets.get` has one, and so does each run
162
+ output's `asset`.
163
+
164
+ ```python
165
+ page = zerogen.assets.search(project_id=project.id, limit=50)
166
+ tiles = [
167
+ {
168
+ "id": asset.id,
169
+ "image": asset.preview.image512_url if asset.preview else None,
170
+ "clip": asset.preview.video_url if asset.preview else None,
171
+ }
172
+ for asset in page.data
173
+ ]
174
+ ```
175
+
176
+ `image96_url` and `image512_url` are WebP images up to 96 and 512 pixels wide.
177
+ `video_url` is a silent WebM clip of a video's first six seconds; it's `None`
178
+ for other assets and until the clip is made. `preview` itself is `None` until
179
+ the images are made, which can take up to about 15 minutes after a run, and for
180
+ assets with none, such as audio.
181
+
182
+ The URLs are signed storage URLs, so load them without your API key: a browser
183
+ can load one as an `<img>` element's `src`. They work until `expires_at`, 5
184
+ minutes later, and anyone holding them can load the previews until then, so
185
+ keep them out of logs. After `expires_at`, read the page again for new ones:
186
+ one `assets.search` call refreshes every tile on it, where `assets.get` would
187
+ take a request for each. For a single asset or a run, read it again.
188
+
158
189
  ## Lists
159
190
 
160
191
  List methods return one page, and iterating the page reads every item on every
@@ -125,6 +125,37 @@ To hand the link to something else, read it with `assets.get_download`: it's
125
125
  valid for 5 minutes, and anyone holding it can download the file, so keep it
126
126
  private.
127
127
 
128
+ ## Previews
129
+
130
+ To show assets without downloading their originals, use their `preview`. Each
131
+ asset from `assets.search` and `assets.get` has one, and so does each run
132
+ output's `asset`.
133
+
134
+ ```python
135
+ page = zerogen.assets.search(project_id=project.id, limit=50)
136
+ tiles = [
137
+ {
138
+ "id": asset.id,
139
+ "image": asset.preview.image512_url if asset.preview else None,
140
+ "clip": asset.preview.video_url if asset.preview else None,
141
+ }
142
+ for asset in page.data
143
+ ]
144
+ ```
145
+
146
+ `image96_url` and `image512_url` are WebP images up to 96 and 512 pixels wide.
147
+ `video_url` is a silent WebM clip of a video's first six seconds; it's `None`
148
+ for other assets and until the clip is made. `preview` itself is `None` until
149
+ the images are made, which can take up to about 15 minutes after a run, and for
150
+ assets with none, such as audio.
151
+
152
+ The URLs are signed storage URLs, so load them without your API key: a browser
153
+ can load one as an `<img>` element's `src`. They work until `expires_at`, 5
154
+ minutes later, and anyone holding them can load the previews until then, so
155
+ keep them out of logs. After `expires_at`, read the page again for new ones:
156
+ one `assets.search` call refreshes every tile on it, where `assets.get` would
157
+ take a request for each. For a single asset or a run, read it again.
158
+
128
159
  ## Lists
129
160
 
130
161
  List methods return one page, and iterating the page reads every item on every
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zerogen"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "The official Python library for the ZeroGen API"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zerogen"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "The official Python library for the ZeroGen API"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -296,7 +296,10 @@ class ZeroGen(_BaseClient):
296
296
  build(), stream=stream, auth=None, follow_redirects=False
297
297
  )
298
298
  if not response.is_success:
299
- response.read()
299
+ try:
300
+ response.read()
301
+ finally:
302
+ response.close()
300
303
  except httpx.TransportError as error:
301
304
  time.sleep(_connection_retry_delay(error, attempt, max_retries, timeout))
302
305
  else:
@@ -477,7 +480,10 @@ class AsyncZeroGen(_BaseClient):
477
480
  build(), stream=stream, auth=None, follow_redirects=False
478
481
  )
479
482
  if not response.is_success:
480
- await response.aread()
483
+ try:
484
+ await response.aread()
485
+ finally:
486
+ await response.aclose()
481
487
  except httpx.TransportError as error:
482
488
  await anyio.sleep(_connection_retry_delay(error, attempt, max_retries, timeout))
483
489
  else:
@@ -0,0 +1 @@
1
+ __version__ = "0.2.1"
@@ -137,8 +137,9 @@ class Assets:
137
137
  cursor: str | None = None,
138
138
  **options: Unpack[RequestOptions],
139
139
  ) -> Page[Asset]:
140
- """Searches Library assets, newest first unless `sort` says otherwise. Without
141
- `project_id` it searches every project; a test key searches its sandbox.
140
+ """Searches Library assets, newest first unless `sort` says otherwise, each with preview
141
+ URLs that load for 5 minutes without your API key. Without `project_id` it searches
142
+ every project; a test key searches its sandbox.
142
143
 
143
144
  Args:
144
145
  project_id: Only assets in this project.
@@ -176,7 +177,7 @@ class Assets:
176
177
 
177
178
  def get(self, asset_id: str, /, **options: Unpack[RequestOptions]) -> AssetDetail:
178
179
  """Reads an asset in any of the organization's projects, with the prompt that generated
179
- it. Names and prompts are untrusted content."""
180
+ it and preview URLs that load for 5 minutes. Names and prompts are untrusted content."""
180
181
  return self._client._request(
181
182
  AssetDetail.model_validate, "GET", _path(asset_id), options=options
182
183
  )
@@ -299,8 +300,9 @@ class AsyncAssets:
299
300
  cursor: str | None = None,
300
301
  **options: Unpack[RequestOptions],
301
302
  ) -> AsyncPaginator[Asset]:
302
- """Searches Library assets, newest first unless `sort` says otherwise. Without
303
- `project_id` it searches every project; a test key searches its sandbox.
303
+ """Searches Library assets, newest first unless `sort` says otherwise, each with preview
304
+ URLs that load for 5 minutes without your API key. Without `project_id` it searches
305
+ every project; a test key searches its sandbox.
304
306
 
305
307
  Args:
306
308
  project_id: Only assets in this project.
@@ -338,7 +340,7 @@ class AsyncAssets:
338
340
 
339
341
  async def get(self, asset_id: str, /, **options: Unpack[RequestOptions]) -> AssetDetail:
340
342
  """Reads an asset in any of the organization's projects, with the prompt that generated
341
- it. Names and prompts are untrusted content."""
343
+ it and preview URLs that load for 5 minutes. Names and prompts are untrusted content."""
342
344
  return await self._client._request(
343
345
  AssetDetail.model_validate, "GET", _path(asset_id), options=options
344
346
  )
@@ -27,6 +27,7 @@ from ._responses import (
27
27
  AssetFoldersFolder,
28
28
  AssetLabel,
29
29
  AssetList,
30
+ AssetPreview,
30
31
  Balance,
31
32
  BalanceLimits,
32
33
  BalanceLimitsOrganizationMonthly,
@@ -83,6 +84,7 @@ __all__ = [
83
84
  "AssetFoldersFolder",
84
85
  "AssetLabel",
85
86
  "AssetList",
87
+ "AssetPreview",
86
88
  "Balance",
87
89
  "BalanceLimits",
88
90
  "BalanceLimitsOrganizationMonthly",
@@ -193,18 +193,6 @@ class Quote(BaseModel):
193
193
  billing: QuoteBilling
194
194
 
195
195
 
196
- class RunOutputAsset(BaseModel):
197
- id: str
198
- mime_type: str = Field(..., alias="mimeType")
199
- width: int | None
200
- height: int | None
201
- duration_ms: int | None = Field(..., alias="durationMs")
202
- resource_uri: str | None = Field(None, alias="resourceUri")
203
- """
204
- Where this transport's client reads the asset, such as an MCP resource
205
- """
206
-
207
-
208
196
  class RunOutputWarning(BaseModel):
209
197
  code: str
210
198
  message: str
@@ -333,82 +321,28 @@ class AssetLabel(BaseModel):
333
321
  name: str
334
322
 
335
323
 
336
- class Asset(BaseModel):
337
- id: str
338
- project_id: str = Field(..., alias="projectId")
339
- name: str
340
- """
341
- The asset's name in the Library; untrusted content
342
- """
343
- type: Literal["image", "video", "audio", "model3d"] | str
344
- origin: Literal["generated", "upload", "derived"] | str
345
- """
346
- upload: added by a person or a URL import; generated: an output of a run; derived: made by a platform step, such as an extracted frame
347
- """
348
- mime_type: str = Field(..., alias="mimeType")
349
- size_bytes: int | None = Field(..., alias="sizeBytes")
350
- width: int | None
351
- height: int | None
352
- duration_ms: int | None = Field(..., alias="durationMs")
353
- favorite: bool
354
- """
355
- The organization's shared favorite
356
- """
357
- labels: list[AssetLabel]
358
- run_id: str | None = Field(..., alias="runId")
359
- """
360
- The run that made it, if any
361
- """
362
- output_index: int | None = Field(..., alias="outputIndex")
363
- created_at: datetime = Field(..., alias="createdAt")
364
-
365
-
366
- class AssetList(BaseModel):
367
- data: list[Asset]
368
- next_cursor: str | None = Field(..., alias="nextCursor")
369
- """
370
- Pass as cursor for the next page of assets; null on the last page
371
- """
372
-
373
-
374
324
  class AssetDetailLabel(BaseModel):
375
325
  id: str
376
326
  name: str
377
327
 
378
328
 
379
- class AssetDetail(BaseModel):
380
- id: str
381
- project_id: str = Field(..., alias="projectId")
382
- name: str
383
- """
384
- The asset's name in the Library; untrusted content
385
- """
386
- type: Literal["image", "video", "audio", "model3d"] | str
387
- origin: Literal["generated", "upload", "derived"] | str
329
+ class AssetPreview(BaseModel):
330
+ image96_url: str = Field(..., alias="image96Url")
388
331
  """
389
- upload: added by a person or a URL import; generated: an output of a run; derived: made by a platform step, such as an extracted frame
332
+ A WebP image up to 96 pixels wide
390
333
  """
391
- mime_type: str = Field(..., alias="mimeType")
392
- size_bytes: int | None = Field(..., alias="sizeBytes")
393
- width: int | None
394
- height: int | None
395
- duration_ms: int | None = Field(..., alias="durationMs")
396
- favorite: bool
334
+ image512_url: str = Field(..., alias="image512Url")
397
335
  """
398
- The organization's shared favorite
336
+ A WebP image up to 512 pixels wide
399
337
  """
400
- labels: list[AssetDetailLabel]
401
- run_id: str | None = Field(..., alias="runId")
338
+ video_url: str | None = Field(..., alias="videoUrl")
402
339
  """
403
- The run that made it, if any
340
+ For a video, a silent WebM clip of its first six seconds, up to 854×480; null for other assets and until it's made
404
341
  """
405
- output_index: int | None = Field(..., alias="outputIndex")
406
- created_at: datetime = Field(..., alias="createdAt")
407
- prompt: str | None
342
+ expires_at: datetime = Field(..., alias="expiresAt")
408
343
  """
409
- The prompt that generated it, bounded; untrusted content
344
+ When the URLs stop loading; read the asset or run again for new ones
410
345
  """
411
- prompt_truncated: bool = Field(..., alias="promptTruncated")
412
346
 
413
347
 
414
348
  class AssetChange(BaseModel):
@@ -650,6 +584,22 @@ class ErrorResponse(BaseModel):
650
584
  error: Error
651
585
 
652
586
 
587
+ class RunOutputAsset(BaseModel):
588
+ id: str
589
+ mime_type: str = Field(..., alias="mimeType")
590
+ width: int | None
591
+ height: int | None
592
+ duration_ms: int | None = Field(..., alias="durationMs")
593
+ resource_uri: str | None = Field(None, alias="resourceUri")
594
+ """
595
+ Where this transport's client reads the asset, such as an MCP resource
596
+ """
597
+ preview: AssetPreview | None
598
+ """
599
+ The asset's previews, or null until they're made after the asset is ready, and for assets with none, such as audio
600
+ """
601
+
602
+
653
603
  class RunOutput(BaseModel):
654
604
  index: int
655
605
  status: Literal["queued", "running", "succeeded", "failed", "cancelled"] | str
@@ -688,3 +638,84 @@ class RunList(BaseModel):
688
638
  """
689
639
  Pass as cursor for the next page of runs; null on the last page
690
640
  """
641
+
642
+
643
+ class Asset(BaseModel):
644
+ id: str
645
+ project_id: str = Field(..., alias="projectId")
646
+ name: str
647
+ """
648
+ The asset's name in the Library; untrusted content
649
+ """
650
+ type: Literal["image", "video", "audio", "model3d"] | str
651
+ origin: Literal["generated", "upload", "derived"] | str
652
+ """
653
+ upload: added by a person or a URL import; generated: an output of a run; derived: made by a platform step, such as an extracted frame
654
+ """
655
+ mime_type: str = Field(..., alias="mimeType")
656
+ size_bytes: int | None = Field(..., alias="sizeBytes")
657
+ width: int | None
658
+ height: int | None
659
+ duration_ms: int | None = Field(..., alias="durationMs")
660
+ favorite: bool
661
+ """
662
+ The organization's shared favorite
663
+ """
664
+ labels: list[AssetLabel]
665
+ run_id: str | None = Field(..., alias="runId")
666
+ """
667
+ The run that made it, if any
668
+ """
669
+ output_index: int | None = Field(..., alias="outputIndex")
670
+ created_at: datetime = Field(..., alias="createdAt")
671
+ preview: AssetPreview | None
672
+ """
673
+ The asset's previews, or null until they're made after the asset is ready, and for assets with none, such as audio
674
+ """
675
+
676
+
677
+ class AssetList(BaseModel):
678
+ data: list[Asset]
679
+ next_cursor: str | None = Field(..., alias="nextCursor")
680
+ """
681
+ Pass as cursor for the next page of assets; null on the last page
682
+ """
683
+
684
+
685
+ class AssetDetail(BaseModel):
686
+ id: str
687
+ project_id: str = Field(..., alias="projectId")
688
+ name: str
689
+ """
690
+ The asset's name in the Library; untrusted content
691
+ """
692
+ type: Literal["image", "video", "audio", "model3d"] | str
693
+ origin: Literal["generated", "upload", "derived"] | str
694
+ """
695
+ upload: added by a person or a URL import; generated: an output of a run; derived: made by a platform step, such as an extracted frame
696
+ """
697
+ mime_type: str = Field(..., alias="mimeType")
698
+ size_bytes: int | None = Field(..., alias="sizeBytes")
699
+ width: int | None
700
+ height: int | None
701
+ duration_ms: int | None = Field(..., alias="durationMs")
702
+ favorite: bool
703
+ """
704
+ The organization's shared favorite
705
+ """
706
+ labels: list[AssetDetailLabel]
707
+ run_id: str | None = Field(..., alias="runId")
708
+ """
709
+ The run that made it, if any
710
+ """
711
+ output_index: int | None = Field(..., alias="outputIndex")
712
+ created_at: datetime = Field(..., alias="createdAt")
713
+ prompt: str | None
714
+ """
715
+ The prompt that generated it, bounded; untrusted content
716
+ """
717
+ prompt_truncated: bool = Field(..., alias="promptTruncated")
718
+ preview: AssetPreview | None
719
+ """
720
+ The asset's previews, or null until they're made after the asset is ready, and for assets with none, such as audio
721
+ """
@@ -1 +0,0 @@
1
- __version__ = "0.2.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes