Skip to main content

ConvoZen Voice SDK

Text-to-Speech (TTS) and Speech-to-Text (STT) for Python.

One API key for both TTS and STT.

Install

pip install convozen

Requires Python 3.9+


TTS — Convert Text to Speech

Copy and run:

import convozen

client = convozen.Client(api_key="your-api-key")

audio = client.tts.synthesize("नमस्ते… मुझे आपके सर्विस के बारे में थोड़ी जानकारी चाहिए।")
# language omitted → server auto-detects Devanagari as Hindi

with open("output.wav", "wb") as f:
    f.write(audio)

With options:

import convozen

client = convozen.Client(api_key="your-api-key")

audio = client.tts.synthesize(
    text="Welcome to Playground.",
    language="en",                    # optional — omit for native-script auto-detect
    voice="roohi",                    # default: "roohi"
    model="ragini-v1",                # default: "ragini-v1"
    speed=1.2,                        # default: 1.0
    enable_transliteration=False,     # default: False — opt-in Roman→native
    is_roman_input=False,             # default: False — Latin as Indic romanization
)

with open("output.wav", "wb") as f:
    f.write(audio)

Parameters

Parameter Type Default Description
text str required Text to convert to speech
language str | None None Language code. Optional — omit for native Indic script auto-detect on the server
voice str "roohi" Voice ID for synthesis (see available voices below)
model str "ragini-v1" TTS model: "ragini-v1" (Indian languages), "ragini-v2" (Ragini 2.0, higher fidelity), "ragini-lite" / "ragini_lite" (lightweight Hindi), or "rawi-v1" (Arabic)
speed float 1.0 Speech speed. 0.5 = half speed, 2.0 = double speed. Not supported on ragini-v2 or ragini_lite — accepted but silently ignored.
sample_rate int model-dependent Output sample rate in Hz. Defaults to 48000 for ragini-v2, 22050 for ragini_lite, 24000 for other models
stream bool False If True, returns audio chunks as they are generated
format str "wav" Audio output format. Currently only wav is supported
enable_transliteration bool False Opt-in Roman→native transliteration for romanized Indic (adds latency)
is_roman_input bool False Treat Latin text as Indic romanization; pass a language hint when transliteration is off

Language auto-detect & romanized Indic

# Native script — no language needed
audio = client.tts.synthesize("नमस्ते आप कैसे हैं")

# Romanized Hindi — high quality (transliterate first)
audio = client.tts.synthesize(
    "namaste kaise ho",
    language="hi",
    enable_transliteration=True,
)

# Romanized Hindi — faster path (keep Latin, hint language for phonemize)
audio = client.tts.synthesize(
    "namaste kaise ho",
    language="hi",
    is_roman_input=True,
)

Streaming

import convozen

client = convozen.Client(api_key="your-api-key")

for chunk in client.tts.synthesize("Long text here...", language="en", stream=True):
    audio_player.write(chunk)

Available Voices

These are the ragini-v1 voices. ragini-v2 has different voice sets — see Ragini 2.0 → Voices; ragini_lite has a single voice, and rawi-v1 has its own. Passing a voice to a model that does not have it is not an error: the name is forwarded as-is and you get an arbitrary voice back with a 200.

Voice ID Default
Roohi roohi Yes
Amaya amaya
Kiyansh kiyansh
Neeraj neeraj
Manya manya
Nidhi nidhi
Ira ira
Trisha trisha
Charvi charvi
audio = client.tts.synthesize("Hello", language="en", voice="roohi")

Choosing a TTS model

Model Languages Rate Speed control Use it for
ragini-v1 (default) en, hi, kn, ta, te 24 kHz Yes The general default
ragini-v2 en, hi, kn, ta, te 48 kHz Not yet Highest fidelity
ragini_lite hi, en 22.05 kHz No Smallest and fastest
rawi-v1 Arabic + 6 dialects 24 kHz Yes Arabic

ragini-v1 and ragini-v2 cover the same languages, so switching is a one-word change — but the voices differ, so change voice alongside model.

Ragini 2.0

ragini-v2 is the second-generation Ragini backend (VoxCPM2), serving the same languages as ragini-v1 at 48 kHz instead of 24 kHz.

audio = client.tts.synthesize(
    "नमस्ते, आप कैसे हैं?",
    language="hi",
    model="ragini-v2",
    voice="sherin",
)   # note: `speed` is not supported on ragini-v2 yet — see below

