Python SDK

The official Python client for the Speech Revolutions STT API. It includes a synchronous SpeechRevolutions client and an asyncio AsyncSpeechRevolutions client. Both expose the same transcribe() method.

Source on GitHub · report an issue · PyPI

Install

bash
pip install speechrevolutions

# optional console progress bars (tqdm)
pip install "speechrevolutions[progress]"

Quickstart

Pass transcribe() a local path, a URL, raw bytes, or a file object. With the default output_type="json", the SDK parses the response into a result object.

transcribe.py
from speechrevolutions import SpeechRevolutions

client = SpeechRevolutions()  # reads SPEECHREVOLUTIONS_API_KEY
result = client.transcribe("meeting.mp3", speaker_labels=True)

print(result.text)
for u in result.utterances:
    print(f"{u.speaker}: {u.text}")

From a URL or file

transcribe() detects http(s) URLs automatically. Use the transcribe_url() and transcribe_file() aliases to make the source explicit.

python
# auto-detected
result = client.transcribe("https://example.com/audio.mp3")

# explicit aliases
result = client.transcribe_url("https://example.com/audio.mp3")
result = client.transcribe_file("./local.wav")

Options

Pass options as keyword arguments or as a TranscribeOptions object:

python
from speechrevolutions import TranscribeOptions

# kwargs — `diarize` is a Deepgram-compatible alias for `speaker_labels`
result = client.transcribe("a.mp3", diarize=True, output_type="srt")

# config object
result = client.transcribe(
    "a.mp3",
    options=TranscribeOptions(speaker_labels=True),
)
KwargTypeDefaultNotes
output_typestr"json"txt | json | srt | vtt | docx | pdf
word_timestampsboolTruePer-word start/end times
speaker_labelsboolTrueLabel who spoke each segment
diarizebool—Alias for speaker_labels
nltkboolTrueRestore punctuation & capitalization
tierstr"standard"standard — the only tier currently available
custom_vocabularylist[str] | NoneNoneDomain terms to bias toward
languagestr | NoneNoneISO 639-1 code (e.g. "en") to skip detection; None auto-detects. When to pin
on_progressCallableNoneTranscription-progress callback (see below)
on_upload_progressCallableNoneUpload byte-progress callback
progressboolFalseRender live console bars

Live progress

The SDK reports progress for both the file upload and the transcription, as a console bar, a callback, or both. When you enable both, the bars render and your callbacks fire for every event. AssemblyAI and Deepgram expose no percentage for pre-recorded audio.

Files under about 3 MiB may report no transcription progress before they complete. Expect the bar to jump from the end of the upload to done.

python
# 1. Console bars — an "Uploading" byte bar, then a "Transcribing" bar.
#    Uses tqdm if installed: pip install "speechrevolutions[progress]"
result = client.transcribe("meeting.mp3", progress=True)

# 2. Programmatic — read event.percent (0-100, or None until total is known)
def on_progress(event):        # transcription
    print(event.percent, event.step)      # e.g. 42.0 "transcribe"

def on_upload(event):          # upload (event.step == "upload")
    print("upload", event.percent)

result = client.transcribe(
    "meeting.mp3",
    on_progress=on_progress,
    on_upload_progress=on_upload,
    progress=True,             # bars AND callbacks together
)

Each ProgressEvent carries .completed, .total, .step, .elapsed_seconds, and a computed .percent (0–100, or None when the total is not yet known).

For a web UI, see Live progress for web apps. It combines both callbacks into a single 0–100 bar for your frontend.

Async

The asyncio client has the same API as the sync client. Use async with so the underlying HTTP client closes on exit.

transcribe_async.py
import asyncio
from speechrevolutions import AsyncSpeechRevolutions

async def main():
    async with AsyncSpeechRevolutions() as client:
        result = await client.transcribe(
            "meeting.mp3",
            speaker_labels=True,
            progress=True,
        )
        print(result.text)

asyncio.run(main())

Result shape

With output_type="json", the SDK returns a Transcript object. The client writes files only when you call save().

