Skip to main content

Official Python SDK for the VoiceMaker API

Project description

myvoicemaker

Official Python SDK for the VoiceMaker API.

Generate dialect-accurate speech, transcribe audio in Nigerian languages, create lip-sync animations, and more — all from a single, fully typed client.

PyPI version Python versions License: MIT


Table of Contents


Installation

pip install myvoicemaker

Requires Python 3.9+. The only runtime dependency is httpx.


Quick Start

from myvoicemaker import VoiceMaker

client = VoiceMaker(api_key="vmk_live_...")

# Generate speech
tts = client.tts.generate(
    text="Bawo ni o se wa?",
    voice_id="masoyinbo-male-conversational",
    language="yo",
)
print(tts.audio_url)

# Transcribe an audio file
job = client.asr.transcribe_file("./sermon.mp3", language="yo")
result = client.asr.poll(job.job_id, timeout_seconds=120)
print(result.text)

Authentication

All requests require a developer API key. Create and manage your keys from the VoiceMaker Developer Dashboard.

client = VoiceMaker(api_key="vmk_live_...")
Key environment Prefix Credits consumed
Production vmk_live_ Yes
Test / Sandbox vmk_test_ No

Keep your API key secret. Use environment variables in production:

import os
from myvoicemaker import VoiceMaker

client = VoiceMaker(api_key=os.environ["VOICEMAKER_API_KEY"])

Configuration options

client = VoiceMaker(
    api_key="vmk_live_...",
    base_url="https://api.myvoicemaker.ai",  # default
    timeout=30.0,                             # default: 30 seconds
)

Context manager

with VoiceMaker(api_key="vmk_live_...") as client:
    result = client.tts.generate(...)
# underlying HTTP connection is closed automatically

Supported Languages

Language Code Auto-detect (ASR)
Yoruba yo
Igbo ig
Hausa ha
Nigerian Pidgin pcm
English en
Auto-detect auto

Modules

Text-to-Speech (TTS)

Convert text into natural-sounding speech. Requests are synchronous — the audio URL is returned immediately.

client.tts.list_voices(*, language=None)

Retrieve all available voices, optionally filtered by language.

response = client.tts.list_voices(language="yo")

for voice in response.voices:
    print(f"{voice.id}{voice.name} ({voice.gender}, {voice.style})")
    print(f"  Sample: {voice.sample_url}")

Parameters

Parameter Type Description
language str (optional) Filter by language code: yo, ig, ha, pcm, en

Returns VoiceListResponse

Field Type
voices list[Voice]

Each Voice has: id, name, gender, language, style, sample_url.


client.tts.generate(text, voice_id, language, *, speed=None, output_format=None)

result = client.tts.generate(
    text="Nne, ka anyị bido oge a.",
    voice_id="sunday-okafor-male-conversational",
    language="ig",
    speed=0.9,
    output_format="mp3",
)

print(result.audio_url)        # https://media.myvoicemaker.ai/...
print(result.duration_seconds) # e.g. 3.2
print(result.credits_used)     # e.g. 28

Parameters

Parameter Type Required Description
text str Text to synthesise (max 5,000 characters)
voice_id str Voice identifier from list_voices()
language str Language code
speed float Playback speed: 0.52.0 (default 1.0)
output_format str mp3 | wav | ogg (default mp3)

Returns TtsGenerateResponse

Field Type
id str
audio_url str
duration_seconds float | None
characters int
credits_used int
language str
voice_id str
created_at str (ISO 8601)

Automatic Speech Recognition (ASR)

Transcribe pre-recorded audio files. Jobs are asynchronous — submit a job, then poll for the result.

client.asr.transcribe(audio, *, language="auto", webhook_url=None) — from URL

job = client.asr.transcribe(
    "https://storage.example.com/interview.wav",
    language="ha",
    webhook_url="https://myapp.com/webhooks/voicemaker",
)
print(job.job_id)  # use this to poll

Parameters

Parameter Type Required Description
audio str Publicly accessible URL of the audio file
language str Language code or auto (default)
webhook_url str Callback URL when the job completes

client.asr.transcribe_file(file_path, *, language="auto", webhook_url=None) — from file

job = client.asr.transcribe_file(
    "./hausa-interview.mp3",
    language="ha",
)

Parameters

Parameter Type Required Description
file_path str Path to the audio file
language str Language code or auto (default)
webhook_url str Callback URL when the job completes

Supported formats: .mp3, .wav, .ogg, .m4a, .webm — max 500 MB.


client.asr.get_result(job_id)