"ragini-v2", "ragini_v2", "ragini-2" and "ragini-2.0" are all accepted — the SDK normalizes them to the same model.

Supported parameters

Parameter Value for ragini-v2 Notes
text any non-empty string Required
language "en", "hi", "kn", "ta", "te" Anything else is rejected — see below
voice see the voice table below Voice sets differ per language group
sample_rate int, defaults to 48000 The pods always return 48 kHz; see below
stream True / False Chunked streaming supported
format "wav" Only wav is supported

Not supported / no effect

Parameter Behavior on ragini-v2
speed Not supported yet. The request is accepted and the audio comes back at normal pace — you get no error, so do not rely on it. Use ragini-v1 if you need speed control today.
sample_rate Output is always 48 kHz. Passing another value does not resample; resample client-side if you need a different rate.

Voices

Ragini 2.0 runs two checkpoints with different voice sets. A voice from the wrong group does not error — the pod passes an unknown name through as a raw speaker tag, so a typo returns an arbitrary voice rather than a 400.

Languages Voices Default
en, hi shrajay, siddharth, parmi, sherin, bhavya, shreya shrajay
kn, ta, te amaya, parmi, roohi, bhavya/bhagya, shrajay, siddharth amaya

Unsupported languages are rejected

Unlike ragini-v1, a language with no Ragini 2.0 deployment returns a 400 rather than falling back to another checkpoint — sending Marathi to the en/hi model would otherwise produce plausible-sounding but wrong audio.

client.tts.synthesize("...", language="mr", model="ragini-v2")
# APIError: 400 - ragini-v2 is not available for language 'mr'.
#                Supported languages: ['en', 'hi', 'kn', 'ta', 'te']

If the Ragini 2.0 pods are unreachable, the request fails with a 502. It never silently falls back to ragini-v1.

Ragini Lite

ragini_lite is the lightweight Ragini backend — a Piper/VITS Hindi voice served at 22.05 kHz. Use it when you want a smaller, faster Hindi voice.

audio = client.tts.synthesize(
    "नमस्ते, आप कैसे हैं?",
    language="hi",
    model="ragini-lite",   # "ragini-lite" and "ragini_lite" both work
)

Both "ragini-lite" (hyphen, matching ragini-v1) and "ragini_lite" (underscore) are accepted — the SDK normalizes them to the same model.

Supported parameters

Parameter Value for ragini_lite Notes
text any non-empty string Required
model "ragini-lite" or "ragini_lite" Both forms accepted
language "hi", "en" Hindi voice
sample_rate int, defaults to 22050 When omitted, the SDK sends 22050 (vs 24000 for other models)
stream True / False Chunked streaming supported
format "wav" Only wav is supported

Not supported / no effect

Parameter Behavior on ragini_lite
voice Single voice only. Defaults to roohi; any other voice ID falls back to roohi.
speed Not applied. Accepted for API compatibility but has no effect on the output.

Rawi — Arabic TTS

Use model="rawi-v1" for Arabic dialect synthesis:

import convozen

client = convozen.Client(api_key="your-api-key")

audio = client.tts.synthesize(
    text="Welcome to Playground.",
    language="jo",          # Jordanian dialect
    voice="hadi",
    model="rawi-v1",
    speed=1.2,
)

with open("output.wav", "wb") as f:
    f.write(audio)

Rawi languages: en, ar, ae, eg, jo, ms, hz, nj

Rawi voices: ahmad, hadi, karim, mohammad, rafoush, ghaida, hana, heba, layan, salma


STT — Convert Speech to Text

Copy and run:

import convozen

client = convozen.Client(api_key="your-api-key")

result = client.stt.transcribe("recording.wav")
print(result.text)    # "hello how can I help you"
print(result.score)   # -2.45  (confidence — closer to 0 is better)

By default this transcribes mono, single-speaker audio and returns an STTResponse.

Alif — Arabic STT

Use model="alif-v1" for Arabic speech recognition:

import convozen

client = convozen.Client(api_key="your-api-key")

result = client.stt.transcribe(
    "arabic_recording.wav",
    model="alif-v1",
)
print(result.text)    # Arabic transcript
print(result.score)   # confidence — closer to 0 is better

Notes for alif-v1:

  • Optimized for Arabic audio (all dialects supported by the model)
  • Plain transcription only — use akshara-pro for diarization, stereo, or Indian-language STT
  • lang_tags are not required (the model does not use language-penalty hints)

Word-level timestamps

Timestamps are opt-in — pass word_time_stamps=True:

