Metadata-Version: 2.5
Name: adityalab
Version: 0.1.0
Summary: Official Python client for the Aditya API (Indian-language AI models by Aditya Lab)
Project-URL: Homepage, https://adityalab.in
Project-URL: Documentation, https://docs.adityalab.in
Project-URL: Source, https://github.com/shivam-9090/Aroxa/tree/main/sdk/python
Author: Aditya Lab
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: aditya,ai,api,hindi,indic,llm,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1,>=0.24
Provides-Extra: test
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# adityalab — Python client for the Aditya API

The official Python library for [Aditya](https://adityalab.in), a family of AI models built for Indian languages.

```bash
pip install adityalab
```

Python 3.9+. Its only dependency is `httpx`.

## Quick start

Create an API key at [platform.adityalab.in](https://platform.adityalab.in/keys), then:

```bash
export ADITYA_API_KEY="bk_..."
```

```python
from adityalab import Aditya

client = Aditya()   # reads ADITYA_API_KEY

reply = client.chat.completions.create(
    model="aditya-latest",
    messages=[{"role": "user", "content": "Explain an API in Hindi."}],
)
print(reply.text)
```

`reply` is the standard chat-completion object, so `reply.choices[0].message.content` and `reply.usage.total_tokens` work too.

## Streaming

```python
with client.chat.completions.create(
    model="aditya-latest",
    messages=[{"role": "user", "content": "Tell me a short story in Tamil."}],
    stream=True,
) as stream:
    for piece in stream.text():
        print(piece, end="", flush=True)
```

To read the raw chunks instead of only the text, iterate `stream` directly.

## Conversations kept on the server

Pass `conversation="new"` on the first call. After that, send only the new message with the returned id, and the server supplies the earlier turns:

```python
first = client.chat.completions.create(
    model="aditya-latest",
    messages=[{"role": "user", "content": "मेरा नाम रिया है।"}],
    conversation="new",
)
cid = first.conversation_id

second = client.chat.completions.create(
    model="aditya-latest",
    messages=[{"role": "user", "content": "मेरा नाम क्या है?"}],
    conversation=cid,
)
print(second.text)
```

Calls without `conversation` are stateless, and nothing is stored.

To list, read and delete stored conversations:

```python
for conv in client.conversations.iter():
    print(conv.id, conv.title)

page = client.conversations.messages(cid)      # .items, .nextAfter
client.conversations.delete(cid)
```

## Models, credits and pricing

```python
client.models.list()          # the models your key can call
client.credits.balance()      # .balance (in credits), .planTier
client.credits.usage()        # spend over the last 5 hours, day and 30 days
client.pricing.retrieve()     # public price list
```

## Async

```python
import asyncio
from adityalab import AsyncAditya

async def main():
    async with AsyncAditya() as client:
        reply = await client.chat.completions.create(
            model="aditya-latest", messages=[{"role": "user", "content": "नमस्ते"}])
        print(reply.text)

        stream = await client.chat.completions.create(
            model="aditya-latest", messages=[{"role": "user", "content": "नमस्ते"}], stream=True)
        async for piece in stream.text():
            print(piece, end="")

asyncio.run(main())
```

## Errors

Every API error is raised as a typed exception. Each one has `.status_code`, `.code` (a stable string to branch on), `.message` and `.request_id`; quote the request id when you contact support.

```python
import adityalab

try:
    client.chat.completions.create(model="aditya-latest", messages=[...])
except adityalab.InsufficientCreditsError:
    ...  # top up at platform.adityalab.in
except adityalab.RateLimitError as e:
    ...  # e.code == "window_cap_reached" means your plan's 5-hour window is used up; see e.retry_after
except adityalab.AuthenticationError:
    ...  # wrong, revoked or expired key
except adityalab.APIConnectionError:
    ...  # network trouble, or a timeout (APITimeoutError)
```

| Exception | When |
|---|---|
| `BadRequestError` | 400: the request is malformed |
| `AuthenticationError` | 401: missing, invalid, revoked or expired key |
| `InsufficientCreditsError` | out of credits |
| `PermissionDeniedError` | 403 |
| `NotFoundError` | 404: unknown model or conversation |
| `RateLimitError` | 429 |
| `InternalServerError` | 5xx, including a busy model (`model_busy`) |
| `StreamError` | the model stopped partway through a stream |

## Retries and timeouts

The client retries automatically, up to `max_retries` times (default 2):
- a busy model or rate limit (the server refused before doing any work);
- 5xx errors on reads;
- network errors.

It never re-sends a conversation turn after the server may have stored it. It also does not wait out a long `Retry-After`, such as a used-up usage window; you get the error straight away.

```python
client = Aditya(timeout=60, max_retries=3)
client.chat.completions.create(..., timeout=10)   # per call
```

## OpenAI compatibility

The API is also OpenAI-compatible, so existing OpenAI code works with `base_url="https://api.adityalab.in/v1"`. Use this library to get typed errors, server-side conversations, and the credits and pricing calls.

## Configuration

| Option | Environment variable | Default |
|---|---|---|
| `api_key` | `ADITYA_API_KEY` | none (required) |
| `base_url` | `ADITYA_BASE_URL` | `https://api.adityalab.in/v1` |
| `timeout` | none | 120 seconds |
| `max_retries` | none | 2 |

Pass `http_client=httpx.Client(...)` to set up proxies or custom TLS.

## License

Apache-2.0