MemberDescription
result.textFull transcript text
result.transcriptAlias for result.text
result.wordsWords with start, end, and speaker
result.utterancesSpeaker turns
result.to_deepgram()Deepgram-shaped dict, for migrations
result.to_dict()Normalized JSON dict
result.content / result.save(path)Raw bytes / write the output to disk
python
dg = result.to_deepgram()
print(dg["results"]["channels"][0]["alternatives"][0]["transcript"])

# save() appends the output type when the path has no extension
out = result.save("output")   # -> "output.json"
print("saved to", out)

Webhooks

Pass callback_url to get notified when a job finishes instead of holding the call open. Use this for server and background workloads. When the job completes or fails permanently, Speech Revolutions sends a signed JSON POST to your URL:

python
client.transcribe("meeting.mp3", callback_url="https://you.example.com/hook")

The POST body is {job_id, status: "completed"|"failed", download_url?, step?, reason?}. It is signed with HMAC-SHA256 over the raw body, in the X-SR-Signature: sha256=<hex> header. The request also carries X-SR-Event (the status) and a unique X-SR-Delivery ID. Verify the signature against the raw bytes you received, not a re-serialized dict, and use a constant-time comparison. Copy your signing secret from the console (API Keys → Webhook signing secret) into SPEECHREVOLUTIONS_WEBHOOK_SECRET. The webhooks guide covers the payload, retries, and secret rotation.

webhooks.py
import hashlib
import hmac


def verify_signature(raw_body: bytes, signature_header: str, signing_secret: str) -> bool:
    """Return True if X-SR-Signature matches the raw request body."""
    expected = "sha256=" + hmac.new(
        signing_secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")


# FastAPI receiver
# @app.post("/webhooks/speechrevolutions")
# async def receive(request: Request):
#     raw = await request.body()
#     if not verify_signature(raw, request.headers.get("X-SR-Signature", ""), SECRET):
#         raise HTTPException(status_code=401, detail="bad signature")
#     event = json.loads(raw)
#     if event["status"] == "completed":
#         ...  # mark done; fetch event["download_url"]
#     else:
#         ...  # event["step"], event["reason"]
#     return {"ok": True}  # a 2xx acks delivery (we retry on 5xx)

Retrieve results later

Fetch a job by ID at any time, for example after a webhook arrives or after your service restarts. The download URL is generated on each request, so you can fetch results long after the original upload.

retrieve.py
# Get a job's current status (processing | completed | failed)
status = client.get_job_status(job_id)
print(status.status)

if status.is_completed:
    result = client.get_transcript(job_id)  # downloads + parses into a Transcript
    print(result.text)
elif status.is_failed:
    print(status.failed_stage, status.reason)

# List your most-recent jobs (newest first), cursor-paginated
page = client.list_jobs(limit=50)
print(page["jobs"], page["next_before"])
for job in page["jobs"]:
    print(job["job_id"], job["created_at"])

Robustness

Configure retries, backoff, and an outbound proxy on the client. The SDK retries 429, 5xx, and network errors automatically and honors the Retry-After header.

python
client = SpeechRevolutions(
    max_retries=3,
    retry_backoff=0.5,               # seconds, exponential
    proxies={"https": "http://proxy.internal:8080"},
)

Errors are typed. Each carries a .status_code and the server's .request_id. Include the request ID when you contact support.

python
from speechrevolutions.exceptions import RateLimitError, AuthenticationError

try:
    result = client.transcribe("meeting.mp3")
except RateLimitError as e:
    print(e.status_code, e.request_id)  # e.g. 429 "req_..."
except AuthenticationError as e:
    print(e.status_code, e.request_id)

Authentication

The SDK reads your API key from the environment:

bash
export SPEECHREVOLUTIONS_API_KEY=stt_...

Or pass it explicitly:

python
client = SpeechRevolutions(api_key="stt_...")

The SDK uploads the file in parts, retrying any part that fails. It then listens on the SSE job stream and converts the completed and total counts into percent.