# clore-ai

[![PyPI version](https://badge.fury.io/py/clore-ai.svg)](https://badge.fury.io/py/clore-ai)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Modern Python SDK and CLI for [Clore.ai](https://clore.ai) GPU marketplace.**

Rent powerful GPUs for AI/ML workloads with a simple, intuitive interface. Supports both synchronous and asynchronous operations.

---

## 🚀 Features

- **Full API Coverage** — All Clore.ai endpoints (marketplace, orders, servers, wallets, spot market)
- **Sync & Async** — `CloreAI` (sync) and `AsyncCloreAI` (async) clients
- **Rate Limiting** — Built-in rate limiter with exponential backoff
- **Rich CLI** — Beautiful terminal interface with `rich` tables
- **Type Safe** — Full type hints and Pydantic models
- **SSH Helper** — One-command SSH into your instances
- **Production Ready** — Error handling, retries, configurable timeouts

---

## 📦 Installation

```bash
pip install clore-ai
```

### From source

```bash
git clone https://gitlab.com/cloreai/clore-ai-sdk.git
cd clore-ai
pip install -e .
```

---

## 🔑 Authentication

Get your API key from [Clore.ai dashboard](https://clore.ai).

### Option 1: Environment variable (recommended)

```bash
export CLORE_API_KEY=your_api_key_here
```

### Option 2: CLI config

```bash
clore config set api_key YOUR_API_KEY
```

### Option 3: Pass directly

```python
from clore_ai import CloreAI

client = CloreAI(api_key="your_key")
```

---

## 🐍 SDK Usage

### Basic Example

```python
from clore_ai import CloreAI

# Initialize client
client = CloreAI(api_key="your_key")

# Browse marketplace
servers = client.marketplace(gpu="RTX 4090", max_price_usd=5.0)
for server in servers:
    print(f"{server.id}: {server.gpu_model} - ${server.price_usd_per_hour}/h")

# Create order
order = client.create_order(
    server_id=123,
    image="cloreai/ubuntu22.04-cuda12",
    type="on-demand",
    currency="bitcoin",
    ports={"22": "tcp", "8888": "http"},
    ssh_password="mysecret"
)
print(f"Order created: {order.id} @ {order.pub_cluster}")

# List active orders
orders = client.my_orders()
for order in orders:
    print(f"{order.id}: {order.status} - {order.pub_cluster}")

# Cancel order
client.cancel_order(order_id=38)
```

### Async Example

```python
import asyncio
from clore_ai import AsyncCloreAI

async def main():
    async with AsyncCloreAI(api_key="your_key") as client:
        # Search marketplace
        servers = await client.marketplace(gpu="RTX 4090")
        
        # Create order
        order = await client.create_order(
            server_id=servers[0].id,
            image="cloreai/pytorch",
            type="spot",
            currency="bitcoin",
            spot_price=0.0001
        )
        
        print(f"Created order {order.id}")

asyncio.run(main())
```

### Wallets

```python
wallets = client.wallets()
for wallet in wallets:
    print(f"{wallet.currency}: {wallet.balance:.8f}")
```

### Server Management

```python
# Your hosted servers
my_servers = client.my_servers()

# Server configuration
config = client.server_config("MyGPU")
print(f"Availability: {config.availability}")

# Update settings
client.set_server_settings(
    name="MyGPU",
    availability=True,
    mrl=96,
    on_demand=0.0001,
    spot=0.00000113
)
```

### Spot Market

```python
# View spot offers
offers = client.spot_marketplace(server_id=6)

# Set your spot price
client.set_spot_price(order_id=39, price=0.000003)
```

---

## 🖥️ CLI Usage

### Search Marketplace

```bash
# All servers
clore search

# Filter by GPU
clore search --gpu "RTX 4090" --max-price 5.0

# Sort and limit
clore search --sort price --limit 10
```

### Manage Orders

```bash
# List active orders
clore orders

# Include completed
clore orders --completed

# Create new order
clore deploy 123 \
  --image cloreai/ubuntu22.04-cuda12 \
  --type on-demand \
  --currency bitcoin \
  --ssh-password mysecret \
  --port 22:tcp \
  --port 8888:http

# Cancel order
clore cancel 38
```

### SSH Access

```bash
# Auto-connect to order
clore ssh 38

# Custom user
clore ssh 38 --user ubuntu
```

### Wallets & Servers

```bash
# View balances
clore wallets

# List your servers
clore servers

# Server configuration
clore server-config "MyGPU"
```

### Spot Market

```bash
# View spot offers
clore spot 6

# Set spot price
clore spot-price 39 0.000003
```

---

## 📚 API Reference

### `CloreAI` / `AsyncCloreAI`

#### Constructor

```python
CloreAI(
    api_key: str | None = None,
    base_url: str | None = None,
    timeout: float = 30.0,
    max_retries: int = 3
)
```

#### Methods

| Method | Description |
|--------|-------------|
| `wallets()` | Get wallet balances |
| `marketplace(gpu?, min_gpu_count?, max_price_usd?, ...)` | Search marketplace |
| `my_servers()` | List your hosted servers |
| `server_config(name)` | Get server configuration |
| `my_orders(include_completed?)` | List your orders |
| `create_order(server_id, image, type, currency, ...)` | Create new order |
| `cancel_order(order_id, issue?)` | Cancel order |
| `spot_marketplace(server_id)` | Get spot market offers |
| `set_spot_price(order_id, price)` | Update spot price |
| `set_server_settings(name, availability?, mrl?, ...)` | Update server settings |

---

## 🔒 Error Handling

```python
from clore_ai import CloreAI
from clore_ai.exceptions import (
    CloreAPIError,
    RateLimitError,
    AuthError,
    InvalidInputError
)

try:
    client = CloreAI(api_key="invalid")
    client.wallets()
except AuthError:
    print("Invalid API key")
except RateLimitError:
    print("Rate limited - retry with backoff")
except CloreAPIError as e:
    print(f"API error: {e} (code {e.code})")
```

### Error Codes

| Code | Exception | Description |
|------|-----------|-------------|
| 0 | — | Success |
| 1 | `DBError` | Database error |
| 2 | `InvalidInputError` | Invalid input |
| 3 | `AuthError` | Authentication failed |
| 4 | `InvalidEndpointError` | Invalid endpoint |
| 5 | `RateLimitError` | Rate limit exceeded |
| 6 | `FieldError` | Error in specific field |

---

## 🛠️ Development

### Setup

```bash
git clone https://gitlab.com/cloreai/clore-ai-sdk.git
cd clore-ai
pip install -e ".[dev]"
```

### Run Tests

```bash
pytest tests/ -v
```

### Format Code

```bash
black src/ tests/
ruff check src/ tests/
mypy src/
```

---

## 📝 License

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

---

## 🔗 Links

- **Website:** [clore.ai](https://clore.ai)
- **API Docs:** [api.clore.ai](https://api.clore.ai)
- **GitHub:** [cloreai/clore-ai-sdk](https://gitlab.com/cloreai/clore-ai-sdk)
- **PyPI:** [pypi.org/project/clore-ai](https://pypi.org/project/clore-ai)

---

## 🤝 Contributing

Contributions welcome! Please open an issue or PR.

1. Fork the repo
2. Create feature branch (`git checkout -b feature/amazing`)
3. Commit changes (`git commit -am 'Add amazing feature'`)
4. Push to branch (`git push origin feature/amazing`)
5. Open Pull Request

---

**Made with ❤️ for the Clore.ai community**
