OpenAITTSService: add speed arg

This commit is contained in:
Mark Backman
2025-09-11 13:53:52 -04:00
parent 9b3f6927c2
commit fafcd79870
3 changed files with 31 additions and 10 deletions

View File

@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added a `speed` arg to `OpenAITTSService` to control the speed of the voice
response.
- Added `FrameProcessor.push_interruption_task_frame_and_wait()`. Use this - Added `FrameProcessor.push_interruption_task_frame_and_wait()`. Use this
method to programatically interrupt the bot from any part of the method to programatically interrupt the bot from any part of the
pipeline. This guarantees that all the processors in the pipeline are pipeline. This guarantees that all the processors in the pipeline are

View File

@@ -64,6 +64,7 @@ class OpenAITTSService(TTSService):
model: str = "gpt-4o-mini-tts", model: str = "gpt-4o-mini-tts",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
instructions: Optional[str] = None, instructions: Optional[str] = None,
speed: Optional[float] = None,
**kwargs, **kwargs,
): ):
"""Initialize OpenAI TTS service. """Initialize OpenAI TTS service.
@@ -75,6 +76,7 @@ class OpenAITTSService(TTSService):
model: TTS model to use. Defaults to "gpt-4o-mini-tts". model: TTS model to use. Defaults to "gpt-4o-mini-tts".
sample_rate: Output audio sample rate in Hz. If None, uses OpenAI's default 24kHz. sample_rate: Output audio sample rate in Hz. If None, uses OpenAI's default 24kHz.
instructions: Optional instructions to guide voice synthesis behavior. instructions: Optional instructions to guide voice synthesis behavior.
speed: Voice speed control (0.25 to 4.0, default 1.0).
**kwargs: Additional keyword arguments passed to TTSService. **kwargs: Additional keyword arguments passed to TTSService.
""" """
if sample_rate and sample_rate != self.OPENAI_SAMPLE_RATE: if sample_rate and sample_rate != self.OPENAI_SAMPLE_RATE:
@@ -84,6 +86,7 @@ class OpenAITTSService(TTSService):
) )
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
self._speed = speed
self.set_model_name(model) self.set_model_name(model)
self.set_voice(voice) self.set_voice(voice)
self._instructions = instructions self._instructions = instructions
@@ -133,17 +136,22 @@ class OpenAITTSService(TTSService):
try: try:
await self.start_ttfb_metrics() await self.start_ttfb_metrics()
# Setup extra body parameters # Setup API parameters
extra_body = {} create_params = {
"input": text,
"model": self.model_name,
"voice": VALID_VOICES[self._voice_id],
"response_format": "pcm",
}
if self._instructions: if self._instructions:
extra_body["instructions"] = self._instructions create_params["instructions"] = self._instructions
if self._speed:
create_params["speed"] = self._speed
async with self._client.audio.speech.with_streaming_response.create( async with self._client.audio.speech.with_streaming_response.create(
input=text, **create_params
model=self.model_name,
voice=VALID_VOICES[self._voice_id],
response_format="pcm",
extra_body=extra_body,
) as r: ) as r:
if r.status_code != 200: if r.status_code != 200:
error = await r.text() error = await r.text()

14
uv.lock generated
View File

