livekit-evals 0.1.1__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
+ MIT License
2
+
3
+ Copyright (c) 2025 SuperBryn
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.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ recursive-include livekit_evals *.py
5
+ recursive-exclude tests *
6
+ recursive-exclude examples *
7
+
@@ -0,0 +1,474 @@
1
+ Metadata-Version: 2.4
2
+ Name: livekit-evals
3
+ Version: 0.1.1
4
+ Summary: Track and evaluate LiveKit agent sessions with automatic metrics, transcripts, and usage analytics
5
+ Author-email: Speechify <support@speechify.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/speechify/livekit-evals
8
+ Project-URL: Documentation, https://github.com/speechify/livekit-evals#readme
9
+ Project-URL: Repository, https://github.com/speechify/livekit-evals
10
+ Project-URL: Issues, https://github.com/speechify/livekit-evals/issues
11
+ Keywords: livekit,agents,analytics,metrics,evaluation,voice-ai
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Communications :: Telephony
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: livekit-agents>=0.8.0
27
+ Requires-Dist: aiohttp>=3.9.0
28
+ Dynamic: license-file
29
+
30
+ # LiveKit Evals
31
+
32
+ [![PyPI version](https://badge.fury.io/py/livekit-evals.svg)](https://badge.fury.io/py/livekit-evals)
33
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
34
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
35
+
36
+ **Track and evaluate your LiveKit voice AI agents with just 3 lines of code.**
37
+
38
+ Automatically capture transcripts, usage metrics, latency data, and session analytics from your LiveKit agents. Perfect for monitoring, debugging, and optimizing your voice AI applications.
39
+
40
+ ## ✨ Features
41
+
42
+ - 🎯 **3-Line Integration** - Add to any LiveKit agent in seconds
43
+ - 📝 **Precise Transcripts** - Accurate timing using VAD state change events
44
+ - 📊 **Usage Metrics** - Track LLM tokens, STT duration, TTS characters
45
+ - ⚡ **Latency Tracking** - Monitor LLM, STT, and TTS performance
46
+ - 🔍 **Auto-Detection** - Automatically extracts models, providers, and configuration
47
+ - 📞 **SIP Support** - Detects SIP trunking and phone numbers
48
+ - 🎥 **Recording URLs** - Captures egress recording links
49
+ - 🔐 **Secure** - API key authentication with webhook delivery
50
+
51
+ ## 🚀 Quick Start
52
+
53
+ ### Prerequisites
54
+
55
+ 1. **Get your API key** from [https://your-platform.com/api-keys](https://your-platform.com/api-keys) *(placeholder)*
56
+ 2. **Set environment variable:**
57
+ ```bash
58
+ export SUPERBRYN_API_KEY=your_api_key_here
59
+ ```
60
+
61
+ ### Installation
62
+
63
+ ```bash
64
+ pip install livekit-evals
65
+ ```
66
+
67
+ ### Integration (3 Lines)
68
+
69
+ Add these lines to your LiveKit agent:
70
+
71
+ ```python
72
+ from livekit_evals import create_webhook_handler
73
+
74
+ async def entrypoint(ctx: JobContext):
75
+ # ... your existing setup code ...
76
+
77
+ # 1. Create webhook handler
78
+ webhook_handler = create_webhook_handler(
79
+ room=ctx.room,
80
+ is_deployed_on_lk_cloud=True # Set to False if self-hosting
81
+ )
82
+
83
+ # ... create your session ...
84
+ session = AgentSession(
85
+ llm=openai.LLM(model="gpt-4o-mini"),
86
+ stt=deepgram.STT(model="nova-3"),
87
+ tts=cartesia.TTS(voice="..."),
88
+ )
89
+
90
+ # ... your session setup ...
91
+ await session.start(agent=YourAgent(), room=ctx.room)
92
+
93
+ # 2. Attach to session (MUST be after session.start, before ctx.connect)
94
+ if webhook_handler:
95
+ webhook_handler.attach_to_session(session)
96
+ # 3. Send webhook on shutdown
97
+ ctx.add_shutdown_callback(webhook_handler.send_webhook)
98
+
99
+ await ctx.connect()
100
+ ```
101
+
102
+ **That's it!** 🎉 Your agent will now automatically track all session data and send it to your webhook endpoint.
103
+
104
+ ## 📖 Full Example
105
+
106
+ Here's a complete working example:
107
+
108
+ ```python
109
+ import logging
110
+ from dotenv import load_dotenv
111
+ from livekit.agents import (
112
+ Agent,
113
+ AgentSession,
114
+ JobContext,
115
+ WorkerOptions,
116
+ cli,
117
+ )
118
+ from livekit.plugins import cartesia, deepgram, openai, silero
119
+
120
+ # Import livekit-evals
121
+ from livekit_evals import create_webhook_handler
122
+
123
+ logger = logging.getLogger("agent")
124
+ load_dotenv()
125
+
126
+
127
+ class Assistant(Agent):
128
+ def __init__(self) -> None:
129
+ super().__init__(
130
+ instructions="""You are a helpful voice AI assistant.
131
+ You eagerly assist users with their questions.""",
132
+ )
133
+
134
+
135
+ async def entrypoint(ctx: JobContext):
136
+ # Logging setup
137
+ ctx.log_context_fields = {"room": ctx.room.name}
138
+
139
+ # Initialize webhook handler (auto-detects all metadata)
140
+ webhook_handler = create_webhook_handler(
141
+ room=ctx.room,
142
+ is_deployed_on_lk_cloud=True # Set to False if self-hosting
143
+ )
144
+
145
+ # Set up voice AI pipeline
146
+ session = AgentSession(
147
+ llm=openai.LLM(model="gpt-4o-mini"),
148
+ stt=deepgram.STT(model="nova-3", language="en"),
149
+ tts=cartesia.TTS(voice="your-voice-id"),
150
+ vad=silero.VAD.load(),
151
+ )
152
+
153
+ # Start the session
154
+ await session.start(agent=Assistant(), room=ctx.room)
155
+
156
+ # Attach webhook handler to capture events
157
+ # IMPORTANT: Must be after session.start() and before ctx.connect()
158
+ if webhook_handler:
159
+ webhook_handler.attach_to_session(session)
160
+ ctx.add_shutdown_callback(webhook_handler.send_webhook)
161
+
162
+ # Connect to room
163
+ await ctx.connect()
164
+
165
+
166
+ if __name__ == "__main__":
167
+ cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
168
+ ```
169
+
170
+ ## 🔧 Configuration
171
+
172
+ ### Environment Variables
173
+
174
+ | Variable | Required | Description | Default |
175
+ |----------|----------|-------------|---------|
176
+ | `SUPERBRYN_API_KEY` | ✅ Yes | API key for webhook authentication | - |
177
+ | `LIVEKIT_PROJECT_ID` | ⚪ Optional | LiveKit project ID | Auto-detected from `LIVEKIT_URL` |
178
+ | `AGENT_ID` | ⚪ Optional | Unique agent identifier | Auto-detected from job metadata or `"livekit-agent"` |
179
+ | `VERSION_ID` | ⚪ Optional | Agent version identifier | Auto-detected from job metadata or `"v1"` |
180
+
181
+ ### Setting Environment Variables
182
+
183
+ **Linux/Mac:**
184
+ ```bash
185
+ export SUPERBRYN_API_KEY=your_api_key_here
186
+ ```
187
+
188
+ **Windows (CMD):**
189
+ ```cmd
190
+ set SUPERBRYN_API_KEY=your_api_key_here
191
+ ```
192
+
193
+ **Windows (PowerShell):**
194
+ ```powershell
195
+ $env:SUPERBRYN_API_KEY="your_api_key_here"
196
+ ```
197
+
198
+ **Docker:**
199
+ ```bash
200
+ docker run -e SUPERBRYN_API_KEY=your_api_key_here ...
201
+ ```
202
+
203
+ **.env file:**
204
+ ```env
205
+ SUPERBRYN_API_KEY=your_api_key_here
206
+ LIVEKIT_PROJECT_ID=my-project-id
207
+ AGENT_ID=my-agent
208
+ VERSION_ID=v1.0.0
209
+ ```
210
+
211
+ ## 📊 What Gets Tracked
212
+
213
+ ### Transcript Data
214
+ - **Precise timing** using VAD state change events
215
+ - Speaker turns (user/assistant)
216
+ - Start/end timestamps (ISO 8601)
217
+ - Start/end times in milliseconds (relative to call start)
218
+ - Response delays between turns
219
+ - Interruption detection
220
+ - Confidence scores (when available)
221
+ - Language detection
222
+ - Speaker IDs
223
+
224
+ ### Usage Metrics
225
+ - **LLM:** Input tokens, output tokens, total tokens, model, provider
226
+ - **STT:** Audio duration, model, provider
227
+ - **TTS:** Character count, audio duration, model, provider, voice ID
228
+
229
+ ### Latency Metrics
230
+ - **LLM:** Time to first token (TTFT), total duration
231
+ - **STT:** Processing duration
232
+ - **TTS:** Time to first byte (TTFB), total duration
233
+ - **Aggregated:** Average latencies per component
234
+
235
+ ### Session Metadata
236
+ - Agent ID and version
237
+ - LiveKit project ID
238
+ - System prompt
239
+ - Call duration
240
+ - Phone number (if SIP call)
241
+ - SIP trunking detection
242
+ - Egress recording URLs
243
+ - LiveKit Cloud deployment status
244
+
245
+ ## 🔍 How It Works
246
+
247
+ 1. **Event Listening:** Attaches to LiveKit session events (`user_state_changed`, `agent_state_changed`, `metrics_collected`, `conversation_item_added`)
248
+ 2. **Data Aggregation:** Collects and processes events during the session
249
+ 3. **Auto-Detection:** Extracts configuration from session objects and job metadata
250
+ 4. **Webhook Delivery:** Sends comprehensive payload to webhook endpoint when session ends
251
+
252
+ ### Webhook Payload Format
253
+
254
+ ```json
255
+ {
256
+ "event": "call.ended",
257
+ "call": {
258
+ "id": "room-name",
259
+ "room_name": "room-name",
260
+ "participant_identity": "user-123",
261
+ "started_at": "2025-10-19T12:00:00.000Z",
262
+ "ended_at": "2025-10-19T12:05:30.000Z",
263
+ "duration_seconds": 330,
264
+ "transcript": {
265
+ "turns": [
266
+ {
267
+ "speaker": "user",
268
+ "text": "Hello, how are you?",
269
+ "timestamp": "2025-10-19T12:00:05.000Z",
270
+ "start_timestamp": "2025-10-19T12:00:05.000Z",
271
+ "end_timestamp": "2025-10-19T12:00:07.000Z",
272
+ "start_time_ms": 5000,
273
+ "end_time_ms": 7000,
274
+ "interrupted": false,
275
+ "confidence_score": 0.98,
276
+ "language": "en"
277
+ },
278
+ {
279
+ "speaker": "assistant",
280
+ "text": "I'm doing great, thanks for asking!",
281
+ "timestamp": "2025-10-19T12:00:08.000Z",
282
+ "start_timestamp": "2025-10-19T12:00:08.000Z",
283
+ "end_timestamp": "2025-10-19T12:00:11.000Z",
284
+ "start_time_ms": 8000,
285
+ "end_time_ms": 11000,
286
+ "response_delay_ms": 1000,
287
+ "interrupted": false
288
+ }
289
+ ]
290
+ },
291
+ "recording_url": "https://...",
292
+ "metadata": {
293
+ "agent_id": "my-agent",
294
+ "livekit_project_id": "my-project",
295
+ "llm_model": "gpt-4o-mini",
296
+ "llm_provider": "openai",
297
+ "stt_model": "nova-3",
298
+ "stt_provider": "deepgram",
299
+ "tts_model": "sonic-english",
300
+ "tts_provider": "cartesia",
301
+ "tts_voice_id": "...",
302
+ "system_prompt": "You are a helpful assistant...",
303
+ "sip_trunking_enabled": false,
304
+ "egress_enabled": true,
305
+ "lk_agent_enabled": true,
306
+ "phone_number": null
307
+ },
308
+ "usage": {
309
+ "llm_model": "gpt-4o-mini",
310
+ "llm_provider": "openai",
311
+ "llm_input_tokens": 1250,
312
+ "llm_output_tokens": 850,
313
+ "llm_total_tokens": 2100,
314
+ "stt_provider": "deepgram",
315
+ "stt_model": "nova-3",
316
+ "stt_duration_seconds": 45.2,
317
+ "audio_duration_seconds": 45.2,
318
+ "tts_provider": "cartesia",
319
+ "tts_model": "sonic-english",
320
+ "tts_characters": 1200,
321
+ "tts_audio_duration_seconds": 42.5
322
+ },
323
+ "latency": {
324
+ "llm_ms": 450.5,
325
+ "stt_ms": 120.3,
326
+ "tts_ms": 180.7,
327
+ "total_ms": 751.5
328
+ }
329
+ }
330
+ }
331
+ ```
332
+
333
+ ## 🛠️ Advanced Usage
334
+
335
+ ### Custom API Key
336
+
337
+ Pass API key directly instead of using environment variable:
338
+
339
+ ```python
340
+ webhook_handler = create_webhook_handler(
341
+ room=ctx.room,
342
+ is_deployed_on_lk_cloud=True,
343
+ api_key="your_api_key_here"
344
+ )
345
+ ```
346
+
347
+ ### Custom LiveKit Project ID
348
+
349
+ ```python
350
+ webhook_handler = create_webhook_handler(
351
+ room=ctx.room,
352
+ is_deployed_on_lk_cloud=True,
353
+ livekit_project_id="my-custom-project-id"
354
+ )
355
+ ```
356
+
357
+ ### Self-Hosted Agents
358
+
359
+ If you're self-hosting your LiveKit agents (not using LiveKit Cloud):
360
+
361
+ ```python
362
+ webhook_handler = create_webhook_handler(
363
+ room=ctx.room,
364
+ is_deployed_on_lk_cloud=False # Important for cost calculation
365
+ )
366
+ ```
367
+
368
+ ### Passing Metadata via Job Context
369
+
370
+ You can pass custom metadata when creating LiveKit jobs:
371
+
372
+ ```python
373
+ # When creating a job
374
+ job_metadata = {
375
+ "agent_id": "customer-support-bot",
376
+ "version_id": "v2.1.0",
377
+ "phone_number": "+1234567890"
378
+ }
379
+ ```
380
+
381
+ The webhook handler will automatically extract these values.
382
+
383
+ ## 🐛 Troubleshooting
384
+
385
+ ### Webhook Not Sending
386
+
387
+ **Check API Key:**
388
+ ```bash
389
+ echo $SUPERBRYN_API_KEY
390
+ ```
391
+
392
+ **Enable Debug Logging:**
393
+ ```python
394
+ import logging
395
+ logging.basicConfig(level=logging.DEBUG)
396
+ ```
397
+
398
+ **Look for these log messages:**
399
+ - `SPEECHIFY_WEBHOOK_HANDLER_CREATED` - Handler initialized
400
+ - `SPEECHIFY_WEBHOOK_SENT` - Webhook delivered successfully
401
+ - `SPEECHIFY_WEBHOOK_UNAUTHORIZED` - Invalid API key
402
+ - `SPEECHIFY_WEBHOOK_FAILED` - Delivery failed
403
+ - `SPEECHIFY_WEBHOOK_ERROR` - Exception occurred
404
+
405
+ ### Common Errors
406
+
407
+ | Error | Cause | Solution |
408
+ |-------|-------|----------|
409
+ | `SUPERBRYN_API_KEY not configured` | Missing API key | Set `SUPERBRYN_API_KEY` environment variable |
410
+ | `SPEECHIFY_WEBHOOK_UNAUTHORIZED` | Invalid API key | Verify your API key is correct |
411
+ | `SPEECHIFY_WEBHOOK_FORBIDDEN` | Expired/disabled key | Generate a new API key |
412
+ | `No empty turn found to fill` | State change timing issue | Usually harmless, check logs for patterns |
413
+
414
+ ### Missing Transcript Data
415
+
416
+ Ensure `webhook_handler.attach_to_session(session)` is called:
417
+ - ✅ **After** `await session.start()`
418
+ - ✅ **Before** `await ctx.connect()`
419
+ - ✅ At the **end** of your entrypoint (no early returns)
420
+
421
+ ### Provider Detection Issues
422
+
423
+ The package auto-detects providers from model names. Supported providers:
424
+ - OpenAI (gpt, whisper, tts-1)
425
+ - Anthropic (claude)
426
+ - Google (gemini, palm)
427
+ - Sarvam (saarika)
428
+ - ElevenLabs (eleven)
429
+ - Cartesia (cartesia, sonic)
430
+ - Deepgram (deepgram, nova)
431
+
432
+ If your provider isn't detected, it will show as `"unknown"` but won't affect functionality.
433
+
434
+ ## 📝 Migration Guide
435
+
436
+ If you're currently using the standalone `webhook_handler.py`:
437
+
438
+ **Before:**
439
+ ```python
440
+ from webhook_handler import create_webhook_handler
441
+ ```
442
+
443
+ **After:**
444
+ ```python
445
+ from livekit_evals import create_webhook_handler
446
+ ```
447
+
448
+ Everything else stays the same! The API is identical.
449
+
450
+ ## 🤝 Contributing
451
+
452
+ Contributions are welcome! Please feel free to submit a Pull Request.
453
+
454
+ ## 📄 License
455
+
456
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
457
+
458
+ ## 🔗 Links
459
+
460
+ - [LiveKit Agents Documentation](https://docs.livekit.io/agents/)
461
+ - [GitHub Repository](https://github.com/speechify/livekit-evals)
462
+ - [Issue Tracker](https://github.com/speechify/livekit-evals/issues)
463
+ - [Get API Key](https://your-platform.com/api-keys) *(placeholder)*
464
+
465
+ ## 💡 Support
466
+
467
+ - 📧 Email: support@speechify.com
468
+ - 💬 GitHub Issues: [Report a bug](https://github.com/speechify/livekit-evals/issues)
469
+ - 📚 Documentation: [README](https://github.com/speechify/livekit-evals#readme)
470
+
471
+ ---
472
+
473
+ Made with ❤️ by [Speechify](https://speechify.com)
474
+