Metadata-Version: 2.4
Name: vakyamai
Version: 0.1.7
Summary: Python SDK for the Vakyam Text-to-Speech API
Author: Vakyam AI
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Requires-Dist: websockets<16,>=13
Provides-Extra: dev
Requires-Dist: bandit[toml]<2,>=1.9.4; extra == 'dev'
Requires-Dist: build<2,>=1.2; extra == 'dev'
Requires-Dist: pip-audit<3,>=2.10; extra == 'dev'
Requires-Dist: pytest<10,>=9.0.3; extra == 'dev'
Requires-Dist: ruff<1,>=0.4; extra == 'dev'
Requires-Dist: twine<7,>=6; extra == 'dev'
Provides-Extra: livekit
Requires-Dist: livekit-agents<2,>=1.6; extra == 'livekit'
Provides-Extra: pipecat
Requires-Dist: pipecat-ai<2,>=1.5; extra == 'pipecat'
Description-Content-Type: text/markdown

# VakyamAI Python SDK

Python SDK for the Vakyam Text-to-Speech API.

This package intentionally exposes only the public TTS API surface:

- `GET /v1/voices`
- `POST /v1/tts/generate`
- `POST /v1/tts/stream`
- `WS /v1/tts/websocket`

API-key management and health endpoints are server/dashboard concerns and are not included.

## Install

```bash
pip install vakyamai
```

Optional realtime-agent integrations:

```bash
pip install "vakyamai[livekit]"
pip install "vakyamai[pipecat]"
```

## Examples

All examples use the production API URL by default. Set your API key first:

```bash
export VAKYAM_API_KEY="vak_live_..."
```

Then run:

```bash
python examples/env_key_usage.py
python examples/synthesize.py
python examples/error_handling.py
python examples/async_streaming.py
python examples/async_websocket.py
```

Available examples:

- [env_key_usage.py](examples/env_key_usage.py): create a client from `VAKYAM_API_KEY`
- [synthesize.py](examples/synthesize.py): generate an MP3 file from text
- [error_handling.py](examples/error_handling.py): handle typed SDK/API errors
- [async_streaming.py](examples/async_streaming.py): stream PCM bytes asynchronously
- [async_websocket.py](examples/async_websocket.py): synthesize one sentence over async WebSocket
- [livekit_tts.py](examples/livekit_tts.py): construct `VakyamTTS` for LiveKit Agents
- [pipecat_tts.py](examples/pipecat_tts.py): construct `VakyamTTSService` for Pipecat

## Initialize

```python
from vakyamai import VakyamAI

Vakyam = VakyamAI(api_key="vak_live_...")
```

By default, the SDK reads configuration from the environment:

```bash
export VAKYAM_API_KEY="vak_live_..."
```

Then create the client without arguments:

```python
from vakyamai import VakyamAI

Vakyam = VakyamAI()
```

Precedence:

- `api_key=` passed in code overrides `VAKYAM_API_KEY`
- the SDK uses `https://api.vakyam.ai` by default

`VakyamAI` uses a 300-second default timeout for non-streaming requests.
`AsyncVakyamAI` uses a 60-second default for streaming connection and
initial-response handling.

## List Voices

```python
voices = Vakyam.voices.list(group_by="language")
print(voices)
```

Use a returned `voice_name` as the synthesis request's singular `voice`
parameter (with its language). Values beginning with `vc_` select a durable
custom voice owned by the authenticated account; every other value is a preset
name. The deprecated API field `voice_name` is not used by this SDK.

## Generate Speech

```python
response = Vakyam.tts.generate(
    text="வணக்கம், நான் வாக்யம் AI பேசுகிறேன்.",
    model_id="raaga-v1",
    voice="Archana",
    language="ta-IN",
    output_format="mp3",
    sample_rate=24000,
    speed=1.0,
)

response.save("speech.mp3")
print(response.duration_seconds, response.characters_used)
```

Custom voices use the same `voice` field with a public ID:

```python
response = Vakyam.tts.generate(
    text="வணக்கம்.",
    model_id="raaga-v1",
    voice="vc_01EXAMPLE",
    language="ta-IN",
)
```

`response.audio` contains decoded audio bytes. `response.audio_base64` preserves the raw API field.
`sample_rate` accepts `8000`, `16000`, `24000`, or `48000`; the default is `24000`.
Supported languages are `ta-IN`, `hi-IN`, `mr-IN`, `te-IN`, `en-IN`, `gu-IN`, `bn-IN`, and `kn-IN`.
Supported output formats are `mp3`, `wav`, `pcm`, and `mulaw`.

