Merge pull request #2984 from pipecat-ai/mb/11labs-pronunciation-dictionary
Add ElevenLabs pronunciation dictionary support
This commit is contained in:
@@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
metrics types are logged (TTFB, processing time, LLM token usage, TTS usage,
|
metrics types are logged (TTFB, processing time, LLM token usage, TTS usage,
|
||||||
smart turn metrics).
|
smart turn metrics).
|
||||||
|
|
||||||
|
- Added `pronunciation_dictionary_locators` to `ElevenLabsTTSService` and
|
||||||
|
`ElevenLabsHttpTTSService`.
|
||||||
|
|
||||||
- Added support for loading external observers. You can now register custom
|
- Added support for loading external observers. You can now register custom
|
||||||
pipeline observers by setting the `PIPECAT_OBSERVER_FILES` environment
|
pipeline observers by setting the `PIPECAT_OBSERVER_FILES` environment
|
||||||
variable. This variable should contain a colon-separated list of Python files
|
variable. This variable should contain a colon-separated list of Python files
|
||||||
|
|||||||
@@ -157,6 +157,18 @@ def build_elevenlabs_voice_settings(
|
|||||||
return voice_settings or None
|
return voice_settings or None
|
||||||
|
|
||||||
|
|
||||||
|
class PronunciationDictionaryLocator(BaseModel):
|
||||||
|
"""Locator for a pronunciation dictionary.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
pronunciation_dictionary_id: The ID of the pronunciation dictionary.
|
||||||
|
version_id: The version ID of the pronunciation dictionary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pronunciation_dictionary_id: str
|
||||||
|
version_id: str
|
||||||
|
|
||||||
|
|
||||||
def calculate_word_times(
|
def calculate_word_times(
|
||||||
alignment_info: Mapping[str, Any],
|
alignment_info: Mapping[str, Any],
|
||||||
cumulative_time: float,
|
cumulative_time: float,
|
||||||
@@ -239,6 +251,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
|
|||||||
enable_ssml_parsing: Whether to parse SSML tags in text.
|
enable_ssml_parsing: Whether to parse SSML tags in text.
|
||||||
enable_logging: Whether to enable ElevenLabs logging.
|
enable_logging: Whether to enable ElevenLabs logging.
|
||||||
apply_text_normalization: Text normalization mode ("auto", "on", "off").
|
apply_text_normalization: Text normalization mode ("auto", "on", "off").
|
||||||
|
pronunciation_dictionary_locators: List of pronunciation dictionary locators to use.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
language: Optional[Language] = None
|
language: Optional[Language] = None
|
||||||
@@ -251,6 +264,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
|
|||||||
enable_ssml_parsing: Optional[bool] = None
|
enable_ssml_parsing: Optional[bool] = None
|
||||||
enable_logging: Optional[bool] = None
|
enable_logging: Optional[bool] = None
|
||||||
apply_text_normalization: Optional[Literal["auto", "on", "off"]] = None
|
apply_text_normalization: Optional[Literal["auto", "on", "off"]] = None
|
||||||
|
pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -321,6 +335,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
|
|||||||
self.set_voice(voice_id)
|
self.set_voice(voice_id)
|
||||||
self._output_format = "" # initialized in start()
|
self._output_format = "" # initialized in start()
|
||||||
self._voice_settings = self._set_voice_settings()
|
self._voice_settings = self._set_voice_settings()
|
||||||
|
self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators
|
||||||
|
|
||||||
# Indicates if we have sent TTSStartedFrame. It will reset to False when
|
# Indicates if we have sent TTSStartedFrame. It will reset to False when
|
||||||
# there's an interruption or TTSStoppedFrame.
|
# there's an interruption or TTSStoppedFrame.
|
||||||
@@ -704,12 +719,17 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
|
|||||||
if not self.audio_context_available(self._context_id):
|
if not self.audio_context_available(self._context_id):
|
||||||
await self.create_audio_context(self._context_id)
|
await self.create_audio_context(self._context_id)
|
||||||
|
|
||||||
# Initialize context with voice settings
|
# Initialize context with voice settings and pronunciation dictionaries
|
||||||
msg = {"text": " ", "context_id": self._context_id}
|
msg = {"text": " ", "context_id": self._context_id}
|
||||||
if self._voice_settings:
|
if self._voice_settings:
|
||||||
msg["voice_settings"] = self._voice_settings
|
msg["voice_settings"] = self._voice_settings
|
||||||
|
if self._pronunciation_dictionary_locators:
|
||||||
|
msg["pronunciation_dictionary_locators"] = [
|
||||||
|
locator.model_dump()
|
||||||
|
for locator in self._pronunciation_dictionary_locators
|
||||||
|
]
|
||||||
await self._websocket.send(json.dumps(msg))
|
await self._websocket.send(json.dumps(msg))
|
||||||
logger.trace(f"Created new context {self._context_id} with voice settings")
|
logger.trace(f"Created new context {self._context_id}")
|
||||||
|
|
||||||
await self._send_text(text)
|
await self._send_text(text)
|
||||||
await self.start_tts_usage_metrics(text)
|
await self.start_tts_usage_metrics(text)
|
||||||
@@ -745,6 +765,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
|
|||||||
use_speaker_boost: Whether to use speaker boost enhancement.
|
use_speaker_boost: Whether to use speaker boost enhancement.
|
||||||
speed: Voice speed control (0.25 to 4.0).
|
speed: Voice speed control (0.25 to 4.0).
|
||||||
apply_text_normalization: Text normalization mode ("auto", "on", "off").
|
apply_text_normalization: Text normalization mode ("auto", "on", "off").
|
||||||
|
pronunciation_dictionary_locators: List of pronunciation dictionary locators to use.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
language: Optional[Language] = None
|
language: Optional[Language] = None
|
||||||
@@ -755,6 +776,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
|
|||||||
use_speaker_boost: Optional[bool] = None
|
use_speaker_boost: Optional[bool] = None
|
||||||
speed: Optional[float] = None
|
speed: Optional[float] = None
|
||||||
apply_text_normalization: Optional[Literal["auto", "on", "off"]] = None
|
apply_text_normalization: Optional[Literal["auto", "on", "off"]] = None
|
||||||
|
pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -813,6 +835,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
|
|||||||
self.set_voice(voice_id)
|
self.set_voice(voice_id)
|
||||||
self._output_format = "" # initialized in start()
|
self._output_format = "" # initialized in start()
|
||||||
self._voice_settings = self._set_voice_settings()
|
self._voice_settings = self._set_voice_settings()
|
||||||
|
self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators
|
||||||
|
|
||||||
# Track cumulative time to properly sequence word timestamps across utterances
|
# Track cumulative time to properly sequence word timestamps across utterances
|
||||||
self._cumulative_time = 0
|
self._cumulative_time = 0
|
||||||
@@ -977,6 +1000,11 @@ class ElevenLabsHttpTTSService(WordTTSService):
|
|||||||
if self._voice_settings:
|
if self._voice_settings:
|
||||||
payload["voice_settings"] = self._voice_settings
|
payload["voice_settings"] = self._voice_settings
|
||||||
|
|
||||||
|
if self._pronunciation_dictionary_locators:
|
||||||
|
payload["pronunciation_dictionary_locators"] = [
|
||||||
|
locator.model_dump() for locator in self._pronunciation_dictionary_locators
|
||||||
|
]
|
||||||
|
|
||||||
if self._settings["apply_text_normalization"] is not None:
|
if self._settings["apply_text_normalization"] is not None:
|
||||||
payload["apply_text_normalization"] = self._settings["apply_text_normalization"]
|
payload["apply_text_normalization"] = self._settings["apply_text_normalization"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user