result = client.stt.transcribe("recording.wav", word_time_stamps=True)

for w in result.word_timestamps:
    print(f"{w.word}  {w.start_s:.2f}s – {w.end_s:.2f}s")

Works on both the transcript and diarization paths (per-turn timestamps on DiarizeTurn.word_timestamps).


Speaker Diarization (mono)

For a mono recording with multiple speakers, set diarize=True to get a per-speaker breakdown (DiarizeResponse):

result = client.stt.transcribe("call.wav", diarize=True)

for turn in result.turns:
    print(f"[{turn.speaker_id}]  {turn.start_sec:.1f}s – {turn.end_sec:.1f}s")
    print(f"  {turn.transcript}")

# [s0]  0.0s – 3.2s
#   Hello, this is support. How can I help you?
# [s1]  4.0s – 7.8s
#   Hi, I'd like to reschedule my appointment.

If you know how many speakers to expect, pass n_speakers (an integer 2–20) as a hint. Leave it as None (default) to auto-detect:

result = client.stt.transcribe("interview.wav", diarize=True, n_speakers=2)

Response fields (DiarizeResponse):

Field Type Description
turns list[DiarizeTurn] Speaker turns in order
num_speakers int Number of distinct speakers detected
total_duration_sec float Total audio duration in seconds

Each DiarizeTurn has speaker_id, start_sec, end_sec, transcript, and word_timestamps (populated when word_time_stamps=True).


Stereo audio

If each speaker is on a separate channel (e.g. a 2-channel call recording), set audio_channels="stereo". Each channel is treated as one speaker, and you get a DiarizeResponse:

result = client.stt.transcribe("stereo_call.wav", audio_channels="stereo")

For stereo, keep diarize=False (the channels already are the speakers) and leave n_speakers=None. The declared audio_channels must match the file — a mono file declared "stereo" (or vice-versa) is rejected with a 400.


Denoising

For noisy multi-speaker audio, enable denoise=True. It applies on the diarization path (diarize=True or audio_channels="stereo"):

result = client.stt.transcribe("noisy_call.wav", diarize=True, denoise=True)

Specify Languages

If you know which languages are spoken in the audio, pass them in lang_tags. This improves accuracy — especially for multilingual audio like Hindi + English call recordings:

result = client.stt.transcribe(
    "recording.wav",
    lang_tags=["hi", "en"],
)
print(result.text)  # "हां मुझे appointment reschedule करना है"

Keyword Boosting

Have domain-specific words the model keeps getting wrong? Pass them in keywords and the model will bias towards recognizing them:

# Without keyword boosting: "can you tell me about conversion"
# With keyword boosting:    "can you tell me about convozen"

result = client.stt.transcribe(
    "recording.wav",
    keywords=["convozen", "akshara"],
)

Choose a Model

Use model to select which ASR model processes the audio:

result = client.stt.transcribe("recording.wav", model="akshara-pro")   # default
result = client.stt.transcribe("recording.wav", model="akshara-base")
result = client.stt.transcribe("arabic.wav", model="alif-v1")          # Arabic STT
Model Best for
akshara-pro Maximum accuracy for Indian languages (default)
akshara-base Lighter / faster Indian-language STT
alif-v1 Arabic speech-to-text

Parameters

Parameter Type Default Description
audio str | os.PathLike required Path to the audio file
model str "akshara-pro" ASR model: "akshara-pro", "akshara-base", or "alif-v1" (Arabic)
audio_channels str "mono" "mono" or "stereo". Must match the actual file
diarize bool False True to return per-speaker turns (mono only)
n_speakers int None Expected speaker count (2–20) for mono diarization. None → auto-detect
denoise bool False Apply denoising on the diarization path — helps on noisy audio
lang_tags list[str] None Languages spoken in the audio — improves accuracy when known
word_time_stamps bool False True to return per-word timestamps
blank_penalty float None Penalizes silence/blank tokens; increase to reduce empty gaps. None → derived from lang_tags
keywords list[str] None Domain words the model should bias towards recognizing

When to use what

audio_channels diarize n_speakers Result
"mono" False None Plain transcript → STTResponse
"mono" True None Auto speaker count → DiarizeResponse
"mono" True 2–4 Hinted speaker count → DiarizeResponse
"stereo" False None Channel-split diarization → DiarizeResponse

Anything outside these rows raises a ValueError (e.g. n_speakers without diarize, n_speakers outside 2–20, diarize=True with "stereo").


