ai_api_unified 2.5.3__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.
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/PKG-INFO +96 -7
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/README.md +94 -5
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/pyproject.toml +2 -2
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/__init__.py +8 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/__version__.py +1 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_base.py +444 -34
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_exceptions.py +7 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_bedrock_completions.py +150 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_google_gemini_capabilities.py +2 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_google_gemini_completions.py +114 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/ai_openai_completions.py +122 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_google_gemini_embeddings.py +232 -68
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_openai_embeddings.py +46 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/ai_titan_embeddings.py +35 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/observability_runtime.py +118 -1
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_google_gemini_videos.py +14 -7
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/LICENSE +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_bedrock_base.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_completions_exceptions.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_factory.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_google_base.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_openai_base.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_loader.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/ai_provider_registry.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/completions/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/embeddings/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/images/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_bedrock_images.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_google_gemini_images.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/images/ai_openai_images.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/_presidio_redactor.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/base_redactor.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/custom_recognizer_factory.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/middleware_extensibility_poc.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/noop_redactor.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/impl/presidio_log_control.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/middleware.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/middleware_config.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/observability.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/pii_redactor.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/middleware/redaction_exceptions.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/util/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/util/_lazy_pydub.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/util/env_settings.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/util/package_metadata_validation.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/util/utils.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_bedrock_videos.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/ai_openai_videos.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/videos/frame_helpers.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/__init__.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_azure.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_base.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_elevenlabs.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_factory.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_google.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_google_gemini_voices.py +0 -0
- {ai_api_unified-2.5.3 → ai_api_unified-2.7.0}/src/ai_api_unified/voice/ai_voice_openai.py +0 -0
- {ai_api_unified-2.5.3 → 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.
|
|
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 (>=
|
|
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.
|
|
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.
|
|
645
|
-
4.
|
|
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.
|
|
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.
|
|
583
|
-
4.
|
|
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.
|
|
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 (>=
|
|
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",
|