livellm 1.1.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.
- livellm-1.1.0/.gitignore +5 -0
- livellm-1.1.0/LICENSE +21 -0
- livellm-1.1.0/PKG-INFO +573 -0
- livellm-1.1.0/README.md +548 -0
- livellm-1.1.0/livellm/__init__.py +15 -0
- livellm-1.1.0/livellm/livellm.py +236 -0
- livellm-1.1.0/livellm/models/__init__.py +41 -0
- livellm-1.1.0/livellm/models/agent/__init__.py +19 -0
- livellm-1.1.0/livellm/models/agent/agent.py +23 -0
- livellm-1.1.0/livellm/models/agent/chat.py +30 -0
- livellm-1.1.0/livellm/models/agent/tools.py +39 -0
- livellm-1.1.0/livellm/models/audio/__init__.py +12 -0
- livellm-1.1.0/livellm/models/audio/speak.py +23 -0
- livellm-1.1.0/livellm/models/audio/transcribe.py +48 -0
- livellm-1.1.0/livellm/models/common.py +46 -0
- livellm-1.1.0/livellm/models/fallback.py +25 -0
- livellm-1.1.0/livellm/py.typed +0 -0
- livellm-1.1.0/pyproject.toml +79 -0
livellm-1.1.0/.gitignore
ADDED
livellm-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Kamil Saliamov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
livellm-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: livellm
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Python client for the LiveLLM Server
|
|
5
|
+
Project-URL: Homepage, https://github.com/qalby-tech/livellm-client-py
|
|
6
|
+
Project-URL: Repository, https://github.com/qalby-tech/livellm-client-py
|
|
7
|
+
Author: Kamil Saliamov
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Requires-Dist: pydantic>=2.0.0
|
|
20
|
+
Provides-Extra: testing
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'testing'
|
|
22
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'testing'
|
|
23
|
+
Requires-Dist: pytest>=8.4.2; extra == 'testing'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# LiveLLM Python Client
|
|
27
|
+
|
|
28
|
+
[](https://www.python.org/downloads/)
|
|
29
|
+
[](https://opensource.org/licenses/MIT)
|
|
30
|
+
|
|
31
|
+
Python client library for the LiveLLM Server - a unified proxy for AI agent, audio, and transcription services.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- 🚀 **Async-first design** - Built on httpx for high-performance async operations
|
|
36
|
+
- 🔒 **Type-safe** - Full type hints and Pydantic validation
|
|
37
|
+
- 🎯 **Multi-provider support** - OpenAI, Google, Anthropic, Groq, ElevenLabs
|
|
38
|
+
- 🔄 **Streaming support** - Real-time streaming for agent and audio responses
|
|
39
|
+
- 🛠️ **Agent tools** - Web search and MCP server integration
|
|
40
|
+
- 🎙️ **Audio services** - Text-to-speech and transcription
|
|
41
|
+
- ⚡ **Fallback strategies** - Sequential and parallel fallback handling
|
|
42
|
+
- 📦 **Context manager support** - Automatic cleanup with async context managers
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install livellm-client
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or with development dependencies:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install livellm-client[testing]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
from livellm import LivellmClient
|
|
61
|
+
from livellm.models import Settings, ProviderKind, AgentRequest, TextMessage, MessageRole
|
|
62
|
+
from pydantic import SecretStr
|
|
63
|
+
|
|
64
|
+
async def main():
|
|
65
|
+
# Initialize the client with context manager for automatic cleanup
|
|
66
|
+
async with LivellmClient(base_url="http://localhost:8000") as client:
|
|
67
|
+
# Configure a provider
|
|
68
|
+
config = Settings(
|
|
69
|
+
uid="my-openai-config",
|
|
70
|
+
provider=ProviderKind.OPENAI,
|
|
71
|
+
api_key=SecretStr("your-api-key")
|
|
72
|
+
)
|
|
73
|
+
await client.update_config(config)
|
|
74
|
+
|
|
75
|
+
# Run an agent query
|
|
76
|
+
request = AgentRequest(
|
|
77
|
+
provider_uid="my-openai-config",
|
|
78
|
+
model="gpt-4",
|
|
79
|
+
messages=[
|
|
80
|
+
TextMessage(role=MessageRole.USER, content="Hello, how are you?")
|
|
81
|
+
],
|
|
82
|
+
tools=[]
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
response = await client.agent_run(request)
|
|
86
|
+
print(response.output)
|
|
87
|
+
|
|
88
|
+
asyncio.run(main())
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
### Client Initialization
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from livellm import LivellmClient
|
|
97
|
+
|
|
98
|
+
# Basic initialization
|
|
99
|
+
client = LivellmClient(base_url="http://localhost:8000")
|
|
100
|
+
|
|
101
|
+
# With timeout
|
|
102
|
+
client = LivellmClient(
|
|
103
|
+
base_url="http://localhost:8000",
|
|
104
|
+
timeout=30.0
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# With pre-configured providers (sync operation)
|
|
108
|
+
from livellm.models import Settings, ProviderKind
|
|
109
|
+
from pydantic import SecretStr
|
|
110
|
+
|
|
111
|
+
configs = [
|
|
112
|
+
Settings(
|
|
113
|
+
uid="openai-config",
|
|
114
|
+
provider=ProviderKind.OPENAI,
|
|
115
|
+
api_key=SecretStr("sk-..."),
|
|
116
|
+
base_url="https://api.openai.com/v1" # Optional custom base URL
|
|
117
|
+
),
|
|
118
|
+
Settings(
|
|
119
|
+
uid="anthropic-config",
|
|
120
|
+
provider=ProviderKind.ANTHROPIC,
|
|
121
|
+
api_key=SecretStr("sk-ant-..."),
|
|
122
|
+
blacklist_models=["claude-instant-1"] # Optional model blacklist
|
|
123
|
+
)
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
client = LivellmClient(
|
|
127
|
+
base_url="http://localhost:8000",
|
|
128
|
+
configs=configs
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Provider Configuration
|
|
133
|
+
|
|
134
|
+
Supported providers:
|
|
135
|
+
- `OPENAI` - OpenAI GPT models
|
|
136
|
+
- `GOOGLE` - Google Gemini models
|
|
137
|
+
- `ANTHROPIC` - Anthropic Claude models
|
|
138
|
+
- `GROQ` - Groq models
|
|
139
|
+
- `ELEVENLABS` - ElevenLabs text-to-speech
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
# Add a provider configuration
|
|
143
|
+
config = Settings(
|
|
144
|
+
uid="unique-provider-id",
|
|
145
|
+
provider=ProviderKind.OPENAI,
|
|
146
|
+
api_key=SecretStr("your-api-key"),
|
|
147
|
+
base_url="https://custom-endpoint.com", # Optional
|
|
148
|
+
blacklist_models=["deprecated-model"] # Optional
|
|
149
|
+
)
|
|
150
|
+
await client.update_config(config)
|
|
151
|
+
|
|
152
|
+
# Get all configurations
|
|
153
|
+
configs = await client.get_configs()
|
|
154
|
+
|
|
155
|
+
# Delete a configuration
|
|
156
|
+
await client.delete_config("unique-provider-id")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Usage Examples
|
|
160
|
+
|
|
161
|
+
### Agent Services
|
|
162
|
+
|
|
163
|
+
#### Basic Agent Run
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from livellm.models import AgentRequest, TextMessage, MessageRole
|
|
167
|
+
|
|
168
|
+
request = AgentRequest(
|
|
169
|
+
provider_uid="my-openai-config",
|
|
170
|
+
model="gpt-4",
|
|
171
|
+
messages=[
|
|
172
|
+
TextMessage(role=MessageRole.SYSTEM, content="You are a helpful assistant."),
|
|
173
|
+
TextMessage(role=MessageRole.USER, content="Explain quantum computing")
|
|
174
|
+
],
|
|
175
|
+
tools=[],
|
|
176
|
+
gen_config={"temperature": 0.7, "max_tokens": 500}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
response = await client.agent_run(request)
|
|
180
|
+
print(f"Output: {response.output}")
|
|
181
|
+
print(f"Tokens used - Input: {response.usage.input_tokens}, Output: {response.usage.output_tokens}")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Streaming Agent Response
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
request = AgentRequest(
|
|
188
|
+
provider_uid="my-openai-config",
|
|
189
|
+
model="gpt-4",
|
|
190
|
+
messages=[
|
|
191
|
+
TextMessage(role=MessageRole.USER, content="Tell me a story")
|
|
192
|
+
],
|
|
193
|
+
tools=[]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
stream = await client.agent_run_stream(request)
|
|
197
|
+
async for chunk in stream:
|
|
198
|
+
print(chunk.output, end="", flush=True)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Agent with Binary Messages
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
import base64
|
|
205
|
+
|
|
206
|
+
# Read and encode image
|
|
207
|
+
with open("image.jpg", "rb") as f:
|
|
208
|
+
image_data = base64.b64encode(f.read()).decode("utf-8")
|
|
209
|
+
|
|
210
|
+
from livellm.models import BinaryMessage
|
|
211
|
+
|
|
212
|
+
request = AgentRequest(
|
|
213
|
+
provider_uid="my-openai-config",
|
|
214
|
+
model="gpt-4-vision",
|
|
215
|
+
messages=[
|
|
216
|
+
BinaryMessage(
|
|
217
|
+
role=MessageRole.USER,
|
|
218
|
+
content=image_data,
|
|
219
|
+
mime_type="image/jpeg",
|
|
220
|
+
caption="What's in this image?"
|
|
221
|
+
)
|
|
222
|
+
],
|
|
223
|
+
tools=[]
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
response = await client.agent_run(request)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### Agent with Web Search Tool
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from livellm.models import WebSearchInput, ToolKind
|
|
233
|
+
|
|
234
|
+
request = AgentRequest(
|
|
235
|
+
provider_uid="my-openai-config",
|
|
236
|
+
model="gpt-4",
|
|
237
|
+
messages=[
|
|
238
|
+
TextMessage(role=MessageRole.USER, content="What's the latest news about AI?")
|
|
239
|
+
],
|
|
240
|
+
tools=[
|
|
241
|
+
WebSearchInput(
|
|
242
|
+
kind=ToolKind.WEB_SEARCH,
|
|
243
|
+
search_context_size="high" # Options: "low", "medium", "high"
|
|
244
|
+
)
|
|
245
|
+
]
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
response = await client.agent_run(request)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### Agent with MCP Server Tool
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from livellm.models import MCPStreamableServerInput, ToolKind
|
|
255
|
+
|
|
256
|
+
request = AgentRequest(
|
|
257
|
+
provider_uid="my-openai-config",
|
|
258
|
+
model="gpt-4",
|
|
259
|
+
messages=[
|
|
260
|
+
TextMessage(role=MessageRole.USER, content="Execute tool")
|
|
261
|
+
],
|
|
262
|
+
tools=[
|
|
263
|
+
MCPStreamableServerInput(
|
|
264
|
+
kind=ToolKind.MCP_STREAMABLE_SERVER,
|
|
265
|
+
url="http://mcp-server:8080",
|
|
266
|
+
prefix="mcp_",
|
|
267
|
+
timeout=15,
|
|
268
|
+
kwargs={"custom_param": "value"}
|
|
269
|
+
)
|
|
270
|
+
]
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
response = await client.agent_run(request)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Audio Services
|
|
277
|
+
|
|
278
|
+
#### Text-to-Speech
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
from livellm.models import SpeakRequest, SpeakMimeType
|
|
282
|
+
|
|
283
|
+
request = SpeakRequest(
|
|
284
|
+
provider_uid="elevenlabs-config",
|
|
285
|
+
model="eleven_turbo_v2",
|
|
286
|
+
text="Hello, this is a test of text to speech.",
|
|
287
|
+
voice="rachel",
|
|
288
|
+
mime_type=SpeakMimeType.MP3,
|
|
289
|
+
sample_rate=44100,
|
|
290
|
+
gen_config={"stability": 0.5, "similarity_boost": 0.75}
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# Get audio as bytes
|
|
294
|
+
audio_bytes = await client.speak(request)
|
|
295
|
+
with open("output.mp3", "wb") as f:
|
|
296
|
+
f.write(audio_bytes)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### Streaming Text-to-Speech
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
request = SpeakRequest(
|
|
303
|
+
provider_uid="elevenlabs-config",
|
|
304
|
+
model="eleven_turbo_v2",
|
|
305
|
+
text="This is a longer text that will be streamed.",
|
|
306
|
+
voice="rachel",
|
|
307
|
+
mime_type=SpeakMimeType.MP3,
|
|
308
|
+
sample_rate=44100,
|
|
309
|
+
chunk_size=20 # Chunk size in milliseconds
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# Stream audio chunks
|
|
313
|
+
stream = await client.speak_stream(request)
|
|
314
|
+
with open("output.mp3", "wb") as f:
|
|
315
|
+
async for chunk in stream:
|
|
316
|
+
f.write(chunk)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Audio Transcription (Multipart)
|
|
320
|
+
|
|
321
|
+
```python
|
|
322
|
+
# Using multipart upload
|
|
323
|
+
with open("audio.mp3", "rb") as f:
|
|
324
|
+
file_tuple = ("audio.mp3", f.read(), "audio/mpeg")
|
|
325
|
+
|
|
326
|
+
response = await client.transcribe(
|
|
327
|
+
provider_uid="openai-config",
|
|
328
|
+
file=file_tuple,
|
|
329
|
+
model="whisper-1",
|
|
330
|
+
language="en",
|
|
331
|
+
gen_config={"temperature": 0.2}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
print(f"Transcription: {response.text}")
|
|
335
|
+
print(f"Detected language: {response.language}")
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### Audio Transcription (JSON)
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
import base64
|
|
342
|
+
from livellm.models import TranscribeRequest
|
|
343
|
+
|
|
344
|
+
with open("audio.mp3", "rb") as f:
|
|
345
|
+
audio_data = base64.b64encode(f.read()).decode("utf-8")
|
|
346
|
+
|
|
347
|
+
request = TranscribeRequest(
|
|
348
|
+
provider_uid="openai-config",
|
|
349
|
+
model="whisper-1",
|
|
350
|
+
file=("audio.mp3", audio_data, "audio/mpeg"),
|
|
351
|
+
language="en"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
response = await client.transcribe_json(request)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Fallback Strategies
|
|
358
|
+
|
|
359
|
+
#### Sequential Fallback (Try each provider in order)
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from livellm.models import AgentFallbackRequest, FallbackStrategy
|
|
363
|
+
|
|
364
|
+
fallback_request = AgentFallbackRequest(
|
|
365
|
+
requests=[
|
|
366
|
+
AgentRequest(
|
|
367
|
+
provider_uid="primary-provider",
|
|
368
|
+
model="gpt-4",
|
|
369
|
+
messages=[TextMessage(role=MessageRole.USER, content="Hello")],
|
|
370
|
+
tools=[]
|
|
371
|
+
),
|
|
372
|
+
AgentRequest(
|
|
373
|
+
provider_uid="backup-provider",
|
|
374
|
+
model="claude-3",
|
|
375
|
+
messages=[TextMessage(role=MessageRole.USER, content="Hello")],
|
|
376
|
+
tools=[]
|
|
377
|
+
)
|
|
378
|
+
],
|
|
379
|
+
strategy=FallbackStrategy.SEQUENTIAL,
|
|
380
|
+
timeout_per_request=30
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
response = await client.agent_run(fallback_request)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
#### Parallel Fallback (Try all providers simultaneously)
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
fallback_request = AgentFallbackRequest(
|
|
390
|
+
requests=[
|
|
391
|
+
AgentRequest(provider_uid="provider-1", model="gpt-4", messages=messages, tools=[]),
|
|
392
|
+
AgentRequest(provider_uid="provider-2", model="claude-3", messages=messages, tools=[]),
|
|
393
|
+
AgentRequest(provider_uid="provider-3", model="gemini-pro", messages=messages, tools=[])
|
|
394
|
+
],
|
|
395
|
+
strategy=FallbackStrategy.PARALLEL,
|
|
396
|
+
timeout_per_request=10
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
response = await client.agent_run(fallback_request)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### Audio Fallback
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
from livellm.models import AudioFallbackRequest
|
|
406
|
+
|
|
407
|
+
fallback_request = AudioFallbackRequest(
|
|
408
|
+
requests=[
|
|
409
|
+
SpeakRequest(provider_uid="elevenlabs", model="model-1", text=text, voice="voice1",
|
|
410
|
+
mime_type=SpeakMimeType.MP3, sample_rate=44100),
|
|
411
|
+
SpeakRequest(provider_uid="openai", model="tts-1", text=text, voice="alloy",
|
|
412
|
+
mime_type=SpeakMimeType.MP3, sample_rate=44100)
|
|
413
|
+
],
|
|
414
|
+
strategy=FallbackStrategy.SEQUENTIAL
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
audio = await client.speak(fallback_request)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Context Manager Support
|
|
421
|
+
|
|
422
|
+
The client supports async context managers for automatic cleanup:
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
async with LivellmClient(base_url="http://localhost:8000") as client:
|
|
426
|
+
config = Settings(uid="temp-config", provider=ProviderKind.OPENAI,
|
|
427
|
+
api_key=SecretStr("key"))
|
|
428
|
+
await client.update_config(config)
|
|
429
|
+
|
|
430
|
+
# Use client...
|
|
431
|
+
response = await client.ping()
|
|
432
|
+
|
|
433
|
+
# Automatically cleans up configs and closes HTTP client
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Or manually:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
client = LivellmClient(base_url="http://localhost:8000")
|
|
440
|
+
try:
|
|
441
|
+
# Use client...
|
|
442
|
+
pass
|
|
443
|
+
finally:
|
|
444
|
+
await client.cleanup()
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## API Reference
|
|
448
|
+
|
|
449
|
+
### Client Methods
|
|
450
|
+
|
|
451
|
+
#### Health Check
|
|
452
|
+
- `ping() -> SuccessResponse` - Check server health
|
|
453
|
+
|
|
454
|
+
#### Configuration Management
|
|
455
|
+
- `update_config(config: Settings) -> SuccessResponse` - Add/update a provider config
|
|
456
|
+
- `update_configs(configs: List[Settings]) -> SuccessResponse` - Add/update multiple configs
|
|
457
|
+
- `get_configs() -> List[Settings]` - Get all provider configurations
|
|
458
|
+
- `delete_config(config_uid: str) -> SuccessResponse` - Delete a provider config
|
|
459
|
+
|
|
460
|
+
#### Agent Services
|
|
461
|
+
- `agent_run(request: AgentRequest | AgentFallbackRequest) -> AgentResponse` - Run agent query
|
|
462
|
+
- `agent_run_stream(request: AgentRequest | AgentFallbackRequest) -> AsyncIterator[AgentResponse]` - Stream agent response
|
|
463
|
+
|
|
464
|
+
#### Audio Services
|
|
465
|
+
- `speak(request: SpeakRequest | AudioFallbackRequest) -> bytes` - Text-to-speech
|
|
466
|
+
- `speak_stream(request: SpeakRequest | AudioFallbackRequest) -> AsyncIterator[bytes]` - Streaming TTS
|
|
467
|
+
- `transcribe(provider_uid, file, model, language?, gen_config?) -> TranscribeResponse` - Multipart transcription
|
|
468
|
+
- `transcribe_json(request: TranscribeRequest | TranscribeFallbackRequest) -> TranscribeResponse` - JSON transcription
|
|
469
|
+
|
|
470
|
+
#### Cleanup
|
|
471
|
+
- `cleanup() -> None` - Clean up resources and close client
|
|
472
|
+
- `__aenter__() / __aexit__()` - Async context manager support
|
|
473
|
+
|
|
474
|
+
### Models
|
|
475
|
+
|
|
476
|
+
#### Common Models
|
|
477
|
+
- `Settings` - Provider configuration
|
|
478
|
+
- `ProviderKind` - Enum of supported providers
|
|
479
|
+
- `SuccessResponse` - Generic success response
|
|
480
|
+
- `BaseRequest` - Base class for all requests
|
|
481
|
+
|
|
482
|
+
#### Agent Models
|
|
483
|
+
- `AgentRequest` - Agent query request
|
|
484
|
+
- `AgentResponse` - Agent query response
|
|
485
|
+
- `AgentResponseUsage` - Token usage information
|
|
486
|
+
- `TextMessage` - Text-based message
|
|
487
|
+
- `BinaryMessage` - Binary message (images, audio, etc.)
|
|
488
|
+
- `MessageRole` - Enum: USER, MODEL, SYSTEM
|
|
489
|
+
|
|
490
|
+
#### Tool Models
|
|
491
|
+
- `ToolKind` - Enum: WEB_SEARCH, MCP_STREAMABLE_SERVER
|
|
492
|
+
- `WebSearchInput` - Web search tool configuration
|
|
493
|
+
- `MCPStreamableServerInput` - MCP server tool configuration
|
|
494
|
+
|
|
495
|
+
#### Audio Models
|
|
496
|
+
- `SpeakRequest` - Text-to-speech request
|
|
497
|
+
- `SpeakMimeType` - Enum: PCM, WAV, MP3, ULAW, ALAW
|
|
498
|
+
- `TranscribeRequest` - Transcription request
|
|
499
|
+
- `TranscribeResponse` - Transcription response
|
|
500
|
+
|
|
501
|
+
#### Fallback Models
|
|
502
|
+
- `FallbackStrategy` - Enum: SEQUENTIAL, PARALLEL
|
|
503
|
+
- `AgentFallbackRequest` - Agent fallback configuration
|
|
504
|
+
- `AudioFallbackRequest` - Audio fallback configuration
|
|
505
|
+
- `TranscribeFallbackRequest` - Transcription fallback configuration
|
|
506
|
+
|
|
507
|
+
## Error Handling
|
|
508
|
+
|
|
509
|
+
The client raises exceptions for HTTP errors:
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
try:
|
|
513
|
+
response = await client.agent_run(request)
|
|
514
|
+
except Exception as e:
|
|
515
|
+
print(f"Error: {e}")
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
For more granular error handling:
|
|
519
|
+
|
|
520
|
+
```python
|
|
521
|
+
import httpx
|
|
522
|
+
|
|
523
|
+
try:
|
|
524
|
+
response = await client.ping()
|
|
525
|
+
except httpx.HTTPStatusError as e:
|
|
526
|
+
print(f"HTTP error: {e.response.status_code}")
|
|
527
|
+
except httpx.RequestError as e:
|
|
528
|
+
print(f"Request error: {e}")
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Development
|
|
532
|
+
|
|
533
|
+
### Running Tests
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
# Install development dependencies
|
|
537
|
+
pip install -e ".[testing]"
|
|
538
|
+
|
|
539
|
+
# Run tests
|
|
540
|
+
pytest tests/
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Type Checking
|
|
544
|
+
|
|
545
|
+
The library is fully typed. Run type checking with:
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
pip install mypy
|
|
549
|
+
mypy livellm
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## Requirements
|
|
553
|
+
|
|
554
|
+
- Python 3.10+
|
|
555
|
+
- httpx >= 0.27.0
|
|
556
|
+
- pydantic >= 2.0.0
|
|
557
|
+
|
|
558
|
+
## License
|
|
559
|
+
|
|
560
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
561
|
+
|
|
562
|
+
## Contributing
|
|
563
|
+
|
|
564
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
565
|
+
|
|
566
|
+
## Links
|
|
567
|
+
|
|
568
|
+
- [GitHub Repository](https://github.com/qalby-tech/livellm-client-py)
|
|
569
|
+
- [Issue Tracker](https://github.com/qalby-tech/livellm-client-py/issues)
|
|
570
|
+
|
|
571
|
+
## Changelog
|
|
572
|
+
|
|
573
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history and changes.
|