zooid 0.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.
- zooid-0.1.0/.gitignore +61 -0
- zooid-0.1.0/LICENSE +21 -0
- zooid-0.1.0/PKG-INFO +164 -0
- zooid-0.1.0/README.md +123 -0
- zooid-0.1.0/dashboards/trust_center_dashboard.json +102 -0
- zooid-0.1.0/dashboards/voice_agent_dashboard.json +114 -0
- zooid-0.1.0/examples/basic_voice_agent.py +64 -0
- zooid-0.1.0/examples/docker-compose.yml +14 -0
- zooid-0.1.0/examples/pipecat_agent.py +28 -0
- zooid-0.1.0/pyproject.toml +62 -0
- zooid-0.1.0/skills/zooid-instrumentation/SKILL.md +180 -0
- zooid-0.1.0/src/zooid/__init__.py +25 -0
- zooid-0.1.0/src/zooid/_version.py +1 -0
- zooid-0.1.0/src/zooid/context.py +218 -0
- zooid-0.1.0/src/zooid/exporters/__init__.py +1 -0
- zooid-0.1.0/src/zooid/exporters/signoz.py +49 -0
- zooid-0.1.0/src/zooid/instrumentor.py +150 -0
- zooid-0.1.0/src/zooid/metrics.py +108 -0
- zooid-0.1.0/src/zooid/scaffold/__init__.py +6 -0
- zooid-0.1.0/src/zooid/scaffold/cli.py +94 -0
- zooid-0.1.0/src/zooid/scaffold/generator.py +69 -0
- zooid-0.1.0/src/zooid/scaffold/templates/__init__.py +1 -0
- zooid-0.1.0/src/zooid/scaffold/templates/agent.py +262 -0
- zooid-0.1.0/src/zooid/scaffold/templates/common.py +95 -0
- zooid-0.1.0/src/zooid/scaffold/templates/frameworks.py +123 -0
- zooid-0.1.0/src/zooid/scaffold/templates/project.py +362 -0
- zooid-0.1.0/src/zooid/trust/__init__.py +27 -0
- zooid-0.1.0/src/zooid/trust/aggregator.py +64 -0
- zooid-0.1.0/src/zooid/trust/ai_advisor.py +64 -0
- zooid-0.1.0/src/zooid/trust/context_writer.py +115 -0
- zooid-0.1.0/src/zooid/trust/mcp_server.py +163 -0
- zooid-0.1.0/src/zooid/trust/recommendations.py +71 -0
- zooid-0.1.0/src/zooid/trust/reporter.py +40 -0
- zooid-0.1.0/src/zooid/trust/rules/__init__.py +9 -0
- zooid-0.1.0/src/zooid/trust/rules/base.py +61 -0
- zooid-0.1.0/src/zooid/trust/rules/naming_rules.py +58 -0
- zooid-0.1.0/src/zooid/trust/rules/resource_rules.py +86 -0
- zooid-0.1.0/src/zooid/trust/rules/span_rules.py +125 -0
- zooid-0.1.0/src/zooid/trust/rules/voice_rules.py +50 -0
- zooid-0.1.0/src/zooid/trust/scorer.py +87 -0
- zooid-0.1.0/src/zooid/wrappers/__init__.py +14 -0
- zooid-0.1.0/src/zooid/wrappers/base_wrapper.py +68 -0
- zooid-0.1.0/src/zooid/wrappers/deepgram_wrapper.py +121 -0
- zooid-0.1.0/src/zooid/wrappers/elevenlabs_wrapper.py +125 -0
- zooid-0.1.0/src/zooid/wrappers/openai_wrapper.py +180 -0
- zooid-0.1.0/tests/test_mcp_context.py +140 -0
- zooid-0.1.0/tests/test_scaffold.py +381 -0
zooid-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
.coverage
|
|
26
|
+
htmlcov/
|
|
27
|
+
.venv
|
|
28
|
+
venv/
|
|
29
|
+
ENV/
|
|
30
|
+
env/
|
|
31
|
+
|
|
32
|
+
# Node / Web
|
|
33
|
+
node_modules/
|
|
34
|
+
web/node_modules/
|
|
35
|
+
web/dist/
|
|
36
|
+
web/.vite/
|
|
37
|
+
.npm
|
|
38
|
+
*.log
|
|
39
|
+
|
|
40
|
+
# Web source dir — not the Python "lib/" build artifact excluded above
|
|
41
|
+
!web/src/lib/
|
|
42
|
+
!web/src/lib/**
|
|
43
|
+
|
|
44
|
+
# IDE & OS
|
|
45
|
+
.DS_Store
|
|
46
|
+
Thumbs.db
|
|
47
|
+
.vscode/
|
|
48
|
+
.idea/
|
|
49
|
+
*.swp
|
|
50
|
+
|
|
51
|
+
# Docker / Local logs
|
|
52
|
+
*.log
|
|
53
|
+
docker/*.log
|
|
54
|
+
docker/.bin/
|
|
55
|
+
docker/pours/
|
|
56
|
+
docker/casting.yaml.lock
|
|
57
|
+
|
|
58
|
+
# Secrets — never commit real API keys
|
|
59
|
+
.env
|
|
60
|
+
server/.env
|
|
61
|
+
!server/.env.example
|
zooid-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zooid Team
|
|
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.
|
zooid-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zooid
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zero-code OpenTelemetry auto-instrumentation for Voice AI pipelines & Telemetry Trust Center
|
|
5
|
+
Project-URL: Homepage, https://github.com/Priyank911/zooid
|
|
6
|
+
Project-URL: Repository, https://github.com/Priyank911/zooid
|
|
7
|
+
Author-email: Zooid Team <zooid@signoz.io>
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: llm,opentelemetry,signoz,speech-to-text,text-to-speech,voice
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: opentelemetry-api>=1.20.0
|
|
19
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0
|
|
20
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
21
|
+
Requires-Dist: wrapt>=1.14.0
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: deepgram-sdk>=3.0.0; extra == 'all'
|
|
24
|
+
Requires-Dist: elevenlabs>=0.2.0; extra == 'all'
|
|
25
|
+
Requires-Dist: mcp>=1.0.0; extra == 'all'
|
|
26
|
+
Requires-Dist: openai>=1.0.0; extra == 'all'
|
|
27
|
+
Provides-Extra: deepgram
|
|
28
|
+
Requires-Dist: deepgram-sdk>=3.0.0; extra == 'deepgram'
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: mcp>=1.0.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
34
|
+
Provides-Extra: elevenlabs
|
|
35
|
+
Requires-Dist: elevenlabs>=0.2.0; extra == 'elevenlabs'
|
|
36
|
+
Provides-Extra: mcp
|
|
37
|
+
Requires-Dist: mcp>=1.0.0; extra == 'mcp'
|
|
38
|
+
Provides-Extra: openai
|
|
39
|
+
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# zooid
|
|
43
|
+
|
|
44
|
+
`zooid` provides OpenTelemetry auto-instrumentation and SDK helpers specifically engineered for conversational Voice AI applications (such as speech-to-speech agents, streaming LLM cascades, and voice bots) along with Telemetry Trust Center scoring for **SigNoz**.
|
|
45
|
+
|
|
46
|
+
It helps you track critical voice metrics like Time-To-First-Audio (TTFA), token stream latencies, interruptions, and multi-stage (STT -> LLM -> TTS) timing boundaries.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install zooid
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For local development within this workspace:
|
|
57
|
+
```bash
|
|
58
|
+
pip install -e .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
### 1. Initialize Instrumentation
|
|
66
|
+
|
|
67
|
+
Initialize OpenTelemetry providers and the Telemetry Trust Center at your application entry point:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from zooid import instrument_voice_app
|
|
71
|
+
|
|
72
|
+
handle = instrument_voice_app(
|
|
73
|
+
service_name="voice-assistant-service",
|
|
74
|
+
signoz_endpoint="localhost:4317",
|
|
75
|
+
insecure=True,
|
|
76
|
+
enable_trust_center=True
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2. Trace Voice Turns
|
|
81
|
+
|
|
82
|
+
Wrap your conversational turns using the async context manager or decorator:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import asyncio
|
|
86
|
+
from zooid import VoiceTurnContext, voice_turn
|
|
87
|
+
|
|
88
|
+
# Option A: Async Context Manager (Recommended)
|
|
89
|
+
async def process_turn(audio_stream):
|
|
90
|
+
async with VoiceTurnContext(architecture_mode="cascade") as turn:
|
|
91
|
+
# 1. Speech-to-Text
|
|
92
|
+
text = await process_stt(audio_stream)
|
|
93
|
+
turn.mark_stt_complete()
|
|
94
|
+
|
|
95
|
+
# 2. LLM Streaming
|
|
96
|
+
async for chunk in stream_llm(text):
|
|
97
|
+
if turn.llm_first_token_ms is None:
|
|
98
|
+
turn.mark_llm_first_token()
|
|
99
|
+
|
|
100
|
+
# 3. Text-to-Speech Output
|
|
101
|
+
audio_out = await generate_tts(chunk)
|
|
102
|
+
turn.mark_first_audio() # Captures TTFA metric
|
|
103
|
+
|
|
104
|
+
# Option B: Decorator
|
|
105
|
+
@voice_turn(architecture_mode="hybrid")
|
|
106
|
+
async def handle_turn(input_data):
|
|
107
|
+
current_turn = VoiceTurnContext.get_current()
|
|
108
|
+
# Execute turn logic...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Core Features
|
|
114
|
+
|
|
115
|
+
- **Automatic TTFA Tracking:** Dedicated timing hooks to accurately record Time-To-First-Audio.
|
|
116
|
+
- **Stage Latency Isolation:** Measure STT duration, LLM Time-To-First-Token (TTFT), and TTS generation independently.
|
|
117
|
+
- **Telemetry Trust Center:** Live span quality evaluation calculating a score (0-100) with critical violation detection.
|
|
118
|
+
- **Asyncio Context Propagation:** Preserves OpenTelemetry trace context across `asyncio.create_task()` background loops.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## API Reference
|
|
123
|
+
|
|
124
|
+
### `instrument_voice_app(...)`
|
|
125
|
+
Initializes OpenTelemetry Tracer and Meter Providers configured for SigNoz OTLP gRPC export.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def instrument_voice_app(
|
|
129
|
+
service_name: str = 'voice-agent',
|
|
130
|
+
signoz_endpoint: str = 'localhost:4317',
|
|
131
|
+
insecure: bool = True,
|
|
132
|
+
enable_trust_center: bool = True,
|
|
133
|
+
trust_center_mode: str = 'template',
|
|
134
|
+
llm_endpoint: Optional[str] = None,
|
|
135
|
+
export_interval_ms: int = 5000
|
|
136
|
+
) -> InstrumentationHandle
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `VoiceTurnContext`
|
|
140
|
+
Context manager for tracking voice turn timing and metrics.
|
|
141
|
+
|
|
142
|
+
- `VoiceTurnContext.get_current()`: Returns the active `VoiceTurnContext` instance for the current `asyncio` context.
|
|
143
|
+
- `turn.mark_stt_complete()`: Marks STT processing completion and records STT duration.
|
|
144
|
+
- `turn.mark_llm_first_token()`: Marks the arrival of the first LLM token stream chunk.
|
|
145
|
+
- `turn.mark_first_audio()`: Marks the output of the first synthesized audio chunk and exports the TTFA metric.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Metrics Reference
|
|
150
|
+
|
|
151
|
+
| Metric Name | Type | Unit | Description |
|
|
152
|
+
|---|---|---|---|
|
|
153
|
+
| `voice.time_to_first_audio_ms` | Histogram | ms | Time from user turn start to first synthesized audio |
|
|
154
|
+
| `voice.stt_duration_ms` | Histogram | ms | Speech-To-Text processing duration |
|
|
155
|
+
| `voice.llm_first_token_ms` | Histogram | ms | LLM Time-To-First-Token latency |
|
|
156
|
+
| `voice.turns_total` | Counter | 1 | Total number of conversational turns processed |
|
|
157
|
+
| `voice.interruptions_total` | Counter | 1 | Total number of user interruptions recorded |
|
|
158
|
+
| `instrumentation.score` | Gauge | 1 | Telemetry quality score (0-100) evaluated by Trust Center |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
Apache License 2.0
|
zooid-0.1.0/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# zooid
|
|
2
|
+
|
|
3
|
+
`zooid` provides OpenTelemetry auto-instrumentation and SDK helpers specifically engineered for conversational Voice AI applications (such as speech-to-speech agents, streaming LLM cascades, and voice bots) along with Telemetry Trust Center scoring for **SigNoz**.
|
|
4
|
+
|
|
5
|
+
It helps you track critical voice metrics like Time-To-First-Audio (TTFA), token stream latencies, interruptions, and multi-stage (STT -> LLM -> TTS) timing boundaries.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install zooid
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For local development within this workspace:
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Initialize Instrumentation
|
|
25
|
+
|
|
26
|
+
Initialize OpenTelemetry providers and the Telemetry Trust Center at your application entry point:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from zooid import instrument_voice_app
|
|
30
|
+
|
|
31
|
+
handle = instrument_voice_app(
|
|
32
|
+
service_name="voice-assistant-service",
|
|
33
|
+
signoz_endpoint="localhost:4317",
|
|
34
|
+
insecure=True,
|
|
35
|
+
enable_trust_center=True
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Trace Voice Turns
|
|
40
|
+
|
|
41
|
+
Wrap your conversational turns using the async context manager or decorator:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import asyncio
|
|
45
|
+
from zooid import VoiceTurnContext, voice_turn
|
|
46
|
+
|
|
47
|
+
# Option A: Async Context Manager (Recommended)
|
|
48
|
+
async def process_turn(audio_stream):
|
|
49
|
+
async with VoiceTurnContext(architecture_mode="cascade") as turn:
|
|
50
|
+
# 1. Speech-to-Text
|
|
51
|
+
text = await process_stt(audio_stream)
|
|
52
|
+
turn.mark_stt_complete()
|
|
53
|
+
|
|
54
|
+
# 2. LLM Streaming
|
|
55
|
+
async for chunk in stream_llm(text):
|
|
56
|
+
if turn.llm_first_token_ms is None:
|
|
57
|
+
turn.mark_llm_first_token()
|
|
58
|
+
|
|
59
|
+
# 3. Text-to-Speech Output
|
|
60
|
+
audio_out = await generate_tts(chunk)
|
|
61
|
+
turn.mark_first_audio() # Captures TTFA metric
|
|
62
|
+
|
|
63
|
+
# Option B: Decorator
|
|
64
|
+
@voice_turn(architecture_mode="hybrid")
|
|
65
|
+
async def handle_turn(input_data):
|
|
66
|
+
current_turn = VoiceTurnContext.get_current()
|
|
67
|
+
# Execute turn logic...
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Core Features
|
|
73
|
+
|
|
74
|
+
- **Automatic TTFA Tracking:** Dedicated timing hooks to accurately record Time-To-First-Audio.
|
|
75
|
+
- **Stage Latency Isolation:** Measure STT duration, LLM Time-To-First-Token (TTFT), and TTS generation independently.
|
|
76
|
+
- **Telemetry Trust Center:** Live span quality evaluation calculating a score (0-100) with critical violation detection.
|
|
77
|
+
- **Asyncio Context Propagation:** Preserves OpenTelemetry trace context across `asyncio.create_task()` background loops.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## API Reference
|
|
82
|
+
|
|
83
|
+
### `instrument_voice_app(...)`
|
|
84
|
+
Initializes OpenTelemetry Tracer and Meter Providers configured for SigNoz OTLP gRPC export.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
def instrument_voice_app(
|
|
88
|
+
service_name: str = 'voice-agent',
|
|
89
|
+
signoz_endpoint: str = 'localhost:4317',
|
|
90
|
+
insecure: bool = True,
|
|
91
|
+
enable_trust_center: bool = True,
|
|
92
|
+
trust_center_mode: str = 'template',
|
|
93
|
+
llm_endpoint: Optional[str] = None,
|
|
94
|
+
export_interval_ms: int = 5000
|
|
95
|
+
) -> InstrumentationHandle
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `VoiceTurnContext`
|
|
99
|
+
Context manager for tracking voice turn timing and metrics.
|
|
100
|
+
|
|
101
|
+
- `VoiceTurnContext.get_current()`: Returns the active `VoiceTurnContext` instance for the current `asyncio` context.
|
|
102
|
+
- `turn.mark_stt_complete()`: Marks STT processing completion and records STT duration.
|
|
103
|
+
- `turn.mark_llm_first_token()`: Marks the arrival of the first LLM token stream chunk.
|
|
104
|
+
- `turn.mark_first_audio()`: Marks the output of the first synthesized audio chunk and exports the TTFA metric.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Metrics Reference
|
|
109
|
+
|
|
110
|
+
| Metric Name | Type | Unit | Description |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| `voice.time_to_first_audio_ms` | Histogram | ms | Time from user turn start to first synthesized audio |
|
|
113
|
+
| `voice.stt_duration_ms` | Histogram | ms | Speech-To-Text processing duration |
|
|
114
|
+
| `voice.llm_first_token_ms` | Histogram | ms | LLM Time-To-First-Token latency |
|
|
115
|
+
| `voice.turns_total` | Counter | 1 | Total number of conversational turns processed |
|
|
116
|
+
| `voice.interruptions_total` | Counter | 1 | Total number of user interruptions recorded |
|
|
117
|
+
| `instrumentation.score` | Gauge | 1 | Telemetry quality score (0-100) evaluated by Trust Center |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
Apache License 2.0
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Zooid Trust Center",
|
|
3
|
+
"description": "Dashboard for voice agent instrumentation scoring and health",
|
|
4
|
+
"widgets": [
|
|
5
|
+
{
|
|
6
|
+
"id": "w1",
|
|
7
|
+
"title": "Instrumentation Score",
|
|
8
|
+
"description": "Average instrumentation score across services",
|
|
9
|
+
"panelType": "value",
|
|
10
|
+
"query": {
|
|
11
|
+
"metrics": [
|
|
12
|
+
{
|
|
13
|
+
"name": "instrumentation_score",
|
|
14
|
+
"aggregate": "avg",
|
|
15
|
+
"groupBy": ["service_name"]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"layout": { "w": 4, "h": 2, "x": 0, "y": 0 }
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "w2",
|
|
23
|
+
"title": "Score by Service",
|
|
24
|
+
"description": "Detailed scores per service",
|
|
25
|
+
"panelType": "table",
|
|
26
|
+
"query": {
|
|
27
|
+
"metrics": [
|
|
28
|
+
{
|
|
29
|
+
"name": "instrumentation_score",
|
|
30
|
+
"aggregate": "avg",
|
|
31
|
+
"groupBy": ["service_name"]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"layout": { "w": 8, "h": 4, "x": 4, "y": 0 }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "w3",
|
|
39
|
+
"title": "Score Trend",
|
|
40
|
+
"description": "Score over time",
|
|
41
|
+
"panelType": "graph",
|
|
42
|
+
"query": {
|
|
43
|
+
"metrics": [
|
|
44
|
+
{
|
|
45
|
+
"name": "instrumentation_score",
|
|
46
|
+
"aggregate": "avg",
|
|
47
|
+
"groupBy": ["service_name"]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"layout": { "w": 6, "h": 4, "x": 0, "y": 2 }
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "w4",
|
|
55
|
+
"title": "Top Violations",
|
|
56
|
+
"description": "Most frequent instrumentation violations",
|
|
57
|
+
"panelType": "bar",
|
|
58
|
+
"query": {
|
|
59
|
+
"metrics": [
|
|
60
|
+
{
|
|
61
|
+
"name": "instrumentation_violations_total",
|
|
62
|
+
"aggregate": "sum",
|
|
63
|
+
"groupBy": ["rule_id"]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"layout": { "w": 6, "h": 4, "x": 6, "y": 4 }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "w5",
|
|
71
|
+
"title": "Unscorable Spans",
|
|
72
|
+
"description": "Total unscorable spans",
|
|
73
|
+
"panelType": "value",
|
|
74
|
+
"query": {
|
|
75
|
+
"metrics": [
|
|
76
|
+
{
|
|
77
|
+
"name": "instrumentation_unscorable_total",
|
|
78
|
+
"aggregate": "sum"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
"layout": { "w": 4, "h": 2, "x": 0, "y": 6 }
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "w6",
|
|
86
|
+
"title": "Category Distribution",
|
|
87
|
+
"description": "Distribution of violation categories",
|
|
88
|
+
"panelType": "pie",
|
|
89
|
+
"query": {
|
|
90
|
+
"metrics": [
|
|
91
|
+
{
|
|
92
|
+
"name": "instrumentation_violations_total",
|
|
93
|
+
"aggregate": "sum",
|
|
94
|
+
"groupBy": ["category"]
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
"layout": { "w": 4, "h": 4, "x": 4, "y": 6 }
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"layout": []
|
|
102
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Voice Agent Dashboard",
|
|
3
|
+
"description": "Performance and health metrics for voice agents",
|
|
4
|
+
"widgets": [
|
|
5
|
+
{
|
|
6
|
+
"id": "w1",
|
|
7
|
+
"title": "TTFA (p50)",
|
|
8
|
+
"description": "Time to First Audio (50th percentile)",
|
|
9
|
+
"panelType": "value",
|
|
10
|
+
"query": {
|
|
11
|
+
"metrics": [
|
|
12
|
+
{
|
|
13
|
+
"name": "voice_time_to_first_audio_ms",
|
|
14
|
+
"aggregate": "p50"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"layout": { "w": 4, "h": 2, "x": 0, "y": 0 }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "w2",
|
|
22
|
+
"title": "TTFA Distribution",
|
|
23
|
+
"description": "Histogram of Time to First Audio",
|
|
24
|
+
"panelType": "graph",
|
|
25
|
+
"query": {
|
|
26
|
+
"metrics": [
|
|
27
|
+
{
|
|
28
|
+
"name": "voice_ttfa_distribution",
|
|
29
|
+
"aggregate": "sum"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"layout": { "w": 8, "h": 4, "x": 4, "y": 0 }
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "w3",
|
|
37
|
+
"title": "TTFA by Architecture",
|
|
38
|
+
"description": "Time to First Audio categorized by voice architecture",
|
|
39
|
+
"panelType": "bar",
|
|
40
|
+
"query": {
|
|
41
|
+
"metrics": [
|
|
42
|
+
{
|
|
43
|
+
"name": "voice_time_to_first_audio_ms",
|
|
44
|
+
"aggregate": "avg",
|
|
45
|
+
"groupBy": ["voice_architecture"]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"layout": { "w": 6, "h": 4, "x": 0, "y": 2 }
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "w4",
|
|
53
|
+
"title": "Stage Latency",
|
|
54
|
+
"description": "Latency for STT, LLM, TTS stages",
|
|
55
|
+
"panelType": "table",
|
|
56
|
+
"query": {
|
|
57
|
+
"metrics": [
|
|
58
|
+
{
|
|
59
|
+
"name": "voice_stage_latency_ms",
|
|
60
|
+
"aggregate": "avg",
|
|
61
|
+
"groupBy": ["stage_name"]
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"layout": { "w": 6, "h": 4, "x": 6, "y": 4 }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "w5",
|
|
69
|
+
"title": "Total Turns",
|
|
70
|
+
"description": "Total number of conversational turns",
|
|
71
|
+
"panelType": "value",
|
|
72
|
+
"query": {
|
|
73
|
+
"metrics": [
|
|
74
|
+
{
|
|
75
|
+
"name": "voice_turns_total",
|
|
76
|
+
"aggregate": "sum"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"layout": { "w": 4, "h": 2, "x": 0, "y": 6 }
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": "w6",
|
|
84
|
+
"title": "Error Rate",
|
|
85
|
+
"description": "Percentage of turns with errors",
|
|
86
|
+
"panelType": "value",
|
|
87
|
+
"query": {
|
|
88
|
+
"metrics": [
|
|
89
|
+
{
|
|
90
|
+
"name": "voice_errors_total",
|
|
91
|
+
"aggregate": "sum"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"layout": { "w": 4, "h": 2, "x": 4, "y": 6 }
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": "w7",
|
|
99
|
+
"title": "Interruptions",
|
|
100
|
+
"description": "User interruptions during generation",
|
|
101
|
+
"panelType": "value",
|
|
102
|
+
"query": {
|
|
103
|
+
"metrics": [
|
|
104
|
+
{
|
|
105
|
+
"name": "voice_interruptions_total",
|
|
106
|
+
"aggregate": "sum"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"layout": { "w": 4, "h": 2, "x": 8, "y": 6 }
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"layout": []
|
|
114
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import random
|
|
3
|
+
import time
|
|
4
|
+
from zooid import instrument_voice_app, voice_turn, VoiceTurnContext
|
|
5
|
+
|
|
6
|
+
from opentelemetry import trace
|
|
7
|
+
|
|
8
|
+
# Initialize instrumentation for the demo
|
|
9
|
+
instrument_voice_app(service_name='demo-voice-agent', signoz_endpoint='localhost:4317')
|
|
10
|
+
|
|
11
|
+
@voice_turn()
|
|
12
|
+
async def process_turn(turn_idx: int):
|
|
13
|
+
print(f"--- Starting Turn {turn_idx} ---")
|
|
14
|
+
context = VoiceTurnContext.get_current()
|
|
15
|
+
|
|
16
|
+
# 1. STT Phase
|
|
17
|
+
with context.tracer.start_as_current_span("stt.transcribe") as span:
|
|
18
|
+
print("Listening...")
|
|
19
|
+
# Intentional "bad" instrumentation for turn 3
|
|
20
|
+
if turn_idx != 3:
|
|
21
|
+
span.set_attribute("gen_ai.system", "deepgram")
|
|
22
|
+
await asyncio.sleep(random.uniform(0.15, 0.25))
|
|
23
|
+
transcript = "Hello, how are you?"
|
|
24
|
+
span.set_attribute("stt.transcript", transcript)
|
|
25
|
+
|
|
26
|
+
# 2. LLM Phase
|
|
27
|
+
with context.tracer.start_as_current_span("llm.generate") as span:
|
|
28
|
+
print("Thinking...")
|
|
29
|
+
span.set_attribute("gen_ai.system", "openai")
|
|
30
|
+
span.set_attribute("llm.model", "gpt-4o-mini")
|
|
31
|
+
|
|
32
|
+
# Simulate LLM streaming and latency
|
|
33
|
+
await asyncio.sleep(random.uniform(0.2, 0.4))
|
|
34
|
+
|
|
35
|
+
if turn_idx == 7: # Simulate an error
|
|
36
|
+
span.record_exception(Exception("LLM API Timeout"))
|
|
37
|
+
span.set_status(2, "Error occurred") # Status.ERROR = 2
|
|
38
|
+
print("LLM Error!")
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
response_text = "I am doing great, thank you!"
|
|
42
|
+
|
|
43
|
+
# 3. TTS Phase
|
|
44
|
+
with context.tracer.start_as_current_span("tts.synthesize") as span:
|
|
45
|
+
print("Speaking...")
|
|
46
|
+
span.set_attribute("gen_ai.system", "elevenlabs")
|
|
47
|
+
|
|
48
|
+
await asyncio.sleep(random.uniform(0.05, 0.15))
|
|
49
|
+
|
|
50
|
+
# Mark time to first audio
|
|
51
|
+
context.record_ttfa()
|
|
52
|
+
|
|
53
|
+
await asyncio.sleep(0.5) # Simulate audio playing out
|
|
54
|
+
print("Finished speaking.")
|
|
55
|
+
|
|
56
|
+
async def main():
|
|
57
|
+
print("Starting simulated voice agent...")
|
|
58
|
+
for i in range(1, 11):
|
|
59
|
+
await process_turn(i)
|
|
60
|
+
await asyncio.sleep(1)
|
|
61
|
+
print("Simulation complete.")
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
services:
|
|
3
|
+
# This is a reference docker-compose for running examples.
|
|
4
|
+
# It assumes you have the main SigNoz stack running in the zooid-net network.
|
|
5
|
+
example-agent:
|
|
6
|
+
build: .
|
|
7
|
+
environment:
|
|
8
|
+
- OTEL_EXPORTER_OTLP_ENDPOINT=http://signoz-otel-collector:4317
|
|
9
|
+
networks:
|
|
10
|
+
- zooid-net
|
|
11
|
+
|
|
12
|
+
networks:
|
|
13
|
+
zooid-net:
|
|
14
|
+
external: true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from zooid import instrument_voice_app, voice_turn
|
|
3
|
+
|
|
4
|
+
# NOTE: This is a structural example showing how you might integrate with Pipecat.
|
|
5
|
+
# It assumes a typical Pipecat pipeline setup.
|
|
6
|
+
|
|
7
|
+
# instrument_voice_app(service_name='pipecat-voice-agent')
|
|
8
|
+
|
|
9
|
+
@voice_turn
|
|
10
|
+
async def handle_user_input(pipeline, user_audio):
|
|
11
|
+
"""
|
|
12
|
+
In a real Pipecat app, you might wrap your main event handlers
|
|
13
|
+
or pipeline execution points with the @voice_turn decorator.
|
|
14
|
+
"""
|
|
15
|
+
print("Processing user audio through Pipecat pipeline...")
|
|
16
|
+
# await pipeline.process(user_audio)
|
|
17
|
+
await asyncio.sleep(0.5)
|
|
18
|
+
print("Response generated.")
|
|
19
|
+
|
|
20
|
+
async def main():
|
|
21
|
+
print("Pipecat integration example (mocked)")
|
|
22
|
+
# pipeline = build_pipeline()
|
|
23
|
+
# while True:
|
|
24
|
+
# audio = get_audio()
|
|
25
|
+
# await handle_user_input(pipeline, audio)
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
asyncio.run(main())
|