Skip to content

Commit 02dee09

Browse files
AssemblyAIbgotthold-aai
authored andcommitted
Project import generated by Copybara.
GitOrigin-RevId: e75527160d41d82d1fe4747445db14cd88af3b02
1 parent 2080c80 commit 02dee09

11 files changed

Lines changed: 349 additions & 21 deletions

File tree

README.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ aai.settings.api_key = "YOUR_API_KEY"
104104
audio_file = "./example.mp3"
105105

106106
config = aai.TranscriptionConfig(
107-
speech_models=["universal-3-pro", "universal-2"],
107+
speech_models=["universal-3-5-pro", "universal-2"],
108108
language_detection=True,
109109
speaker_labels=True,
110110
)
@@ -130,7 +130,7 @@ aai.settings.api_key = "YOUR_API_KEY"
130130
audio_file = "https://assembly.ai/wildfires.mp3"
131131

132132
config = aai.TranscriptionConfig(
133-
speech_models=["universal-3-pro", "universal-2"],
133+
speech_models=["universal-3-5-pro", "universal-2"],
134134
language_detection=True,
135135
speaker_labels=True,
136136
)
@@ -177,7 +177,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
177177
audio_file = "https://assembly.ai/wildfires.mp3"
178178

179179
config = aai.TranscriptionConfig(
180-
speech_models=["universal-3-pro", "universal-2"],
180+
speech_models=["universal-3-5-pro", "universal-2"],
181181
language_detection=True
182182
)
183183

@@ -214,7 +214,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
214214
audio_file = "https://assembly.ai/wildfires.mp3"
215215

216216
config = aai.TranscriptionConfig(
217-
speech_models=["universal-3-pro", "universal-2"],
217+
speech_models=["universal-3-5-pro", "universal-2"],
218218
language_detection=True
219219
)
220220

@@ -248,7 +248,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
248248
audio_file = "https://assembly.ai/wildfires.mp3"
249249

250250
config = aai.TranscriptionConfig(
251-
speech_models=["universal-3-pro", "universal-2"],
251+
speech_models=["universal-3-5-pro", "universal-2"],
252252
language_detection=True
253253
)
254254

@@ -280,7 +280,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
280280
audio_file = "https://assembly.ai/wildfires.mp3"
281281

