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
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ jobs:
python-version: ${{ matrix.py }}
- name: Setup test suite
run: |
sudo apt-get update && sudo apt-get install -y portaudio19-dev
python_version="${{ matrix.py }}"
python_version="${python_version/./}"
tox -f "py$python_version" -vvvv --notest
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ async def main():
asyncio.run(main())
```

**Microphone streaming** (both clients): `pip install "assemblyai[extras]"` for `pyaudio`, then pass `aai.extras.MicrophoneStream(sample_rate=16000)` to `client.stream(...)`.
**Microphone streaming**: the SDK does not capture audio — supply 16-bit PCM chunks yourself (e.g. via `pyaudio` or `sounddevice`) and pass the iterable to `client.stream(...)`.

**Voice-agent tuning** (knobs that matter most when building a voice agent):
```python
Expand Down Expand Up @@ -404,7 +404,7 @@ async with AsyncStreamingClient(StreamingClientOptions(token=token_from_server))
```

**Other gotchas**:
- Don't pass `aai.extras.stream_file(...)` to `AsyncStreamingClient.stream()` — it uses blocking `time.sleep` and starves the read task. Use an `async def` generator with `await asyncio.sleep(...)` instead.
- Don't feed `AsyncStreamingClient.stream()` from a sync generator that blocks (e.g. `time.sleep` pacing) — it starves the read task. Use an `async def` generator with `await asyncio.sleep(...)` instead.
- `format_turns=True` enables punctuation/casing on confirmed end-of-turns. Toggle mid-session via `client.set_params(StreamingSessionParameters(format_turns=True))`.
- `AsyncStreamingClient` used as `async with` calls `disconnect(terminate=True)` on normal block exit and `disconnect(terminate=False)` on exception — no explicit `disconnect()` needed inside the block.

Expand All @@ -414,14 +414,14 @@ async with AsyncStreamingClient(StreamingClientOptions(token=token_from_server))
- **`speech_models` takes a list** with fallback ordering: `["universal-3-5-pro", "universal-2"]`
- **PII redaction uses `set_redact_pii()`**, not a constructor parameter
- **Streaming v3 lives in its own module**: `assemblyai.streaming.v3` (there is no other streaming API in this SDK). See the "Streaming (real-time)" section above.
- **Microphone streaming needs extras**: `pip install "assemblyai[extras]"` for `pyaudio`
- **The SDK does not capture microphone audio**: bring your own capture (e.g. `pyaudio`, `sounddevice`) and stream the PCM chunks
- **`transcribe_async()` returns a `concurrent.futures.Future`**, not an asyncio coroutine. In asyncio code use `aai.AsyncTranscriber` (see "Asyncio transcription" above) — or `aai.AsyncSyncTranscriber` for the sync API
- **Timestamps are in milliseconds** throughout the SDK
- **Minimum Python**: 3.8+

## Dependencies

`httpx`, `pydantic`, `typing-extensions`, `websockets`. Optional: `pyaudio` via `[extras]`.
`httpx`, `pydantic`, `typing-extensions`, `websockets`.

## Docs

Expand Down
44 changes: 11 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1017,12 +1017,20 @@ Real-time speech-to-text via WebSocket against the `universal-3-5-pro` model. Th
<summary>Stream a local file (sync)</summary>

```python
import assemblyai as aai
import time

from assemblyai.streaming.v3 import (
BeginEvent, StreamingClient, StreamingClientOptions, StreamingError,
StreamingEvents, StreamingParameters, TerminationEvent, TurnEvent,
)

def stream_file(path: str, sample_rate: int, chunk_duration: float = 0.3):
bytes_per_chunk = int(sample_rate * chunk_duration) * 2
with open(path, "rb") as f:
while chunk := f.read(bytes_per_chunk):
yield chunk
time.sleep(chunk_duration)

def on_begin(client, event: BeginEvent):
print(f"Session started: {event.id}")

Expand All @@ -1045,37 +1053,7 @@ client.connect(StreamingParameters(
sample_rate=16000, speech_model="universal-3-5-pro",
))
try:
client.stream(aai.extras.stream_file(filepath="audio.wav", sample_rate=16000))
finally:
client.disconnect(terminate=True)
```

</details>

<details>
<summary>Stream your microphone (sync)</summary>

`MicrophoneStream` requires PyAudio:

```bash
pip install -U "assemblyai[extras]"
```

```python
import assemblyai as aai
from assemblyai.streaming.v3 import (
StreamingClient, StreamingClientOptions, StreamingEvents, StreamingParameters,
)

def on_turn(client, event):
print(f"{event.transcript} (end_of_turn={event.end_of_turn})")

client = StreamingClient(StreamingClientOptions(api_key="<YOUR_API_KEY>"))
client.on(StreamingEvents.Turn, on_turn)
client.connect(StreamingParameters(sample_rate=16000, speech_model="universal-3-5-pro"))

try:
client.stream(aai.extras.MicrophoneStream(sample_rate=16000))
client.stream(stream_file("audio.wav", sample_rate=16000))
finally:
client.disconnect(terminate=True)
```
Expand Down Expand Up @@ -1149,7 +1127,7 @@ See [`examples/streaming_dual_channel.py`](./examples/streaming_dual_channel.py)
<details>
<summary>Stream a local file (async)</summary>

`AsyncStreamingClient` mirrors `StreamingClient` with async methods. It's safe to use as an async context manager — `disconnect()` runs on block exit even if user code raises. Don't pass `extras.stream_file` directly (it uses blocking `time.sleep`); pace from an async generator instead.
`AsyncStreamingClient` mirrors `StreamingClient` with async methods. It's safe to use as an async context manager — `disconnect()` runs on block exit even if user code raises. Pace the audio from an async generator so the event loop is never blocked.

```python
import asyncio
Expand Down
3 changes: 0 additions & 3 deletions assemblyai/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from . import extras
from .__version__ import __version__
from .async_client import AsyncClient
from .client import Client
Expand Down Expand Up @@ -149,8 +148,6 @@
"WordSearchMatch",
# package globals
"settings",
# packages
"extras",
# version
"__version__",
]
215 changes: 0 additions & 215 deletions assemblyai/extras.py

This file was deleted.

3 changes: 0 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ def get_version() -> str:
"typing-extensions>=3.7",
"websockets>=11.0",
],
extras_require={
"extras": ["pyaudio>=0.2.13"],
},
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
Expand Down
Loading
Loading