result = client.asr.get_result("trans_1a2b3c...")
print(result.status)  # 'queued' | 'processing' | 'completed' | 'failed'
print(result.text)

client.asr.list(*, limit=20, cursor=None, status=None)

page = client.asr.list(limit=10, status="COMPLETED")

for job in page.items:
    print(f"{job.job_id}: {(job.text or '')[:60]}")

# Load the next page
if page.next_cursor:
    next_page = client.asr.list(cursor=page.next_cursor)

Parameters

Parameter Type Description
limit int Items per page: 1–100 (default 20)
cursor str Pagination cursor from a previous response
status str Filter: QUEUED | PROCESSING | COMPLETED | FAILED

client.asr.poll(job_id, *, interval_seconds=2.0, timeout_seconds=120.0) — wait for completion

Polls get_result at a regular interval until the job reaches a terminal state (completed or failed).

result = client.asr.poll(
    job.job_id,
    interval_seconds=3.0,   # poll every 3 seconds (default: 2.0)
    timeout_seconds=120.0,  # give up after 2 minutes (default: 120.0)
)

if result.status == "completed":
    print(f"Transcript: {result.text}")
    print(f"Language detected: {result.detected_language}")
    print(f"Duration: {result.duration_seconds}s")

Raises TimeoutError if timeout_seconds is exceeded before the job completes.

TranscriptionJob fields

Field Type
job_id str
status Literal['queued', 'processing', 'completed', 'failed']
language str
detected_language str | None
text str | None
confidence float | None
duration_seconds float | None
credits_used int | None
created_at str (ISO 8601)
completed_at str | None (ISO 8601)

Lip-Sync Animation

Generate a lip-sync video by combining a portrait image with an audio file. Jobs are asynchronous.

client.animate.generate(image_url, audio_url, *, output_format="mp4")

job = client.animate.generate(
    image_url="https://example.com/speaker-portrait.jpg",
    audio_url=tts.audio_url,
    output_format="mp4",
)
print(job.job_id)
print(f"Estimated credits: {job.estimated_credits}")

Parameters

Parameter Type Required Description
image_url str URL of the source portrait image (max 5 MB, up to 4K)
audio_url str URL of the audio file (max 30 seconds)
output_format str mp4 | webm (default mp4)

client.animate.get_result(job_id)

result = client.animate.get_result("anim_1a2b3c...")
print(result.status)    # 'queued' | 'processing' | 'completed' | 'failed'
print(result.video_url) # None until completed

client.animate.poll(job_id, *, interval_seconds=2.0, timeout_seconds=120.0)

result = client.animate.poll(
    job.job_id,
    interval_seconds=5.0,
    timeout_seconds=300.0,
)

if result.status == "completed":
    print(f"Video: {result.video_url}")
    print(f"Duration: {result.duration_seconds}s")

Explain

Process text in Nigerian languages — explain, summarise, translate, or simplify content using AI.

Note: This module targets a planned endpoint. Check the changelog for availability.

client.explain.process(text, language, action, *, target_language=None, max_tokens=None)

result = client.explain.process(
    text="Ìwé Mímọ̀ sọ pé...",
    language="yo",
    action="translate",
    target_language="en",
    max_tokens=500,
)

print(result.result)        # translated text
print(result.tokens_used)   # e.g. 145
print(result.credits_used)  # e.g. 145

Parameters

Parameter Type Required Description
text str Input text to process
language str Source language code
action str explain | summarize | translate | simplify
target_language str Required when action is translate
max_tokens int Response length limit: 1–2000 (default 500)

Usage & Billing

client.usage.get_balance()

balance = client.usage.get_balance()

print(f"Tier:              {balance.tier}")
print(f"Credits remaining: {balance.credits_remaining:,}")
print(f"Credits used:      {balance.credits_used:,}")

Returns UsageBalanceResponse

Field Type
account_id str
tier Literal['free', 'starter', 'growth', 'pro', 'enterprise']
credits_remaining int
credits_used int
credits_total int | None (present only if credits were ever purchased)
credits_expire str | None
created_at str (ISO 8601)

client.usage.get_breakdown(start_date, end_date, *, module=None)

report = client.usage.get_breakdown(
    start_date="2026-05-01T00:00:00Z",
    end_date="2026-05-31T23:59:59Z",
    module="asr",  # optional filter
)

for entry in report.breakdown:
    print(f"{entry.module}: {entry.requests} requests, {entry.credits_used} credits")

print(f"Total: {report.total_credits_used} credits")

Parameters

Parameter Type Required Description
start_date str ISO 8601 datetime (inclusive)
end_date str ISO 8601 datetime (inclusive)
module str Filter: tts | asr | animate | explain

