addisai (Python)
The official Addis AI SDK for Python — voice (text‑to‑speech), chat/LLM with system prompts, personas and function calling, speech‑to‑text, and translation for Amharic (am) and Afan Oromo (om).
Mirrors the Node SDK surface, Pythonic and snake_case.
pip install addisai
Requires Python 3.8+.
Quickstart
from addisai import AddisAI
addis = AddisAI() # reads ADDIS_API_KEY from the environment
# Text-to-speech
clip = addis.voice.generate(voice_id="am-hamen", text="ሰላም ለዓለም።", language="am")
clip.to_file("welcome.mp3")
# Chat
res = addis.chat.completions.create(
language="am",
system="Answer in concise bullet points.",
messages=[{"role": "user", "content": "ስለ አዲስ አበባ ንገረኝ"}],
)
print(res["choices"][0]["message"]["content"])
Configuration
addis = AddisAI(
api_key="...", # or set ADDIS_API_KEY
timeout=60.0, # seconds (voice.generate raises this to >= 95s)
max_retries=2, # backoff on 408/409/425/429/5xx
)
The key is read from api_key= or ADDIS_API_KEY, never logged, and redacted in repr(). The SDK only talks to the Cloudflare‑wrapped API and refuses raw *.supabase.co hosts.
Voice (text‑to‑speech)
clip = addis.voice.generate(
voice_id="am-hamen",
text="ሰላም።",
language="am",
output_format="mp3_44100", # mp3_44100 | wav_44100 | pcm_16000
voice_settings={"speed": 50, "stability": 50, "similarity": 50, "style": 0},
)
clip.audio_url
clip.usage # {"credits_used": ..., "currency": "ETB", ...}
data = clip.content() # bytes
clip.to_file("out.mp3")
Idempotency keys are generated automatically and reused across retries so a retry is never double‑billed. Pass client_request_id= for full control.
addis.voices.list(language="am", gender="female")
addis.voice.estimate(voice_id="am-hamen", text="ሰላም", language="am")
addis.voice.usage()
for clip in addis.voice.clips.list(language="am"): # auto-paginates
print(clip.id)
addis.voice.clips.delete("clip_123")
Chat / LLM
res = addis.chat.completions.create(
language="am",
system="Be concise.",
persona="You are RecipeBot by AcmeCorp.",
messages=[{"role": "user", "content": "የእንጀራ አሰራር አስተምረኝ"}],
temperature=0.7,
max_tokens=1200,
)
The model is selected by Addis AI; responses report the id
addis-1-alef.
Function calling
def get_order_status(args):
return {"status": "shipped", "eta": "tomorrow"}
final = addis.chat.run_tools(
language="am",
messages=[{"role": "user", "content": "Check order 123 and summarize it."}],
tools=[{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Fetch order status by order ID.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]},
"callable": get_order_status,
},
}],
)
print(final["choices"][0]["message"]["content"])
Streaming (beta)
stream=True returns a ChatStream — iterate for OpenAI‑style chunk dicts, or use the accumulators:
stream = addis.chat.completions.create(
language="am", messages=[{"role": "user", "content": "Capital?"}], stream=True
)
for chunk in stream:
print(chunk["choices"][0]["delta"].get("content", ""), end="", flush=True)
# or, instead of iterating:
text = addis.chat.completions.create(language="am", messages=[...], stream=True).final_text()
completion = addis.chat.completions.create(language="am", messages=[...], stream=True).final_completion()
Streaming is beta and not available with tools.
Speech‑to‑text & translation
with open("call.wav", "rb") as f:
t = addis.speech.transcribe(audio=f, language="am") # am|om|en|ha|sw
print(t["text"])
out = addis.translate.create(text="Hello", source="en", target="am") # am|om|en
print(out["text"])
Legacy audio (deprecated)
# ⚠️ deprecated — use addis.voice.generate
out = addis.legacy.audio.generate(text="ሰላም", language="am")
out.to_file("legacy.wav")
# streaming bridge — yields audio bytes, handles both legacy encodings
audio = addis.legacy.audio.stream(text="ሰላም", language="am")
audio.to_file("legacy.wav") # or: data = audio.read()
Errors
from addisai import InsufficientCreditsError, RateLimitError, APIError
try:
addis.voice.generate(voice_id="am-hamen", text="ሰላም", language="am")
except InsufficientCreditsError as e:
show_top_up(e.available_balance)
except RateLimitError as e:
sleep(e.retry_after or 1)
except APIError as e:
print(e.status, e.code, e.details)
Not yet in the Python SDK
An async client (AsyncAddisAI) is the one planned follow‑up. Everything else — including streaming — is at parity with the Node SDK.
Live smoke test
scripts/smoke.py exercises the real API end-to-end. It is not a PR gate —
the smoke workflow runs on manual dispatch and a daily schedule, only where the
repo secret ADDIS_SMOKE_API_KEY (a low-balance sandbox key) is set. Run locally
with ADDIS_API_KEY=<key> python scripts/smoke.py.
License
MIT
Tigrigna
Use language="ti" for chat (including attachments) and speech transcription.
Use source="ti" or target="ti" for translation with am, om, or en.
Tigrigna transcription uses /api/v2/stt; confidence may be None.
Real-time voice (0.3.0)
# HTTP streaming: no extra dependency needed.
audio = addis.voice.stream(voice_id="am-hamen", language="am", text=text)
audio.to_file("speech.mp3")
print(audio.metadata["usage"])
# Persistent sockets: pip install "addisai[realtime]"
with addis.realtime.connect(voice_id="am-hamen", language="am") as voice:
with open("speech.mp3", "wb") as output:
for chunk in voice.speak(text, "unique-turn-id"):
output.write(chunk)
print(voice.last_completion["usage"])
realtime.create_session() creates a scoped, one-use ticket valid for 60 seconds;
connect_realtime(ticket) opens its socket without a developer key. Keep keys on
your application server. Sessions last up to 10 minutes, allow one utterance at
a time, and carry a cumulative text budget of up to 5,000 characters. Cancellation
mutes delivery; an already-started synthesis completes and is billed.
Use append() and commit() to buffer a complete generated utterance before
synthesis. For early WAV pieces, select audio_format="wav_mp3", iterate raw
audio.delta events and use decode_realtime_audio(event); play each piece
according to its format. speak() yields concatenatable MP3 and requires an
mp3 session. Real-time voice languages documented here are Amharic (am),
Afaan Oromo (om), and Tigrigna (ti). Choose an available voice
from the live catalog. HTTP streams support MP3 only. Keep request IDs stable when recovering a failed request in a
new session to avoid a second charge; use a fresh ID for each new utterance.
See examples/realtime.py.
Metadata
Release files for addisai 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| addisai-0.3.0.tar.gz | 26.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| addisai-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.7 kB
Release files / addisai-0.3.0.tar.gz
| Download URL | addisai-0.3.0.tar.gz |
|---|---|
| Size | 26.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b68ed5f4464e54469522196132360b22581f2793fc39d1864292bb8b3b21540
|
|
BLAKE2b-256 checksum How to use checksums |
c0a83129088f09864cd1dbf2b8d67d479906d0fd5919cf834b246c63b5744178
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / addisai-0.3.0-py3-none-any.whl
| Download URL | addisai-0.3.0-py3-none-any.whl |
|---|---|
| Size | 26.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5910f5240f96da8fa65846b3617bb09a6301d4fbed7173ed7836d0d9d5dcb3e
|
|
BLAKE2b-256 checksum How to use checksums |
ec6c36ea74b645859e3b7240a765b326788483a2293cb7dd6af7e38fe7c0332d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for addisai 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.