genblaze-google 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,6 @@
1
+ """Google provider adapters for genblaze (Veo video, Imagen image)."""
2
+
3
+ from genblaze_google.imagen import ImagenProvider
4
+ from genblaze_google.provider import VeoProvider
5
+
6
+ __all__ = ["VeoProvider", "ImagenProvider"]
@@ -0,0 +1,19 @@
1
+ """Shared Google API error mapping — used by provider.py, imagen.py."""
2
+
3
+ from genblaze_core.models.enums import ProviderErrorCode
4
+
5
+
6
+ def map_google_error(exc: Exception) -> ProviderErrorCode:
7
+ """Map a Google API exception to a ProviderErrorCode."""
8
+ msg = str(exc).lower()
9
+ if "rate" in msg or "429" in msg or "resource_exhausted" in msg:
10
+ return ProviderErrorCode.RATE_LIMIT
11
+ if "auth" in msg or "401" in msg or "403" in msg or "permission" in msg:
12
+ return ProviderErrorCode.AUTH_FAILURE
13
+ if "invalid" in msg or "400" in msg:
14
+ return ProviderErrorCode.INVALID_INPUT
15
+ if "timeout" in msg or "deadline" in msg:
16
+ return ProviderErrorCode.TIMEOUT
17
+ if "500" in msg or "unavailable" in msg or "internal" in msg:
18
+ return ProviderErrorCode.SERVER_ERROR
19
+ return ProviderErrorCode.UNKNOWN
@@ -0,0 +1,162 @@
1
+ """ImagenProvider — adapter for Google Imagen image generation.
2
+
3
+ Synchronous API: client.models.generate_images() returns images directly.
4
+
5
+ Docs: https://ai.google.dev/gemini-api/docs/image-generation
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import tempfile
12
+ from pathlib import Path
13
+ from typing import Any
14
+ from urllib.parse import quote
15
+
16
+ from genblaze_core.exceptions import ProviderError
17
+ from genblaze_core.models.asset import Asset
18
+ from genblaze_core.models.enums import Modality, ProviderErrorCode
19
+ from genblaze_core.models.step import Step
20
+ from genblaze_core.providers.base import ProviderCapabilities, SyncProvider
21
+ from genblaze_core.runnable.config import RunnableConfig
22
+
23
+ from genblaze_google._errors import map_google_error
24
+
25
+ _VALID_ASPECT_RATIOS = {"1:1", "3:4", "4:3", "9:16", "16:9"}
26
+
27
+ # Per-image pricing by model (USD)
28
+ _IMAGEN_PRICING: dict[str, float] = {
29
+ "imagen-3.0-generate-002": 0.04,
30
+ "imagen-3.0-fast-generate-001": 0.02,
31
+ }
32
+
33
+
34
+ class ImagenProvider(SyncProvider):
35
+ """Provider adapter for Google Imagen image generation.
36
+
37
+ Models: ``imagen-3.0-generate-002`` (latest), ``imagen-3.0-fast-generate-001``.
38
+
39
+ Imagen returns image bytes directly (synchronous, not operation-based).
40
+ Output is saved to files; use ObjectStorageSink for cloud upload.
41
+
42
+ Args:
43
+ api_key: Gemini API key. Falls back to GEMINI_API_KEY env var.
44
+ project: GCP project ID for Vertex AI auth.
45
+ location: GCP region for Vertex AI (default "us-central1").
46
+ output_dir: Directory for output image files (default system temp).
47
+ """
48
+
49
+ name = "google-imagen"
50
+
51
+ def get_capabilities(self) -> ProviderCapabilities:
52
+ """Imagen: image generation from text prompts."""
53
+ return ProviderCapabilities(
54
+ supported_modalities=[Modality.IMAGE],
55
+ supported_inputs=["text"],
56
+ models=["imagen-3.0-generate-002", "imagen-3.0-fast-generate-001"],
57
+ output_formats=["image/png", "image/jpeg"],
58
+ )
59
+
60
+ def __init__(
61
+ self,
62
+ api_key: str | None = None,
63
+ *,
64
+ project: str | None = None,
65
+ location: str = "us-central1",
66
+ output_dir: str | Path | None = None,
67
+ ):
68
+ super().__init__()
69
+ self._api_key = api_key
70
+ self._project = project
71
+ self._location = location
72
+ self._output_dir = Path(output_dir) if output_dir else None
73
+ self._client: Any = None
74
+
75
+ def _get_client(self):
76
+ if self._client is None:
77
+ try:
78
+ from google import genai
79
+ except ImportError as exc:
80
+ raise ProviderError(
81
+ "google-genai package not installed. Run: pip install google-genai"
82
+ ) from exc
83
+ if self._project:
84
+ self._client = genai.Client(
85
+ vertexai=True, project=self._project, location=self._location
86
+ )
87
+ else:
88
+ kwargs: dict = {}
89
+ if self._api_key:
90
+ kwargs["api_key"] = self._api_key
91
+ self._client = genai.Client(**kwargs)
92
+ return self._client
93
+
94
+ def generate(self, step: Step, config: RunnableConfig | None = None) -> Step:
95
+ """Generate image(s) via the Google Imagen API."""
96
+ client = self._get_client()
97
+ try:
98
+ from google.genai import types
99
+
100
+ config_kwargs: dict = {}
101
+
102
+ if "number_of_images" in step.params:
103
+ config_kwargs["number_of_images"] = int(step.params["number_of_images"])
104
+ if "aspect_ratio" in step.params:
105
+ ar = step.params["aspect_ratio"]
106
+ if ar not in _VALID_ASPECT_RATIOS:
107
+ raise ProviderError(
108
+ f"Invalid aspect_ratio={ar!r}. Must be one of {_VALID_ASPECT_RATIOS}",
109
+ error_code=ProviderErrorCode.INVALID_INPUT,
110
+ )
111
+ config_kwargs["aspect_ratio"] = ar
112
+ if "person_generation" in step.params:
113
+ config_kwargs["person_generation"] = step.params["person_generation"]
114
+ if "safety_filter_level" in step.params:
115
+ config_kwargs["safety_filter_level"] = step.params["safety_filter_level"]
116
+ if "output_mime_type" in step.params:
117
+ config_kwargs["output_mime_type"] = step.params["output_mime_type"]
118
+
119
+ gen_config = types.GenerateImagesConfig(**config_kwargs) if config_kwargs else None
120
+
121
+ kwargs: dict = {"model": step.model, "prompt": step.prompt or ""}
122
+ if gen_config is not None:
123
+ kwargs["config"] = gen_config
124
+
125
+ response = client.models.generate_images(**kwargs)
126
+
127
+ # Safety filter can return 0 images without raising an error
128
+ if not response.generated_images:
129
+ raise ProviderError(
130
+ "Imagen returned no images — prompt may have been blocked by safety filters",
131
+ error_code=ProviderErrorCode.INVALID_INPUT,
132
+ )
133
+
134
+ mime_type = step.params.get("output_mime_type", "image/png")
135
+ suffix = ".jpeg" if "jpeg" in mime_type else ".png"
136
+
137
+ for i, img in enumerate(response.generated_images):
138
+ if self._output_dir:
139
+ self._output_dir.mkdir(parents=True, exist_ok=True)
140
+ out_path = self._output_dir / f"{step.step_id}_{i}{suffix}"
141
+ else:
142
+ fd, tmp = tempfile.mkstemp(suffix=suffix)
143
+ os.close(fd)
144
+ out_path = Path(tmp)
145
+
146
+ img.image.save(str(out_path))
147
+ file_url = f"file://{quote(str(out_path.resolve()))}"
148
+ step.assets.append(Asset(url=file_url, media_type=mime_type))
149
+
150
+ # Track cost
151
+ price = _IMAGEN_PRICING.get(step.model)
152
+ if price is not None:
153
+ step.cost_usd = price * len(step.assets)
154
+
155
+ return step
156
+ except ProviderError:
157
+ raise
158
+ except Exception as exc:
159
+ raise ProviderError(
160
+ f"Imagen generation failed: {exc}",
161
+ error_code=map_google_error(exc),
162
+ ) from exc
@@ -0,0 +1,276 @@
1
+ """VeoProvider — adapter for Google Veo video generation.
2
+
3
+ Uses the google-genai SDK with the async operation-based workflow:
4
+ client.models.generate_videos() → poll operation → download video
5
+
6
+ Docs: https://ai.google.dev/gemini-api/docs/video
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+
13
+ from genblaze_core.exceptions import ProviderError
14
+ from genblaze_core.models.asset import Asset, AudioMetadata, Track, VideoMetadata
15
+ from genblaze_core.models.enums import Modality, ProviderErrorCode
16
+ from genblaze_core.models.step import Step
17
+ from genblaze_core.providers.base import BaseProvider, ProviderCapabilities, validate_asset_url
18
+ from genblaze_core.runnable.config import RunnableConfig
19
+
20
+ from genblaze_google._errors import map_google_error
21
+
22
+ # Valid Veo parameter values
23
+ _VALID_ASPECT_RATIOS = {"16:9", "9:16"}
24
+ _VALID_RESOLUTIONS = {"720p", "1080p", "4k"}
25
+ _VALID_DURATIONS = {"4", "6", "8"}
26
+
27
+ # Per-second pricing by model (USD)
28
+ _VEO_PRICING: dict[str, float] = {
29
+ "veo-2.0-generate-001": 0.35,
30
+ "veo-3.0-generate-001": 0.50,
31
+ "veo-3.0-fast-generate-001": 0.25,
32
+ }
33
+
34
+
35
+ class VeoProvider(BaseProvider):
36
+ """Provider adapter for Google Veo video generation.
37
+
38
+ Models: ``veo-2.0-generate-001`` (stable), ``veo-3.0-generate-001`` (GA, audio),
39
+ ``veo-3.0-fast-generate-001`` (GA, fast).
40
+
41
+ Supports both Gemini API (api_key) and Vertex AI (project/location) auth.
42
+
43
+ Args:
44
+ api_key: Gemini API key. Falls back to GEMINI_API_KEY env var.
45
+ project: GCP project ID for Vertex AI auth (mutually exclusive with api_key).
46
+ location: GCP region for Vertex AI (default "us-central1").
47
+ poll_interval: Seconds between operation polls (default 10).
48
+ """
49
+
50
+ name = "google-veo"
51
+
52
+ def get_capabilities(self) -> ProviderCapabilities:
53
+ """Veo: video generation from text prompts with configurable resolution and duration."""
54
+ return ProviderCapabilities(
55
+ supported_modalities=[Modality.VIDEO],
56
+ supported_inputs=["text"],
57
+ max_duration=8.0,
58
+ resolutions=["720p", "1080p", "4k"],
59
+ models=[
60
+ "veo-2.0-generate-001",
61
+ "veo-3.0-generate-001",
62
+ "veo-3.0-fast-generate-001",
63
+ ],
64
+ output_formats=["video/mp4"],
65
+ )
66
+
67
+ def __init__(
68
+ self,
69
+ api_key: str | None = None,
70
+ *,
71
+ project: str | None = None,
72
+ location: str = "us-central1",
73
+ poll_interval: float = 10.0,
74
+ ):
75
+ super().__init__()
76
+ self.poll_interval = poll_interval
77
+ self._api_key = api_key
78
+ self._project = project
79
+ self._location = location
80
+ self._client: Any = None
81
+
82
+ def normalize_params(self, params: dict, modality: Any = None) -> dict:
83
+ """Map standard params to Veo-native names."""
84
+ p = dict(params)
85
+ # duration → duration_seconds (Veo's native key)
86
+ if "duration" in p and "duration_seconds" not in p:
87
+ p["duration_seconds"] = p.pop("duration")
88
+ return p
89
+
90
+ def _get_client(self):
91
+ if self._client is None:
92
+ try:
93
+ from google import genai
94
+ except ImportError as exc:
95
+ raise ProviderError(
96
+ "google-genai package not installed. Run: pip install google-genai"
97
+ ) from exc
98
+
99
+ if self._project:
100
+ # Vertex AI auth
101
+ self._client = genai.Client(
102
+ vertexai=True,
103
+ project=self._project,
104
+ location=self._location,
105
+ )
106
+ else:
107
+ # Gemini API key auth
108
+ kwargs: dict = {}
109
+ if self._api_key:
110
+ kwargs["api_key"] = self._api_key
111
+ self._client = genai.Client(**kwargs)
112
+ return self._client
113
+
114
+ def _build_config(self, step: Step) -> Any:
115
+ """Build a GenerateVideosConfig from step.params."""
116
+ from google.genai import types
117
+
118
+ config_kwargs: dict = {}
119
+
120
+ if "aspect_ratio" in step.params:
121
+ ar = step.params["aspect_ratio"]
122
+ if ar not in _VALID_ASPECT_RATIOS:
123
+ raise ProviderError(
124
+ f"Invalid aspect_ratio={ar!r}. Must be one of {_VALID_ASPECT_RATIOS}",
125
+ error_code=ProviderErrorCode.INVALID_INPUT,
126
+ )
127
+ config_kwargs["aspect_ratio"] = ar
128
+
129
+ if "resolution" in step.params:
130
+ res = step.params["resolution"]
131
+ if res not in _VALID_RESOLUTIONS:
132
+ raise ProviderError(
133
+ f"Invalid resolution={res!r}. Must be one of {_VALID_RESOLUTIONS}",
134
+ error_code=ProviderErrorCode.INVALID_INPUT,
135
+ )
136
+ config_kwargs["resolution"] = res
137
+
138
+ # Duration (normalize_params already mapped duration → duration_seconds)
139
+ raw_dur = step.params.get("duration_seconds")
140
+ if raw_dur is not None:
141
+ dur = str(raw_dur)
142
+ if dur not in _VALID_DURATIONS:
143
+ raise ProviderError(
144
+ f"Invalid duration_seconds={dur!r}. Must be one of {_VALID_DURATIONS}",
145
+ error_code=ProviderErrorCode.INVALID_INPUT,
146
+ )
147
+ config_kwargs["duration_seconds"] = dur
148
+
149
+ if "person_generation" in step.params:
150
+ config_kwargs["person_generation"] = step.params["person_generation"]
151
+
152
+ if "number_of_videos" in step.params:
153
+ config_kwargs["number_of_videos"] = int(step.params["number_of_videos"])
154
+
155
+ if "enhance_prompt" in step.params:
156
+ config_kwargs["enhance_prompt"] = bool(step.params["enhance_prompt"])
157
+
158
+ if step.seed is not None:
159
+ config_kwargs["seed"] = step.seed
160
+
161
+ return types.GenerateVideosConfig(**config_kwargs) if config_kwargs else None
162
+
163
+ def submit(self, step: Step, config: RunnableConfig | None = None) -> Any:
164
+ """Start a video generation operation."""
165
+ client = self._get_client()
166
+ try:
167
+ gen_config = self._build_config(step)
168
+ kwargs: dict = {
169
+ "model": step.model,
170
+ "prompt": step.prompt or "",
171
+ }
172
+ if gen_config is not None:
173
+ kwargs["config"] = gen_config
174
+
175
+ operation = client.models.generate_videos(**kwargs)
176
+ # Return the provider-native operation name for resume() compatibility
177
+ return operation.name
178
+ except ProviderError:
179
+ raise
180
+ except Exception as exc:
181
+ raise ProviderError(
182
+ f"Veo submit failed: {exc}",
183
+ error_code=map_google_error(exc),
184
+ ) from exc
185
+
186
+ def poll(self, prediction_id: Any, config: RunnableConfig | None = None) -> bool:
187
+ """Check if the video generation operation is done."""
188
+ client = self._get_client()
189
+ try:
190
+ operation = client.operations.get(prediction_id)
191
+ if operation.done:
192
+ self._cache_poll_result(prediction_id, operation)
193
+ return True
194
+ return False
195
+ except ProviderError:
196
+ raise
197
+ except Exception as exc:
198
+ raise ProviderError(
199
+ f"Veo poll failed: {exc}",
200
+ error_code=map_google_error(exc),
201
+ ) from exc
202
+
203
+ def fetch_output(self, prediction_id: Any, step: Step) -> Step:
204
+ """Download generated video(s) and attach asset URLs."""
205
+ client = self._get_client()
206
+ try:
207
+ # Use cached poll result if available, otherwise fetch fresh
208
+ operation = self._get_cached_poll_result(prediction_id)
209
+ if operation is None:
210
+ operation = client.operations.get(prediction_id)
211
+
212
+ # Store provider metadata
213
+ step.provider_payload = {
214
+ "google": {
215
+ "operation_name": getattr(operation, "name", None),
216
+ "model": step.model,
217
+ }
218
+ }
219
+
220
+ # Check for errors in the operation result
221
+ if hasattr(operation, "error") and operation.error:
222
+ raise ProviderError(
223
+ str(operation.error),
224
+ error_code=ProviderErrorCode.UNKNOWN,
225
+ )
226
+
227
+ response = operation.response
228
+ if response is None or not hasattr(response, "generated_videos"):
229
+ raise ProviderError("No video generated in response")
230
+
231
+ # Veo 3.0 models generate audio alongside video
232
+ is_veo3 = step.model.startswith("veo-3")
233
+
234
+ for gv in response.generated_videos:
235
+ video = gv.video
236
+ # Download to get the file URI
237
+ client.files.download(file=video)
238
+ # Use the video's URI as the asset URL
239
+ video_uri = getattr(video, "uri", None)
240
+ if video_uri:
241
+ validate_asset_url(video_uri)
242
+ vm_kwargs: dict[str, Any] = {"has_audio": is_veo3}
243
+ if "resolution" in step.params:
244
+ vm_kwargs["resolution"] = step.params["resolution"]
245
+ asset = Asset(url=video_uri, media_type="video/mp4")
246
+ asset.video = VideoMetadata(**vm_kwargs)
247
+ # Multi-track metadata for Veo 3 (video + generated audio)
248
+ if is_veo3:
249
+ asset.tracks = [
250
+ Track(kind="video", codec="h264"),
251
+ Track(kind="audio", codec="aac", label="generated-audio"),
252
+ ]
253
+ asset.audio = AudioMetadata(codec="aac")
254
+ step.assets.append(asset)
255
+ else:
256
+ # Fallback: save locally and use file path
257
+ raise ProviderError(
258
+ "Veo response missing video URI — "
259
+ "use client.files.download() to save locally"
260
+ )
261
+
262
+ # Track cost — accept both native and standard duration key
263
+ price_per_sec = _VEO_PRICING.get(step.model)
264
+ if price_per_sec is not None:
265
+ raw_dur = step.params.get("duration_seconds") or step.params.get("duration")
266
+ duration = int(raw_dur) if raw_dur is not None else 4
267
+ step.cost_usd = price_per_sec * duration * len(step.assets)
268
+
269
+ return step
270
+ except ProviderError:
271
+ raise
272
+ except Exception as exc:
273
+ raise ProviderError(
274
+ f"Veo fetch_output failed: {exc}",
275
+ error_code=map_google_error(exc),
276
+ ) from exc
File without changes
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: genblaze-google
3
+ Version: 0.1.0
4
+ Summary: Google provider adapters for genblaze (Veo video, Imagen image)
5
+ Project-URL: Documentation, https://github.com/backblaze-labs/genblaze
6
+ Project-URL: Repository, https://github.com/backblaze-labs/genblaze
7
+ Project-URL: Issues, https://github.com/backblaze-labs/genblaze/issues
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Typing :: Typed
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: genblaze-core<0.2,>=0.1.0
14
+ Requires-Dist: google-genai>=1.0
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ <!-- last_verified: 2026-04-22 -->
20
+ # genblaze-google
21
+
22
+ **Google provider adapters for [genblaze](https://github.com/backblaze-labs/genblaze) — [Veo](https://deepmind.google/technologies/veo/) text-to-video and [Imagen](https://deepmind.google/technologies/imagen-3/) text-to-image — with SHA-256 provenance manifests on every output.**
23
+
24
+ `genblaze-google` wraps Google's generative media models (Veo 2, Veo 3, Imagen 3) as genblaze providers via the unified `google-genai` SDK. Works with both Gemini API keys and Google Cloud Vertex AI authentication. Compose Veo/Imagen calls into multi-step AI pipelines, persist outputs to [Backblaze B2](https://www.backblaze.com/cloud-storage?utm_source=github&utm_medium=referral&utm_campaign=ai_artifacts&utm_content=genblaze) or any S3-compatible store, and emit a tamper-evident provenance manifest for every run.
25
+
26
+ ## Why genblaze-google
27
+
28
+ - **Veo 3 with synchronized audio** — text-to-video + native audio, wrapped in a provenance manifest.
29
+ - **Imagen 3 high-fidelity images** — photorealistic stills with full parameter tracking.
30
+ - **Two auth modes** — Gemini API (`GEMINI_API_KEY`) for quick start, Vertex AI for enterprise / GCP orgs.
31
+ - **Same SDK, any provider** — swap to Sora, Runway, Luma, Flux without rewriting pipeline logic.
32
+ - **Provenance by default** — SHA-256 hash + canonical manifest on every generation.
33
+ - **Durable storage** — plug `genblaze-s3` in for Backblaze B2 / AWS S3 / Cloudflare R2 / MinIO.
34
+
35
+ ## Providers + models
36
+
37
+ | Provider class | Modality | Models |
38
+ |---|---|---|
39
+ | `VeoProvider` | video | `veo-3.0-generate-001` (with audio), `veo-3.0-fast-generate-001`, `veo-2.0-generate-001` |
40
+ | `ImagenProvider` | image | `imagen-3.0-generate-002`, `imagen-3.0-fast-generate-001` |
41
+
42
+ Each is registered via entry points (`google-veo`, `google-imagen`).
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install genblaze-google
48
+ ```
49
+
50
+ ## Quickstart — Veo 3 text-to-video (with audio)
51
+
52
+ ```bash
53
+ export GEMINI_API_KEY="..." # or use Vertex AI auth
54
+ ```
55
+
56
+ ```python
57
+ from genblaze_core import Modality, Pipeline
58
+ from genblaze_google import VeoProvider
59
+
60
+ run, manifest = (
61
+ Pipeline("veo-demo")
62
+ .step(VeoProvider(), model="veo-3.0-generate-001",
63
+ prompt="A time-lapse of a coral reef coming to life, colorful fish "
64
+ "swimming through vibrant coral, natural ocean lighting",
65
+ modality=Modality.VIDEO,
66
+ aspect_ratio="16:9", duration_seconds="8", resolution="720p",
67
+ enhance_prompt=True)
68
+ .run(timeout=600)
69
+ )
70
+ print(run.steps[0].assets[0].url, manifest.canonical_hash)
71
+ ```
72
+
73
+ Vertex AI auth instead:
74
+
75
+ ```python
76
+ provider = VeoProvider(project="my-gcp-project", location="us-central1")
77
+ ```
78
+
79
+ ## Quickstart — Imagen 3 text-to-image
80
+
81
+ ```python
82
+ from genblaze_google import ImagenProvider
83
+
84
+ run, manifest = (
85
+ Pipeline("imagen-demo")
86
+ .step(ImagenProvider(output_dir="output/images"),
87
+ model="imagen-3.0-generate-002",
88
+ prompt="A photorealistic aerial view of a coral reef teeming with tropical fish",
89
+ modality=Modality.IMAGE, aspect_ratio="16:9")
90
+ .run(timeout=120)
91
+ )
92
+ ```
93
+
94
+ ## Persist to Backblaze B2
95
+
96
+ ```python
97
+ from genblaze_core import KeyStrategy, ObjectStorageSink
98
+ from genblaze_s3 import S3StorageBackend
99
+
100
+ storage = ObjectStorageSink(
101
+ S3StorageBackend.for_backblaze("my-bucket"),
102
+ key_strategy=KeyStrategy.HIERARCHICAL,
103
+ )
104
+ # pass sink=storage to .run(…) to push assets + manifest to B2
105
+ ```
106
+
107
+ [Backblaze B2](https://www.backblaze.com/cloud-storage?utm_source=github&utm_medium=referral&utm_campaign=ai_artifacts&utm_content=genblaze) is the recommended default sink for genblaze — cost-efficient, S3-compatible, with Object Lock for tamper-evident manifests.
108
+
109
+ ## Credentials
110
+
111
+ | Auth mode | Env var / config |
112
+ |---|---|
113
+ | Gemini API (quickest) | `GEMINI_API_KEY` — https://aistudio.google.com/apikey |
114
+ | Vertex AI | `VeoProvider(project=..., location=...)` + `gcloud auth application-default login` |
115
+
116
+ ## Documentation
117
+
118
+ - **Main repo**: https://github.com/backblaze-labs/genblaze
119
+ - **Examples**: [`veo_video_pipeline.py`](https://github.com/backblaze-labs/genblaze/blob/main/examples/veo_video_pipeline.py) · [`imagen_pipeline.py`](https://github.com/backblaze-labs/genblaze/blob/main/examples/imagen_pipeline.py)
120
+
121
+ ## Related packages
122
+
123
+ - [`genblaze-core`](https://pypi.org/project/genblaze-core/) — the pipeline SDK
124
+ - [`genblaze-s3`](https://pypi.org/project/genblaze-s3/) — durable storage on Backblaze B2 and other S3-compatible backends
125
+
126
+ ## License
127
+
128
+ MIT
@@ -0,0 +1,9 @@
1
+ genblaze_google/__init__.py,sha256=O8gr3PLZUZ-12sA2a34nkMTNrr_tT_K81J2otHuCk4g,216
2
+ genblaze_google/_errors.py,sha256=mkaSFA-o_Q82jTue-nRurcoyMQ8sXCe5PbohWR8v5lE,841
3
+ genblaze_google/imagen.py,sha256=KcswCjHrtSCLnp5J1SkrcNenhMIuRNzkO9e8NKong98,6224
4
+ genblaze_google/provider.py,sha256=cYsHF3npwXy6aBGJXiFW5bHP2yTLzFJ2nc2_O5qori0,10747
5
+ genblaze_google/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ genblaze_google-0.1.0.dist-info/METADATA,sha256=eXEnaPNmjxOT_PMs8u7J6RQjUip0VJvK_JrYPxR-MDw,5197
7
+ genblaze_google-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
8
+ genblaze_google-0.1.0.dist-info/entry_points.txt,sha256=9jRx0y51zgPAxz_VJHOnVE2SOcBwDahKDVZMhVk3T-8,109
9
+ genblaze_google-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [genblaze.providers]
2
+ google-imagen = genblaze_google:ImagenProvider
3
+ google-veo = genblaze_google:VeoProvider