Skip to content

Commit f86bec2

Browse files
renovate[bot]tommaso-ascani
authored andcommitted
chore(deps): update dependency deepgram-sdk to v6 (#32)
1 parent 60e0b13 commit f86bec2

3 files changed

Lines changed: 62 additions & 20 deletions

File tree

‎api.py‎

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from dataclasses import dataclass
12
from fastapi import APIRouter, Depends, FastAPI, HTTPException, UploadFile, File, Request
23
from fastapi.concurrency import run_in_threadpool
34
from fastapi.responses import StreamingResponse
@@ -11,8 +12,8 @@
1112
import sys
1213
import shutil
1314
import tempfile
14-
from deepgram import DeepgramClient, SpeakOptions
15-
from deepgram.clients.common.v1.errors import DeepgramApiError
15+
from deepgram import DeepgramClient
16+
from deepgram.core.api_error import ApiError
1617
from langchain_text_splitters import RecursiveCharacterTextSplitter
1718

1819

@@ -129,6 +130,36 @@
129130
"aura-zeus-en",
130131
]
131132

133+
134+
@dataclass(slots=True)
135+
class TTSOptions:
136+
model: str | None = None
137+
sample_rate: int | None = None
138+
bit_rate: int | None = None
139+
encoding: str | None = None
140+
container: str | None = None
141+
callback: str | None = None
142+
callback_method: str | None = None
143+
mip_opt_out: bool | None = None
144+
tag: str | list[str] | None = None
145+
146+
def to_dict(self) -> dict:
147+
return {
148+
key: value
149+
for key, value in {
150+
"model": self.model,
151+
"sample_rate": self.sample_rate,
152+
"bit_rate": self.bit_rate,
153+
"encoding": self.encoding,
154+
"container": self.container,
155+
"callback": self.callback,
156+
"callback_method": self.callback_method,
157+
"mip_opt_out": self.mip_opt_out,
158+
"tag": self.tag,
159+
}.items()
160+
if value is not None
161+
}
162+
132163
def _iter_bytes(data: bytes, *, chunk_size: int):
133164
for i in range(0, len(data), chunk_size):
134165
yield data[i : i + chunk_size]
@@ -186,17 +217,19 @@ async def _concat_and_boost_mp3_ffmpeg(chunks: list[bytes], gain: float = 8.0) -
186217
return await run_in_threadpool(_concat_and_boost_mp3_ffmpeg_sync, chunks, gain)
187218

188219

189-
def _tts_chunk_to_bytes_sync(text: str, options: SpeakOptions) -> bytes:
190-
"""Synthesize a single text chunk via Deepgram SDK and return audio bytes."""
191-
deepgram = DeepgramClient(DEEPGRAM_API_KEY)
192-
timeout = httpx.Timeout(connect=10.0, read=300.0, write=300.0, pool=10.0)
193-
response = deepgram.speak.rest.v("1").stream_memory(
194-
{"text": text}, options, timeout=timeout
220+
def _tts_chunk_to_bytes_sync(text: str, options: TTSOptions) -> bytes:
221+
"""Synthesize a single text chunk via Deepgram SDK v6 and return audio bytes."""
222+
deepgram = DeepgramClient(api_key=DEEPGRAM_API_KEY, timeout=300.0)
223+
return b"".join(
224+
deepgram.speak.v1.audio.generate(
225+
text=text,
226+
request_options={"timeout_in_seconds": 300, "chunk_size": 65536},
227+
**options.to_dict(),
228+
)
195229
)
196-
return response.stream_memory.read()
197230

198231

199-
def _require_api_token_if_configured(request: Request) -> None:
232+
async def _require_api_token_if_configured(request: Request) -> None:
200233
configured_token = (os.getenv("API_TOKEN") or "").strip()
201234
if not configured_token:
202235
return
@@ -317,7 +350,7 @@ async def get_speech(request: Request):
317350
raise HTTPException(status_code=400, detail=f"No TTS model available for language: {language}")
318351
input_params["model"] = models[0]
319352

320-
# Build SpeakOptions with valid TTS parameters
353+
# Build TTS options with only Deepgram-supported TTS parameters.
321354
speak_kwargs = {}
322355
if input_params.get("model"):
323356
speak_kwargs["model"] = input_params["model"]
@@ -326,8 +359,16 @@ async def get_speech(request: Request):
326359
if input_params.get("bit_rate"):
327360
speak_kwargs["bit_rate"] = int(input_params["bit_rate"])
328361
speak_kwargs["encoding"] = "mp3"
329-
330-
options = SpeakOptions(**speak_kwargs)
362+
if input_params.get("callback"):
363+
speak_kwargs["callback"] = input_params["callback"]
364+
if input_params.get("callback_method"):
365+
speak_kwargs["callback_method"] = input_params["callback_method"]
366+
if input_params.get("mip_opt_out"):
367+
speak_kwargs["mip_opt_out"] = input_params["mip_opt_out"].strip().lower() in ("1", "true", "yes")
368+
if input_params.get("tag"):
369+
speak_kwargs["tag"] = input_params["tag"]
370+
371+
options = TTSOptions(**speak_kwargs)
331372
logger.debug("Deepgram TTS options: %s", speak_kwargs)
332373

333374
audio_parts: list[bytes] = []
@@ -341,12 +382,13 @@ async def get_speech(request: Request):
341382
idx, len(chunks), len(audio_data),
342383
)
343384
audio_parts.append(audio_data)
344-
except DeepgramApiError as e:
345-
status = int(e.status) if e.status else 502
346-
logger.error("Deepgram TTS API error: status=%s message=%s", e.status, e.message)
385+
except ApiError as e:
386+
status = int(e.status_code) if e.status_code else 502
387+
message = e.body if isinstance(e.body, str) else str(e.body)
388+
logger.error("Deepgram TTS API error: status=%s message=%s", e.status_code, message)
347389
raise HTTPException(
348390
status_code=status,
349-
detail=f"Deepgram API error: {e.message}",
391+
detail=f"Deepgram API error: {message}",
350392
)
351393
except httpx.TimeoutException:
352394
logger.warning("Deepgram TTS request timed out")

‎requirements.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
aiohttp
22
aiomqtt
3-
deepgram-sdk==3.*
3+
deepgram-sdk==6.*
44
fastapi
55
langchain
66
langchain_openai

‎tests/test_api.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,9 +493,9 @@ def test_get_speech_deepgram_timeout_returns_504(self, mock_tts, client):
493493

494494
@patch("api._tts_chunk_to_bytes_sync")
495495
def test_get_speech_deepgram_http_error_propagates_status(self, mock_tts, client):
496-
from deepgram.clients.common.v1.errors import DeepgramApiError
496+
from deepgram.core.api_error import ApiError
497497

498-
mock_tts.side_effect = DeepgramApiError("Invalid API key", "401")
498+
mock_tts.side_effect = ApiError(status_code=401, body="Invalid API key")
499499

500500
response = client.post("/api/get_speech", data={"text": "hello"})
501501
assert response.status_code == 401

0 commit comments

Comments
 (0)