[Cartesia] Fix streaming truncation bug with Twilio Fast API WS
This commit is contained in:
@@ -4,33 +4,24 @@
|
|||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import json
|
|
||||||
import uuid
|
|
||||||
import base64
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import base64
|
||||||
|
import io
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
|
||||||
CancelFrame,
|
|
||||||
ErrorFrame,
|
|
||||||
Frame,
|
|
||||||
AudioRawFrame,
|
|
||||||
StartInterruptionFrame,
|
|
||||||
StartFrame,
|
|
||||||
EndFrame,
|
|
||||||
TTSStartedFrame,
|
|
||||||
TTSStoppedFrame,
|
|
||||||
TextFrame,
|
|
||||||
LLMFullResponseEndFrame
|
|
||||||
)
|
|
||||||
from pipecat.processors.frame_processor import FrameDirection
|
|
||||||
from pipecat.transcriptions.language import Language
|
|
||||||
from pipecat.services.ai_services import AsyncWordTTSService
|
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
from pipecat.frames.frames import (AudioRawFrame, CancelFrame, EndFrame,
|
||||||
|
ErrorFrame, Frame, LLMFullResponseEndFrame,
|
||||||
|
StartFrame, StartInterruptionFrame,
|
||||||
|
TextFrame, TTSStartedFrame, TTSStoppedFrame)
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection
|
||||||
|
from pipecat.services.ai_services import AsyncWordTTSService
|
||||||
|
from pipecat.transcriptions.language import Language
|
||||||
|
|
||||||
# See .env.example for Cartesia configuration needed
|
# See .env.example for Cartesia configuration needed
|
||||||
try:
|
try:
|
||||||
import websockets
|
import websockets
|
||||||
@@ -161,6 +152,25 @@ class CartesiaTTSService(AsyncWordTTSService):
|
|||||||
await self.push_frame(LLMFullResponseEndFrame())
|
await self.push_frame(LLMFullResponseEndFrame())
|
||||||
self._context_id = None
|
self._context_id = None
|
||||||
|
|
||||||
|
async def flush_audio(self):
|
||||||
|
if not self._context_id or not self._websocket:
|
||||||
|
return
|
||||||
|
logger.debug("Flushing audio")
|
||||||
|
msg = {
|
||||||
|
"transcript": "",
|
||||||
|
"continue": False,
|
||||||
|
"context_id": self._context_id,
|
||||||
|
"model_id": self._model_id,
|
||||||
|
"voice": {
|
||||||
|
"mode": "id",
|
||||||
|
"id": self._voice_id
|
||||||
|
},
|
||||||
|
"output_format": self._output_format,
|
||||||
|
"language": self._language,
|
||||||
|
"add_timestamps": True,
|
||||||
|
}
|
||||||
|
await self._websocket.send(json.dumps(msg))
|
||||||
|
|
||||||
async def _receive_task_handler(self):
|
async def _receive_task_handler(self):
|
||||||
try:
|
try:
|
||||||
async for message in self._websocket:
|
async for message in self._websocket:
|
||||||
|
|||||||
@@ -8,19 +8,19 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import io
|
import io
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
from typing import Awaitable, Callable
|
from typing import Awaitable, Callable
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
from pydantic.main import BaseModel
|
from pydantic.main import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import AudioRawFrame, CancelFrame, EndFrame, Frame, StartFrame, StartInterruptionFrame
|
from pipecat.frames.frames import (AudioRawFrame, CancelFrame, EndFrame, Frame,
|
||||||
|
StartFrame, StartInterruptionFrame)
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.serializers.base_serializer import FrameSerializer
|
from pipecat.serializers.base_serializer import FrameSerializer
|
||||||
from pipecat.transports.base_input import BaseInputTransport
|
from pipecat.transports.base_input import BaseInputTransport
|
||||||
from pipecat.transports.base_output import BaseOutputTransport
|
from pipecat.transports.base_output import BaseOutputTransport
|
||||||
from pipecat.transports.base_transport import BaseTransport, TransportParams
|
from pipecat.transports.base_transport import BaseTransport, TransportParams
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from fastapi import WebSocket
|
from fastapi import WebSocket
|
||||||
from starlette.websockets import WebSocketState
|
from starlette.websockets import WebSocketState
|
||||||
@@ -101,7 +101,7 @@ class FastAPIWebsocketOutputTransport(BaseOutputTransport):
|
|||||||
|
|
||||||
async def write_raw_audio_frames(self, frames: bytes):
|
async def write_raw_audio_frames(self, frames: bytes):
|
||||||
self._websocket_audio_buffer += frames
|
self._websocket_audio_buffer += frames
|
||||||
while len(self._websocket_audio_buffer) >= self._params.audio_frame_size:
|
while len(self._websocket_audio_buffer):
|
||||||
frame = AudioRawFrame(
|
frame = AudioRawFrame(
|
||||||
audio=self._websocket_audio_buffer[:
|
audio=self._websocket_audio_buffer[:
|
||||||
self._params.audio_frame_size],
|
self._params.audio_frame_size],
|
||||||
|
|||||||
Reference in New Issue
Block a user