ai_api_unified 1.3.0__tar.gz → 2.5.2__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 (83) hide show
  1. ai_api_unified-2.5.2/PKG-INFO +681 -0
  2. ai_api_unified-2.5.2/README.md +618 -0
  3. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/pyproject.toml +48 -16
  4. ai_api_unified-2.5.2/src/ai_api_unified/__init__.py +69 -0
  5. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/__version__.py +1 -1
  6. ai_api_unified-2.5.2/src/ai_api_unified/ai_base.py +1840 -0
  7. ai_api_unified-2.5.2/src/ai_api_unified/ai_bedrock_base.py +248 -0
  8. ai_api_unified-2.5.2/src/ai_api_unified/ai_completions_exceptions.py +51 -0
  9. ai_api_unified-2.5.2/src/ai_api_unified/ai_factory.py +507 -0
  10. ai_api_unified-2.5.2/src/ai_api_unified/ai_google_base.py +465 -0
  11. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/ai_openai_base.py +1 -0
  12. ai_api_unified-2.5.2/src/ai_api_unified/ai_provider_exceptions.py +34 -0
  13. ai_api_unified-2.5.2/src/ai_api_unified/ai_provider_loader.py +218 -0
  14. ai_api_unified-2.5.2/src/ai_api_unified/ai_provider_registry.py +483 -0
  15. ai_api_unified-2.5.2/src/ai_api_unified/completions/__init__.py +11 -0
  16. ai_api_unified-2.5.2/src/ai_api_unified/completions/ai_bedrock_completions.py +514 -0
  17. ai_api_unified-2.5.2/src/ai_api_unified/completions/ai_google_gemini_completions.py +681 -0
  18. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/completions/ai_openai_completions.py +291 -58
  19. ai_api_unified-2.5.2/src/ai_api_unified/embeddings/__init__.py +11 -0
  20. ai_api_unified-2.5.2/src/ai_api_unified/embeddings/ai_google_gemini_embeddings.py +431 -0
  21. ai_api_unified-2.5.2/src/ai_api_unified/embeddings/ai_openai_embeddings.py +391 -0
  22. ai_api_unified-2.5.2/src/ai_api_unified/embeddings/ai_titan_embeddings.py +341 -0
  23. ai_api_unified-2.5.2/src/ai_api_unified/images/__init__.py +11 -0
  24. ai_api_unified-2.5.2/src/ai_api_unified/images/ai_bedrock_images.py +344 -0
  25. ai_api_unified-2.5.2/src/ai_api_unified/images/ai_google_gemini_images.py +237 -0
  26. ai_api_unified-2.5.2/src/ai_api_unified/images/ai_openai_images.py +329 -0
  27. ai_api_unified-2.5.2/src/ai_api_unified/middleware/__init__.py +61 -0
  28. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/__init__.py +0 -0
  29. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/_presidio_redactor.py +1831 -0
  30. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/base_redactor.py +92 -0
  31. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/custom_recognizer_factory.py +607 -0
  32. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/middleware_extensibility_poc.py +372 -0
  33. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/noop_redactor.py +89 -0
  34. ai_api_unified-2.5.2/src/ai_api_unified/middleware/impl/presidio_log_control.py +131 -0
  35. ai_api_unified-2.5.2/src/ai_api_unified/middleware/middleware.py +270 -0
  36. ai_api_unified-2.5.2/src/ai_api_unified/middleware/middleware_config.py +1469 -0
  37. ai_api_unified-2.5.2/src/ai_api_unified/middleware/observability.py +804 -0
  38. ai_api_unified-2.5.2/src/ai_api_unified/middleware/observability_runtime.py +416 -0
  39. ai_api_unified-2.5.2/src/ai_api_unified/middleware/pii_redactor.py +213 -0
  40. ai_api_unified-2.5.2/src/ai_api_unified/middleware/redaction_exceptions.py +25 -0
  41. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/util/_lazy_pydub.py +10 -5
  42. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/util/env_settings.py +28 -8
  43. ai_api_unified-2.5.2/src/ai_api_unified/util/package_metadata_validation.py +233 -0
  44. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/util/utils.py +5 -5
  45. ai_api_unified-2.5.2/src/ai_api_unified/videos/__init__.py +5 -0
  46. ai_api_unified-2.5.2/src/ai_api_unified/videos/ai_bedrock_videos.py +536 -0
  47. ai_api_unified-2.5.2/src/ai_api_unified/videos/ai_google_gemini_videos.py +631 -0
  48. ai_api_unified-2.5.2/src/ai_api_unified/videos/ai_openai_videos.py +582 -0
  49. ai_api_unified-2.5.2/src/ai_api_unified/videos/frame_helpers.py +129 -0
  50. ai_api_unified-2.5.2/src/ai_api_unified/voice/__init__.py +23 -0
  51. ai_api_unified-2.5.2/src/ai_api_unified/voice/ai_voice_azure.py +443 -0
  52. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/voice/ai_voice_base.py +359 -20
  53. ai_api_unified-2.5.2/src/ai_api_unified/voice/ai_voice_elevenlabs.py +507 -0
  54. ai_api_unified-2.5.2/src/ai_api_unified/voice/ai_voice_factory.py +82 -0
  55. ai_api_unified-2.5.2/src/ai_api_unified/voice/ai_voice_google.py +845 -0
  56. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/voice/ai_voice_openai.py +135 -28
  57. ai_api_unified-1.3.0/PKG-INFO +0 -770
  58. ai_api_unified-1.3.0/README.md +0 -727
  59. ai_api_unified-1.3.0/src/ai_api_unified/__init__.py +0 -148
  60. ai_api_unified-1.3.0/src/ai_api_unified/ai_base.py +0 -522
  61. ai_api_unified-1.3.0/src/ai_api_unified/ai_bedrock_base.py +0 -265
  62. ai_api_unified-1.3.0/src/ai_api_unified/ai_factory.py +0 -249
  63. ai_api_unified-1.3.0/src/ai_api_unified/ai_google_base.py +0 -436
  64. ai_api_unified-1.3.0/src/ai_api_unified/completions/__init__.py +0 -29
  65. ai_api_unified-1.3.0/src/ai_api_unified/completions/ai_bedrock_completions.py +0 -318
  66. ai_api_unified-1.3.0/src/ai_api_unified/completions/ai_google_gemini_completions.py +0 -453
  67. ai_api_unified-1.3.0/src/ai_api_unified/embeddings/__init__.py +0 -29
  68. ai_api_unified-1.3.0/src/ai_api_unified/embeddings/ai_google_gemini_embeddings.py +0 -228
  69. ai_api_unified-1.3.0/src/ai_api_unified/embeddings/ai_openai_embeddings.py +0 -219
  70. ai_api_unified-1.3.0/src/ai_api_unified/embeddings/ai_titan_embeddings.py +0 -192
  71. ai_api_unified-1.3.0/src/ai_api_unified/images/__init__.py +0 -21
  72. ai_api_unified-1.3.0/src/ai_api_unified/images/ai_bedrock_images.py +0 -312
  73. ai_api_unified-1.3.0/src/ai_api_unified/images/ai_openai_images.py +0 -212
  74. ai_api_unified-1.3.0/src/ai_api_unified/voice/__init__.py +0 -56
  75. ai_api_unified-1.3.0/src/ai_api_unified/voice/ai_voice_azure.py +0 -351
  76. ai_api_unified-1.3.0/src/ai_api_unified/voice/ai_voice_elevenlabs.py +0 -418
  77. ai_api_unified-1.3.0/src/ai_api_unified/voice/ai_voice_factory.py +0 -83
  78. ai_api_unified-1.3.0/src/ai_api_unified/voice/ai_voice_google.py +0 -720
  79. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/LICENSE +0 -0
  80. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/completions/ai_google_gemini_capabilities.py +0 -0
  81. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/util/__init__.py +0 -0
  82. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/voice/ai_voice_google_gemini_voices.py +0 -0
  83. {ai_api_unified-1.3.0 → ai_api_unified-2.5.2}/src/ai_api_unified/voice/audio_models.py +0 -0
