omniai-kit 1.0.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.
omniai/client.py ADDED
@@ -0,0 +1,316 @@
1
+ """OmniAI Python Client SDK.
2
+
3
+ Provides synchronous and asynchronous clients with nested resource namespaces
4
+ and top-level convenience methods for chat, streaming, background tasks, and LiveKit sessions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import (
11
+ Any,
12
+ AsyncGenerator,
13
+ Dict,
14
+ Generator,
15
+ List,
16
+ Mapping,
17
+ Optional,
18
+ Type,
19
+ TypeVar,
20
+ Union,
21
+ )
22
+ import httpx
23
+
24
+ from omniai._base import AsyncBaseClient, BaseClient
25
+ from omniai._constants import (
26
+ DEFAULT_BASE_URL,
27
+ DEFAULT_MAX_RETRIES,
28
+ DEFAULT_TIMEOUT,
29
+ SUPPORTED_PROVIDERS,
30
+ )
31
+ from omniai.resources.chat import AsyncChatResource, ChatResource
32
+ from omniai.resources.livekit import AsyncLiveKitResource, LiveKitResource
33
+ from omniai.resources.models import AsyncModelsResource, ModelsResource
34
+ from omniai.resources.tasks import AsyncTasksResource, TasksResource
35
+ from omniai.types.livekit import LiveSessionInfo
36
+ from omniai.types.models import ModelInfo, ModelList
37
+ from omniai.types.tasks import AsyncTaskJob, TaskJob
38
+
39
+ logger = logging.getLogger("omniai.client")
40
+
41
+ T = TypeVar("T")
42
+
43
+
44
+ class OmniaiClient(BaseClient):
45
+ """
46
+ Synchronous client for OmniAI.
47
+
48
+ Usage:
49
+ >>> from omniai import OmniaiClient
50
+ >>> client = OmniaiClient()
51
+ >>> response = client.chat(model="gemini:gemini-2.5-flash", prompt="Hello!")
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ api_key: Optional[str] = None,
57
+ base_url: Optional[str] = None,
58
+ timeout: float = DEFAULT_TIMEOUT,
59
+ max_retries: int = DEFAULT_MAX_RETRIES,
60
+ headers: Optional[Mapping[str, str]] = None,
61
+ http_client: Optional[httpx.Client] = None,
62
+ ):
63
+ super().__init__(
64
+ api_key=api_key,
65
+ base_url=base_url,
66
+ timeout=timeout,
67
+ max_retries=max_retries,
68
+ headers=headers,
69
+ http_client=http_client,
70
+ )
71
+ self.chat = ChatResource(self)
72
+ self.models = ModelsResource(self)
73
+ self.tasks = TasksResource(self)
74
+ self.livekit = LiveKitResource(self)
75
+
76
+ def chat(
77
+ self,
78
+ model: str,
79
+ prompt: Optional[str] = None,
80
+ messages: Optional[List[Dict[str, str]]] = None,
81
+ response_model: Optional[Type[T]] = None,
82
+ tools: Optional[List[Any]] = None,
83
+ output_format: Optional[Union[str, Dict[str, Any]]] = None,
84
+ system_instruction: Optional[str] = None,
85
+ temperature: float = 0.1,
86
+ max_tokens: Optional[int] = None,
87
+ timeout: Optional[float] = None,
88
+ ) -> Union[str, T]:
89
+ """Convenience method to execute a chat completion."""
90
+ return self.chat.completions.create(
91
+ model=model,
92
+ prompt=prompt,
93
+ messages=messages,
94
+ response_model=response_model,
95
+ tools=tools,
96
+ output_format=output_format,
97
+ system_instruction=system_instruction,
98
+ temperature=temperature,
99
+ max_tokens=max_tokens,
100
+ timeout=timeout,
101
+ )
102
+
103
+ def stream(
104
+ self,
105
+ model: str,
106
+ prompt: Optional[str] = None,
107
+ messages: Optional[List[Dict[str, str]]] = None,
108
+ system_instruction: Optional[str] = None,
109
+ temperature: float = 0.1,
110
+ max_tokens: Optional[int] = None,
111
+ timeout: Optional[float] = None,
112
+ ) -> Generator[str, None, None]:
113
+ """Convenience method to stream a chat completion chunk-by-chunk."""
114
+ return self.chat.completions.stream(
115
+ model=model,
116
+ prompt=prompt,
117
+ messages=messages,
118
+ system_instruction=system_instruction,
119
+ temperature=temperature,
120
+ max_tokens=max_tokens,
121
+ timeout=timeout,
122
+ )
123
+
124
+ def submit_task(
125
+ self,
126
+ model: str,
127
+ prompt: Optional[str] = None,
128
+ messages: Optional[List[Dict[str, str]]] = None,
129
+ response_model: Optional[Type[T]] = None,
130
+ tools: Optional[List[Any]] = None,
131
+ output_format: Optional[Union[str, Dict[str, Any]]] = None,
132
+ system_instruction: Optional[str] = None,
133
+ temperature: float = 0.1,
134
+ max_tokens: Optional[int] = None,
135
+ timeout: Optional[float] = None,
136
+ ) -> TaskJob[T]:
137
+ """Submits a background task to the OmniAI Celery queue."""
138
+ return self.tasks.submit(
139
+ model=model,
140
+ prompt=prompt,
141
+ messages=messages,
142
+ response_model=response_model,
143
+ tools=tools,
144
+ output_format=output_format,
145
+ system_instruction=system_instruction,
146
+ temperature=temperature,
147
+ max_tokens=max_tokens,
148
+ timeout=timeout,
149
+ )
150
+
151
+ def create_live_session(
152
+ self,
153
+ model: str = "gemini:gemini-2.5-flash",
154
+ voice: str = "Aoede",
155
+ video_input: bool = False,
156
+ timeout: Optional[float] = None,
157
+ ) -> LiveSessionInfo:
158
+ """Requests room and participant credentials for a LiveKit WebRTC session."""
159
+ return self.livekit.create_session(
160
+ model=model,
161
+ voice=voice,
162
+ video_input=video_input,
163
+ timeout=timeout,
164
+ )
165
+
166
+ def list_models(self, timeout: Optional[float] = None) -> ModelList:
167
+ """Lists available AI models."""
168
+ return self.models.list(timeout=timeout)
169
+
170
+
171
+ class AsyncOmniaiClient(AsyncBaseClient):
172
+ """
173
+ Asynchronous client for OmniAI.
174
+
175
+ Usage:
176
+ >>> import asyncio
177
+ >>> from omniai import AsyncOmniaiClient
178
+ >>> async def main():
179
+ ... async with AsyncOmniaiClient() as client:
180
+ ... res = await client.chat(model="gemini:gemini-2.5-flash", prompt="Hello!")
181
+ ... print(res)
182
+ >>> asyncio.run(main())
183
+ """
184
+
185
+ def __init__(
186
+ self,
187
+ api_key: Optional[str] = None,
188
+ base_url: Optional[str] = None,
189
+ timeout: float = DEFAULT_TIMEOUT,
190
+ max_retries: int = DEFAULT_MAX_RETRIES,
191
+ headers: Optional[Mapping[str, str]] = None,
192
+ http_client: Optional[httpx.AsyncClient] = None,
193
+ ):
194
+ super().__init__(
195
+ api_key=api_key,
196
+ base_url=base_url,
197
+ timeout=timeout,
198
+ max_retries=max_retries,
199
+ headers=headers,
200
+ http_client=http_client,
201
+ )
202
+ self.chat = AsyncChatResource(self)
203
+ self.models = AsyncModelsResource(self)
204
+ self.tasks = AsyncTasksResource(self)
205
+ self.livekit = AsyncLiveKitResource(self)
206
+
207
+ async def chat(
208
+ self,
209
+ model: str,
210
+ prompt: Optional[str] = None,
211
+ messages: Optional[List[Dict[str, str]]] = None,
212
+ response_model: Optional[Type[T]] = None,
213
+ tools: Optional[List[Any]] = None,
214
+ output_format: Optional[Union[str, Dict[str, Any]]] = None,
215
+ system_instruction: Optional[str] = None,
216
+ temperature: float = 0.1,
217
+ max_tokens: Optional[int] = None,
218
+ timeout: Optional[float] = None,
219
+ ) -> Union[str, T]:
220
+ """Convenience method to execute an async chat completion."""
221
+ return await self.chat.completions.create(
222
+ model=model,
223
+ prompt=prompt,
224
+ messages=messages,
225
+ response_model=response_model,
226
+ tools=tools,
227
+ output_format=output_format,
228
+ system_instruction=system_instruction,
229
+ temperature=temperature,
230
+ max_tokens=max_tokens,
231
+ timeout=timeout,
232
+ )
233
+
234
+ async def stream(
235
+ self,
236
+ model: str,
237
+ prompt: Optional[str] = None,
238
+ messages: Optional[List[Dict[str, str]]] = None,
239
+ system_instruction: Optional[str] = None,
240
+ temperature: float = 0.1,
241
+ max_tokens: Optional[int] = None,
242
+ timeout: Optional[float] = None,
243
+ ) -> AsyncGenerator[str, None]:
244
+ """Convenience method to stream an async chat completion chunk-by-chunk."""
245
+ async for chunk in self.chat.completions.stream(
246
+ model=model,
247
+ prompt=prompt,
248
+ messages=messages,
249
+ system_instruction=system_instruction,
250
+ temperature=temperature,
251
+ max_tokens=max_tokens,
252
+ timeout=timeout,
253
+ ):
254
+ yield chunk
255
+
256
+ async def submit_task(
257
+ self,
258
+ model: str,
259
+ prompt: Optional[str] = None,
260
+ messages: Optional[List[Dict[str, str]]] = None,
261
+ response_model: Optional[Type[T]] = None,
262
+ tools: Optional[List[Any]] = None,
263
+ output_format: Optional[Union[str, Dict[str, Any]]] = None,
264
+ system_instruction: Optional[str] = None,
265
+ temperature: float = 0.1,
266
+ max_tokens: Optional[int] = None,
267
+ timeout: Optional[float] = None,
268
+ ) -> AsyncTaskJob[T]:
269
+ """Submits an async background task to the OmniAI Celery queue."""
270
+ return await self.tasks.submit(
271
+ model=model,
272
+ prompt=prompt,
273
+ messages=messages,
274
+ response_model=response_model,
275
+ tools=tools,
276
+ output_format=output_format,
277
+ system_instruction=system_instruction,
278
+ temperature=temperature,
279
+ max_tokens=max_tokens,
280
+ timeout=timeout,
281
+ )
282
+
283
+ async def create_live_session(
284
+ self,
285
+ model: str = "gemini:gemini-2.5-flash",
286
+ voice: str = "Aoede",
287
+ video_input: bool = False,
288
+ timeout: Optional[float] = None,
289
+ ) -> LiveSessionInfo:
290
+ """Requests room and participant credentials for a LiveKit WebRTC session asynchronously."""
291
+ return await self.livekit.create_session(
292
+ model=model,
293
+ voice=voice,
294
+ video_input=video_input,
295
+ timeout=timeout,
296
+ )
297
+
298
+ async def list_models(self, timeout: Optional[float] = None) -> ModelList:
299
+ """Lists available AI models asynchronously."""
300
+ return await self.models.list(timeout=timeout)
301
+
302
+
303
+ # Aliases for brand and convenience consistency
304
+ OmniAIClient = OmniaiClient
305
+ AsyncOmniAIClient = AsyncOmniaiClient
306
+ OmniClient = OmniaiClient
307
+ AsyncOmniClient = AsyncOmniaiClient
308
+
309
+ __all__ = [
310
+ "OmniaiClient",
311
+ "AsyncOmniaiClient",
312
+ "OmniAIClient",
313
+ "AsyncOmniAIClient",
314
+ "OmniClient",
315
+ "AsyncOmniClient",
316
+ ]
omniai/exceptions.py ADDED
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ class OmniaiError(Exception):
7
+ """Base exception for all errors raised by the OmniAI Python SDK."""
8
+
9
+ def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
10
+ super().__init__(message)
11
+ self.message = message
12
+ self.details = details or {}
13
+
14
+ def __str__(self) -> str:
15
+ return self.message
16
+
17
+ def __repr__(self) -> str:
18
+ return f"<{self.__class__.__name__} message={self.message!r}>"
19
+
20
+
21
+ class OmniaiAuthError(OmniaiError):
22
+ """Raised when authentication or authorization fails (HTTP 401 / 403)."""
23
+ pass
24
+
25
+
26
+ class OmniaiPaymentRequiredError(OmniaiError):
27
+ """Raised when API credit balance is exhausted or payment is required (HTTP 402)."""
28
+ pass
29
+
30
+
31
+ class OmniaiNotFoundError(OmniaiError):
32
+ """Raised when a requested resource, model, or task is not found (HTTP 404)."""
33
+ pass
34
+
35
+
36
+ class OmniaiRateLimitError(OmniaiError):
37
+ """Raised when request rate limits or concurrency quotas are exceeded (HTTP 429)."""
38
+
39
+ def __init__(
40
+ self,
41
+ message: str,
42
+ retry_after: Optional[float] = None,
43
+ details: Optional[Dict[str, Any]] = None,
44
+ ):
45
+ super().__init__(message, details)
46
+ self.retry_after = retry_after
47
+
48
+
49
+ class OmniaiTimeoutError(OmniaiError):
50
+ """Raised when a network request, streaming chunk, or task polling times out."""
51
+ pass
52
+
53
+
54
+ class OmniaiConnectionError(OmniaiError):
55
+ """Raised when network connectivity fails (DNS resolution, connection refused, broken pipe)."""
56
+ pass
57
+
58
+
59
+ class OmniaiExecutionError(OmniaiError):
60
+ """Raised when the OmniAI gateway or upstream LLM provider encounters an execution error (HTTP 5xx / provider failure)."""
61
+
62
+ def __init__(
63
+ self,
64
+ message: str,
65
+ status_code: int = 500,
66
+ details: Optional[Dict[str, Any]] = None,
67
+ ):
68
+ super().__init__(message, details)
69
+ self.status_code = status_code
70
+
71
+
72
+ class OmniaiValidationError(OmniaiError):
73
+ """Raised when structured outputs or response_model validation fails against expected schema."""
74
+
75
+ def __init__(
76
+ self,
77
+ message: str,
78
+ raw_output: Optional[str] = None,
79
+ details: Optional[Dict[str, Any]] = None,
80
+ ):
81
+ super().__init__(message, details)
82
+ self.raw_output = raw_output
83
+
84
+
85
+ class OmniaiUnsupportedProviderError(OmniaiError):
86
+ """
87
+ Raised when an unsupported provider is requested.
88
+ The OmniAI SDK strictly supports: 'openai', 'gemini', 'anthropic', and 'vllm'.
89
+ """
90
+ pass
91
+
92
+
93
+ # Standard OpenAI-style & OmniAI naming aliases
94
+ OmniaiAPIError = OmniaiExecutionError
95
+ OmniaiAuthenticationError = OmniaiAuthError
96
+ OmniaiPermissionDeniedError = OmniaiAuthError
97
+ OmniaiBadRequestError = OmniaiValidationError
98
+
99
+ # Aliases with OmniAI / Omni casing
100
+ OmniAIError = OmniaiError
101
+ OmniAIAuthError = OmniaiAuthError
102
+ OmniAIAuthenticationError = OmniaiAuthError
103
+ OmniAIAPIError = OmniaiAPIError
104
+ OmniAIRateLimitError = OmniaiRateLimitError
105
+ OmniAITimeoutError = OmniaiTimeoutError
106
+ OmniAIConnectionError = OmniaiConnectionError
107
+ OmniAIValidationError = OmniaiValidationError
108
+
109
+ OmniError = OmniaiError
110
+ OmniAuthError = OmniaiAuthError
111
+ OmniExecutionError = OmniaiExecutionError
112
+ OmniTimeoutError = OmniaiTimeoutError
113
+ OmniRateLimitError = OmniaiRateLimitError
omniai/py.typed ADDED
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561 compliance
@@ -0,0 +1,26 @@
1
+ """Resource modules for the OmniAI Python SDK."""
2
+
3
+ from omniai.resources.chat import (
4
+ ChatResource,
5
+ AsyncChatResource,
6
+ CompletionsResource,
7
+ AsyncCompletionsResource,
8
+ )
9
+ from omniai.resources.models import ModelsResource, AsyncModelsResource
10
+ from omniai.resources.tasks import TasksResource, AsyncTasksResource
11
+ from omniai.resources.livekit import LiveKitResource, AsyncLiveKitResource
12
+ from omniai.resources.router import RouterEngine
13
+
14
+ __all__ = [
15
+ "ChatResource",
16
+ "AsyncChatResource",
17
+ "CompletionsResource",
18
+ "AsyncCompletionsResource",
19
+ "ModelsResource",
20
+ "AsyncModelsResource",
21
+ "TasksResource",
22
+ "AsyncTasksResource",
23
+ "LiveKitResource",
24
+ "AsyncLiveKitResource",
25
+ "RouterEngine",
26
+ ]