ai_api_unified 2.5.4__tar.gz → 2.7.0__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 (61) hide show
  1. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/PKG-INFO +96 -7
  2. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/README.md +94 -5
  3. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/pyproject.toml +2 -2
  4. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/__init__.py +8 -0
  5. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/__version__.py +1 -1
  6. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_base.py +444 -34
  7. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_exceptions.py +7 -0
  8. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_bedrock_completions.py +150 -1
  9. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_google_gemini_capabilities.py +2 -0
  10. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_google_gemini_completions.py +114 -1
  11. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_openai_completions.py +122 -1
  12. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_google_gemini_embeddings.py +232 -68
  13. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_openai_embeddings.py +46 -1
  14. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_titan_embeddings.py +35 -1
  15. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/observability_runtime.py +118 -1
  16. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/LICENSE +0 -0
  17. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_bedrock_base.py +0 -0
  18. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_completions_exceptions.py +0 -0
  19. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_factory.py +0 -0
  20. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_google_base.py +0 -0
  21. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_openai_base.py +0 -0
  22. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_loader.py +0 -0
  23. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_registry.py +0 -0
  24. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/__init__.py +0 -0
  25. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/__init__.py +0 -0
  26. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/images/__init__.py +0 -0
  27. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_bedrock_images.py +0 -0
  28. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_google_gemini_images.py +0 -0
  29. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_openai_images.py +0 -0
  30. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/__init__.py +0 -0
  31. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/__init__.py +0 -0
  32. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/_presidio_redactor.py +0 -0
  33. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/base_redactor.py +0 -0
  34. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/custom_recognizer_factory.py +0 -0
  35. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/middleware_extensibility_poc.py +0 -0
  36. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/noop_redactor.py +0 -0
  37. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/presidio_log_control.py +0 -0
  38. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/middleware.py +0 -0
  39. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/middleware_config.py +0 -0
  40. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/observability.py +0 -0
  41. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/pii_redactor.py +0 -0
  42. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/redaction_exceptions.py +0 -0
  43. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/util/__init__.py +0 -0
  44. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/util/_lazy_pydub.py +0 -0
  45. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/util/env_settings.py +0 -0
  46. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/util/package_metadata_validation.py +0 -0
  47. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/util/utils.py +0 -0
  48. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/__init__.py +0 -0
  49. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_bedrock_videos.py +0 -0
  50. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_google_gemini_videos.py +0 -0
  51. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_openai_videos.py +0 -0
  52. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/frame_helpers.py +0 -0
  53. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/__init__.py +0 -0
  54. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_azure.py +0 -0
  55. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_base.py +0 -0
  56. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_elevenlabs.py +0 -0
  57. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_factory.py +0 -0
  58. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_google.py +0 -0
  59. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_google_gemini_voices.py +0 -0
  60. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_openai.py +0 -0
  61. {ai_api_unified-2.5.4 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/audio_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ai_api_unified
3
- Version: 2.5.4
3
+ Version: 2.7.0
4
4
  Summary: Unified access layer for AI completions (LLM), embedding (semantic), image, video, and voice services
5
5
  License: MIT
6
6
  Keywords: llm,openai,bedrock,gemini,vertex,embeddings,completion,video,voice,api
@@ -33,7 +33,7 @@ Requires-Dist: boto3 (>=1.34.0,<2.0.0) ; extra == "bedrock"
33
33
  Requires-Dist: elevenlabs (>=2.3.0,<3.0.0) ; extra == "elevenlabs"
34
34
  Requires-Dist: google-cloud-speech (>=2.25.0,<3.0.0) ; extra == "google-gemini"
35
35
  Requires-Dist: google-cloud-texttospeech (>=2.29.0) ; extra == "google-gemini"
36
- Requires-Dist: google-genai (>=1.41.0,<2.0.0) ; extra == "google-gemini"
36
+ Requires-Dist: google-genai (>=2.10.0,<3.0.0) ; extra == "google-gemini"
37
37
  Requires-Dist: googleapis-common-protos (>=1.63.0,<2.0.0) ; extra == "google-gemini"
38
38
  Requires-Dist: httpx (>=0.27.0,<1.0.0)
39
39
  Requires-Dist: imageio (>=2.37.0,<3.0.0) ; extra == "video-frames"
@@ -60,7 +60,7 @@ Requires-Dist: usaddress (>=0.5.16,<0.6.0) ; extra == "middleware-pii-redaction-
60
60
  Requires-Dist: usaddress (>=0.5.16,<0.6.0) ; extra == "middleware-pii-redaction-small"
61
61
  Description-Content-Type: text/markdown
62
62
 
63
- # ai-api-unified 2.5.0
63
+ # ai-api-unified 2.7.0
64
64
 
65
65
  `ai-api-unified` is a unified Python library for AI completions, embeddings, image generation, video generation, and voice. Application code targets stable base interfaces and factory entry points while concrete providers are selected at runtime from environment configuration.
66
66
 
@@ -109,7 +109,7 @@ The public entry points are the stable base interfaces and factories:
109
109
  Default model guidance in the checked-in OSS env files:
110
110
 
111
111
  - Google completions: `gemini-2.5-flash`
112
- - Google embeddings: `gemini-embedding-001`
112
+ - Google embeddings: `gemini-embedding-001` (text-only) or `gemini-embedding-2` (multimodal)
113
113
  - Google images: `imagen-4.0-generate-001`
114
114
  - Google videos: `veo-3.1-lite-generate-preview`
115
115
  - Google voice: `gemini-2.5-pro-tts`
@@ -218,6 +218,27 @@ response: str = client.send_prompt("Say hello in one short sentence.")
218
218
  print(response)
219
219
  ```
220
220
 
221
+ ### Streaming Completions
222
+
223
+ Every completions client exposes a `capabilities` descriptor with a
224
+ `supports_streaming` flag set per model. Models without streaming support raise
225
+ `AiProviderCapabilityUnsupportedError` from `send_prompt_streaming`. OpenAI,
226
+ Google Gemini, and Bedrock chat models all stream:
227
+
228
+ ```python
229
+ from ai_api_unified import AIFactory
230
+
231
+ client = AIFactory.get_ai_completions_client()
232
+
233
+ if client.capabilities.supports_streaming:
234
+ for chunk in client.send_prompt_streaming("Tell me a short story."):
235
+ print(chunk, end="", flush=True)
236
+ ```
237
+
238
+ Streaming is unavailable while the PII redaction middleware is enabled
239
+ (`AiProviderConfigurationError`): redaction cannot be guaranteed across chunk
240
+ boundaries, so use `send_prompt` in PII-redacting deployments.
241
+
221
242
  ### Embeddings
222
243
 
223
244
  ```python
@@ -229,6 +250,40 @@ embedding = result.get("embedding")
229
250
  print(len(embedding) if embedding else None)
230
251
  ```
231
252
 
253
+ ### Multimodal Embeddings
254
+
255
+ Every embeddings client exposes a `capabilities` descriptor stating which input
256
+ types the configured model supports. Text-only models raise
257
+ `AiProviderCapabilityUnsupportedError` from `generate_embeddings_multimodal`.
258
+ Google `gemini-embedding-2` embeds interleaved text, images, video, audio, and
259
+ PDFs into one vector space (set `EMBEDDING_MODEL_NAME=gemini-embedding-2`):
260
+
261
+ ```python
262
+ from ai_api_unified import (
263
+ AIEmbeddingsMultimodalParams,
264
+ AIFactory,
265
+ SupportedDataType,
266
+ )
267
+
268
+ client = AIFactory.get_ai_embedding_client() # EMBEDDING_MODEL_NAME=gemini-embedding-2
269
+
270
+ if SupportedDataType.IMAGE in client.capabilities.supported_data_types:
271
+ with open("bicycle.png", "rb") as file_image:
272
+ params = AIEmbeddingsMultimodalParams(
273
+ text="a red bicycle",
274
+ included_types=[SupportedDataType.IMAGE],
275
+ included_data=[file_image.read()],
276
+ included_mime_types=["image/png"],
277
+ )
278
+ result = client.generate_embeddings_multimodal(params)
279
+ print(result["dimensions"])
280
+ ```
281
+
282
+ Media attachments are capped at 20MB per attachment and per request. They also
283
+ require API-key auth (`GOOGLE_AUTH_METHOD=api_key`): the google-genai SDK sends
284
+ only text parts to the Vertex embedding endpoint, so in service-account mode
285
+ the client rejects media attachments up front.
286
+
232
287
  ### Image Generation
233
288
 
234
289
  ```python
@@ -378,7 +433,7 @@ There is no implicit default provider. Set the selector for each capability you
378
433
  | Environment variable | Notes |
379
434
  | --------------------------- | ------------------------------------------------------------------------------------------- |
380
435
  | `COMPLETIONS_MODEL_NAME` | Optional completions model override |
381
- | `EMBEDDING_MODEL_NAME` | Optional embeddings model override |
436
+ | `EMBEDDING_MODEL_NAME` | Optional embeddings model override. `gemini-embedding-2` enables multimodal embeddings. |
382
437
  | `IMAGE_MODEL_NAME` | Optional image model override |
383
438
  | `VIDEO_MODEL_NAME` | Optional video model override |
384
439
  | `VIDEO_OUTPUT_DIR` | Optional local output directory for materialized video artifacts |
@@ -449,6 +504,32 @@ Optional service-account mode:
449
504
 
450
505
  This auth policy applies across Google completions, embeddings, images, videos, and voice.
451
506
 
507
+ ##### Google auth modes per capability
508
+
509
+ The two `GOOGLE_AUTH_METHOD` values select different google-genai clients:
510
+ `api_key` creates the Gemini Developer client
511
+ (`genai.Client(api_key=...)`, generativelanguage endpoint) and
512
+ `service_account` creates the Vertex client
513
+ (`genai.Client(vertexai=True, project=..., location=...)`). Some capabilities
514
+ work in only one client:
515
+
516
+ | Google capability | `api_key` (Developer) | `service_account` (Vertex) | Notes |
517
+ | --- | :---: | :---: | --- |
518
+ | Completions (incl. streaming) | ✅ | ✅ | |
519
+ | Text embeddings | ✅ | ✅ | |
520
+ | Image generation (Imagen) | ✅ | ✅ | |
521
+ | Multimodal (media) embeddings | ✅ | ❌ | the SDK sends only text parts to the Vertex embedding endpoint, so the library raises `NotImplementedError` when media is attached in Vertex mode |
522
+ | Text-to-video with local download | ✅ | ❌ | downloaded via the Files API (`client.files.download`), which the SDK supports only in the Developer client; under Vertex set `download_outputs=False` to receive a remote `gs://` URI instead |
523
+ | `source_video` (video continuation) | ❌ | ✅ | the library raises `NotImplementedError` in `api_key` mode; this path requires Vertex |
524
+ | Voice (Gemini TTS / STT) | ⚠️ | ✅ | the library wires API keys into the Cloud TTS/STT clients, but Google may reject API keys that are not enabled for those APIs; `service_account` is the reliable mode |
525
+
526
+ Pick the mode for what you need: multimodal-media embeddings and
527
+ text-to-video-with-download require `api_key`, and `source_video` requires
528
+ `service_account`. Running both families means switching `GOOGLE_AUTH_METHOD`
529
+ between runs or constructing two clients. For a single call, `get_client(...,
530
+ use_api_key=True)` on the shared Google base forces the Developer client
531
+ without changing the environment.
532
+
452
533
  #### Azure TTS
453
534
 
454
535
  Required:
@@ -480,6 +561,11 @@ from ai_api_unified import (
480
561
  AIBaseImages,
481
562
  AIBaseVideos,
482
563
  AIVoiceBase,
564
+ AIEmbeddingsCapabilitiesBase,
565
+ AIEmbeddingsMultimodalParams,
566
+ AIIncludedMediaParamsBase,
567
+ AiProviderCapabilityUnsupportedError,
568
+ SupportedDataType,
483
569
  )
484
570
  ```
485
571
 
@@ -504,6 +590,7 @@ Typical factory failure modes:
504
590
  - unsupported engine selector: `ValueError`
505
591
  - selected provider extra is not installed: `AiProviderDependencyUnavailableError`
506
592
  - provider load/runtime failure: `AiProviderRuntimeError`
593
+ - input modality unsupported by the configured embedding model: `AiProviderCapabilityUnsupportedError`
507
594
 
508
595
  ## Middleware
509
596
 
@@ -641,8 +728,10 @@ Before publishing:
641
728
 
642
729
  1. Bump the version in `pyproject.toml`.
643
730
  2. Bump the version in `src/ai_api_unified/__version__.py`.
644
- 3. Ensure the working tree is clean.
645
- 4. Ensure your PyPI token is configured for Poetry.
731
+ 3. Bump the version in the `README.md` title heading (line 1).
732
+ 4. Run `poetry run pytest tests/test_version_sync.py` to confirm all three agree.
733
+ 5. Ensure the working tree is clean.
734
+ 6. Ensure your PyPI token is configured for Poetry.
646
735
 
647
736
  Publish with the checked-in script:
648
737
 
@@ -1,4 +1,4 @@
1
- # ai-api-unified 2.5.0
1
+ # ai-api-unified 2.7.0
2
2
 
3
3
  `ai-api-unified` is a unified Python library for AI completions, embeddings, image generation, video generation, and voice. Application code targets stable base interfaces and factory entry points while concrete providers are selected at runtime from environment configuration.
4
4
 
@@ -47,7 +47,7 @@ The public entry points are the stable base interfaces and factories:
47
47
  Default model guidance in the checked-in OSS env files:
48
48
 
49
49
  - Google completions: `gemini-2.5-flash`
50
- - Google embeddings: `gemini-embedding-001`
50
+ - Google embeddings: `gemini-embedding-001` (text-only) or `gemini-embedding-2` (multimodal)
51
51
  - Google images: `imagen-4.0-generate-001`
52
52
  - Google videos: `veo-3.1-lite-generate-preview`
53
53
  - Google voice: `gemini-2.5-pro-tts`
@@ -156,6 +156,27 @@ response: str = client.send_prompt("Say hello in one short sentence.")
156
156
  print(response)
157
157
  ```
158
158
 
159
+ ### Streaming Completions
160
+
161
+ Every completions client exposes a `capabilities` descriptor with a
162
+ `supports_streaming` flag set per model. Models without streaming support raise
163
+ `AiProviderCapabilityUnsupportedError` from `send_prompt_streaming`. OpenAI,
164
+ Google Gemini, and Bedrock chat models all stream:
165
+
166
+ ```python
167
+ from ai_api_unified import AIFactory
168
+
169
+ client = AIFactory.get_ai_completions_client()
170
+
171
+ if client.capabilities.supports_streaming:
172
+ for chunk in client.send_prompt_streaming("Tell me a short story."):
173
+ print(chunk, end="", flush=True)
174
+ ```
175
+
176
+ Streaming is unavailable while the PII redaction middleware is enabled
177
+ (`AiProviderConfigurationError`): redaction cannot be guaranteed across chunk
178
+ boundaries, so use `send_prompt` in PII-redacting deployments.
179
+
159
180
  ### Embeddings
160
181
 
161
182
  ```python
@@ -167,6 +188,40 @@ embedding = result.get("embedding")
167
188
  print(len(embedding) if embedding else None)
168
189
  ```
169
190
 
191
+ ### Multimodal Embeddings
192
+
193
+ Every embeddings client exposes a `capabilities` descriptor stating which input
194
+ types the configured model supports. Text-only models raise
195
+ `AiProviderCapabilityUnsupportedError` from `generate_embeddings_multimodal`.
196
+ Google `gemini-embedding-2` embeds interleaved text, images, video, audio, and
197
+ PDFs into one vector space (set `EMBEDDING_MODEL_NAME=gemini-embedding-2`):
198
+
199
+ ```python
200
+ from ai_api_unified import (
201
+ AIEmbeddingsMultimodalParams,
202
+ AIFactory,
203
+ SupportedDataType,
204
+ )
205
+
206
+ client = AIFactory.get_ai_embedding_client() # EMBEDDING_MODEL_NAME=gemini-embedding-2
207
+
208
+ if SupportedDataType.IMAGE in client.capabilities.supported_data_types:
209
+ with open("bicycle.png", "rb") as file_image:
210
+ params = AIEmbeddingsMultimodalParams(
211
+ text="a red bicycle",
212
+ included_types=[SupportedDataType.IMAGE],
213
+ included_data=[file_image.read()],
214
+ included_mime_types=["image/png"],
215
+ )
216
+ result = client.generate_embeddings_multimodal(params)
217
+ print(result["dimensions"])
218
+ ```
219
+
220
+ Media attachments are capped at 20MB per attachment and per request. They also
221
+ require API-key auth (`GOOGLE_AUTH_METHOD=api_key`): the google-genai SDK sends
222
+ only text parts to the Vertex embedding endpoint, so in service-account mode
223
+ the client rejects media attachments up front.
224
+
170
225
  ### Image Generation
171
226
 
172
227
  ```python
@@ -316,7 +371,7 @@ There is no implicit default provider. Set the selector for each capability you
316
371
  | Environment variable | Notes |
317
372
  | --------------------------- | ------------------------------------------------------------------------------------------- |
318
373
  | `COMPLETIONS_MODEL_NAME` | Optional completions model override |
319
- | `EMBEDDING_MODEL_NAME` | Optional embeddings model override |
374
+ | `EMBEDDING_MODEL_NAME` | Optional embeddings model override. `gemini-embedding-2` enables multimodal embeddings. |
320
375
  | `IMAGE_MODEL_NAME` | Optional image model override |
321
376
  | `VIDEO_MODEL_NAME` | Optional video model override |
322
377
  | `VIDEO_OUTPUT_DIR` | Optional local output directory for materialized video artifacts |
@@ -387,6 +442,32 @@ Optional service-account mode:
387
442
 
388
443
  This auth policy applies across Google completions, embeddings, images, videos, and voice.
389
444
 
445
+ ##### Google auth modes per capability
446
+
447
+ The two `GOOGLE_AUTH_METHOD` values select different google-genai clients:
448
+ `api_key` creates the Gemini Developer client
449
+ (`genai.Client(api_key=...)`, generativelanguage endpoint) and
450
+ `service_account` creates the Vertex client
451
+ (`genai.Client(vertexai=True, project=..., location=...)`). Some capabilities
452
+ work in only one client:
453
+
454
+ | Google capability | `api_key` (Developer) | `service_account` (Vertex) | Notes |
455
+ | --- | :---: | :---: | --- |
456
+ | Completions (incl. streaming) | ✅ | ✅ | |
457
+ | Text embeddings | ✅ | ✅ | |
458
+ | Image generation (Imagen) | ✅ | ✅ | |
459
+ | Multimodal (media) embeddings | ✅ | ❌ | the SDK sends only text parts to the Vertex embedding endpoint, so the library raises `NotImplementedError` when media is attached in Vertex mode |
460
+ | Text-to-video with local download | ✅ | ❌ | downloaded via the Files API (`client.files.download`), which the SDK supports only in the Developer client; under Vertex set `download_outputs=False` to receive a remote `gs://` URI instead |
461
+ | `source_video` (video continuation) | ❌ | ✅ | the library raises `NotImplementedError` in `api_key` mode; this path requires Vertex |
462
+ | Voice (Gemini TTS / STT) | ⚠️ | ✅ | the library wires API keys into the Cloud TTS/STT clients, but Google may reject API keys that are not enabled for those APIs; `service_account` is the reliable mode |
463
+
464
+ Pick the mode for what you need: multimodal-media embeddings and
465
+ text-to-video-with-download require `api_key`, and `source_video` requires
466
+ `service_account`. Running both families means switching `GOOGLE_AUTH_METHOD`
467
+ between runs or constructing two clients. For a single call, `get_client(...,
468
+ use_api_key=True)` on the shared Google base forces the Developer client
469
+ without changing the environment.
470
+
390
471
  #### Azure TTS
391
472
 
392
473
  Required:
@@ -418,6 +499,11 @@ from ai_api_unified import (
418
499
  AIBaseImages,
419
500
  AIBaseVideos,
420
501
  AIVoiceBase,
502
+ AIEmbeddingsCapabilitiesBase,
503
+ AIEmbeddingsMultimodalParams,
504
+ AIIncludedMediaParamsBase,
505
+ AiProviderCapabilityUnsupportedError,
506
+ SupportedDataType,
421
507
  )
422
508
  ```
423
509
 
@@ -442,6 +528,7 @@ Typical factory failure modes:
442
528
  - unsupported engine selector: `ValueError`
443
529
  - selected provider extra is not installed: `AiProviderDependencyUnavailableError`
444
530
  - provider load/runtime failure: `AiProviderRuntimeError`
531
+ - input modality unsupported by the configured embedding model: `AiProviderCapabilityUnsupportedError`
445
532
 
446
533
  ## Middleware
447
534
 
@@ -579,8 +666,10 @@ Before publishing:
579
666
 
580
667
  1. Bump the version in `pyproject.toml`.
581
668
  2. Bump the version in `src/ai_api_unified/__version__.py`.
582
- 3. Ensure the working tree is clean.
583
- 4. Ensure your PyPI token is configured for Poetry.
669
+ 3. Bump the version in the `README.md` title heading (line 1).
670
+ 4. Run `poetry run pytest tests/test_version_sync.py` to confirm all three agree.
671
+ 5. Ensure the working tree is clean.
672
+ 6. Ensure your PyPI token is configured for Poetry.
584
673
 
585
674
  Publish with the checked-in script:
586
675
 
@@ -36,7 +36,7 @@
36
36
  [project]
37
37
  name = "ai_api_unified"
38
38
 
39
- version = "2.5.4" # keep in sync with src/ai_api_unified/__version__.py
39
+ version = "2.7.0" # keep in sync with src/ai_api_unified/__version__.py and the README.md title
40
40
  description = "Unified access layer for AI completions (LLM), embedding (semantic), image, video, and voice services"
41
41
  authors = [{ name = "Dave Thomas", email = "davidcthomas@gmail.com" }]
42
42
  license = "MIT"
@@ -87,7 +87,7 @@ google_gemini = [
87
87
  "google-cloud-speech>=2.25.0,<3.0.0",
88
88
  "protobuf>=3.20.2,<5.0.0dev",
89
89
  "googleapis-common-protos>=1.63.0,<2.0.0",
90
- "google-genai (>=1.41.0,<2.0.0)",
90
+ "google-genai (>=2.10.0,<3.0.0)",
91
91
  "google-cloud-texttospeech (>=2.29.0)",
92
92
  ]
93
93
  middleware-pii-redaction = [
@@ -27,6 +27,9 @@ from .ai_base import (
27
27
  AIBaseVideos,
28
28
  AICompletionsCapabilitiesBase,
29
29
  AICompletionsPromptParamsBase,
30
+ AIEmbeddingsCapabilitiesBase,
31
+ AIEmbeddingsMultimodalParams,
32
+ AIIncludedMediaParamsBase,
30
33
  AIMediaReference,
31
34
  AIVideoArtifact,
32
35
  AIVideoGenerationJob,
@@ -36,6 +39,7 @@ from .ai_base import (
36
39
  SupportedDataType,
37
40
  )
38
41
  from .ai_completions_exceptions import StructuredResponseTokenLimitError
42
+ from .ai_provider_exceptions import AiProviderCapabilityUnsupportedError
39
43
  from .ai_factory import AIFactory
40
44
  from .voice.ai_voice_base import AIVoiceBase, AIVoiceCapabilities, AIVoiceSelectionBase
41
45
  from .voice.ai_voice_factory import AIVoiceFactory
@@ -59,6 +63,10 @@ __all__: list[str] = [
59
63
  "AIStructuredPrompt",
60
64
  "AICompletionsCapabilitiesBase",
61
65
  "AICompletionsPromptParamsBase",
66
+ "AIEmbeddingsCapabilitiesBase",
67
+ "AIEmbeddingsMultimodalParams",
68
+ "AIIncludedMediaParamsBase",
69
+ "AiProviderCapabilityUnsupportedError",
62
70
  "StructuredResponseTokenLimitError",
63
71
  "SupportedDataType",
64
72
  "AIVoiceSelectionBase",
@@ -9,4 +9,4 @@ from __future__ import annotations
9
9
 
10
10
  __all__: list[str] = ["__version__"]
11
11
 
12
- __version__: str = "2.5.4"
12
+ __version__: str = "2.7.0"