voiceground 0.1.4__py3-none-any.whl

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.
voiceground/events.py ADDED
@@ -0,0 +1,72 @@
1
+ """Voiceground event types for conversation observability."""
2
+
3
+ import uuid
4
+ from dataclasses import dataclass, field
5
+ from enum import Enum
6
+ from typing import Any
7
+
8
+
9
+ class EventCategory(str, Enum):
10
+ """Categories of conversation events."""
11
+
12
+ USER_SPEAK = "user_speak"
13
+ BOT_SPEAK = "bot_speak"
14
+ STT = "stt"
15
+ LLM = "llm"
16
+ TTS = "tts"
17
+ TOOL_CALL = "tool_call"
18
+ SYSTEM = "system"
19
+
20
+
21
+ class EventType(str, Enum):
22
+ """Types of events within each category."""
23
+
24
+ START = "start"
25
+ END = "end"
26
+ FIRST_BYTE = "first_byte"
27
+
28
+
29
+ @dataclass
30
+ class VoicegroundEvent:
31
+ """A normalized conversation event.
32
+
33
+ Attributes:
34
+ id: Unique identifier for this event.
35
+ timestamp: Unix timestamp in seconds when the event occurred.
36
+ category: The category of the event (user_speak, bot_speak, stt, llm, tts, tool_call, system).
37
+ type: The type of event (start, end, first_byte).
38
+ source: The name of the processor/frame source that triggered this event.
39
+ data: Additional event-specific data.
40
+ """
41
+
42
+ id: str
43
+ timestamp: float
44
+ category: EventCategory
45
+ type: EventType
46
+ source: str = ""
47
+ data: dict[str, Any] = field(default_factory=dict)
48
+
49
+ def to_dict(self) -> dict[str, Any]:
50
+ """Convert the event to a dictionary for JSON serialization."""
51
+ return {
52
+ "id": self.id,
53
+ "timestamp": self.timestamp,
54
+ "category": self.category.value,
55
+ "type": self.type.value,
56
+ "source": self.source,
57
+ "data": self.data,
58
+ }
59
+
60
+ @classmethod
61
+ def from_dict(cls, data: dict[str, Any]) -> "VoicegroundEvent":
62
+ """Create an event from a dictionary."""
63
+ # Generate ID if not present (for backward compatibility)
64
+ event_id = data.get("id") or str(uuid.uuid4())
65
+ return cls(
66
+ id=event_id,
67
+ timestamp=data["timestamp"],
68
+ category=EventCategory(data["category"]),
69
+ type=EventType(data["type"]),
70
+ source=data.get("source", ""),
71
+ data=data.get("data", {}),
72
+ )
voiceground/metrics.py ADDED
@@ -0,0 +1,164 @@
1
+ """Voiceground custom metrics frame classes for opinionated metrics."""
2
+
3
+ from pipecat.frames.frames import MetricsFrame
4
+ from pipecat.metrics.metrics import MetricsData
5
+
6
+
7
+ class VoicegroundMetricsData(MetricsData):
8
+ """Base class for all Voiceground metrics data.
9
+
10
+ Automatically sets processor="voiceground" for all metrics.
11
+ """
12
+
13
+ processor: str = "voiceground"
14
+
15
+
16
+ class TurnDurationMetricsData(VoicegroundMetricsData):
17
+ """Turn Duration metrics data."""
18
+
19
+ value: float
20
+
21
+
22
+ class ResponseTimeMetricsData(VoicegroundMetricsData):
23
+ """Response Time metrics data."""
24
+
25
+ value: float
26
+
27
+
28
+ class TranscriptionOverheadMetricsData(VoicegroundMetricsData):
29
+ """Transcription Overhead metrics data."""
30
+
31
+ value: float
32
+
33
+
34
+ class VoiceSynthesisOverheadMetricsData(VoicegroundMetricsData):
35
+ """Voice Synthesis Overhead metrics data."""
36
+
37
+ value: float
38
+
39
+
40
+ class LLMResponseTimeMetricsData(VoicegroundMetricsData):
41
+ """LLM Response Time metrics data."""
42
+
43
+ value: float
44
+ net_value: float | None = None
45
+
46
+
47
+ class SystemOverheadMetricsData(VoicegroundMetricsData):
48
+ """System Overhead metrics data."""
49
+
50
+ value: float
51
+ operation_name: str
52
+
53
+
54
+ class ToolUsageMetricsData(VoicegroundMetricsData):
55
+ """Tool Usage metrics data."""
56
+
57
+ value: float
58
+ tool_name: str
59
+
60
+
61
+ class VoicegroundMetricFrame(MetricsFrame):
62
+ """Base class for all Voiceground metric frames.
63
+
64
+ Automatically sets up the MetricsFrame with the metric data and name.
65
+ """
66
+
67
+ name: str = ""
68
+
69
+ def __init__(self, metric_data: MetricsData, name: str):
70
+ super().__init__(data=[metric_data])
71
+ self.name = name
72
+
73
+
74
+ class VoicegroundTurnDurationFrame(VoicegroundMetricFrame):
75
+ """Turn Duration metric frame: Total time from first event to last event in the turn.
76
+
77
+ Parameters:
78
+ value: Turn duration in seconds.
79
+ """
80
+
81
+ def __init__(self, value: float):
82
+ metric_data = TurnDurationMetricsData(processor="voiceground", value=value)
83
+ super().__init__(metric_data, "turn_duration")
84
+
85
+
86
+ class VoicegroundResponseTimeFrame(VoicegroundMetricFrame):
87
+ """Response Time metric frame: Time from user_speak:end to bot_speak:start.
88
+
89
+ Parameters:
90
+ value: Response time in seconds.
91
+ """
92
+
93
+ def __init__(self, value: float):
94
+ metric_data = ResponseTimeMetricsData(processor="voiceground", value=value)
95
+ super().__init__(metric_data, "response_time")
96
+
97
+
98
+ class VoicegroundTranscriptionOverheadFrame(VoicegroundMetricFrame):
99
+ """Transcription Overhead metric frame: Time from user_speak:end to stt:end.
100
+
101
+ Parameters:
102
+ value: Transcription overhead in seconds.
103
+ """
104
+
105
+ def __init__(self, value: float):
106
+ metric_data = TranscriptionOverheadMetricsData(processor="voiceground", value=value)
107
+ super().__init__(metric_data, "transcription_overhead")
108
+
109
+
110
+ class VoicegroundVoiceSynthesisOverheadFrame(VoicegroundMetricFrame):
111
+ """Voice Synthesis Overhead metric frame: Time from tts:start to bot_speak:start.
112
+
113
+ Parameters:
114
+ value: Voice synthesis overhead in seconds.
115
+ """
116
+
117
+ def __init__(self, value: float):
118
+ metric_data = VoiceSynthesisOverheadMetricsData(processor="voiceground", value=value)
119
+ super().__init__(metric_data, "voice_synthesis_overhead")
120
+
121
+
122
+ class VoicegroundLLMResponseTimeFrame(VoicegroundMetricFrame):
123
+ """LLM Response Time metric frame: Time from llm:start to llm:first_byte.
124
+
125
+ Parameters:
126
+ value: LLM response time in seconds (includes tools overhead).
127
+ net_value: LLM response time in seconds excluding tools overhead.
128
+ """
129
+
130
+ def __init__(self, value: float, net_value: float | None = None):
131
+ metric_data = LLMResponseTimeMetricsData(
132
+ processor="voiceground", value=value, net_value=net_value
133
+ )
134
+ super().__init__(metric_data, "llm_response_time")
135
+
136
+
137
+ class VoicegroundSystemOverheadFrame(VoicegroundMetricFrame):
138
+ """System Overhead metric frame: Duration of a specific system operation.
139
+
140
+ Parameters:
141
+ value: System overhead in seconds.
142
+ operation_name: Name/type of the system operation (e.g., "context_aggregation_timeout").
143
+ """
144
+
145
+ def __init__(self, value: float, operation_name: str):
146
+ metric_data = SystemOverheadMetricsData(
147
+ processor="voiceground", value=value, operation_name=operation_name
148
+ )
149
+ super().__init__(metric_data, f"system_overhead_{operation_name}")
150
+
151
+
152
+ class VoicegroundToolUsageFrame(VoicegroundMetricFrame):
153
+ """Individual Tool Usage metric frame: Duration of a specific tool call.
154
+
155
+ Parameters:
156
+ value: Tool call duration in seconds.
157
+ tool_name: Name of the tool/function that was called.
158
+ """
159
+
160
+ def __init__(self, value: float, tool_name: str):
161
+ metric_data = ToolUsageMetricsData(
162
+ processor="voiceground", value=value, tool_name=tool_name
163
+ )
164
+ super().__init__(metric_data, f"tool_usage_{tool_name}")