282282
config = aai.TranscriptionConfig(
283-
speech_models=["universal-3-pro", "universal-2"],
283+
speech_models=["universal-3-5-pro", "universal-2"],
284284
language_detection=True
285285
)
286286
config.set_custom_spelling(
@@ -324,7 +324,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
324324
audio_file = "https://assembly.ai/wildfires.mp3"
325325

326326
config = aai.TranscriptionConfig(
327-
speech_models=["universal-3-pro", "universal-2"],
327+
speech_models=["universal-3-5-pro", "universal-2"],
328328
language_detection=True
329329
)
330330

@@ -402,7 +402,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
402402
audio_file = "https://assembly.ai/wildfires.mp3"
403403

404404
config = aai.TranscriptionConfig(
405-
speech_models=["universal-3-pro", "universal-2"],
405+
speech_models=["universal-3-5-pro", "universal-2"],
406406
language_detection=True,
407407
).set_redact_pii(
408408
policies=[
@@ -431,7 +431,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
431431
audio_file = "https://assembly.ai/wildfires.mp3"
432432

433433
config = aai.TranscriptionConfig(
434-
speech_models=["universal-3-pro", "universal-2"],
434+
speech_models=["universal-3-5-pro", "universal-2"],
435435
language_detection=True,
436436
).set_redact_pii(
437437
policies=[
@@ -465,7 +465,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
465465
audio_file = "https://assembly.ai/wildfires.mp3"
466466

467467
config = aai.TranscriptionConfig(
468-
speech_models=["universal-3-pro", "universal-2"],
468+
speech_models=["universal-3-5-pro", "universal-2"],
469469
language_detection=True,
470470
auto_chapters=True
471471
)
@@ -493,7 +493,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
493493
audio_file = "https://assembly.ai/wildfires.mp3"
494494

495495
config = aai.TranscriptionConfig(
496-
speech_models=["universal-3-pro", "universal-2"],
496+
speech_models=["universal-3-5-pro", "universal-2"],
497497
language_detection=True,
498498
summarization=True,
499499
summary_model=aai.SummarizationModel.informative,
@@ -531,7 +531,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
531531
audio_file = "https://assembly.ai/wildfires.mp3"
532532

533533
config = aai.TranscriptionConfig(
534-
speech_models=["universal-3-pro", "universal-2"],
534+
speech_models=["universal-3-5-pro", "universal-2"],
535535
language_detection=True,
536536
content_safety=True
537537
)
@@ -583,7 +583,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
583583
audio_file = "https://assembly.ai/wildfires.mp3"
584584

585585
config = aai.TranscriptionConfig(
586-
speech_models=["universal-3-pro", "universal-2"],
586+
speech_models=["universal-3-5-pro", "universal-2"],
587587
language_detection=True,
588588
sentiment_analysis=True
589589
)
@@ -626,7 +626,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
626626
audio_file = "https://assembly.ai/wildfires.mp3"
627627

628628
config = aai.TranscriptionConfig(
629-
speech_models=["universal-3-pro", "universal-2"],
629+
speech_models=["universal-3-5-pro", "universal-2"],
630630
language_detection=True,
631631
entity_detection=True
632632
)
@@ -655,7 +655,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
655655
audio_file = "https://assembly.ai/wildfires.mp3"
656656

657657
config = aai.TranscriptionConfig(
658-
speech_models=["universal-3-pro", "universal-2"],
658+
speech_models=["universal-3-5-pro", "universal-2"],
659659
language_detection=True,
660660
iab_categories=True
661661
)
@@ -690,7 +690,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
690690
audio_file = "https://assembly.ai/wildfires.mp3"
691691

692692
config = aai.TranscriptionConfig(
693-
speech_models=["universal-3-pro", "universal-2"],
693+
speech_models=["universal-3-5-pro", "universal-2"],
694694
language_detection=True,
695695
auto_highlights=True
696696
)
@@ -745,7 +745,7 @@ client.on(StreamingEvents.Termination, on_terminated)
745745
client.on(StreamingEvents.Error, on_error)
746746

747747
client.connect(StreamingParameters(
748-
sample_rate=16000, speech_model="universal-3-5-pro", format_turns=True,
748+
sample_rate=16000, speech_model="universal-3-5-pro",
749749
))
750750
try:
751751
client.stream(aai.extras.stream_file(filepath="audio.wav", sample_rate=16000))
@@ -874,7 +874,7 @@ async def main():
874874
async with AsyncStreamingClient(StreamingClientOptions(api_key="<YOUR_API_KEY>")) as client:
875875
client.on(StreamingEvents.Turn, on_turn)
876876
await client.connect(StreamingParameters(
877-
sample_rate=16000, speech_model="universal-3-5-pro", format_turns=True,
877+
sample_rate=16000, speech_model="universal-3-5-pro",
878878
))
879879
await client.stream(stream_file_async("audio.wav", 16000))
880880

@@ -1032,7 +1032,7 @@ transcriber = aai.Transcriber(config=config)
10321032
transcriber.transcribe(
10331033
"https://example.com/audio.mp3",
10341034
# overrides the above configuration on the `Transcriber` with the following
1035-
config=aai.TranscriptionConfig(speech_models=["universal-3-pro", "universal-2"], multichannel=True, disfluencies=True)
1035+
config=aai.TranscriptionConfig(speech_models=["universal-3-5-pro", "universal-2"], multichannel=True, disfluencies=True)
10361036
)
10371037
```
10381038

assemblyai/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.64.21"
1+
__version__ = "0.64.25"

assemblyai/client.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,17 @@ def __init__(
4747
def _store_response(response):
4848
self._last_response = response
4949

50+
keepalive_expiry = self.settings.keepalive_expiry
51+
limits = (
52+
httpx.Limits(keepalive_expiry=keepalive_expiry)
53+
if keepalive_expiry is not None
54+
else httpx.Limits()
55+
)
5056
self._http_client = httpx.Client(
5157
base_url=self.settings.base_url,
5258
headers=headers,
5359
timeout=self.settings.http_timeout,
60+
limits=limits,
5461
event_hooks={"response": [_store_response]},
5562
)
5663

assemblyai/streaming/v3/_base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ def _emit_param_warnings(params: StreamingParameters) -> None:
135135
"`customer_support_audio_capture=True` will record session audio. "
136136
"Only enable this when explicitly coordinating with AssemblyAI support."
137137
)
138+
if params.language_code is not None:
139+
logger.warning(
140+
"[Deprecation Warning] `language_code` is deprecated and will be removed in a future release. "
141+
"Please use `language_codes` instead."
142+
)
138143

139144

140145
def _build_uri(host: str, params: StreamingParameters) -> str:

assemblyai/streaming/v3/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,18 @@ class StreamingSessionParameters(BaseModel):
147147
agent_context: Optional[str] = None
148148
interruption_delay: Optional[int] = None
149149
turn_left_pad_ms: Optional[int] = None
150+
language_codes: Optional[List[str]] = None
150151

151152

152153
class Encoding(str, Enum):
153154
pcm_s16le = "pcm_s16le"
154155
pcm_mulaw = "pcm_mulaw"
156+
# Raw Opus packets, one packet per binary WS message. `sample_rate` is
157+
# optional and ignored — the Opus stream is self-describing.
158+
opus = "opus"
159+
# Ogg-encapsulated Opus byte stream (ffmpeg, gstreamer, opusenc, browser
160+
# MediaRecorder output). `sample_rate` is optional and ignored.
161+
ogg_opus = "ogg_opus"
155162

156163
def __str__(self):
157164
return self.value
@@ -259,6 +266,8 @@ class StreamingParameters(StreamingSessionParameters):
259266
sample_rate: int
260267
encoding: Optional[Encoding] = None
261268
speech_model: Optional[SpeechModel] = None
269+
# Deprecated: use language_codes instead (pass a single-element list, e.g.
270+
# ["es"], for the same behavior). Still supported for backward compatibility.
262271
language_code: Optional[str] = None
263272
language_detection: Optional[bool] = None
264273
domain: Optional[StreamingDomain] = None

assemblyai/sync.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import concurrent.futures
44
import os
5-
from typing import BinaryIO, Optional, Tuple, Union
5+
from typing import Any, BinaryIO, Optional, Tuple, Union
66
from urllib.parse import urlparse
77

8+
import httpx
9+
810
from . import client as _client
911
from . import sync_api, types
1012

@@ -201,3 +203,52 @@ def transcribe_async(
201203
data=data,
202204
config=config,
203205
)
206+
207+
def warm(self) -> bool:
208+
"""
209+
Opens the connection to the sync API ahead of time.
210+
211+
The sync API is a single request/response, so a `transcribe()` that
212+
opens its connection on demand pays the full DNS + TCP + TLS handshake
213+
on the critical path — one network round trip that, for a distant
214+
client, can rival the transcription itself. Calling `warm()` as soon as
215+
you know audio is coming — typically while the clip is still being
216+
recorded — spends that setup concurrently: the next `transcribe()`
217+
reuses the already-open connection.
218+
219+
The warmed connection is reused while it stays in the HTTP pool —
220+
`settings.keepalive_expiry` seconds (httpx's 5s default unless raised).
221+
Call `warm()` shortly before `transcribe()`, or raise
222+
`keepalive_expiry` (e.g. to 120, the sync audio cap) so a single call
223+
covers a whole in-progress recording. `warm()` is idempotent and cheap,
224+
so calling it again to refresh the connection is fine.
225+
226+
Routing the same `config.model` as the eventual transcription ensures
227+
the warmed connection lands on the right backend.
228+
229+
Returns:
230+
True once the connection is open (any HTTP response — even a
231+
non-200 health probe — means the socket is established); False if
232+
the connection could not be opened (transport error).
233+
"""
234+
settings = self._client.settings
235+
url = settings.sync_base_url.rstrip("/") + sync_api.ENDPOINT_HEALTH
236+
try:
237+
self._client.http_client.get(
238+
url,
239+
headers={sync_api.MODEL_HEADER: self.config.model},
240+
timeout=min(settings.sync_http_timeout, 10.0),
241+
)
242+
except httpx.HTTPError:
243+
return False
244+
return True
245+
246+
def close(self) -> None:
247+
"""Shuts down the worker-thread pool used by `transcribe_async`."""
248+
self._executor.shutdown(wait=False)
249+
250+
def __enter__(self) -> "SyncTranscriber":
251+
return self
252+
253+
def __exit__(self, *_exc: Any) -> None:
254+
self.close()

assemblyai/sync_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from . import types
77

88
ENDPOINT_TRANSCRIBE = "/transcribe"
9+
ENDPOINT_HEALTH = "/healthz"
910
MODEL_HEADER = "X-AAI-Model"
1011

1112

assemblyai/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class Settings(BaseSettings):
126126
http_timeout: float = 30.0
127127
"The default HTTP timeout for general requests"
128128

129+
keepalive_expiry: Optional[float] = None
130+
"Seconds an idle connection is kept in the HTTP pool before being closed. None uses httpx's default (5s). Raise it (e.g. to 120) so a connection opened by `SyncTranscriber.warm()` stays reusable across an in-progress recording."
131+
129132
base_url: str = "https://api.assemblyai.com"
130133
"The base URL for the AssemblyAI API"
131134

0 commit comments

Comments
 (0)