obscura-ai 0.1.0
Obscura AI Gateway Python SDK - Unified interface for multiple AI model providers
License: MIT
Requires Python: >=3.8
Keywords: ai, anthropic, api, claude, gateway, gpt, llm, openai

# Obscura Python SDK

Official Python SDK for Obscura AI Gateway - A unified interface for multiple AI model providers.

[![PyPI version](https://badge.fury.io/py/obscura.svg)](https://badge.fury.io/py/obscura)
[![Python Support](https://img.shields.io/pypi/pyversions/obscura.svg)](https://pypi.org/project/obscura/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- 🚀 **OpenAI-Compatible API** - Drop-in replacement for OpenAI SDK
- 🔄 **Streaming Support** - Full SSE streaming for real-time responses
- ⚡ **Async/Sync** - Both synchronous and asynchronous interfaces
- 🎯 **Type Safe** - Complete type hints for better IDE support
- 🔌 **Multi-Provider** - Access OpenAI, Anthropic, Google, and more through one API
- 🛡️ **Error Handling** - Granular exception types for better error management
- 🔁 **Auto-Retry** - Built-in retry logic for transient failures

## Installation

```bash
pip install obscura-ai
```

Or install from source:

```bash
git clone https://github.com/obscura/obscura-python.git
cd obscura-python/sdk/python
pip install -e .
```

## Quick Start

### Basic Chat Completion

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Hello! How are you?"}
    ]
)

print(response.choices[0].message.content)
```

### Streaming Chat

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

print("AI: ", end="")
for chunk in client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True
):
    content = chunk.choices[0].delta.get("content", "")
    print(content, end="", flush=True)
print()
```

### Async Usage

```python
from obscura import AsyncObscura
import asyncio

async def main():
    async with AsyncObscura(api_key="obscura_xxx") as client:
        response = await client.chat.completions.create(
            model="gpt-4",
            messages=[{"role": "user", "content": "Hello!"}]
        )
        print(response.choices[0].message.content)

asyncio.run(main())
```

### Embeddings

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

response = client.embeddings.create(
    input=["Hello world", "Goodbye world"],
    model="text-embedding-3-small"
)

for embedding in response.data:
    print(f"Embedding {embedding.index}: {len(embedding.embedding)} dimensions")
```

### List Available Models

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

models = client.models.list()
for model in models:
    print(f"{model.id} - {model.owned_by}")
```

### Audio Transcription

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

with open("audio.mp3", "rb") as audio_file:
    response = client.audio.transcriptions.create(
        file=audio_file,
        model="whisper-1"
    )
    print(response.text)
```

### Image Generation

```python
from obscura import Obscura

client = Obscura(api_key="obscura_xxx")

response = client.images.generate(
    prompt="A beautiful sunset over mountains",
    model="dall-e-3"
)

print(f"Generated image: {response.data[0]['url']}")
```

## Advanced Usage

### Custom Base URL

```python
from obscura import Obscura

client = Obscura(
    api_key="obscura_xxx",
    base_url="https://custom-endpoint.com/functions/v1",
    timeout=120.0
)
```

### Context Manager

```python
from obscura import Obscura

with Obscura(api_key="obscura_xxx") as client:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello"}]
    )
    print(response.choices[0].message.content)
# Client automatically closed
```

### Error Handling

```python
from obscura import Obscura
from obscura.exceptions import (
    AuthenticationError,
    RateLimitError,
    QuotaExceededError,
    APIError
)

client = Obscura(api_key="obscura_xxx")

try:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello"}]
    )
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limit exceeded. Retry after {e.retry_after}s")
except QuotaExceededError:
    print("Quota exceeded. Please top up your account")
except APIError as e:
    print(f"API error: {e.message}")
```

## API Reference

### Client

#### `Obscura(api_key, base_url, timeout, max_retries)`

Synchronous client for Obscura API.

**Parameters:**
- `api_key` (str): Your Obscura API token (format: `obscura_xxx`)
- `base_url` (str, optional): API base URL. Default: `https://emorprdwdukhmrgeclyg.supabase.co/functions/v1`
- `timeout` (float, optional): Request timeout in seconds. Default: `60.0`
- `max_retries` (int, optional): Maximum retry attempts. Default: `2`

#### `AsyncObscura(api_key, base_url, timeout, max_retries)`

Asynchronous client for Obscura API. Same parameters as `Obscura`.

### Chat Completions

#### `client.chat.completions.create(**kwargs)`

Create a chat completion.

**Parameters:**
- `messages` (List[dict]): Conversation messages
- `model` (str): Model identifier (e.g., "gpt-4", "claude-3-opus")
- `temperature` (float, optional): Sampling temperature (0-2)
- `max_tokens` (int, optional): Maximum tokens to generate
- `top_p` (float, optional): Nucleus sampling parameter
- `stream` (bool, optional): Enable streaming. Default: `False`
- `frequency_penalty` (float, optional): Frequency penalty (-2.0 to 2.0)
- `presence_penalty` (float, optional): Presence penalty (-2.0 to 2.0)

**Returns:** `ChatCompletion` or `Iterator[ChatCompletionChunk]` if streaming

### Embeddings

#### `client.embeddings.create(input, model, **kwargs)`

Create embeddings for input text(s).

**Parameters:**
- `input` (str | List[str]): Text or list of texts to embed
- `model` (str): Embedding model identifier

**Returns:** `Embedding`

### Models

#### `client.models.list()`

List all available models.

**Returns:** `List[Model]`

### Audio

#### `client.audio.transcriptions.create(file, model, **kwargs)`

Transcribe audio file.

**Parameters:**
- `file` (BinaryIO): Audio file opened in binary mode
- `model` (str, optional): Transcription model. Default: "whisper-1"

**Returns:** `TranscriptionResponse`

### Images

#### `client.images.generate(prompt, model, **kwargs)`

Generate image from text prompt.

**Parameters:**
- `prompt` (str): Text description of desired image
- `model` (str, optional): Image generation model. Default: "dall-e-3"

**Returns:** `ImageGenerationResponse`

## Exception Hierarchy

```
ObscuraError
├── AuthenticationError (401)
├── RateLimitError (429)
├── QuotaExceededError (402)
├── ModelNotFoundError
├── ValidationError
└── APIError (general API errors)
```

## Supported Models

The SDK supports all models available through Obscura AI Gateway:

- **OpenAI**: GPT-4, GPT-3.5, GPT-4 Vision, DALL-E, Whisper
- **Anthropic**: Claude 3 Opus, Sonnet, Haiku
- **Google**: Gemini Pro, Gemini Pro Vision
- **And more**: Check `client.models.list()` for complete list

## Rate Limits & Quotas

- Rate limits are enforced per token and can be configured in your dashboard
- When rate limited (429), the SDK includes `retry_after` in the exception
- Quota exceeded (402) indicates you need to add credits to your account

## Development

```bash
# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black obscura/

# Type checking
mypy obscura/
```

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Support

- **Documentation**: https://docs.obscura.ai
- **Issues**: https://github.com/obscura/obscura-python/issues
- **Email**: support@obscura.ai

## Changelog

### 0.1.0 (2024-12-01)

- Initial release
- Chat completions with streaming support
- Embeddings API
- Audio transcription
- Image generation
- Models listing
- Full async/sync support