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.
@@ -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
+ [![PyPI version](https://badge.fury.io/py/anam-ai.svg)](https://badge.fury.io/py/anam-ai)
47
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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)