You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit efc202e
Browse filesBrowse the repository at this point in the historyBrowse files
-`aai.AsyncSyncTranscriber` — Asyncio counterpart of `SyncTranscriber`. Same input types, config, result, and errors; `transcribe()`, `transcribe_live()` and `warm()` are coroutines; `open_live()` returns an `AsyncLiveSession`. Owns an HTTP pool: use `async with` or `await aclose()`, or pass an `aai.AsyncClient` to share one
-`aai.SyncTranscriptResponse` — Sync result: `.text`, `.words` (`SyncWord` with `confidence` always, `start`/`end` only when `timestamps=True`), `.confidence`, `.audio_duration_ms`, `.session_id`, `.request_time_ms`
51
+
-`aai.DictationTranscriber` — Dictation API: audio uploaded as it is spoken over one live request, transcript (and optional LLM pass) out. Methods: `open_live()` (push-style `DictationLiveSession`: `write()`/`close()`/`result()`/`abort()`), `transcribe_live()` (iterable, file object, bytes or path), `warm()`. There is no buffered `transcribe()`: every entry point posts to `/v1/transcribe/live`
52
+
-`aai.AsyncDictationTranscriber` — Asyncio counterpart of `DictationTranscriber`; `open_live()` returns an `AsyncDictationLiveSession`. Owns an HTTP pool: use `async with` or `await aclose()`
|`assemblyai.prerecorded.v2.AsyncTranscriber`| The same, from asyncio code |
105
105
|`assemblyai.sync.v1.SyncTranscriber`| Short clips (≤120s, ≤40MB) where you want the transcript back in one request, at the lowest latency — from a file you already have (`transcribe()`) or uploaded while it is still being recorded (`open_live()`, `transcribe_live()`) |
106
106
|`assemblyai.sync.v1.AsyncSyncTranscriber`| The same, from asyncio code |
107
+
|`assemblyai.dictation.v1.DictationTranscriber`| Dictation: short spoken notes uploaded as they are spoken, returned as one transcript with an optional LLM rewrite (`final_text`). Push audio from a callback (`open_live()`) or hand over an iterator, file object, bytes or path (`transcribe_live()`) |
108
+
|`assemblyai.dictation.v1.AsyncDictationTranscriber`| The same, from asyncio code |
107
109
|`assemblyai.streaming.v3.RealTimeTranscriber`| Live audio (microphone, telephony, voice agents), transcribed as it arrives over a websocket session |
108
110
|`assemblyai.streaming.v3.AsyncRealTimeTranscriber`| The same, from asyncio code |
109
111
110
-
The versioned path is the preferred import for new code. The prerecordedand sync classes are also available as top-level shortcuts (`aai.Transcriber`, `aai.SyncTranscriber`, …) — see [Migrating to 1.0](MIGRATION.md) for the details.
112
+
The versioned path is the preferred import for new code. The prerecorded, sync and dictation classes are also available as top-level shortcuts (`aai.Transcriber`, `aai.SyncTranscriber`, `aai.DictationTranscriber`, …) — see [Migrating to 1.0](MIGRATION.md) for the details.
111
113
112
114
---
113
115
@@ -677,6 +679,205 @@ except aai.SyncTranscriptError as error:
677
679
678
680
---
679
681
682
+
### **Dictation Examples**
683
+
684
+
`aai.DictationTranscriber` is for dictation: a person speaks a short note and gets it back as text, optionally cleaned up or reformatted by an LLM. It has one connection, the live upload — audio is sent as it is spoken, the service transcribes each speech segment as it lands, and when the speaker stops what remains is the final segment and the LLM pass. There is no job id and no polling. Audio must be WAV or raw 16-bit PCM, up to 120 s per request.
685
+
686
+
The result is a `DictationResponse`: `text` is the raw transcript, `llm_response` the rewritten text when the LLM pass ran, and `final_text` is the one to show the user — the rewrite when there is one, the raw transcript otherwise.
687
+
688
+
<details>
689
+
<summary>Dictate from a microphone (`open_live()`)</summary>
690
+
691
+
Most audio sources deliver chunks in a callback. `open_live()` is built for that: the request starts the moment the session opens, `write()` from the callback (safe from any thread, never blocks), leave the `with` block when the speaker stops, and `result()` returns the transcript.
692
+
693
+
```python
694
+
import assemblyai as aai
695
+
import sounddevice as sd # pip install sounddevice
696
+
697
+
aai.settings.api_key ="<YOUR_API_KEY>"
698
+
699
+
RATE=16000
700
+
config = aai.DictationConfig(sample_rate=RATE, channels=1) # raw PCM needs both
# leaving the block ends the audio; the final segment is all that is left
711
+
print(session.result().final_text)
712
+
```
713
+
714
+
Leaving the `with` block calls `close()`. If the block raises, the session is aborted instead and `result()` raises. Call `abort()` yourself to drop a dictation you no longer want transcribed.
715
+
716
+
This is **not** the streaming API. A session returns one finished transcript when the audio ends; use `aai.RealTimeTranscriber` when you need words back while the speaker is still talking.
717
+
718
+
The server aborts an upload that goes silent for long, so keep writing until the speaker is done rather than pausing. Errors that would normally arrive at the end (bad key, rate limit, capacity, audio too large) can surface part-way through the upload; `result()` raises them as `DictationError`.
719
+
720
+
</details>
721
+
722
+
<details>
723
+
<summary>Dictate from an iterator, file object, bytes or path (`transcribe_live()`)</summary>
724
+
725
+
When the audio already comes as something you can iterate, or as a file object that fills over time, hand it to `transcribe_live()` directly. It blocks until the audio ends and returns the transcript. `open_live()` is this method with a queue in front of it.
726
+
727
+
Audio you already hold whole — raw `bytes`, or a local path — goes to `transcribe_live()` too. It travels the same connection as a single chunk; there is no separate buffered request.
result = aai.DictationTranscriber().transcribe_live(recorder.stdout, config=config)
742
+
743
+
# Or any generator of chunks:
744
+
deffrom_call(call):
745
+
while call.active:
746
+
yield call.read_frame()
747
+
748
+
result = aai.DictationTranscriber().transcribe_live(from_call(call), config=config)
749
+
750
+
# Or a recording you already have (WAV carries its own rate and channels):
751
+
result = aai.DictationTranscriber().transcribe_live("./note.wav")
752
+
print(result.final_text)
753
+
```
754
+
755
+
End the iterator to finish. Anything the producer raises propagates unchanged and drops the upload. URLs are not accepted; use `aai.Transcriber` for URL ingestion.
756
+
757
+
</details>
758
+
759
+
<details>
760
+
<summary>Rewrite the transcript with an LLM instruction</summary>
761
+
762
+
Set `llm_instruction` to have the service run a follow-up pass over the transcript. The rewrite comes back in `llm_response`; the raw transcript stays in `text`. If the pass fails, `llm_error` says why and `final_text` falls back to `text`, so reading `final_text` is safe either way.
763
+
764
+
```python
765
+
import assemblyai as aai
766
+
767
+
aai.settings.api_key ="<YOUR_API_KEY>"
768
+
769
+
config = aai.DictationConfig(llm_instruction="Format this as a SOAP note.")
770
+
771
+
result = aai.DictationTranscriber().transcribe_live("./visit.wav", config=config)
772
+
773
+
print(result.final_text) # the SOAP note
774
+
print(result.text) # what was actually said
775
+
if result.llm_error:
776
+
print("LLM pass failed:", result.llm_error)
777
+
```
778
+
779
+
The instruction is capped at 2048 characters.
780
+
781
+
</details>
782
+
783
+
<details>
784
+
<summary>Configure the dictation</summary>
785
+
786
+
```python
787
+
import assemblyai as aai
788
+
789
+
aai.settings.api_key ="<YOUR_API_KEY>"
790
+
791
+
config = aai.DictationConfig(
792
+
language_codes=["en", "es"], # one code, or several for multilingual audio
793
+
keyterms_prompt=["AssemblyAI", "Universal"], # bias the decoder; ≤2048 chars total
result = aai.DictationTranscriber().transcribe_live("./note.wav", config=config)
798
+
```
799
+
800
+
`sample_rate` and `channels` are required only for raw PCM; WAV carries them in its own header. A config passed to `transcribe_live()` or `open_live()` overrides the transcriber's default config for that call. `DictationConfig` rejects unknown fields, so a typo or a sync-only option surfaces as a validation error instead of a setting that quietly does nothing.
801
+
802
+
</details>
803
+
804
+
<details>
805
+
<summary>Pre-warm the connection</summary>
806
+
807
+
A request that connects on demand pays the full DNS + TCP + TLS handshake before the first audio byte can leave. Call `warm()` as soon as you know audio is coming — when the user reaches for the record button — so the request that follows reuses the open connection.
808
+
809
+
```python
810
+
import assemblyai as aai
811
+
812
+
aai.settings.api_key ="<YOUR_API_KEY>"
813
+
814
+
with aai.DictationTranscriber() as transcriber:
815
+
transcriber.warm() # fire when the user is about to speak
816
+
with transcriber.open_live(config) as session:
817
+
record_into(session.write)
818
+
print(session.result().final_text)
819
+
```
820
+
821
+
</details>
822
+
823
+
<details>
824
+
<summary>Use it from asyncio (`AsyncDictationTranscriber`)</summary>
825
+
826
+
`aai.AsyncDictationTranscriber` is the asyncio counterpart — same audio sources, config, result and errors, with `transcribe_live()` and `warm()` as coroutines. `open_live()` returns an `AsyncDictationLiveSession`: `write()` and `close()` are plain functions so a callback can call them, and `result()` and `abort()` are coroutines. The request runs as a task on the event loop. `write()` must be called on the loop's thread; from an audio library's capture thread, schedule it with `loop.call_soon_threadsafe(session.write, chunk)`.
"""Transcribes the PCM frames a browser sends over one websocket."""
838
+
asyncwith aai.AsyncDictationTranscriber() as transcriber:
839
+
asyncwith transcriber.open_live(config) as session:
840
+
asyncfor frame in websocket:
841
+
session.write(frame)
842
+
result =await session.result()
843
+
await websocket.send(result.final_text)
844
+
```
845
+
846
+
`transcribe_live()` also takes an async iterable of chunks, as well as a file object, plain iterable, bytes or path. A file object or path is read in a worker thread, so a blocking `read()` is fine; a plain iterable is consumed inline and must not block the loop.
847
+
848
+
```python
849
+
asyncdefframes(websocket):
850
+
asyncfor frame in websocket:
851
+
yield frame
852
+
853
+
result =await transcriber.transcribe_live(frames(websocket), config=config)
854
+
```
855
+
856
+
The transcriber owns an HTTP connection pool: use `async with`, or call `await transcriber.aclose()`. To share one pool between transcribers, pass an `aai.AsyncClient`, which stays yours to close.
857
+
858
+
</details>
859
+
860
+
<details>
861
+
<summary>Handle errors</summary>
862
+
863
+
Failures raise `aai.DictationError` with the HTTP `status_code`, a machine-readable `error_code` (`bad_audio`, `audio_too_large`, `capacity_exceeded`, `inference_timeout`, …), and `retry_after` (seconds) on 429/503 responses. It is a separate class from `aai.SyncTranscriptError`.
864
+
865
+
```python
866
+
import assemblyai as aai
867
+
868
+
aai.settings.api_key ="<YOUR_API_KEY>"
869
+
870
+
try:
871
+
result = aai.DictationTranscriber().transcribe_live("./note.wav")
0 commit comments