## HTTP Streaming

```python
with open("speech.pcm", "wb") as file:
    for chunk in Vakyam.tts.stream(
        text="வணக்கம்.",
        model_id="raaga-v1",
        voice="Archana",
        language="ta-IN",
        output_format="pcm",
        sample_rate=24000,
    ):
        file.write(chunk)
```

To collect the full stream and response metadata:

```python
streamed = Vakyam.tts.stream_to_bytes(
    text="வணக்கம்.",
    model_id="raaga-v1",
    voice="Archana",
    language="ta-IN",
    sample_rate=24000,
)

streamed.save("speech.pcm")
print(streamed.metadata.characters_used)
```

Async streaming is available through `AsyncVakyamAI`:

```python
from vakyamai import AsyncVakyamAI

async with AsyncVakyamAI() as Vakyam:
    async for chunk in Vakyam.tts.stream(
        text="வணக்கம்.",
        model_id="raaga-v1",
        voice="Archana",
        language="ta-IN",
        output_format="pcm",
        sample_rate=24000,
    ):
        ...
```

`AsyncVakyamAI` is intentionally focused on streaming APIs. Use `VakyamAI` for
`voices.list()` and non-streaming `tts.generate()`.

## WebSocket

```python
with Vakyam.tts.websocket(
    model_id="raaga-v1",
    voice="Archana",
    language="ta-IN",
    output_format="pcm",
    sample_rate=24000,
) as ws:
    result = ws.synthesize("நான் சரியாக இருக்கிறேன்.")
    result.save("sentence.pcm")
```

The WebSocket API expects one complete sentence or utterance at a time.
Idle WebSocket sessions close after 60 seconds without an incoming message by
default. Calling `ws.ping()` sends a client ping and resets the server idle timer.
If `result.truncated` is true, synthesis stopped early; the returned audio is
partial and `result.characters_used` is `0`.

To barge in while audio is streaming, call `ws.cancel()` (or
`await ws.cancel()`). That sends `{"type":"cancel"}`, drains until
`cancellation`, and keeps the socket open for the next utterance. The result
has `cancelled=True` and worker-reported `characters_used`.
When `synthesize()` is already running, invoke `cancel()` from another thread;
for `AsyncVakyamAI`, invoke it from another task. The synthesis call remains
the sole WebSocket receiver and both calls resolve to the same terminal result.

Async WebSocket usage:

```python
from vakyamai import AsyncVakyamAI

async with AsyncVakyamAI() as Vakyam:
    async with Vakyam.tts.websocket(
        model_id="raaga-v1",
        voice="Archana",
        language="ta-IN",
        output_format="pcm",
        sample_rate=24000,
    ) as ws:
        result = await ws.synthesize("நான் சரியாக இருக்கிறேன்.")
        result.save("sentence.pcm")
```

## LiveKit Agents

Install the LiveKit extra, then use `VakyamTTS` in an `AgentSession`:

```bash
pip install "vakyamai[livekit]"
```

```python
from vakyamai.livekit import VakyamTTS

tts = VakyamTTS(
    voice="Archana",
    language="ta-IN",
    model="raaga-v1",
    sample_rate=24000,
)
```

`VakyamTTS` streams PCM over Vakyam's WebSocket API and sentence-tokenizes
input so each utterance matches the realtime protocol.

## Pipecat

Install the Pipecat extra, then add `VakyamTTSService` to your pipeline:

```bash
pip install "vakyamai[pipecat]"
```

```python
from vakyamai.pipecat import VakyamTTSService

tts = VakyamTTSService(
    settings=VakyamTTSService.Settings(
        voice="Archana",
        model="raaga-v1",
        language="ta-IN",
        speed=1.0,
    ),
    sample_rate=24000,
)
```

The service keeps a persistent WebSocket and barge-in sends
``{"type":"cancel"}`` (no reconnect). Defaults to sentence aggregation to
match Vakyam's utterance-oriented API.

## Errors

The SDK maps the API error envelope into typed exceptions:

```python
from vakyamai import RateLimitError, ValidationError

try:
    Vakyam.tts.generate(
        text="...",
        model_id="raaga-v1",
        voice="Archana",
        language="ta-IN",
        sample_rate=24000,
    )
except RateLimitError as exc:
    print(exc.retry_after_seconds)
except ValidationError as exc:
    print(exc.code, exc.message)
```

Common exception classes:

- `AuthenticationError`
- `InsufficientCreditsError`
- `ConcurrencyLimitError`
- `RateLimitError`
- `ServiceUnavailableError`
- `ValidationError`
- `APIError`
- `APIConnectionError`
