dv-pipecat-ai 0.0.85.dev865__py3-none-any.whl → 0.0.85.dev866__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.
Potentially problematic release.
This version of dv-pipecat-ai might be problematic. Click here for more details.
- {dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/METADATA +4 -1
- {dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/RECORD +8 -6
- {dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/WHEEL +1 -1
- pipecat/services/ringg/__init__.py +11 -0
- pipecat/services/ringg/stt.py +377 -0
- pipecat/services/stt_service.py +0 -1
- {dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/licenses/LICENSE +0 -0
- {dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dv-pipecat-ai
|
|
3
|
-
Version: 0.0.85.
|
|
3
|
+
Version: 0.0.85.dev866
|
|
4
4
|
Summary: An open source framework for voice (and multimodal) assistants
|
|
5
5
|
License-Expression: BSD-2-Clause
|
|
6
6
|
Project-URL: Source, https://github.com/pipecat-ai/pipecat
|
|
@@ -33,6 +33,9 @@ Requires-Dist: soxr~=0.5.0
|
|
|
33
33
|
Requires-Dist: openai<3,>=1.74.0
|
|
34
34
|
Requires-Dist: numba==0.61.2
|
|
35
35
|
Requires-Dist: wait_for2>=0.4.1; python_version < "3.12"
|
|
36
|
+
Requires-Dist: boto3>=1.38.27
|
|
37
|
+
Requires-Dist: aioboto3>=15.0.0
|
|
38
|
+
Requires-Dist: redis>=7.1.0
|
|
36
39
|
Provides-Extra: aic
|
|
37
40
|
Requires-Dist: aic-sdk~=1.0.1; extra == "aic"
|
|
38
41
|
Provides-Extra: anthropic
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
dv_pipecat_ai-0.0.85.
|
|
1
|
+
dv_pipecat_ai-0.0.85.dev866.dist-info/licenses/LICENSE,sha256=DWY2QGf2eMCFhuu2ChairtT6CB7BEFffNVhXWc4Od08,1301
|
|
2
2
|
pipecat/__init__.py,sha256=j0Xm6adxHhd7D06dIyyPV_GlBYLlBnTAERVvD_jAARQ,861
|
|
3
3
|
pipecat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
pipecat/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -173,7 +173,7 @@ pipecat/services/ai_services.py,sha256=_RrDWfM8adV17atzY9RxK0nXRVM5kbUkKrvN90GAW
|
|
|
173
173
|
pipecat/services/image_service.py,sha256=tqJun4nYeyN_PaWqTdF_CFsOiqBf3XX7R4et5Y07mEU,2357
|
|
174
174
|
pipecat/services/llm_service.py,sha256=39y9tjrusTr8Zr9sFlg9xz86CXpy39FiyLtsbcbsu8g,25379
|
|
175
175
|
pipecat/services/mcp_service.py,sha256=yS48Uj5qD4jnhYYhs9Kw1aa1cjdYIwxYYjzCc_u6M0o,14345
|
|
176
|
-
pipecat/services/stt_service.py,sha256=
|
|
176
|
+
pipecat/services/stt_service.py,sha256=x07vWXJCKj7TVgR5mXHLU4_nCzZe0jf0XLfS9DGzcWQ,12981
|
|
177
177
|
pipecat/services/tts_service.py,sha256=C1qYmewQ7qzEGd5SyUIISBjknnlhMJzUZ5lRgJgwhII,36540
|
|
178
178
|
pipecat/services/vision_service.py,sha256=v7Ft27xIwECAaL2ZzMZT8wG5aOA-JoUZWx2NxNaJ6pg,2580
|
|
179
179
|
pipecat/services/websocket_service.py,sha256=AWv7CL6G_XAh815xVaKNPpjP5escp8Q880SYHG7kCoI,5745
|
|
@@ -317,6 +317,8 @@ pipecat/services/qwen/__init__.py,sha256=gS81Y-9gy_ke17m-2Tt-8mDrawcFNZ15_i0OnT-
|
|
|
317
317
|
pipecat/services/qwen/llm.py,sha256=X6GOaoKBmQzEI8n-GO2bu4AFdhNFXt6wf7DMMwJ0QFo,1969
|
|
318
318
|
pipecat/services/rime/__init__.py,sha256=lK26ZYuDZS51OybSVPAx6rt710UA1ZBP31wPL1_VeLg,251
|
|
319
319
|
pipecat/services/rime/tts.py,sha256=Iux3gAjiLRN_clC3rxX_OXoA70vAsgMI3gvQI2fmZ_k,20722
|
|
320
|
+
pipecat/services/ringg/__init__.py,sha256=XH_DptHAQ_nUTd4W6WhdMJXIRhxuFI0hrDrWHXxSKyE,233
|
|
321
|
+
pipecat/services/ringg/stt.py,sha256=nO3ymYbzfKIy0krIR7Dk_M7dIp14wkHZmVZrJWY_l_U,13990
|
|
320
322
|
pipecat/services/riva/__init__.py,sha256=rObSsj504O_TMXhPBg_ymqKslZBhovlR-A0aaRZ0O6A,276
|
|
321
323
|
pipecat/services/riva/stt.py,sha256=bAss4dimx8eideaSPmPHM15_rSV3tfXNf13o5n1mfv4,25146
|
|
322
324
|
pipecat/services/riva/tts.py,sha256=idbqx3I2NlWCXtrIFsjEaYapxA3BLIA14ai3aMBh-2w,8158
|
|
@@ -418,7 +420,7 @@ pipecat/utils/tracing/service_decorators.py,sha256=fwzxFpi8DJl6BJbK74G0UEB4ccMJg
|
|
|
418
420
|
pipecat/utils/tracing/setup.py,sha256=7TEgPNpq6M8lww8OQvf0P9FzYc5A30xICGklVA-fua0,2892
|
|
419
421
|
pipecat/utils/tracing/turn_context_provider.py,sha256=ikon3plFOx0XbMrH6DdeHttNpb-U0gzMZIm3bWLc9eI,2485
|
|
420
422
|
pipecat/utils/tracing/turn_trace_observer.py,sha256=dma16SBJpYSOE58YDWy89QzHyQFc_9gQZszKeWixuwc,9725
|
|
421
|
-
dv_pipecat_ai-0.0.85.
|
|
422
|
-
dv_pipecat_ai-0.0.85.
|
|
423
|
-
dv_pipecat_ai-0.0.85.
|
|
424
|
-
dv_pipecat_ai-0.0.85.
|
|
423
|
+
dv_pipecat_ai-0.0.85.dev866.dist-info/METADATA,sha256=doB6BMiS51CvUgSBtX8wIcHw6hlvs8Ky-VS40YqTaB0,33045
|
|
424
|
+
dv_pipecat_ai-0.0.85.dev866.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
425
|
+
dv_pipecat_ai-0.0.85.dev866.dist-info/top_level.txt,sha256=kQzG20CxGf-nSsHmtXHx3hY2-8zHA3jYg8jk0TajqXc,8
|
|
426
|
+
dv_pipecat_ai-0.0.85.dev866.dist-info/RECORD,,
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024–2025, Daily
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""Ringg Parrot speech-to-text service implementation.
|
|
8
|
+
|
|
9
|
+
This service connects to a Ringg Parrot STT WebSocket server for real-time
|
|
10
|
+
transcription. The server provides partial transcripts as audio streams in,
|
|
11
|
+
and final transcripts when explicitly requested via a stop message.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import json
|
|
16
|
+
from typing import AsyncGenerator, Optional
|
|
17
|
+
|
|
18
|
+
from loguru import logger
|
|
19
|
+
from pydantic import BaseModel
|
|
20
|
+
|
|
21
|
+
from pipecat.frames.frames import (
|
|
22
|
+
CancelFrame,
|
|
23
|
+
EndFrame,
|
|
24
|
+
ErrorFrame,
|
|
25
|
+
Frame,
|
|
26
|
+
InterimTranscriptionFrame,
|
|
27
|
+
StartFrame,
|
|
28
|
+
StartInterruptionFrame,
|
|
29
|
+
TranscriptionFrame,
|
|
30
|
+
UserStoppedSpeakingFrame,
|
|
31
|
+
)
|
|
32
|
+
from enum import Enum
|
|
33
|
+
from pipecat.processors.frame_processor import FrameDirection
|
|
34
|
+
from pipecat.services.stt_service import STTService
|
|
35
|
+
from pipecat.utils.time import time_now_iso8601
|
|
36
|
+
from pipecat.utils.tracing.service_decorators import traced_stt
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
import websockets
|
|
40
|
+
from websockets.asyncio.client import connect as websocket_connect
|
|
41
|
+
from websockets.protocol import State
|
|
42
|
+
except ModuleNotFoundError as e:
|
|
43
|
+
logger.error(f"Exception: {e}")
|
|
44
|
+
logger.error("In order to use Ringg Parrot STT, you need to `pip install websockets`.")
|
|
45
|
+
raise Exception(f"Missing module: {e}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
STOP_MESSAGE = '{"type": "end"}'
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class PredictionMethod(str, Enum):
|
|
52
|
+
"""Prediction method for Ringg Parrot STT service."""
|
|
53
|
+
|
|
54
|
+
ON_FINAL = "on_final"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class RinggParrotInputParams(BaseModel):
|
|
58
|
+
"""Configuration parameters for Ringg Parrot STT service.
|
|
59
|
+
|
|
60
|
+
Parameters:
|
|
61
|
+
encoding: Audio encoding format (default: int16 for PCM signed 16-bit).
|
|
62
|
+
language: Language for transcription (default: Hindi).
|
|
63
|
+
punctuate: Whether to add punctuation to transcriptions.
|
|
64
|
+
partial_chunk_ms: Interval in ms for partial transcription updates.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
encoding: str = "int16"
|
|
68
|
+
language: str = "hi"
|
|
69
|
+
punctuate: bool = False
|
|
70
|
+
partial_chunk_ms: int = 400
|
|
71
|
+
prediction_method: PredictionMethod = PredictionMethod.ON_FINAL
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class RinggParrotSTTService(STTService):
|
|
75
|
+
"""Speech-to-Text service using Ringg Parrot's WebSocket API.
|
|
76
|
+
|
|
77
|
+
This service connects to a Ringg Parrot STT WebSocket server for real-time
|
|
78
|
+
transcription. It follows a VAD-forced endpoint pattern where finalization
|
|
79
|
+
is triggered when Pipecat's VAD detects the user stopped speaking.
|
|
80
|
+
|
|
81
|
+
The server:
|
|
82
|
+
- Accepts raw PCM audio frames (16-bit signed, 16kHz)
|
|
83
|
+
- Sends partial transcripts automatically as audio accumulates
|
|
84
|
+
- Sends final transcript when client sends a stop message
|
|
85
|
+
|
|
86
|
+
Example usage::
|
|
87
|
+
|
|
88
|
+
stt = RinggParrotSTTService(
|
|
89
|
+
url="ws://13.234.40.75:7864/v1/audio/stream",
|
|
90
|
+
language="hi",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
pipeline = Pipeline([
|
|
94
|
+
transport.input(),
|
|
95
|
+
stt,
|
|
96
|
+
context_aggregator.user(),
|
|
97
|
+
llm,
|
|
98
|
+
tts,
|
|
99
|
+
transport.output(),
|
|
100
|
+
])
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def __init__(
|
|
104
|
+
self,
|
|
105
|
+
*,
|
|
106
|
+
url: str = "ws://13.234.40.75:8888/v1/audio/stream",
|
|
107
|
+
sample_rate: Optional[int] = 16000,
|
|
108
|
+
params: Optional[RinggParrotInputParams] = None,
|
|
109
|
+
**kwargs,
|
|
110
|
+
):
|
|
111
|
+
"""Initialize the Ringg Parrot STT service.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
url: WebSocket URL for the Ringg Parrot STT server.
|
|
115
|
+
sample_rate: Audio sample rate in Hz (default: 16000).
|
|
116
|
+
params: Additional configuration parameters.
|
|
117
|
+
**kwargs: Additional arguments passed to the STTService.
|
|
118
|
+
"""
|
|
119
|
+
super().__init__(sample_rate=sample_rate, **kwargs)
|
|
120
|
+
params = params or RinggParrotInputParams()
|
|
121
|
+
|
|
122
|
+
self._url = url
|
|
123
|
+
self._params = params
|
|
124
|
+
self._websocket = None
|
|
125
|
+
self._receive_task = None
|
|
126
|
+
self._client_id: Optional[str] = None
|
|
127
|
+
|
|
128
|
+
self.set_model_name("ringg-parrot")
|
|
129
|
+
|
|
130
|
+
async def start(self, frame: StartFrame):
|
|
131
|
+
"""Start the Ringg Parrot STT websocket connection.
|
|
132
|
+
|
|
133
|
+
Connects to the WebSocket server, sends the start configuration,
|
|
134
|
+
waits for ready confirmation, and starts the receive task.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
frame: The start frame containing initialization parameters.
|
|
138
|
+
"""
|
|
139
|
+
await super().start(frame)
|
|
140
|
+
if self._websocket:
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
self._websocket = await websocket_connect(self._url)
|
|
145
|
+
|
|
146
|
+
if not self._websocket:
|
|
147
|
+
logger.error(f"Unable to connect to Ringg Parrot STT at {self._url}")
|
|
148
|
+
await self._call_event_handler("on_connection_error", "Connection failed")
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
# Send the start configuration message
|
|
152
|
+
start_config = {
|
|
153
|
+
"type": "start",
|
|
154
|
+
"sample_rate": self.sample_rate,
|
|
155
|
+
"encoding": self._params.encoding,
|
|
156
|
+
"language": self._params.language,
|
|
157
|
+
"punctuate": self._params.punctuate,
|
|
158
|
+
"partial_chunk_ms": self._params.partial_chunk_ms,
|
|
159
|
+
"prediction_method": "on_final",
|
|
160
|
+
}
|
|
161
|
+
await self._websocket.send(json.dumps(start_config))
|
|
162
|
+
|
|
163
|
+
# Wait for ready response
|
|
164
|
+
ready_response = await asyncio.wait_for(self._websocket.recv(), timeout=10.0)
|
|
165
|
+
ready_data = json.loads(ready_response)
|
|
166
|
+
|
|
167
|
+
if ready_data.get("type") != "ready":
|
|
168
|
+
error_msg = f"Unexpected response: {ready_data}"
|
|
169
|
+
logger.error(f"Ringg Parrot STT: {error_msg}")
|
|
170
|
+
await self._call_event_handler("on_connection_error", error_msg)
|
|
171
|
+
await self._cleanup()
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
self._client_id = ready_data.get("client_id")
|
|
175
|
+
logger.debug(f"Ringg Parrot STT connected, client_id: {self._client_id}")
|
|
176
|
+
|
|
177
|
+
# Start the receive task
|
|
178
|
+
if self._websocket and not self._receive_task:
|
|
179
|
+
self._receive_task = self.create_task(self._receive_task_handler())
|
|
180
|
+
|
|
181
|
+
await self._call_event_handler("on_connected")
|
|
182
|
+
|
|
183
|
+
except asyncio.TimeoutError:
|
|
184
|
+
logger.error("Ringg Parrot STT: Connection timeout waiting for ready response")
|
|
185
|
+
await self._call_event_handler("on_connection_error", "Connection timeout")
|
|
186
|
+
await self._cleanup()
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(f"Ringg Parrot STT: Connection error: {e}")
|
|
189
|
+
await self._call_event_handler("on_connection_error", str(e))
|
|
190
|
+
await self._cleanup()
|
|
191
|
+
|
|
192
|
+
async def _cleanup(self):
|
|
193
|
+
"""Clean up WebSocket connection and tasks."""
|
|
194
|
+
if self._websocket:
|
|
195
|
+
try:
|
|
196
|
+
await self._websocket.close()
|
|
197
|
+
except Exception:
|
|
198
|
+
pass
|
|
199
|
+
self._websocket = None
|
|
200
|
+
|
|
201
|
+
if self._receive_task:
|
|
202
|
+
# Task cannot cancel itself
|
|
203
|
+
if self._receive_task != asyncio.current_task():
|
|
204
|
+
await self._receive_task
|
|
205
|
+
self._receive_task = None
|
|
206
|
+
|
|
207
|
+
self._client_id = None
|
|
208
|
+
logger.debug("Disconnected from Ringg Parrot STT")
|
|
209
|
+
await self._call_event_handler("on_disconnected")
|
|
210
|
+
|
|
211
|
+
async def stop(self, frame: EndFrame):
|
|
212
|
+
"""Stop the Ringg Parrot STT websocket connection.
|
|
213
|
+
|
|
214
|
+
Called when the call/pipeline ends. Closes the connection without
|
|
215
|
+
sending a stop message (final transcripts are triggered by
|
|
216
|
+
UserStoppedSpeakingFrame during the call).
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
frame: The end frame.
|
|
220
|
+
"""
|
|
221
|
+
await super().stop(frame)
|
|
222
|
+
await self._cleanup()
|
|
223
|
+
|
|
224
|
+
async def cancel(self, frame: CancelFrame):
|
|
225
|
+
"""Cancel the Ringg Parrot STT websocket connection immediately.
|
|
226
|
+
|
|
227
|
+
Closes the connection without waiting for final transcript.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
frame: The cancel frame.
|
|
231
|
+
"""
|
|
232
|
+
await super().cancel(frame)
|
|
233
|
+
await self._cleanup()
|
|
234
|
+
|
|
235
|
+
async def run_stt(self, audio: bytes) -> AsyncGenerator[Frame, None]:
|
|
236
|
+
"""Send audio data to Ringg Parrot STT Service.
|
|
237
|
+
|
|
238
|
+
Audio is sent as raw binary bytes to the WebSocket. The server
|
|
239
|
+
will process and send back transcripts via the receive task.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
audio: Raw audio bytes to transcribe (PCM 16-bit signed).
|
|
243
|
+
|
|
244
|
+
Yields:
|
|
245
|
+
Frame: None (transcription results come via WebSocket callbacks).
|
|
246
|
+
"""
|
|
247
|
+
await self.start_processing_metrics()
|
|
248
|
+
if self._websocket and self._websocket.state is State.OPEN:
|
|
249
|
+
try:
|
|
250
|
+
await self._websocket.send(audio)
|
|
251
|
+
except websockets.exceptions.ConnectionClosed:
|
|
252
|
+
logger.warning("Ringg Parrot STT: WebSocket closed while sending audio")
|
|
253
|
+
except Exception as e:
|
|
254
|
+
logger.error(f"Ringg Parrot STT: Error sending audio: {e}")
|
|
255
|
+
await self.stop_processing_metrics()
|
|
256
|
+
|
|
257
|
+
yield None
|
|
258
|
+
|
|
259
|
+
@traced_stt
|
|
260
|
+
async def _handle_transcription(
|
|
261
|
+
self, transcript: str, is_final: bool, language: Optional[str] = None
|
|
262
|
+
):
|
|
263
|
+
"""Handle a transcription result with tracing.
|
|
264
|
+
|
|
265
|
+
This method is decorated with @traced_stt to capture STT metrics
|
|
266
|
+
including transcription latency and text content for observability.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
transcript: The transcribed text.
|
|
270
|
+
is_final: Whether this is a final (not interim) transcription.
|
|
271
|
+
language: The detected/configured language.
|
|
272
|
+
"""
|
|
273
|
+
# Tracing is handled by the @traced_stt decorator
|
|
274
|
+
# This method exists to provide the hook for metrics collection
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
async def _send_end_message(self):
|
|
278
|
+
"""Send end message to finalize current transcription."""
|
|
279
|
+
if self._websocket and self._websocket.state is State.OPEN:
|
|
280
|
+
try:
|
|
281
|
+
await self._websocket.send(STOP_MESSAGE)
|
|
282
|
+
logger.debug("Ringg Parrot STT: Sent end message to finalize transcription")
|
|
283
|
+
except Exception as e:
|
|
284
|
+
logger.error(f"Ringg Parrot STT: Error sending end message: {e}")
|
|
285
|
+
|
|
286
|
+
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
|
287
|
+
"""Process frames, handling interruption and finalization.
|
|
288
|
+
|
|
289
|
+
Handles:
|
|
290
|
+
- UserStoppedSpeakingFrame: Sends end message to get final transcript
|
|
291
|
+
- StartInterruptionFrame: Sends end message to finalize any pending
|
|
292
|
+
transcript before the interruption context switch
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
frame: The frame to process.
|
|
296
|
+
direction: The direction of frame processing.
|
|
297
|
+
"""
|
|
298
|
+
await super().process_frame(frame, direction)
|
|
299
|
+
|
|
300
|
+
if isinstance(frame, UserStoppedSpeakingFrame):
|
|
301
|
+
# User stopped speaking - finalize to get the transcript
|
|
302
|
+
await self._send_end_message()
|
|
303
|
+
|
|
304
|
+
async def _receive_task_handler(self):
|
|
305
|
+
"""Handle incoming messages from the WebSocket server.
|
|
306
|
+
|
|
307
|
+
Processes transcript messages (partial and final), chunk acknowledgments,
|
|
308
|
+
and error responses. Emits appropriate frames for each message type.
|
|
309
|
+
"""
|
|
310
|
+
if not self._websocket:
|
|
311
|
+
return
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
async for message in self._websocket:
|
|
315
|
+
try:
|
|
316
|
+
content = json.loads(message)
|
|
317
|
+
except json.JSONDecodeError:
|
|
318
|
+
logger.warning(f"Ringg Parrot STT: Invalid JSON: {message}")
|
|
319
|
+
continue
|
|
320
|
+
|
|
321
|
+
msg_type = content.get("type")
|
|
322
|
+
|
|
323
|
+
if msg_type == "transcript":
|
|
324
|
+
transcription = content.get("transcription", "")
|
|
325
|
+
is_partial = content.get("is_partial", True)
|
|
326
|
+
|
|
327
|
+
if is_partial:
|
|
328
|
+
# Partial/interim transcription
|
|
329
|
+
if transcription.strip():
|
|
330
|
+
await self.push_frame(
|
|
331
|
+
InterimTranscriptionFrame(
|
|
332
|
+
text=transcription,
|
|
333
|
+
user_id=self._user_id,
|
|
334
|
+
timestamp=time_now_iso8601(),
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
else:
|
|
338
|
+
# Final transcription
|
|
339
|
+
if transcription.strip():
|
|
340
|
+
await self.push_frame(
|
|
341
|
+
TranscriptionFrame(
|
|
342
|
+
text=transcription,
|
|
343
|
+
user_id=self._user_id,
|
|
344
|
+
timestamp=time_now_iso8601(),
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
await self._handle_transcription(
|
|
348
|
+
transcription, is_final=True, language=self._params.language
|
|
349
|
+
)
|
|
350
|
+
await self.stop_processing_metrics()
|
|
351
|
+
|
|
352
|
+
elif msg_type == "chunk":
|
|
353
|
+
# Acknowledgment of received audio chunk - no action needed
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
elif msg_type == "keepalive":
|
|
357
|
+
# Keepalive response - no action needed
|
|
358
|
+
pass
|
|
359
|
+
|
|
360
|
+
elif msg_type == "error":
|
|
361
|
+
error_detail = content.get("detail", "Unknown error")
|
|
362
|
+
logger.error(f"Ringg Parrot STT error: {error_detail}")
|
|
363
|
+
await self.push_error(ErrorFrame(f"Ringg Parrot STT: {error_detail}"))
|
|
364
|
+
|
|
365
|
+
elif msg_type == "ready":
|
|
366
|
+
# Already handled in start(), but log if received again
|
|
367
|
+
logger.debug("Ringg Parrot STT: Received additional ready message")
|
|
368
|
+
|
|
369
|
+
else:
|
|
370
|
+
logger.warning(f"Ringg Parrot STT: Unknown message type: {msg_type}")
|
|
371
|
+
|
|
372
|
+
except websockets.exceptions.ConnectionClosed:
|
|
373
|
+
# Expected when closing the connection
|
|
374
|
+
logger.debug("Ringg Parrot STT: WebSocket connection closed")
|
|
375
|
+
except Exception as e:
|
|
376
|
+
logger.error(f"Ringg Parrot STT receive error: {e}")
|
|
377
|
+
await self.push_error(ErrorFrame(f"Ringg Parrot STT receive error: {e}"))
|
pipecat/services/stt_service.py
CHANGED
{dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{dv_pipecat_ai-0.0.85.dev865.dist-info → dv_pipecat_ai-0.0.85.dev866.dist-info}/top_level.txt
RENAMED
|
File without changes
|