Supported Languages

Code Language TTS STT
en English Yes (ragini-v1, ragini-v2) Yes
hi Hindi Yes (ragini-v1, ragini-v2, ragini_lite) Yes
ta Tamil Yes (ragini-v1, ragini-v2) Yes
te Telugu Yes (ragini-v1, ragini-v2) Yes
kn Kannada Yes (ragini-v1, ragini-v2) Yes
ar Arabic Yes (rawi-v1) Yes (alif-v1)
ae Emirati Arabic Yes (rawi-v1) Yes (alif-v1)
eg Egyptian Arabic Yes (rawi-v1) Yes (alif-v1)
jo Jordanian Arabic Yes (rawi-v1) Yes (alif-v1)
ms Modern Standard Arabic Yes (rawi-v1) Yes (alif-v1)
hz Hijazi Arabic Yes (rawi-v1) Yes (alif-v1)
nj Najdi Arabic Yes (rawi-v1) Yes (alif-v1)
mr Marathi — Yes
bn Bengali — Yes
gu Gujarati — Yes
ml Malayalam — Yes

Check Credits

import convozen

client = convozen.Client(api_key="your-api-key")
info = client.account.info()

print(info.global_balance)      # credits remaining (shared across TTS and STT)
print(info.plan)                # e.g. "pro"
print(info.allowed_services)    # e.g. ["tts", "stt"]
print(info.tts_lifetime_used)   # credits ever spent on TTS
print(info.stt_lifetime_used)   # credits ever spent on STT

print(info.rate_limit.limit)             # requests allowed per window
print(info.rate_limit.remaining)         # requests left in the current window
print(info.rate_limit.reset_in_seconds)  # seconds until the window resets
print(info.rate_limit.window_seconds)    # length of the window

AccountInfo

Field Type Description
account_id str Account identifier
org_id str Organization identifier
plan str Plan tier (e.g. "pro", "free")
global_balance int Credits remaining, shared across TTS and STT
allowed_services List[str] Services enabled for the key, e.g. ["tts", "stt"]
tts_lifetime_used int Credits ever spent on TTS
stt_lifetime_used int Credits ever spent on STT
rate_limit RateLimitInfo limit, remaining, reset_in_seconds, window_seconds

Changed: credits are a single global_balance shared by TTS and STT. The old info.credits.tts.balance / info.credits.stt.balance accessors (and the Credits / CreditBalance types) have been removed — they described a schema the server no longer returns and silently reported 0.


Error Handling

import convozen
from convozen import AuthenticationError, RateLimitError, APIError

client = convozen.Client(api_key="your-api-key")

try:
    audio = client.tts.synthesize("Hello")
except AuthenticationError:
    print("Invalid API key")
except RateLimitError:
    print("Too many requests")
except APIError as e:
    print(f"Server error: {e}")

Standalone Clients

from convozen import TTS, STT

tts = TTS(api_key="your-api-key")
audio = tts.synthesize("Hello", language="hi")

stt = STT(api_key="your-api-key")

# Flat transcript
result = stt.transcribe("recording.wav")
print(result.text)

# Per-speaker diarization (mono, multiple speakers)
result = stt.transcribe("call.wav", diarize=True)
for turn in result.turns:
    print(f"[{turn.speaker_id}] {turn.start_sec:.2f}s – {turn.end_sec:.2f}s : {turn.transcript}")

Release files for convozen 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for convozen 0.4.3
File Size Uploaded
convozen-0.4.3.tar.gz 20.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for convozen 0.4.3
File Interpreter ABI Platform
convozen-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 45.3 kB

Release files / convozen-0.4.3.tar.gz

Download URL convozen-0.4.3.tar.gz
Size 20.3 kB
Tags Source
SHA-256 checksum
How to use checksums
504208cfbe1ca660ae80c80e9919e8183e030641cfd483315917ad67f6cfd9b7
BLAKE2b-256 checksum
How to use checksums
5729fb6ac1c7d2cb9220f6af9c3b9ed5d83e83c0166398348593d415b3bcc751
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / convozen-0.4.3-py3-none-any.whl

Download URL convozen-0.4.3-py3-none-any.whl
Size 25.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4625d245619272601602be680ac79c45ce081e1451d13ef2fcad4d6a87e1f93c
BLAKE2b-256 checksum
How to use checksums
2f4f1b210a18fa580f13b6aa91d816a97c5ef8dd0ff417641f391082997ad5f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.4.3 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page