Error Handling

Every API error is raised as a typed exception that subclasses VoiceMakerAPIError.

from myvoicemaker import (
    VoiceMakerError,
    AuthenticationError,
    InsufficientCreditsError,
    RateLimitError,
    ValidationError,
    NotFoundError,
    TimeoutError,
)

try:
    result = client.tts.generate(...)
except AuthenticationError:
    print("Invalid or expired API key")
except InsufficientCreditsError:
    print("Not enough credits. Top up at myvoicemaker.ai/billing")
except RateLimitError as e:
    wait = e.retry_after or 60
    print(f"Rate limited. Retry in {wait}s")
except ValidationError as e:
    print("Invalid parameters:", e.issues)
except TimeoutError as e:
    print(f"Job {e.job_id} timed out after {e.timeout_seconds}s")
except VoiceMakerError as e:
    print(f"API error {e.status}: {e.detail}")

Exception classes

Class HTTP Status Description
AuthenticationError 401 Missing or invalid API key
InsufficientCreditsError 402 Insufficient purchased credits
PermissionError 403 Key lacks required scope or plan
NotFoundError 404 Resource not found
FileSizeLimitError 413 Audio file exceeds plan size limit
UnsupportedMediaTypeError 415 Unsupported file format
ValidationError 422 Invalid request parameters (check .issues)
RateLimitError 429 Rate limit or concurrency limit exceeded
ServerError 500/503 Internal server error
TimeoutError poll() timed out waiting for job completion

All HTTP exception classes expose:

e.status      # HTTP status code (int)
e.error       # Short error title from the API
e.detail      # Human-readable explanation
e.request_id  # Request ID for support (from X-Request-Id header)
e.issues      # List of validation issue dicts (ValidationError only)

Polling Async Jobs

ASR and Animation jobs are processed asynchronously. The SDK's poll() helper handles the retry loop for you:

# Submit
job = client.asr.transcribe_file("./audio.mp3", language="en")

# Poll until done
result = client.asr.poll(
    job.job_id,
    interval_seconds=2.0,   # how often to check (default: 2.0)
    timeout_seconds=120.0,  # maximum wait time (default: 120.0)
)

Alternatively, manage polling manually:

import time

result = client.asr.get_result(job.job_id)

while result.status in ("queued", "processing"):
    time.sleep(3)
    result = client.asr.get_result(job.job_id)

Type Hints

The SDK is fully typed. All response models are plain Python dataclasses and all parameters carry type annotations — no stubs or additional packages required.

from myvoicemaker import (
    VoiceMaker,
    # Response models
    TranscriptionJob,
    TtsGenerateResponse,
    AnimateResultResponse,
    VoiceListResponse,
    Voice,
    UsageBalanceResponse,
    UsageBreakdownResponse,
    UsageBreakdownEntry,
    # Literals
    SupportedLanguage,
    JobStatus,
    AccountTier,
    # Errors
    VoiceMakerError,
    VoiceMakerAPIError,
)

Editor auto-complete and static analysers (mypy, pyright, Pylance) will surface all fields and parameter types without additional configuration.


Rate Limits

Rate limits are enforced per API key and vary by plan:

Plan Requests / min Concurrent jobs
Growth 60 5
Pro 120 10
Enterprise Custom Custom

When a limit is exceeded the SDK raises RateLimitError. The Retry-After header value (seconds) is available as err.retry_after.


Credit Costs

Module Billable unit Cost
TTS Input characters 1 credit / character
ASR Audio duration 5 credits / second
Animate Video duration 50 credits / second
Explain LLM tokens 1 credit / token

License

MIT © Collins Edim

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

myvoicemaker-0.1.1.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

myvoicemaker-0.1.1-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file myvoicemaker-0.1.1.tar.gz.

File metadata

  • Download URL: myvoicemaker-0.1.1.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for myvoicemaker-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a328a07eaf27233c2a488de9415b8f3cb92a79e6f908e9bc05cdcff043348b14
MD5 358f25602c2c520b8e89dca346256ec4
BLAKE2b-256 0d76bc710f9319e38b80e9e83d71a126e6b0f6c6dee29c45ef99be91c991d8df

See more details on using hashes here.

File details

Details for the file myvoicemaker-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: myvoicemaker-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for myvoicemaker-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2ef09cf56736d6fd3892b2a88013b2bcd48fee6c7196f7b6e29c66e1004ff84b
MD5 9d8abc307db1227da1c54cfb084f691d
BLAKE2b-256 e82e66640e1cc7f8134b6a0681c5a8538ffcd2dd935eb755263c9220cb0300e6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page