Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ aai.settings.api_key = "YOUR_API_KEY"
audio_file = "./example.mp3"

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
speaker_labels=True,
)
Expand Down Expand Up @@ -177,7 +177,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True
)

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True
)

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True
)

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True
)
config.set_custom_spelling(
Expand Down Expand Up @@ -324,7 +324,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True
)

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
).set_redact_pii(
policies=[
Expand Down Expand Up @@ -431,7 +431,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
).set_redact_pii(
policies=[
Expand Down Expand Up @@ -465,7 +465,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
auto_chapters=True
)
Expand Down Expand Up @@ -493,7 +493,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

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

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
content_safety=True
)
Expand Down Expand Up @@ -583,7 +583,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
sentiment_analysis=True
)
Expand Down Expand Up @@ -626,7 +626,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
entity_detection=True
)
Expand Down Expand Up @@ -655,7 +655,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
iab_categories=True
)
Expand Down Expand Up @@ -690,7 +690,7 @@ aai.settings.api_key = "<YOUR_API_KEY>"
audio_file = "https://assembly.ai/wildfires.mp3"

config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
speech_models=["universal-3-5-pro", "universal-2"],
language_detection=True,
auto_highlights=True
)
Expand Down Expand Up @@ -745,7 +745,7 @@ client.on(StreamingEvents.Termination, on_terminated)
client.on(StreamingEvents.Error, on_error)

client.connect(StreamingParameters(
sample_rate=16000, speech_model="universal-3-5-pro", format_turns=True,
sample_rate=16000, speech_model="universal-3-5-pro",
))
try:
client.stream(aai.extras.stream_file(filepath="audio.wav", sample_rate=16000))
Expand Down Expand Up @@ -874,7 +874,7 @@ async def main():
async with AsyncStreamingClient(StreamingClientOptions(api_key="<YOUR_API_KEY>")) as client:
client.on(StreamingEvents.Turn, on_turn)
await client.connect(StreamingParameters(
sample_rate=16000, speech_model="universal-3-5-pro", format_turns=True,
sample_rate=16000, speech_model="universal-3-5-pro",
))
await client.stream(stream_file_async("audio.wav", 16000))

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

Expand Down
2 changes: 1 addition & 1 deletion assemblyai/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.64.21"
__version__ = "0.64.25"
7 changes: 7 additions & 0 deletions assemblyai/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,17 @@ def __init__(
def _store_response(response):
self._last_response = response

keepalive_expiry = self.settings.keepalive_expiry
limits = (
httpx.Limits(keepalive_expiry=keepalive_expiry)
if keepalive_expiry is not None
else httpx.Limits()
)
self._http_client = httpx.Client(
base_url=self.settings.base_url,
headers=headers,
timeout=self.settings.http_timeout,
limits=limits,
event_hooks={"response": [_store_response]},
)

Expand Down
5 changes: 5 additions & 0 deletions assemblyai/streaming/v3/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ def _emit_param_warnings(params: StreamingParameters) -> None:
"`customer_support_audio_capture=True` will record session audio. "
"Only enable this when explicitly coordinating with AssemblyAI support."
)
if params.language_code is not None:
logger.warning(
"[Deprecation Warning] `language_code` is deprecated and will be removed in a future release. "
"Please use `language_codes` instead."
)


def _build_uri(host: str, params: StreamingParameters) -> str:
Expand Down
9 changes: 9 additions & 0 deletions assemblyai/streaming/v3/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,18 @@ class StreamingSessionParameters(BaseModel):
agent_context: Optional[str] = None
interruption_delay: Optional[int] = None
turn_left_pad_ms: Optional[int] = None
language_codes: Optional[List[str]] = None


class Encoding(str, Enum):
pcm_s16le = "pcm_s16le"
pcm_mulaw = "pcm_mulaw"
# Raw Opus packets, one packet per binary WS message. `sample_rate` is
Comment thread
bgotthold-aai marked this conversation as resolved.
# optional and ignored — the Opus stream is self-describing.
opus = "opus"
# Ogg-encapsulated Opus byte stream (ffmpeg, gstreamer, opusenc, browser
# MediaRecorder output). `sample_rate` is optional and ignored.
ogg_opus = "ogg_opus"

def __str__(self):
return self.value
Expand Down Expand Up @@ -259,6 +266,8 @@ class StreamingParameters(StreamingSessionParameters):
sample_rate: int
Comment thread
bgotthold-aai marked this conversation as resolved.
encoding: Optional[Encoding] = None
speech_model: Optional[SpeechModel] = None
# Deprecated: use language_codes instead (pass a single-element list, e.g.
# ["es"], for the same behavior). Still supported for backward compatibility.
language_code: Optional[str] = None
language_detection: Optional[bool] = None
domain: Optional[StreamingDomain] = None
Expand Down
53 changes: 52 additions & 1 deletion assemblyai/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import concurrent.futures
import os
from typing import BinaryIO, Optional, Tuple, Union
from typing import Any, BinaryIO, Optional, Tuple, Union
from urllib.parse import urlparse

import httpx

from . import client as _client
from . import sync_api, types

Expand Down Expand Up @@ -201,3 +203,52 @@ def transcribe_async(
data=data,
config=config,
)

def warm(self) -> bool:
"""
Opens the connection to the sync API ahead of time.

The sync API is a single request/response, so a `transcribe()` that
opens its connection on demand pays the full DNS + TCP + TLS handshake
on the critical path — one network round trip that, for a distant
client, can rival the transcription itself. Calling `warm()` as soon as
you know audio is coming — typically while the clip is still being
recorded — spends that setup concurrently: the next `transcribe()`
reuses the already-open connection.

The warmed connection is reused while it stays in the HTTP pool —
`settings.keepalive_expiry` seconds (httpx's 5s default unless raised).
Call `warm()` shortly before `transcribe()`, or raise
`keepalive_expiry` (e.g. to 120, the sync audio cap) so a single call
covers a whole in-progress recording. `warm()` is idempotent and cheap,
so calling it again to refresh the connection is fine.

Routing the same `config.model` as the eventual transcription ensures
the warmed connection lands on the right backend.

Returns:
True once the connection is open (any HTTP response — even a
non-200 health probe — means the socket is established); False if
the connection could not be opened (transport error).
"""
settings = self._client.settings
url = settings.sync_base_url.rstrip("/") + sync_api.ENDPOINT_HEALTH
try:
self._client.http_client.get(
url,
headers={sync_api.MODEL_HEADER: self.config.model},
timeout=min(settings.sync_http_timeout, 10.0),
)
except httpx.HTTPError:
return False
return True

def close(self) -> None:
"""Shuts down the worker-thread pool used by `transcribe_async`."""
self._executor.shutdown(wait=False)

def __enter__(self) -> "SyncTranscriber":
return self

def __exit__(self, *_exc: Any) -> None:
self.close()
1 change: 1 addition & 0 deletions assemblyai/sync_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from . import types

ENDPOINT_TRANSCRIBE = "/transcribe"
ENDPOINT_HEALTH = "/healthz"
MODEL_HEADER = "X-AAI-Model"


Expand Down
3 changes: 3 additions & 0 deletions assemblyai/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ class Settings(BaseSettings):
http_timeout: float = 30.0
"The default HTTP timeout for general requests"

keepalive_expiry: Optional[float] = None
"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."

base_url: str = "https://api.assemblyai.com"
"The base URL for the AssemblyAI API"

Expand Down
Loading
Loading