Metadata-Version: 2.4
Name: bluma
Version: 1.0.0
Summary: Official Python SDK for the Bluma API
Author-email: Bluma <sdk@bluma.app>
License: MIT
Project-URL: Homepage, https://bluma.app
Project-URL: Documentation, https://docs.bluma.app
Project-URL: Repository, https://github.com/bluma/bluma-python
Project-URL: Issues, https://github.com/bluma/bluma-python/issues
Keywords: bluma,video,ai,sdk,api-client
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: async
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
Requires-Dist: ruff>=0.2.0; extra == "dev"
Dynamic: license-file

# bluma

Official Python SDK for the Bluma API

## Installation

```bash
pip install bluma
```

## Quick Start

```python
from bluma import Bluma

bluma = Bluma(api_key="your_api_key")

# Generate a video
video = bluma.videos.create(
    template_id="meme-dialogue",
    context={"prompt": "Create a funny dialogue between a programmer and their computer"}
)

print(f"Video ID: {video.id}")

# Wait for completion
completed = bluma.videos.wait_for(video.id)
print(f"Video ready: {completed.url}")
```

## Features

- ✅ **Type hints** for full IDE support
- ✅ **Automatic retries** with exponential backoff
- ✅ **Webhook verification** utilities
- ✅ **Polling helpers** for video completion
- ✅ **Custom exception classes** for each error type
- ✅ **Context manager** support
- ✅ **Pydantic models** for response validation

## Configuration

```python
from bluma import Bluma

bluma = Bluma(
    api_key="your_api_key",
    base_url="https://api.bluma.app/api/v1",  # optional
    timeout=30.0,  # seconds
    max_retries=3,
    retry_delay=1.0,  # seconds
    retry_multiplier=2.0  # exponential backoff
)
```

## API Reference

### Videos

```python
# Create video
video = bluma.videos.create(
    template_id="meme-dialogue",
    context={"prompt": "Create a funny video"},
    webhook_url="https://myapp.com/webhook",  # optional
    metadata={"user_id": "user_123"}  # optional
)

# Get video status
video = bluma.videos.get("batch_abc123")

# Wait for completion with progress
def on_progress(progress):
    print(f"Progress: {progress}%")

completed = bluma.videos.wait_for(
    "batch_abc123",
    poll_interval=5.0,
    timeout=600.0,
    on_progress=on_progress
)

# Download video
download = bluma.videos.download("batch_abc123")
print(download.download_url)
```

### Templates

```python
# List all templates
templates = bluma.templates.list()

# Get template details
template = bluma.templates.get("meme-dialogue")
```

### Credits

```python
# Get balance
balance = bluma.credits.get_balance()
print(f"{balance.credits} credits remaining")

# Get history
history = bluma.credits.get_history(limit=50)
for txn in history.transactions:
    print(f"{txn.description}: {txn.amount}")
```

### Webhooks

```python
# Create webhook
webhook = bluma.webhooks.create(
    url="https://myapp.com/webhooks/bluma",
    events=["video.completed", "video.failed"]
)
print(f"Secret: {webhook.secret}")  # Save this!

# List webhooks
webhooks = bluma.webhooks.list()

# Delete webhook
bluma.webhooks.delete("webhook_abc123")

# Get deliveries
deliveries = bluma.webhooks.get_deliveries("webhook_abc123")
```

### Webhook Verification

```python
from bluma import verify_webhook
from flask import Flask, request

app = Flask(__name__)

@app.route('/webhooks/bluma', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Bluma-Signature')
    payload = request.get_data()

    try:
        event = verify_webhook(payload, signature, 'your_webhook_secret')
        print(f"Event: {event['type']}")
        return '', 200
    except ValueError:
        return 'Unauthorized', 401
```

## Error Handling

```python
from bluma import (
    ValidationError,
    AuthenticationError,
    InsufficientCreditsError,
    RateLimitError,
    NotFoundError,
    APIError
)

try:
    video = bluma.videos.create(...)
except ValidationError as error:
    print(f"Invalid input: {error.detail}")
except InsufficientCreditsError:
    print("Out of credits!")
except RateLimitError as error:
    print(f"Rate limited. Retry after {error.retry_after}s")
except APIError as error:
    print(f"API error: {error.status} - {error.detail}")
```

## Context Manager

```python
with Bluma(api_key="your_api_key") as client:
    video = client.videos.create(
        template_id="meme-dialogue",
        context={"prompt": "Test"}
    )
    print(video.id)

# Client is automatically closed here
```

## Type Hints

Full type hint support for IDE autocompletion:

```python
from bluma import Bluma, Video, VideoStatus

bluma = Bluma(api_key="your_api_key")

video: Video = bluma.videos.get("batch_abc123")

if video.status == VideoStatus.COMPLETED:
    print(video.url)
```

## Development

### Setup

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

# Run tests
pytest

# Run type checking
mypy bluma

# Format code
black bluma tests
```

### Testing

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=bluma --cov-report=html
```

## License

MIT

## Support

- **Documentation:** https://docs.bluma.app
- **GitHub:** https://github.com/bluma/bluma-python
- **Email:** sdk@bluma.app