@@ -4307,6 +4307,12 @@ local-smart-turn = [
{ name = "torchaudio" }, { name = "torchaudio" },
{ name = "transformers" }, { name = "transformers" },
] ]
local-smart-turn-v3 = [
{ name = "onnxruntime" },
{ name = "torch" },
{ name = "torchaudio" },
{ name = "transformers" },
]
mcp = [ mcp = [
{ name = "mcp", extra = ["cli"] }, { name = "mcp", extra = ["cli"] },
] ]
@@ -4460,7 +4466,8 @@ requires-dist = [
{ name = "numba", specifier = "==0.61.2" }, { name = "numba", specifier = "==0.61.2" },
{ name = "numpy", specifier = ">=1.26.4,<3" }, { name = "numpy", specifier = ">=1.26.4,<3" },
{ name = "nvidia-riva-client", marker = "extra == 'riva'", specifier = "~=2.21.1" }, { name = "nvidia-riva-client", marker = "extra == 'riva'", specifier = "~=2.21.1" },
{ name = "onnxruntime", marker = "extra == 'silero'", specifier = "~=1.20.1" }, { name = "onnxruntime", marker = "extra == 'local-smart-turn-v3'", specifier = ">=1.20.1,<2" },
{ name = "onnxruntime", marker = "extra == 'silero'", specifier = ">=1.20.1,<2" },
{ name = "openai", specifier = ">=1.74.0,<=1.99.1" }, { name = "openai", specifier = ">=1.74.0,<=1.99.1" },
{ name = "opencv-python", marker = "extra == 'webrtc'", specifier = "~=4.11.0.86" }, { name = "opencv-python", marker = "extra == 'webrtc'", specifier = "~=4.11.0.86" },
{ name = "openpipe", marker = "extra == 'openpipe'", specifier = "~=4.50.0" }, { name = "openpipe", marker = "extra == 'openpipe'", specifier = "~=4.50.0" },
@@ -4488,8 +4495,11 @@ requires-dist = [
{ name = "tenacity", marker = "extra == 'livekit'", specifier = ">=8.2.3,<10.0.0" }, { name = "tenacity", marker = "extra == 'livekit'", specifier = ">=8.2.3,<10.0.0" },
{ name = "timm", marker = "extra == 'moondream'", specifier = "~=1.0.13" }, { name = "timm", marker = "extra == 'moondream'", specifier = "~=1.0.13" },
{ name = "torch", marker = "extra == 'local-smart-turn'", specifier = ">=2.5.0,<3" }, { name = "torch", marker = "extra == 'local-smart-turn'", specifier = ">=2.5.0,<3" },
{ name = "torch", marker = "extra == 'local-smart-turn-v3'", specifier = ">=2.5.0,<3" },
{ name = "torchaudio", marker = "extra == 'local-smart-turn'", specifier = ">=2.5.0,<3" }, { name = "torchaudio", marker = "extra == 'local-smart-turn'", specifier = ">=2.5.0,<3" },
{ name = "torchaudio", marker = "extra == 'local-smart-turn-v3'", specifier = ">=2.5.0,<3" },
{ name = "transformers", marker = "extra == 'local-smart-turn'" }, { name = "transformers", marker = "extra == 'local-smart-turn'" },
{ name = "transformers", marker = "extra == 'local-smart-turn-v3'" },
{ name = "transformers", marker = "extra == 'moondream'", specifier = ">=4.48.0" }, { name = "transformers", marker = "extra == 'moondream'", specifier = ">=4.48.0" },
{ name = "transformers", marker = "extra == 'ultravox'", specifier = ">=4.48.0" }, { name = "transformers", marker = "extra == 'ultravox'", specifier = ">=4.48.0" },
{ name = "uvicorn", marker = "extra == 'runner'", specifier = ">=0.32.0,<1.0.0" }, { name = "uvicorn", marker = "extra == 'runner'", specifier = ">=0.32.0,<1.0.0" },
@@ -4513,7 +4523,7 @@ requires-dist = [
{ name = "websockets", marker = "extra == 'soniox'", specifier = ">=13.1,<15.0" }, { name = "websockets", marker = "extra == 'soniox'", specifier = ">=13.1,<15.0" },
{ name = "websockets", marker = "extra == 'websocket'", specifier = ">=13.1,<15.0" }, { name = "websockets", marker = "extra == 'websocket'", specifier = ">=13.1,<15.0" },
] ]
provides-extras = ["aic", "anthropic", "assemblyai", "asyncai", "aws", "aws-nova-sonic", "azure", "cartesia", "cerebras", "deepseek", "daily", "deepgram", "elevenlabs", "fal", "fireworks", "fish", "gladia", "google", "grok", "groq", "gstreamer", "heygen", "inworld", "krisp", "koala", "langchain", "livekit", "lmnt", "local", "mcp", "mem0", "mistral", "mlx-whisper", "moondream", "nim", "neuphonic", "noisereduce", "openai", "openpipe", "openrouter", "perplexity", "playht", "qwen", "rime", "riva", "runner", "sambanova", "sarvam", "sentry", "local-smart-turn", "remote-smart-turn", "silero", "simli", "soniox", "soundfile", "speechmatics", "tavus", "together", "tracing", "ultravox", "webrtc", "websocket", "whisper"] provides-extras = ["aic", "anthropic", "assemblyai", "asyncai", "aws", "aws-nova-sonic", "azure", "cartesia", "cerebras", "deepseek", "daily", "deepgram", "elevenlabs", "fal", "fireworks", "fish", "gladia", "google", "grok", "groq", "gstreamer", "heygen", "inworld", "krisp", "koala", "langchain", "livekit", "lmnt", "local", "mcp", "mem0", "mistral", "mlx-whisper", "moondream", "nim", "neuphonic", "noisereduce", "openai", "openpipe", "openrouter", "perplexity", "playht", "qwen", "rime", "riva", "runner", "sambanova", "sarvam", "sentry", "local-smart-turn", "local-smart-turn-v3", "remote-smart-turn", "silero", "simli", "soniox", "soundfile", "speechmatics", "tavus", "together", "tracing", "ultravox", "webrtc", "websocket", "whisper"]
[package.metadata.requires-dev] [package.metadata.requires-dev]
dev = [ dev = [