anam 0.0.1a1__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.
- anam-0.0.1a1/.gitignore +21 -0
- anam-0.0.1a1/LICENSE +21 -0
- anam-0.0.1a1/PKG-INFO +357 -0
- anam-0.0.1a1/README.md +316 -0
- anam-0.0.1a1/pyproject.toml +112 -0
- anam-0.0.1a1/src/anam/__init__.py +88 -0
- anam-0.0.1a1/src/anam/_agent_audio_input_stream.py +103 -0
- anam-0.0.1a1/src/anam/_api.py +206 -0
- anam-0.0.1a1/src/anam/_signalling.py +390 -0
- anam-0.0.1a1/src/anam/_streaming.py +664 -0
- anam-0.0.1a1/src/anam/_version.py +3 -0
- anam-0.0.1a1/src/anam/client.py +594 -0
- anam-0.0.1a1/src/anam/errors.py +80 -0
- anam-0.0.1a1/src/anam/py.typed +0 -0
- anam-0.0.1a1/src/anam/types.py +200 -0
anam-0.0.1a1/.gitignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.conda*
|
|
3
|
+
poetry.lock
|
|
4
|
+
__pycache__
|
|
5
|
+
|
|
6
|
+
# Apple
|
|
7
|
+
.DS_Store
|
|
8
|
+
|
|
9
|
+
# Environments
|
|
10
|
+
.env.*
|
|
11
|
+
.env
|
|
12
|
+
|
|
13
|
+
# Code in non-ready-state
|
|
14
|
+
anam_python_sdk/scratch/*
|
|
15
|
+
anam_python_sdk/scratch
|
|
16
|
+
|
|
17
|
+
# Builds
|
|
18
|
+
/dist*
|
|
19
|
+
|
|
20
|
+
# Example outputs
|
|
21
|
+
recordings/
|
anam-0.0.1a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024–2026, Anam AI
|
|
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.
|
anam-0.0.1a1/PKG-INFO
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anam
|
|
3
|
+
Version: 0.0.1a1
|
|
4
|
+
Summary: Official Python SDK for Anam AI - Real-time AI avatar streaming
|
|
5
|
+
Project-URL: Homepage, https://www.anam.ai
|
|
6
|
+
Project-URL: Documentation, https://docs.anam.ai
|
|
7
|
+
Project-URL: Repository, https://github.com/anam-org/python-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/anam-org/python-sdk/issues
|
|
9
|
+
Author-email: Anam AI <support@anam.ai>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,anam,avatar,real-time,streaming,webrtc
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Communications
|
|
22
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
23
|
+
Classifier: Topic :: Multimedia :: Video
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
28
|
+
Requires-Dist: aiortc>=1.14.0
|
|
29
|
+
Requires-Dist: numpy>=1.26.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
31
|
+
Requires-Dist: websockets>=12.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
37
|
+
Provides-Extra: display
|
|
38
|
+
Requires-Dist: opencv-python>=4.9.0; extra == 'display'
|
|
39
|
+
Requires-Dist: sounddevice>=0.4.6; extra == 'display'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# Anam AI Python SDK
|
|
43
|
+
|
|
44
|
+
Official Python SDK for [Anam AI](https://anam.ai) - Real-time AI avatar streaming.
|
|
45
|
+
|
|
46
|
+
[](https://badge.fury.io/py/anam-ai)
|
|
47
|
+
[](https://www.python.org/downloads/)
|
|
48
|
+
[](https://opensource.org/licenses/MIT)
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Using uv (recommended)
|
|
54
|
+
uv add anam-ai
|
|
55
|
+
|
|
56
|
+
# With optional display utilities (for testing)
|
|
57
|
+
uv add anam-ai --extra display
|
|
58
|
+
|
|
59
|
+
# Using pip
|
|
60
|
+
pip install anam-ai
|
|
61
|
+
|
|
62
|
+
# With optional display utilities (for testing)
|
|
63
|
+
pip install anam-ai[display]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import asyncio
|
|
70
|
+
from anam import AnamClient
|
|
71
|
+
from av.video.frame import VideoFrame
|
|
72
|
+
from av.audio.frame import AudioFrame
|
|
73
|
+
|
|
74
|
+
async def main():
|
|
75
|
+
# Create client with your API key and persona
|
|
76
|
+
client = AnamClient(
|
|
77
|
+
api_key="your-api-key",
|
|
78
|
+
persona_id="your-persona-id",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Connect and stream
|
|
82
|
+
async with client.connect() as session:
|
|
83
|
+
print(f"Connected! Session: {session.session_id}")
|
|
84
|
+
|
|
85
|
+
# Consume video and audio frames concurrently
|
|
86
|
+
async def consume_video():
|
|
87
|
+
async for frame in session.video_frames():
|
|
88
|
+
img = frame.to_ndarray(format="rgb24") # numpy array (H, W, 3) in RGB format - use "bgr24" for OpenCV
|
|
89
|
+
print(f"Video: {frame.width}x{frame.height}")
|
|
90
|
+
|
|
91
|
+
async def consume_audio():
|
|
92
|
+
async for frame in session.audio_frames():
|
|
93
|
+
samples = frame.to_ndarray() # int16 samples (1D array, interleaved for stereo)
|
|
94
|
+
# Determine mono/stereo from frame layout
|
|
95
|
+
channel_type = "mono" if frame.layout.nb_channels == 1 else "stereo"
|
|
96
|
+
print(f"Audio: {samples.size} samples ({channel_type}) @ {frame.sample_rate}Hz")
|
|
97
|
+
|
|
98
|
+
# Run both streams concurrently until session closes
|
|
99
|
+
await asyncio.gather(
|
|
100
|
+
consume_video(),
|
|
101
|
+
consume_audio(),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
asyncio.run(main())
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Features
|
|
108
|
+
|
|
109
|
+
- 🎥 **Real-time Audio/Video streaming** - Receive synchronized audio/video frames from the avatar (as PyAV AudioFrame/VideoFrame objects)
|
|
110
|
+
- 💬 **Two-way communication** - Send text messages (like transcribed user speech) and receive generated responses
|
|
111
|
+
- 🎤 **Audio-passthrough** - Send TTS generated audio input and receive rendered synchronized audio/video avatar
|
|
112
|
+
- 🗣️ **Direct text-to-speech** - Send text directly to TTS for immediate speech output (bypasses LLM processing)
|
|
113
|
+
- 🎯 **Async iterator API** - Clean, Pythonic async/await patterns for continuous stream of audio/video frames
|
|
114
|
+
- 🎯 **Event-driven API** - Simple decorator-based event handlers for discrete events
|
|
115
|
+
- 📝 **Fully typed** - Complete type hints for IDE support
|
|
116
|
+
- 🔒 **Server-side ready** - Designed for server-side Python applications (e.g. for use in a web application)
|
|
117
|
+
|
|
118
|
+
## API Reference
|
|
119
|
+
|
|
120
|
+
### AnamClient
|
|
121
|
+
|
|
122
|
+
The main client class for connecting to Anam AI.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from anam import AnamClient, PersonaConfig, ClientOptions
|
|
126
|
+
|
|
127
|
+
# Simple initialization
|
|
128
|
+
client = AnamClient(
|
|
129
|
+
api_key="your-api-key",
|
|
130
|
+
persona_id="your-persona-id",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Advanced initialization with full persona config
|
|
134
|
+
client = AnamClient(
|
|
135
|
+
api_key="your-api-key",
|
|
136
|
+
persona_config=PersonaConfig(
|
|
137
|
+
persona_id="your-persona-id",
|
|
138
|
+
name="My Assistant",
|
|
139
|
+
system_prompt="You are a helpful assistant...",
|
|
140
|
+
voice_id="emma",
|
|
141
|
+
language_code="en",
|
|
142
|
+
),
|
|
143
|
+
options=ClientOptions(
|
|
144
|
+
disable_input_audio=True, # Don't capture microphone
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Video and Audio Frames
|
|
150
|
+
|
|
151
|
+
Frames are **PyAV objects** (VideoFrame/AudioFrame) containing synchronized **decoded audio (PCM) and video (RGB) samples** from the avatar, delivered over WebRTC and extracted by aiortc. All PyAV frame attributes are accessible (samples, format, layout, etc.). Access the frames via **async iterators** and **run both iterators concurrently**, e.g. using `asyncio.gather()`:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
async with client.connect() as session:
|
|
155
|
+
async def process_video():
|
|
156
|
+
async for frame in session.video_frames():
|
|
157
|
+
img = frame.to_ndarray(format="rgb24") # RGB numpy array
|
|
158
|
+
# Process frame...
|
|
159
|
+
|
|
160
|
+
async def process_audio():
|
|
161
|
+
async for frame in session.audio_frames():
|
|
162
|
+
samples = frame.to_ndarray() # int16 samples
|
|
163
|
+
# Process frame...
|
|
164
|
+
|
|
165
|
+
# Both streams run concurrently
|
|
166
|
+
await asyncio.gather(process_video(), process_audio())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Events
|
|
170
|
+
|
|
171
|
+
Register callbacks for connection and message events using the `@client.on()` decorator:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from anam import AnamEvent
|
|
175
|
+
|
|
176
|
+
@client.on(AnamEvent.MESSAGE_RECEIVED)
|
|
177
|
+
async def on_message(message: Message):
|
|
178
|
+
"""Called when a chat message is received."""
|
|
179
|
+
print(f"{message.role}: {message.content}")
|
|
180
|
+
|
|
181
|
+
@client.on(AnamEvent.CONNECTION_ESTABLISHED)
|
|
182
|
+
async def on_connected():
|
|
183
|
+
"""Called when the connection is established."""
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
@client.on(AnamEvent.CONNECTION_CLOSED)
|
|
187
|
+
async def on_closed(code: str, reason: str | None):
|
|
188
|
+
"""Called when the connection is closed."""
|
|
189
|
+
pass
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Session
|
|
193
|
+
|
|
194
|
+
The `Session` object is returned by `client.connect()` and provides methods for interacting with the avatar:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
async with client.connect() as session:
|
|
198
|
+
# Send a text message (simulates user speech)
|
|
199
|
+
await session.send_message("Hello, how are you?")
|
|
200
|
+
|
|
201
|
+
# Interrupt the avatar if speaking
|
|
202
|
+
await session.interrupt()
|
|
203
|
+
|
|
204
|
+
# Wait until the session ends
|
|
205
|
+
await session.wait_until_closed()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
## Examples
|
|
211
|
+
|
|
212
|
+
### Save Video and Audio
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
import cv2
|
|
216
|
+
import wave
|
|
217
|
+
import asyncio
|
|
218
|
+
from anam import AnamClient
|
|
219
|
+
|
|
220
|
+
client = AnamClient(api_key="...", persona_id="...")
|
|
221
|
+
|
|
222
|
+
video_writer = cv2.VideoWriter("output.mp4", ...)
|
|
223
|
+
audio_writer = wave.open("output.wav", "wb")
|
|
224
|
+
|
|
225
|
+
async def save_video(session):
|
|
226
|
+
async for frame in session.video_frames():
|
|
227
|
+
# Read frame as BGR for OpenCV VideoWriter
|
|
228
|
+
bgr_frame = frame.to_ndarray(format="bgr24")
|
|
229
|
+
video_writer.write(bgr_frame)
|
|
230
|
+
|
|
231
|
+
async def save_audio(session):
|
|
232
|
+
async for frame in session.audio_frames():
|
|
233
|
+
# Initialize writer on first frame
|
|
234
|
+
if audio_writer.getnframes() == 0:
|
|
235
|
+
audio_writer.setnchannels(frame.layout.nb_channels)
|
|
236
|
+
audio_writer.setsampwidth(2) # 16-bit
|
|
237
|
+
audio_writer.setframerate(frame.sample_rate)
|
|
238
|
+
# Write audio data (convert to int16 and get bytes)
|
|
239
|
+
audio_writer.writeframes(frame.to_ndarray().tobytes())
|
|
240
|
+
|
|
241
|
+
async with client.connect() as session:
|
|
242
|
+
# Record for 30 seconds
|
|
243
|
+
await asyncio.wait_for(
|
|
244
|
+
asyncio.gather(save_video(session), save_audio(session)),
|
|
245
|
+
timeout=30.0,
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Display Video with OpenCV
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
import cv2
|
|
253
|
+
import asyncio
|
|
254
|
+
from anam import AnamClient
|
|
255
|
+
|
|
256
|
+
client = AnamClient(api_key="...", persona_id="...")
|
|
257
|
+
latest_frame = None
|
|
258
|
+
|
|
259
|
+
async def update_frame(session):
|
|
260
|
+
global latest_frame
|
|
261
|
+
async for frame in session.video_frames():
|
|
262
|
+
# Read frame as BGR for OpenCV display
|
|
263
|
+
latest_frame = frame.to_ndarray(format="bgr24")
|
|
264
|
+
|
|
265
|
+
async def main():
|
|
266
|
+
async with client.connect() as session:
|
|
267
|
+
# Start frame consumer
|
|
268
|
+
frame_task = asyncio.create_task(update_frame(session))
|
|
269
|
+
|
|
270
|
+
# Display loop
|
|
271
|
+
while True:
|
|
272
|
+
if latest_frame is not None:
|
|
273
|
+
cv2.imshow("Avatar", latest_frame)
|
|
274
|
+
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
275
|
+
break
|
|
276
|
+
frame_task.cancel()
|
|
277
|
+
|
|
278
|
+
asyncio.run(main())
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Configuration
|
|
282
|
+
|
|
283
|
+
### Environment Variables
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
export ANAM_API_KEY="your-api-key"
|
|
287
|
+
export ANAM_PERSONA_ID="your-persona-id"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Client Options
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from anam import ClientOptions
|
|
294
|
+
|
|
295
|
+
options = ClientOptions(
|
|
296
|
+
api_base_url="https://api.anam.ai", # API base URL
|
|
297
|
+
api_version="v1", # API version
|
|
298
|
+
disable_input_audio=False, # Disable microphone input
|
|
299
|
+
ice_servers=None, # Custom ICE servers
|
|
300
|
+
)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Persona Configuration
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
from anam import PersonaConfig
|
|
307
|
+
|
|
308
|
+
persona = PersonaConfig(
|
|
309
|
+
persona_id="your-persona-id", # Required
|
|
310
|
+
name="Assistant", # Display name
|
|
311
|
+
avatar_id="anna_v2", # Avatar to use
|
|
312
|
+
voice_id="emma", # Voice to use
|
|
313
|
+
system_prompt="You are...", # Custom system prompt
|
|
314
|
+
language_code="en", # Language code
|
|
315
|
+
llm_id="gpt-4", # LLM model
|
|
316
|
+
max_session_length_seconds=300, # Max session duration
|
|
317
|
+
)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Error Handling
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
from anam import AnamError, AuthenticationError, SessionError
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
async with client.connect() as session:
|
|
327
|
+
await session.wait_until_closed()
|
|
328
|
+
except AuthenticationError as e:
|
|
329
|
+
print(f"Invalid API key: {e}")
|
|
330
|
+
except SessionError as e:
|
|
331
|
+
print(f"Session error: {e}")
|
|
332
|
+
except AnamError as e:
|
|
333
|
+
print(f"Anam error [{e.code}]: {e.message}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Requirements
|
|
337
|
+
|
|
338
|
+
- Python 3.10+
|
|
339
|
+
- Dependencies are installed automatically:
|
|
340
|
+
- `aiortc` - WebRTC implementation
|
|
341
|
+
- `aiohttp` - HTTP client
|
|
342
|
+
- `websockets` - WebSocket client
|
|
343
|
+
- `numpy` - Array handling
|
|
344
|
+
|
|
345
|
+
Optional for display utilities:
|
|
346
|
+
- `opencv-python` - Video display
|
|
347
|
+
- `sounddevice` - Audio playback
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
352
|
+
|
|
353
|
+
## Links
|
|
354
|
+
|
|
355
|
+
- [Anam AI Website](https://anam.ai)
|
|
356
|
+
- [Documentation](https://docs.anam.ai)
|
|
357
|
+
- [API Reference](https://docs.anam.ai/api-reference)
|