services(cartesia): allow setting language and language voices

This commit is contained in:
Aleix Conchillo Flaqué
2024-08-22 22:44:11 -07:00
parent 38cd86ad52
commit 3931cb3235
2 changed files with 41 additions and 3 deletions

View File

@@ -9,7 +9,7 @@ import io
import wave import wave
from abc import abstractmethod from abc import abstractmethod
from typing import AsyncGenerator, Optional from typing import AsyncGenerator, Mapping, Optional
from pipecat.frames.frames import ( from pipecat.frames.frames import (
AudioRawFrame, AudioRawFrame,
@@ -20,16 +20,20 @@ from pipecat.frames.frames import (
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
StartFrame, StartFrame,
StartInterruptionFrame, StartInterruptionFrame,
TTSLanguageUpdateFrame,
TTSLanguageVoicesUpdateFrame,
TTSSpeakFrame, TTSSpeakFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
TTSVoiceUpdateFrame, TTSVoiceUpdateFrame,
TextFrame, TextFrame,
TranscriptionFrame,
UserImageRequestFrame, UserImageRequestFrame,
VisionImageRawFrame VisionImageRawFrame
) )
from pipecat.processors.async_frame_processor import AsyncFrameProcessor from pipecat.processors.async_frame_processor import AsyncFrameProcessor
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.transcriptions.languages import Language
from pipecat.utils.audio import calculate_audio_volume from pipecat.utils.audio import calculate_audio_volume
from pipecat.utils.string import match_endofsentence from pipecat.utils.string import match_endofsentence
from pipecat.utils.utils import exp_smoothing from pipecat.utils.utils import exp_smoothing
@@ -177,6 +181,14 @@ class TTSService(AIService):
async def set_voice(self, voice: str): async def set_voice(self, voice: str):
pass pass
@abstractmethod
async def set_language(self, language: Language):
pass
@abstractmethod
async def set_language_voices(self, voices: Mapping[Language, str]):
pass
# Converts the text to audio. # Converts the text to audio.
@abstractmethod @abstractmethod
async def run_tts(self, text: str) -> AsyncGenerator[Frame, None]: async def run_tts(self, text: str) -> AsyncGenerator[Frame, None]:
@@ -235,6 +247,10 @@ class TTSService(AIService):
await self._push_tts_frames(frame.text, False) await self._push_tts_frames(frame.text, False)
elif isinstance(frame, TTSVoiceUpdateFrame): elif isinstance(frame, TTSVoiceUpdateFrame):
await self.set_voice(frame.voice) await self.set_voice(frame.voice)
elif isinstance(frame, TTSLanguageUpdateFrame):
await self.set_language(frame.language)
elif isinstance(frame, TTSLanguageVoicesUpdateFrame):
await self.set_language_voices(frame.voices)
else: else:
await self.push_frame(frame, direction) await self.push_frame(frame, direction)

View File

@@ -10,9 +10,8 @@ import base64
import asyncio import asyncio
import time import time
from typing import AsyncGenerator from typing import AsyncGenerator, Mapping
from pipecat.processors.frame_processor import FrameDirection
from pipecat.frames.frames import ( from pipecat.frames.frames import (
CancelFrame, CancelFrame,
ErrorFrame, ErrorFrame,
@@ -26,6 +25,8 @@ from pipecat.frames.frames import (
TextFrame, TextFrame,
LLMFullResponseEndFrame LLMFullResponseEndFrame
) )
from pipecat.processors.frame_processor import FrameDirection
from pipecat.transcriptions.languages import Language
from pipecat.services.ai_services import TTSService from pipecat.services.ai_services import TTSService
from loguru import logger from loguru import logger
@@ -40,6 +41,15 @@ except ModuleNotFoundError as e:
raise Exception(f"Missing module: {e}") raise Exception(f"Missing module: {e}")
def language_to_cartesia_language(language: Language) -> str | None:
match language:
case Language.EN:
return "en"
case Language.ES:
return "es"
return None
class CartesiaTTSService(TTSService): class CartesiaTTSService(TTSService):
def __init__( def __init__(
@@ -79,6 +89,7 @@ class CartesiaTTSService(TTSService):
"sample_rate": sample_rate, "sample_rate": sample_rate,
} }
self._language = language self._language = language
self._language_voices = {}
self._websocket = None self._websocket = None
self._context_id = None self._context_id = None
@@ -94,6 +105,17 @@ class CartesiaTTSService(TTSService):
logger.debug(f"Switching TTS voice to: [{voice}]") logger.debug(f"Switching TTS voice to: [{voice}]")
self._voice_id = voice self._voice_id = voice
async def set_language(self, language: Language):
cartesia_language = language_to_cartesia_language(language)
if cartesia_language and language in self._language_voices:
logger.debug(f"Switching TTS language to: [{language}]")
self._language = cartesia_language
await self.set_voice(self._language_voices[language])
async def set_language_voices(self, voices: Mapping[Language, str]):
logger.debug(f"Setting TTS language voices to: {voices}")
self._language_voices = voices
async def start(self, frame: StartFrame): async def start(self, frame: StartFrame):
await super().start(frame) await super().start(frame)
await self._connect() await self._connect()