@@ -0,0 +1,681 @@
1
+ Metadata-Version: 2.3
2
+ Name: ai_api_unified
3
+ Version: 2.5.2
4
+ Summary: Unified access layer for AI completions (LLM), embedding (semantic), image, video, and voice services
5
+ License: MIT
6
+ Keywords: llm,openai,bedrock,gemini,vertex,embeddings,completion,video,voice,api
7
+ Author: Dave Thomas
8
+ Author-email: davidcthomas@gmail.com
9
+ Requires-Python: >=3.11,<3.14
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Provides-Extra: azure-tts
17
+ Provides-Extra: bedrock
18
+ Provides-Extra: dev
19
+ Provides-Extra: elevenlabs
20
+ Provides-Extra: google-gemini
21
+ Provides-Extra: middleware-pii-redaction
22
+ Provides-Extra: middleware-pii-redaction-large
23
+ Provides-Extra: middleware-pii-redaction-small
24
+ Provides-Extra: openai
25
+ Provides-Extra: similarity-score
26
+ Provides-Extra: video-frames
27
+ Requires-Dist: Pillow (>=11.0.0,<12.0.0) ; extra == "video-frames"
28
+ Requires-Dist: PyYAML (>=6.0.1,<7.0.0)
29
+ Requires-Dist: audioop-lts (>=0.2.0) ; python_version >= "3.13"
30
+ Requires-Dist: azure-cognitiveservices-speech (>=1.37.0,<2.0.0) ; extra == "azure-tts"
31
+ Requires-Dist: black (>=24.4.2,<25.0.0) ; extra == "dev"
32
+ Requires-Dist: boto3 (>=1.34.0,<2.0.0) ; extra == "bedrock"
33
+ Requires-Dist: elevenlabs (>=2.3.0,<3.0.0) ; extra == "elevenlabs"
34
+ Requires-Dist: google-cloud-speech (>=2.25.0,<3.0.0) ; extra == "google-gemini"
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"
37
+ Requires-Dist: googleapis-common-protos (>=1.63.0,<2.0.0) ; extra == "google-gemini"
38
+ Requires-Dist: httpx (>=0.27.0,<1.0.0)
39
+ Requires-Dist: imageio (>=2.37.0,<3.0.0) ; extra == "video-frames"
40
+ Requires-Dist: imageio-ffmpeg (>=0.6.0,<1.0.0) ; extra == "video-frames"
41
+ Requires-Dist: numpy (==2.2.6) ; extra == "similarity-score"
42
+ Requires-Dist: openai (>=1.25.0,<2.0.0) ; extra == "openai"
43
+ Requires-Dist: presidio-analyzer (>=2.2.35) ; extra == "middleware-pii-redaction"
44
+ Requires-Dist: presidio-analyzer (>=2.2.35) ; extra == "middleware-pii-redaction-large"
45
+ Requires-Dist: presidio-analyzer (>=2.2.35) ; extra == "middleware-pii-redaction-small"
46
+ Requires-Dist: presidio-anonymizer (>=2.2.35) ; extra == "middleware-pii-redaction"
47
+ Requires-Dist: presidio-anonymizer (>=2.2.35) ; extra == "middleware-pii-redaction-large"
48
+ Requires-Dist: presidio-anonymizer (>=2.2.35) ; extra == "middleware-pii-redaction-small"
49
+ Requires-Dist: protobuf (>=3.20.2,<5.0.0dev) ; extra == "google-gemini"
50
+ Requires-Dist: pydantic (>=2,<3)
51
+ Requires-Dist: pydantic-settings (>=2,<3)
52
+ Requires-Dist: pydub (>=0.25.1,<0.26.0)
53
+ Requires-Dist: pytest (>=8.4.0,<9.0.0) ; extra == "dev"
54
+ Requires-Dist: ruff (>=0.4.4,<1.0.0) ; extra == "dev"
55
+ Requires-Dist: spacy (>=3.4.4,!=3.7.0,<4.0.0) ; extra == "middleware-pii-redaction"
56
+ Requires-Dist: spacy (>=3.4.4,!=3.7.0,<4.0.0) ; extra == "middleware-pii-redaction-large"
57
+ Requires-Dist: spacy (>=3.4.4,!=3.7.0,<4.0.0) ; extra == "middleware-pii-redaction-small"
58
+ Requires-Dist: usaddress (>=0.5.16,<0.6.0) ; extra == "middleware-pii-redaction"
59
+ Requires-Dist: usaddress (>=0.5.16,<0.6.0) ; extra == "middleware-pii-redaction-large"
60
+ Requires-Dist: usaddress (>=0.5.16,<0.6.0) ; extra == "middleware-pii-redaction-small"
61
+ Description-Content-Type: text/markdown
62
+
63
+ # ai-api-unified 2.5.0
64
+
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
+
67
+ Author: Dave Thomas
68
+ Install name: `ai-api-unified`
69
+ Import path: `ai_api_unified`
70
+ Python: `>=3.11,<3.14`
71
+ License: MIT
72
+
73
+ The current package architecture is registry-backed and lazy-loaded:
74
+
75
+ - provider SDKs are optional extras, not base dependencies
76
+ - providers are resolved only when a factory selects them
77
+ - package `__init__` modules export stable interfaces only
78
+ - missing provider selectors are configuration errors, not implicit fallbacks
79
+
80
+ ## Overview
81
+
82
+ Use this library when you want one consistent interface across multiple AI providers without binding application code to a single SDK. The library currently covers:
83
+
84
+ - text completions
85
+ - embeddings
86
+ - image generation
87
+ - video generation
88
+ - text-to-speech and selected speech-to-text flows
89
+
90
+ The public entry points are the stable base interfaces and factories:
91
+
92
+ - `AIFactory.get_ai_completions_client()`
93
+ - `AIFactory.get_ai_embedding_client()`
94
+ - `AIFactory.get_ai_images_client()`
95
+ - `AIFactory.get_ai_video_client()`
96
+ - `AIVoiceFactory.create()`
97
+
98
+ ## Capabilities
99
+
100
+ | Capability | Stable interface | Engines | Required extra(s) |
101
+ | ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
102
+ | Completions | `AIBaseCompletions` | `openai`, `google-gemini`, Bedrock-routed aliases such as `nova`, `anthropic`, `llama`, `mistral`, `cohere`, `ai21`, `rerank` | `openai`, `google_gemini`, `bedrock` |
103
+ | Embeddings | `AIBaseEmbeddings` | `openai`, `titan`, `google-gemini` | `openai`, `bedrock`, `google_gemini` |
104
+ | Images | `AIBaseImages` | `openai`, `google-gemini`, `nova-canvas` and Bedrock image aliases | `openai`, `google_gemini`, `bedrock` |
105
+ | Videos | `AIBaseVideos` | `openai`, `google-gemini`, `nova-reel` and Bedrock video aliases | `openai`, `google_gemini`, `bedrock` |
106
+ | Voice TTS | `AIVoiceBase` | `openai`, `google`, `azure`, `elevenlabs` | `openai`, `google_gemini`, `azure_tts`, `elevenlabs` |
107
+ | Voice STT | `AIVoiceBase` | provider-specific support such as Google and ElevenLabs | `google_gemini`, `elevenlabs` |
108
+
109
+ Default model guidance in the checked-in OSS env files:
110
+
111
+ - Google completions: `gemini-2.5-flash`
112
+ - Google embeddings: `gemini-embedding-001`
113
+ - Google images: `imagen-4.0-generate-001`
114
+ - Google videos: `veo-3.1-lite-generate-preview`
115
+ - Google voice: `gemini-2.5-pro-tts`
116
+
117
+ ## Installation
118
+
119
+ ### Python Requirements
120
+
121
+ This package requires Python `>=3.11,<3.14`.
122
+
123
+ ### Install as a Dependency
124
+
125
+ Base package only:
126
+
127
+ ```bash
128
+ poetry add ai-api-unified
129
+ ```
130
+
131
+ Install with one or more provider extras:
132
+
133
+ ```bash
134
+ poetry add 'ai-api-unified[google_gemini]'
135
+ poetry add 'ai-api-unified[openai]'
136
+ poetry add 'ai-api-unified[bedrock,google_gemini]'
137
+ poetry add 'ai-api-unified[google_gemini,video_frames]'
138
+ poetry add 'ai-api-unified[openai,video_frames]'
139
+ ```
140
+
141
+ ### Install in a Local Clone
142
+
143
+ Base install:
144
+
145
+ ```bash
146
+ poetry install
147
+ ```
148
+
149
+ Common local development installs:
150
+
151
+ ```bash
152
+ poetry install --with dev
153
+ poetry install --extras "google_gemini"
154
+ poetry install --extras "openai"
155
+ poetry install --extras "google_gemini" --extras "video_frames" --with dev
156
+ poetry install --extras "openai" --extras "video_frames" --with dev
157
+ poetry install --all-extras --with dev
158
+ ```
159
+
160
+ ### Optional Extras
161
+
162
+ | Extra | Installs |
163
+ | -------------------------------- | ---------------------------------------------------------------------- |
164
+ | `openai` | OpenAI completions, embeddings, images, and voice |
165
+ | `google_gemini` | Google Gemini completions, embeddings, images, and Google voice |
166
+ | `bedrock` | AWS Bedrock completions, Titan embeddings, Bedrock image providers, and Bedrock video providers |
167
+ | `video_frames` | Optional frame extraction helpers backed by ImageIO + Pillow |
168
+ | `azure_tts` | Azure Cognitive Services TTS |
169
+ | `elevenlabs` | ElevenLabs TTS and STT |
170
+ | `middleware-pii-redaction` | Presidio + spaCy + `usaddress`; install the required spaCy model separately |
171
+ | `middleware-pii-redaction-small` | Compatibility alias for PII redaction deps; pair with separate `en_core_web_sm` install |
172
+ | `middleware-pii-redaction-large` | Compatibility alias for PII redaction deps; pair with separate `en_core_web_lg` install |
173
+ | `similarity_score` | NumPy-based similarity helpers |
174
+ | `dev` | Optional dev dependencies from `[project.optional-dependencies]` |
175
+
176
+ ### Environment File
177
+
178
+ Copy [`env_template`](env_template) to `.env` and fill in only the providers you use.
179
+
180
+ The OSS template now defaults to Google API-key auth:
181
+
182
+ ```dotenv
183
+ COMPLETIONS_ENGINE=google-gemini
184
+ EMBEDDING_ENGINE=google-gemini
185
+ IMAGE_ENGINE=google-gemini
186
+ VIDEO_ENGINE=google-gemini
187
+ AI_VOICE_ENGINE=google
188
+
189
+ GOOGLE_GEMINI_API_KEY=...
190
+ GOOGLE_AUTH_METHOD=api_key
191
+
192
+ COMPLETIONS_MODEL_NAME=gemini-2.5-flash
193
+ EMBEDDING_MODEL_NAME=gemini-embedding-001
194
+ IMAGE_MODEL_NAME=imagen-4.0-generate-001
195
+ VIDEO_MODEL_NAME=veo-3.1-lite-generate-preview
196
+ DEFAULT_GEMINI_TTS_MODEL=gemini-2.5-pro-tts
197
+ ```
198
+
199
+ Leave `EMBEDDING_DIMENSIONS` unset unless you deliberately want a provider-specific override. The library now preserves provider defaults instead of forcing a generic value.
200
+
201
+ ### Smoke Test
202
+
203
+ ```bash
204
+ python -c "import ai_api_unified; print(ai_api_unified.__version__)"
205
+ ```
206
+
207
+ ## Quickstart
208
+
209
+ The examples below assume the Google API-key-first OSS defaults shown above. The same APIs work with OpenAI, Bedrock, Azure, or ElevenLabs by changing env selectors and installing the matching extras.
210
+
211
+ ### Completions
212
+
213
+ ```python
214
+ from ai_api_unified import AIFactory, AIBaseCompletions
215
+
216
+ client: AIBaseCompletions = AIFactory.get_ai_completions_client()
217
+ response: str = client.send_prompt("Say hello in one short sentence.")
218
+ print(response)
219
+ ```
220
+
221
+ ### Embeddings
222
+
223
+ ```python
224
+ from ai_api_unified import AIFactory, AIBaseEmbeddings
225
+
226
+ client: AIBaseEmbeddings = AIFactory.get_ai_embedding_client()
227
+ result: dict[str, object] = client.generate_embeddings("hello world")
228
+ embedding = result.get("embedding")
229
+ print(len(embedding) if embedding else None)
230
+ ```
231
+
232
+ ### Image Generation
233
+
234
+ ```python
235
+ from ai_api_unified import AIFactory, AIBaseImageProperties, AIBaseImages
236
+
237
+ client: AIBaseImages = AIFactory.get_ai_images_client()
238
+ images: list[bytes] = client.generate_images(
239
+ "A watercolor skyline at sunrise.",
240
+ AIBaseImageProperties(width=1024, height=1024, format="png", num_images=1),
241
+ )
242
+
243
+ with open("generated_image.png", "wb") as generated_file:
244
+ generated_file.write(images[0])
245
+ ```
246
+
247
+ ### Video Generation
248
+
249
+ The blocking convenience path is:
250
+
251
+ ```python
252
+ from pathlib import Path
253
+
254
+ from ai_api_unified import AIFactory, AIBaseVideoProperties, AIBaseVideos
255
+
256
+ client: AIBaseVideos = AIFactory.get_ai_video_client()
257
+ result = client.generate_video(
258
+ "A cinematic tracking shot of a neon train crossing the desert at dusk.",
259
+ AIBaseVideoProperties(output_dir=Path("./generated_videos")),
260
+ )
261
+
262
+ video_bytes: bytes = result.artifacts[0].read_bytes()
263
+ frames: list[bytes] = AIBaseVideos.extract_image_frames_from_video_buffer(
264
+ video_bytes,
265
+ time_offsets_seconds=[0.0, 1.0],
266
+ )
267
+ AIBaseVideos.save_image_buffers_as_files(
268
+ frames,
269
+ output_dir=Path("./generated_frames"),
270
+ )
271
+ ```
272
+
273
+ If you want explicit job control instead of the blocking wrapper:
274
+
275
+ ```python
276
+ from ai_api_unified import AIFactory, AIBaseVideos
277
+
278
+ client: AIBaseVideos = AIFactory.get_ai_video_client()
279
+ job = client.submit_video_generation(
280
+ "A stop-motion paper city waking up at sunrise."
281
+ )
282
+ job = client.wait_for_video_generation(job)
283
+ result = client.download_video_result(job)
284
+ print(result.job.status, result.artifacts[0].file_path)
285
+ ```
286
+
287
+ #### Kick Off Google Gemini Video Generation
288
+
289
+ Environment:
290
+
291
+ ```dotenv
292
+ VIDEO_ENGINE=google-gemini
293
+ VIDEO_MODEL_NAME=veo-3.1-lite-generate-preview
294
+ GOOGLE_GEMINI_API_KEY=...
295
+ GOOGLE_AUTH_METHOD=api_key
296
+ ```
297
+
298
+ Code:
299
+
300
+ ```python
301
+ from pathlib import Path
302
+
303
+ from ai_api_unified import AIFactory, AIBaseVideoProperties, AIBaseVideos
304
+
305
+ client: AIBaseVideos = AIFactory.get_ai_video_client()
306
+ result = client.generate_video(
307
+ "A cinematic dolly shot of a red vintage train moving through a desert at sunset.",
308
+ AIBaseVideoProperties(
309
+ output_dir=Path("./generated_videos/google"),
310
+ timeout_seconds=1200,
311
+ poll_interval_seconds=10,
312
+ ),
313
+ )
314
+
315
+ print(result.artifacts[0].file_path)
316
+ ```
317
+
318
+ #### Kick Off OpenAI Video Generation
319
+
320
+ Environment:
321
+
322
+ ```dotenv
323
+ VIDEO_ENGINE=openai
324
+ VIDEO_MODEL_NAME=sora-2
325
+ OPENAI_API_KEY=...
326
+ ```
327
+
328
+ Code:
329
+
330
+ ```python
331
+ from pathlib import Path
332
+
333
+ from ai_api_unified import AIFactory, AIBaseVideoProperties, AIBaseVideos
334
+
335
+ client: AIBaseVideos = AIFactory.get_ai_video_client()
336
+ result = client.generate_video(
337
+ "A wide cinematic shot of gentle ocean waves meeting a rocky coastline at golden hour.",
338
+ AIBaseVideoProperties(
339
+ output_dir=Path("./generated_videos/openai"),
340
+ timeout_seconds=1200,
341
+ poll_interval_seconds=10,
342
+ ),
343
+ )
344
+
345
+ print(result.artifacts[0].file_path)
346
+ ```
347
+
348
+ Frame extraction requires the optional `video_frames` extra.
349
+
350
+ ### Voice
351
+
352
+ ```python
353
+ from ai_api_unified import AIVoiceBase, AIVoiceFactory
354
+
355
+ voice: AIVoiceBase = AIVoiceFactory.create()
356
+ audio_bytes: bytes = voice.text_to_speech("Hello from ai-api-unified")
357
+
358
+ with open("out.wav", "wb") as output_file:
359
+ output_file.write(audio_bytes)
360
+ ```
361
+
362
+ ## Configuration
363
+
364
+ ### Required Engine Selectors
365
+
366
+ There is no implicit default provider. Set the selector for each capability you use.
367
+
368
+ | Environment variable | Valid values |
369
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
370
+ | `COMPLETIONS_ENGINE` | `openai`, `google-gemini`, Bedrock-routed aliases such as `nova`, `anthropic`, `llama`, `mistral`, `cohere`, `ai21`, `rerank` |
371
+ | `EMBEDDING_ENGINE` | `openai`, `titan`, `google-gemini` |
372
+ | `IMAGE_ENGINE` | `openai`, `google-gemini`, `nova-canvas`, `bedrock`, `nova` |
373
+ | `VIDEO_ENGINE` | `openai`, `google-gemini`, `bedrock`, `nova`, `nova-reel` |
374
+ | `AI_VOICE_ENGINE` | `openai`, `google`, `azure`, `elevenlabs` |
375
+
376
+ ### Common Model Settings
377
+
378
+ | Environment variable | Notes |
379
+ | --------------------------- | ------------------------------------------------------------------------------------------- |
380
+ | `COMPLETIONS_MODEL_NAME` | Optional completions model override |
381
+ | `EMBEDDING_MODEL_NAME` | Optional embeddings model override |
382
+ | `IMAGE_MODEL_NAME` | Optional image model override |
383
+ | `VIDEO_MODEL_NAME` | Optional video model override |
384
+ | `VIDEO_OUTPUT_DIR` | Optional local output directory for materialized video artifacts |
385
+ | `VIDEO_POLL_INTERVAL_SECONDS` | Optional default poll interval for video job waits |
386
+ | `VIDEO_TIMEOUT_SECONDS` | Optional default timeout for blocking video generation |
387
+ | `BEDROCK_VIDEO_OUTPUT_S3_URI` | Required for Nova Reel unless provided per request |
388
+ | `DEFAULT_GEMINI_TTS_MODEL` | Optional Google voice model override |
389
+ | `EMBEDDING_DIMENSIONS` | Optional embeddings dimension override. Leave unset for provider defaults. |
390
+ | `AI_API_GEO_RESIDENCY` | Optional geo hint. `US`, `USA`, or `United States` normalize to US routing where supported. |
391
+ | `AI_MIDDLEWARE_CONFIG_PATH` | Optional YAML config path for observability and PII middleware |
392
+
393
+ ### Provider Authentication
394
+
395
+ #### OpenAI
396
+
397
+ Required:
398
+
399
+ - `OPENAI_API_KEY`
400
+
401
+ Common optional settings:
402
+
403
+ - `OPENAI_BASE_URL`
404
+ - `COMPLETIONS_MODEL_NAME`
405
+ - `EMBEDDING_MODEL_NAME`
406
+ - `IMAGE_MODEL_NAME`
407
+ - `VIDEO_MODEL_NAME`
408
+ - `EMBEDDING_DIMENSIONS`
409
+ - `AI_API_GEO_RESIDENCY`
410
+
411
+ #### AWS Bedrock and Titan
412
+
413
+ Required:
414
+
415
+ - `AWS_REGION`
416
+ - standard AWS credentials in environment or runtime IAM context
417
+
418
+ Common optional settings:
419
+
420
+ - `COMPLETIONS_MODEL_NAME`
421
+ - `EMBEDDING_MODEL_NAME`
422
+ - `IMAGE_MODEL_NAME`
423
+ - `VIDEO_MODEL_NAME`
424
+ - `BEDROCK_VIDEO_OUTPUT_S3_URI`
425
+ - `EMBEDDING_DIMENSIONS`
426
+ - `AI_API_GEO_RESIDENCY`
427
+
428
+ For current Bedrock model IDs, use the AWS documentation:
429
+
430
+ - [Supported foundation models in Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html)
431
+ - [Amazon Bedrock foundation model reference](https://docs.aws.amazon.com/bedrock/latest/userguide/foundation-models-reference.html)
432
+
433
+ #### Google-backed Providers
434
+
435
+ Required for the default OSS path:
436
+
437
+ - `GOOGLE_GEMINI_API_KEY`
438
+
439
+ Default auth mode:
440
+
441
+ - `GOOGLE_AUTH_METHOD=api_key`
442
+
443
+ Optional service-account mode:
444
+
445
+ - `GOOGLE_AUTH_METHOD=service_account`
446
+ - `GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json`
447
+ - `GOOGLE_PROJECT_ID=<gcp-project-id>`
448
+ - `GOOGLE_LOCATION=us-central1`
449
+
450
+ This auth policy applies across Google completions, embeddings, images, videos, and voice.
451
+
452
+ #### Azure TTS
453
+
454
+ Required:
455
+
456
+ - `MICROSOFT_COGNITIVE_SERVICES_API_KEY`
457
+ - `MICROSOFT_COGNITIVE_SERVICES_REGION`
458
+
459
+ Optional:
460
+
461
+ - `MICROSOFT_COGNITIVE_SERVICES_ENDPOINT`
462
+ - `AI_VOICE_LANGUAGE`
463
+
464
+ #### ElevenLabs
465
+
466
+ Required:
467
+
468
+ - `ELEVEN_LABS_API_KEY`
469
+
470
+ ## Lazy Loading and Imports
471
+
472
+ Prefer the stable interfaces and factories exported from the root package:
473
+
474
+ ```python
475
+ from ai_api_unified import (
476
+ AIFactory,
477
+ AIVoiceFactory,
478
+ AIBaseCompletions,
479
+ AIBaseEmbeddings,
480
+ AIBaseImages,
481
+ AIBaseVideos,
482
+ AIVoiceBase,
483
+ )
484
+ ```
485
+
486
+ Factory entry points:
487
+
488
+ - `AIFactory.get_ai_completions_client()`
489
+ - `AIFactory.get_ai_embedding_client()`
490
+ - `AIFactory.get_ai_images_client()`
491
+ - `AIFactory.get_ai_video_client()`
492
+ - `AIVoiceFactory.create()`
493
+
494
+ Concrete providers are no longer re-exported from package `__init__.py` modules. If you need a concrete class directly, import it from its implementation module, for example:
495
+
496
+ ```python
497
+ from ai_api_unified.completions.ai_google_gemini_completions import (
498
+ GoogleGeminiCompletions,
499
+ )
500
+ ```
501
+
502
+ Typical factory failure modes:
503
+
504
+ - unsupported engine selector: `ValueError`
505
+ - selected provider extra is not installed: `AiProviderDependencyUnavailableError`
506
+ - provider load/runtime failure: `AiProviderRuntimeError`
507
+
508
+ ## Middleware
509
+
510
+ Middleware is configured by YAML referenced through `AI_MIDDLEWARE_CONFIG_PATH`.
511
+
512
+ ### Observability
513
+
514
+ Observability middleware is built into the base package and does not require a separate extra.
515
+
516
+ Features:
517
+
518
+ - metadata-only input, output, and error events
519
+ - request-scoped correlation via `set_observability_context(...)`
520
+ - coverage for completions, embeddings, images, videos, and text-to-speech
521
+
522
+ Minimal config:
523
+
524
+ ```yaml
525
+ middleware:
526
+ - name: 'observability'
527
+ enabled: true
528
+ ```
529
+
530
+ See [`docs/observability_middleware_example.yaml`](docs/observability_middleware_example.yaml) and [`docs/observability_middleware_design.md`](docs/observability_middleware_design.md).
531
+
532
+ ### PII Redaction
533
+
534
+ PII redaction is optional and requires one of:
535
+
536
+ - `middleware-pii-redaction`
537
+ - `middleware-pii-redaction-small`
538
+ - `middleware-pii-redaction-large`
539
+
540
+ Minimal config:
541
+
542
+ ```yaml
543
+ middleware:
544
+ - name: 'pii_redaction'
545
+ enabled: true
546
+ settings:
547
+ direction: 'input_only'
548
+ ```
549
+
550
+ Notes:
551
+
552
+ - `strict_mode: true` enables fail-closed behavior
553
+ - `balanced`, `high_accuracy`, and `low_memory` detection profiles are supported
554
+ - install a matching spaCy model separately, for example `poetry run python -m spacy download en_core_web_sm` for `balanced` or `poetry run python -m spacy download en_core_web_lg` for `high_accuracy`
555
+ - `middleware-pii-redaction-small` and `middleware-pii-redaction-large` are compatibility aliases for the same Python dependency set; the spaCy model is still installed as a separate build/runtime asset
556
+ - for no-egress images and Lambda-style deployments, install the spaCy model wheel into the build artifact instead of relying on runtime downloads
557
+ - recognizer customization is configured in YAML, not hard-coded in provider implementations
558
+
559
+ See [`docs/pii_redaction_design.md`](docs/pii_redaction_design.md) for the fuller contract and deployment tradeoffs.
560
+
561
+ ## Structured Responses
562
+
563
+ Use `AIStructuredPrompt` together with `strict_schema_prompt(...)` when you want schema-validated structured output.
564
+
565
+ ```python
566
+ from copy import deepcopy
567
+ from typing import Any
568
+
569
+ from ai_api_unified import (
570
+ AIFactory,
571
+ AIStructuredPrompt,
572
+ StructuredResponseTokenLimitError,
573
+ )
574
+
575
+
576
+ class ContactExtraction(AIStructuredPrompt):
577
+ name: str | None = None
578
+ city: str | None = None
579
+
580
+ @staticmethod
581
+ def get_prompt() -> str:
582
+ return "Extract the person's name and city from: Alice lives in Paris."
583
+
584
+ @classmethod
585
+ def model_json_schema(cls) -> dict[str, Any]:
586
+ schema = deepcopy(super().model_json_schema())
587
+ schema["properties"] = {
588
+ "name": {"type": "string"},
589
+ "city": {"type": "string"},
590
+ }
591
+ schema["required"] = ["name", "city"]
592
+ return schema
593
+
594
+
595
+ client = AIFactory.get_ai_completions_client()
596
+
597
+ try:
598
+ result = client.strict_schema_prompt(
599
+ prompt=ContactExtraction.get_prompt(),
600
+ response_model=ContactExtraction,
601
+ max_response_tokens=2048,
602
+ )
603
+ print(result.name, result.city)
604
+ except StructuredResponseTokenLimitError as exc:
605
+ print(exc)
606
+ ```
607
+
608
+ Key behavior:
609
+
610
+ - structured prompts are provider-agnostic at the call site
611
+ - the library validates the response against your output schema
612
+ - undersized or truncated structured responses raise `StructuredResponseTokenLimitError`
613
+
614
+ `AIStructuredPrompt.send_structured_prompt(...)` is also available when you want the prompt to live on the model instance itself.
615
+
616
+ ## Testing
617
+
618
+ Regular test run:
619
+
620
+ ```bash
621
+ poetry run pytest -m "not nonmock"
622
+ ```
623
+
624
+ Live provider tests:
625
+
626
+ ```bash
627
+ poetry run pytest -m nonmock -s -vv
628
+ ```
629
+
630
+ Notes for live tests:
631
+
632
+ - install the matching provider extras first
633
+ - configure credentials in `.env`
634
+ - some tests may skip when a provider account lacks quota, a paid image tier, or an enabled cloud service
635
+
636
+ ## Release and PyPI Publishing
637
+
638
+ The OSS repository publishes to public PyPI only.
639
+
640
+ Before publishing:
641
+
642
+ 1. Bump the version in `pyproject.toml`.
643
+ 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.
646
+
647
+ Publish with the checked-in script:
648
+
649
+ ```bash
650
+ ./publish.sh
651
+ ```
652
+
653
+ The script:
654
+
655
+ - checks for uncommitted changes
656
+ - confirms the version
657
+ - removes old build artifacts
658
+ - builds the wheel and sdist locally
659
+ - fails before upload if built metadata contains direct URL requirements that PyPI rejects
660
+ - runs `poetry publish` only after metadata validation passes
661
+
662
+ After publishing, tag and push the release:
663
+
664
+ ```bash
665
+ git tag v<version>
666
+ git push origin v<version>
667
+ ```
668
+
669
+ ## Troubleshooting
670
+
671
+ - `COMPLETIONS_ENGINE must be configured explicitly` or similar: set the required engine selector for that capability.
672
+ - `AiProviderDependencyUnavailableError`: install the extra for the selected provider.
673
+ - Google auth errors: the OSS default is `GOOGLE_AUTH_METHOD=api_key`. If you switch to `service_account`, make sure `GOOGLE_APPLICATION_CREDENTIALS` points to a valid local JSON credential file and set `GOOGLE_PROJECT_ID` and `GOOGLE_LOCATION` when required.
674
+ - Unexpected embeddings dimensions: leave `EMBEDDING_DIMENSIONS` unset unless you intentionally want a non-default size.
675
+ - Google image generation or TTS failures in live tests can reflect account/service state rather than library bugs, for example a disabled cloud API or missing paid-plan access.
676
+ - `AI_API_GEO_RESIDENCY=US` is a best-effort routing hint. Only providers that expose regional routing controls can honor it directly.
677
+
678
+ ## License
679
+
680
+ This project is released under the MIT License.
681
+