> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-fr/avance/python-sdk.md).

# Guide du SDK Python

{% hint style="success" %}
**Nouveau dans le SDK ?** Commencez par le [tutoriel de démarrage rapide de 5 minutes](/guides/guides_v2-fr/prise-en-main/python-quickstart.md) d'abord.
{% endhint %}

Pour un tutoriel de démarrage rapide avec des exemples réels, voir [Clore.ai Python SDK — Automatisez vos flux de travail GPU en 5 minutes](https://blog.clore.ai/cloreai-python-sdk-automate-your-gpu-workflows-in-5-minutes/)

## Installation

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

Le SDK fournit deux clients :

* **`CloreAI`** — synchrone (plus simple, idéal pour les scripts)
* **`AsyncCloreAI`** — asynchrone (plus rapide pour les opérations concurrentes)

Ils partagent les mêmes méthodes et renvoient les mêmes modèles Pydantic.

***

## Sync vs Async — Quand utiliser l’un ou l’autre

| Cas d'utilisation                   | Client         | Pourquoi                                  |
| ----------------------------------- | -------------- | ----------------------------------------- |
| Scripts simples, tâches ponctuelles | `CloreAI`      | Code plus simple, pas de `async/await`    |
| Boucles de surveillance             | `CloreAI`      | Des vérifications séquentielles suffisent |
| Requêtes massives au marketplace    | `AsyncCloreAI` | Requêtes concurrentes = plus rapide       |
| Création de commandes en lot        | `AsyncCloreAI` | Créer plusieurs commandes en parallèle    |
| Applications web                    | `AsyncCloreAI` | E/S non bloquante                         |

### Exemple synchrone

```python
from clore_ai import CloreAI

client = CloreAI()  # Utilise la variable d'environnement CLORE_API_KEY

servers = client.marketplace(gpu="RTX 4090")
print(f"Found {len(servers)} servers")

client.close()  # Ou utiliser le gestionnaire de contexte
```

### Exemple asynchrone

```python
import asyncio
from clore_ai import AsyncCloreAI

async def main():
    async with AsyncCloreAI() as client:
        servers = await client.marketplace(gpu="RTX 4090")
        print(f"Found {len(servers)} servers")

asyncio.run(main())
```

### Gestionnaires de contexte (recommandé)

Les deux clients supportent les gestionnaires de contexte pour le nettoyage automatique :

```python
# Sync
with CloreAI() as client:
    wallets = client.wallets()

# Async
async with AsyncCloreAI() as client:
    wallets = await client.wallets()
```

***

## Configuration du client

```python
client = CloreAI(
    api_key="votre_cle",      # Ou définissez la variable d'environnement CLORE_API_KEY
    base_url="https://api.clore.ai/v1",  # Endpoint API personnalisé
    timeout=30.0,            # Timeout des requêtes en secondes
    max_retries=3            # Tentatives en cas de limite de débit / erreurs réseau
)
```

Le SDK inclut un limiteur de débit intégré :

* **Requêtes générales :** 1 requête/seconde
* **`create_order`:** Cooldown de 5 secondes entre les appels
* **Erreurs de limitation de débit (code 5) :** Repli exponentiel automatique

***

## Filtrage du marketplace

La `marketplace()` méthode récupère tous les serveurs disponibles et filtre côté client :

```python
from clore_ai import CloreAI

client = CloreAI()

# Tous les serveurs disponibles
all_servers = client.marketplace()

# Filtrer par modèle GPU (correspondance de sous-chaîne insensible à la casse)
rtx_4090s = client.marketplace(gpu="RTX 4090")

# Filtrer par plusieurs critères
budget_gpus = client.marketplace(
    gpu="RTX 4090",
    max_price_usd=1.0,       # Max 1,00 $/heure
    min_gpu_count=2,          # Au moins 2 GPU
    min_ram_gb=64.0,          # Au moins 64 Go de RAM système
    available_only=True       # Seulement les serveurs disponibles (par défaut)
)
```

### Filtrage avancé (côté client)

Pour les filtres non intégrés à la méthode, filtrez vous-même les `Server` objets retournés :

```python
servers = client.marketplace(gpu="RTX 4090")

# Serveurs en UE avec haute fiabilité
eu_servers = [
    s for s in servers
    if s.location and s.location.upper() in ("DE", "FR", "NL", "FI")
    and s.reliability and s.reliability >= 0.95
]

# Trier par prix
cheapest = sorted(servers, key=lambda s: s.price_usd or float("inf"))
print(f"Cheapest: Server {cheapest[0].id} — ${cheapest[0].price_usd:.4f}/h")
```

### Champs du modèle Server

Chaque `MarketplaceServer` objet possède ces attributs et propriétés de commodité :

| Champ            | Type                  | Description                                                            |
| ---------------- | --------------------- | ---------------------------------------------------------------------- |
| `id`             | `int`                 | ID du serveur (utilisez ceci dans `create_order`)                      |
| `gpu_model`      | `str \| None`         | Description du GPU issue des spécifications (propriété)                |
| `gpu_count`      | `int`                 | Nombre de GPU issu de `gpu_array` (propriété)                          |
| `ram_gb`         | `float \| None`       | RAM système en Go (propriété, depuis `specs.ram`)                      |
| `price_usd`      | `float \| None`       | Prix à la demande en USD (propriété, depuis `price.usd.on_demand_usd`) |
| `spot_price_usd` | `float \| None`       | Prix spot en USD (propriété)                                           |
| `available`      | `bool`                | Indique si le serveur n'est pas loué (propriété)                       |
| `location`       | `str \| None`         | Code pays issu des spécifications réseau (propriété)                   |
| `specs`          | `ServerSpecs \| None` | Spécifications matérielles (cpu, ram, disque, gpu, réseau)             |
| `price`          | `ServerPrice \| None` | Structure de tarification complète                                     |
| `rented`         | `bool \| None`        | Indique si le serveur est actuellement loué                            |

***

## Gestion des commandes

### Création de commandes

```python
order = client.create_order(
    server_id=142,
    image="cloreai/ubuntu22.04-cuda12",
    type="on-demand",               # "on-demand" ou "spot"
    currency="bitcoin",             # Devise de paiement
    ssh_password="MySecurePass",    # Accès SSH
    ports={"22": "tcp", "8888": "http"},  # Mappages de ports
    env={"HF_TOKEN": "hf_xxx"},    # Variables d'environnement
    command="bash /start.sh",       # Commande de démarrage personnalisée
    jupyter_token="my_token"        # Jeton du notebook Jupyter
)

print(f"Order ID: {order.id}")
print(f"IP: {order.pub_cluster}")
print(f"Ports: {order.tcp_ports}")
```

### Paramètres `create_order` complets

| Paramètre            | Type    | Obligatoire | Description                               |
| -------------------- | ------- | ----------- | ----------------------------------------- |
| `server_id`          | `int`   | ✅           | Serveur à louer                           |
| `image`              | `str`   | ✅           | Image Docker                              |
| `type`               | `str`   | ✅           | `"on-demand"` ou `"spot"`                 |
| `currency`           | `str`   | ✅           | Devise de paiement (par ex., `"bitcoin"`) |
| `ssh_password`       | `str`   | —           | Mot de passe SSH                          |
| `ssh_key`            | `str`   | —           | Clé publique SSH                          |
| `ports`              | `dict`  | —           | Mappages de ports (`{"22": "tcp"}`)       |
| `env`                | `dict`  | —           | Variables d'environnement                 |
| `jupyter_token`      | `str`   | —           | Jeton du notebook Jupyter                 |
| `command`            | `str`   | —           | Commande de démarrage                     |
| `spot_price`         | `float` | —           | Prix d'enchère spot                       |
| `required_price`     | `float` | —           | Prix requis                               |
| `autossh_entrypoint` | `str`   | —           | Point d'entrée Auto SSH                   |

### Lister les commandes

```python
# Uniquement les commandes actives
active = client.my_orders()
for o in active:
    print(f"Order {o.id}: type={o.type}, IP={o.pub_cluster}, status={o.status}")

# Inclure les commandes terminées
all_orders = client.my_orders(include_completed=True)
```

### Champs du modèle Order

| Champ         | Type            | Description                                  |
| ------------- | --------------- | -------------------------------------------- |
| `id`          | `int`           | ID de la commande                            |
| `server_id`   | `int \| None`   | ID du serveur loué                           |
| `type`        | `str`           | `"on-demand"` ou `"spot"`                    |
| `status`      | `str \| None`   | Statut de la commande                        |
| `image`       | `str \| None`   | Image Docker                                 |
| `currency`    | `str \| None`   | Devise de paiement                           |
| `price`       | `float \| None` | Prix                                         |
| `pub_cluster` | `str \| None`   | IP publique / nom d'hôte                     |
| `tcp_ports`   | `dict \| None`  | Mappages de ports (par ex., `{"22": 50022}`) |
| `created_at`  | `str \| None`   | Horodatage de création                       |

### Surveillance des commandes

```python
import time

def wait_for_ready(client, order_id, timeout=120):
    """Attendre qu'une commande obtienne une IP publique."""
    for _ in range(timeout // 10):
        orders = client.my_orders()
        order = next((o for o in orders if o.id == order_id), None)
        if order and order.pub_cluster:
            return order
        time.sleep(10)
    raise TimeoutError(f"Order {order_id} not ready after {timeout}s")

# Utilisation
order = client.create_order(server_id=142, image="cloreai/ubuntu22.04-cuda12", type="on-demand", currency="bitcoin")
ready = wait_for_ready(client, order.id)
print(f"SSH: ssh root@{ready.pub_cluster} -p {ready.tcp_ports.get('22', 22)}")
```

### Annulation des commandes

```python
# Annuler avec raison optionnelle
client.cancel_order(order_id=38, issue="Job complete")

# Annuler toutes les commandes actives
orders = client.my_orders()
for order in orders:
    client.cancel_order(order.id, issue="Cleanup")
    print(f"Cancelled order {order.id}")
```

***

## Gestion des serveurs (pour les hébergeurs)

Si vous hébergez des GPU sur Clore, le SDK vous permet de gérer vos serveurs :

### Lister vos serveurs

```python
my_servers = client.my_servers()
for s in my_servers:
    print(f"Server {s.id}: {s.gpu_model} — {s.status}")
```

### Obtenir la configuration du serveur

```python
config = client.server_config("MyGPU-Rig")
print(f"Name: {config.name}")
print(f"Visibility: {config.visibility}")
print(f"Online: {config.online}")
print(f"Min rental: {config.mrl}h")
print(f"On-demand price: {config.on_demand_price}")
print(f"Spot price: {config.spot_price}")
```

### Mettre à jour les paramètres du serveur

```python
client.set_server_settings(
    name="MyGPU-Rig",
    availability=True,       # Rendre le serveur disponible
    mrl=24,                  # Location minimale 24h
    on_demand=0.0001,        # Prix on-demand en BTC
    spot=0.00000113          # Prix spot en BTC
)
print("Paramètres mis à jour")
```

***

## Marché spot

Les commandes spot sont 30–50% moins chères mais peuvent être interrompues si quelqu'un vous surenchérit.

### Voir les offres spot

```python
offers = client.spot_marketplace(server_id=6)
for offer in offers:
    print(f"Order {offer.get('order_id')}: price={offer.get('price')}")
```

### Créer une commande spot

```python
order = client.create_order(
    server_id=142,
    image="cloreai/ubuntu22.04-cuda12",
    type="spot",
    currency="bitcoin",
    spot_price=0.0001,       # Votre prix d'enchère
    ssh_password="MyPass"
)
print(f"Spot order {order.id} created")
```

### Ajuster le prix spot

```python
# Augmentez votre enchère pour éviter d'être surenchéri
client.set_spot_price(order_id=39, price=0.000003)
```

### Stratégie d'enchère spot

```python
from clore_ai import CloreAI

client = CloreAI()

def smart_spot_bid(server_id, premium_pct=5):
    """Enchérir légèrement au-dessus du prix spot minimum actuel."""
    offers = client.spot_marketplace(server_id=server_id)
    if not offers:
        print("No spot offers — use on-demand price as baseline")
        return None

    min_price = min(o["price"] for o in offers)
    bid = min_price * (1 + premium_pct / 100)
    print(f"Market min: {min_price}, bidding: {bid:.8f} (+{premium_pct}%)")
    return bid

# Utilisation
bid = smart_spot_bid(server_id=142, premium_pct=10)
if bid:
    order = client.create_order(
        server_id=142,
        image="cloreai/ubuntu22.04-cuda12",
        type="spot",
        currency="bitcoin",
        spot_price=bid
    )
```

***

## Opérations de portefeuille

### Vérifier les soldes

```python
wallets = client.wallets()
for w in wallets:
    print(f"{w.name}: {w.balance:.8f}")
    if w.deposit:
        print(f"  Deposit address: {w.deposit}")
```

### Alerte de faible solde

```python
from clore_ai import CloreAI

def check_balance(min_btc=0.001):
    """Alerter si le solde BTC est inférieur au seuil."""
    client = CloreAI()
    wallets = client.wallets()

    for w in wallets:
        if w.name.lower() == "bitcoin" and w.balance < min_btc:
            print(f"⚠️  Low BTC balance: {w.balance:.8f} (minimum: {min_btc})")
            return False

    print("✅ Soldes OK")
    return True

check_balance(min_btc=0.001)
```

***

## Bonnes pratiques de gestion des erreurs

### Hiérarchie des exceptions

```
CloreAPIError (base)
├── DBError           (code 1) — erreur de base de données
├── InvalidInputError (code 2) — entrée incorrecte
├── AuthError         (code 3) — clé API invalide
├── InvalidEndpointError (code 4) — endpoint incorrect
├── RateLimitError    (code 5) — limitation de débit (retesté automatiquement)
└── FieldError        (code 6) — erreur spécifique à un champ
```

### Gestion d'erreurs basique

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

client = CloreAI()

try:
    order = client.create_order(
        server_id=999999,
        image="cloreai/ubuntu22.04-cuda12",
        type="on-demand",
        currency="bitcoin"
    )
except AuthError:
    print("Clé API invalide — vérifiez CLORE_API_KEY")
except InvalidInputError as e:
    print(f"Entrée incorrecte : {e}")
except RateLimitError:
    print("Limité par le débit — le SDK réessaie automatiquement, mais le nombre maximal de tentatives est dépassé")
except CloreAPIError as e:
    print(f"Erreur API (code {e.code}) : {e}")
```

### Schéma de retry avec backoff

Le SDK inclut des réessais intégrés pour les limites de débit et les erreurs réseau (`max_retries=3`). Pour des réessais au niveau de l'application :

```python
import time
from clore_ai import CloreAI
from clore_ai.exceptions import CloreAPIError, RateLimitError

def retry_operation(func, max_attempts=3, base_delay=2.0):
    """Réessayer une opération de l'API Clore avec un backoff exponentiel."""
    for attempt in range(max_attempts):
        try:
            return func()
        except RateLimitError:
            if attempt < max_attempts - 1:
                delay = base_delay * (2 ** attempt)
                print(f"Rate limited, retrying in {delay}s...")
                time.sleep(delay)
            else:
                raise
        except CloreAPIError as e:
            if e.code in (1,):  # Les erreurs DB peuvent être transitoires
                if attempt < max_attempts - 1:
                    time.sleep(base_delay)
                    continue
            raise

# Utilisation
client = CloreAI()
servers = retry_operation(lambda: client.marketplace(gpu="RTX 4090"))
```

***

## Conseils de performance

### 1. Réutiliser le client

```python
# ❌ Mauvais — crée une nouvelle connexion HTTP à chaque fois
for _ in range(10):
    client = CloreAI()
    client.marketplace()
    client.close()

# ✅ Bien — réutilise la connexion HTTP
client = CloreAI()
for _ in range(10):
    client.marketplace()
client.close()
```

### 2. Utiliser l'async pour les opérations concurrentes

```python
import asyncio
from clore_ai import AsyncCloreAI

async def compare_gpus():
    async with AsyncCloreAI() as client:
        # Exécuter 3 recherches concurrentes
        rtx4090, rtx3090, a100 = await asyncio.gather(
            client.marketplace(gpu="RTX 4090"),
            client.marketplace(gpu="RTX 3090"),
            client.marketplace(gpu="A100"),
        )

        print(f"RTX 4090: {len(rtx4090)} servers")
        print(f"RTX 3090: {len(rtx3090)} servers")
        print(f"A100: {len(a100)} servers")

asyncio.run(compare_gpus())
```

### 3. Création de commandes en lot asynchrone

```python
import asyncio
from clore_ai import AsyncCloreAI

async def batch_deploy(server_ids):
    async with AsyncCloreAI() as client:
        tasks = [
            client.create_order(
                server_id=sid,
                image="cloreai/ubuntu22.04-cuda12",
                type="on-demand",
                currency="bitcoin",
                ssh_password="BatchPass123",
                ports={"22": "tcp"}
            )
            for sid in server_ids
        ]
        orders = await asyncio.gather(*tasks, return_exceptions=True)

        for sid, result in zip(server_ids, orders):
            if isinstance(result, Exception):
                print(f"Server {sid}: FAILED — {result}")
            else:
                print(f"Server {sid}: Order {result.id} created")

        return orders

# Déployer sur 3 serveurs à la fois
asyncio.run(batch_deploy([142, 305, 891]))
```

{% hint style="warning" %}
**Remarque :** Le SDK applique un cooldown de 5 secondes entre les `create_order` appels. Même en mode async, les commandes sont espacées pour respecter les limites de débit.
{% endhint %}

### 4. Fermer les clients une fois terminé

```python
# Le gestionnaire de contexte s'en occupe automatiquement
with CloreAI() as client:
    # travail...
    pass  # client.close() appelé automatiquement

# Ou fermer manuellement
client = CloreAI()
try:
    # travail...
    pass
finally:
    client.close()
```

***

## Exemple complet : Auto-Scale des workers GPU

```python
import asyncio
import time
from clore_ai import AsyncCloreAI
from clore_ai.exceptions import CloreAPIError

async def auto_scale(
    gpu_model="RTX 4090",
    max_price=2.0,
    target_workers=3,
    image="cloreai/ubuntu22.04-cuda12"
):
    """Maintenir une piscine de workers GPU."""
    async with AsyncCloreAI() as client:
        # 1. Vérifier les commandes en cours
        current_orders = await client.my_orders()
        active_count = len(current_orders)
        print(f"Active workers: {active_count}/{target_workers}")

        if active_count >= target_workers:
            print("Déjà à l'objectif. Rien à faire.")
            return

        # 2. Trouver des serveurs disponibles
        servers = await client.marketplace(gpu=gpu_model, max_price_usd=max_price)
        servers.sort(key=lambda s: s.price_usd or float("inf"))

        needed = target_workers - active_count
        candidates = servers[:needed]

        if len(candidates) < needed:
            print(f"Only {len(candidates)} servers available (need {needed})")

        # 3. Deploy
        for server in candidates:
            try:
                order = await client.create_order(
                    server_id=server.id,
                    image=image,
                    type="on-demand",
                    currency="bitcoin",
                    ssh_password="WorkerPass123",
                    ports={"22": "tcp"}
                )
                print(f"Deployed on server {server.id} → order {order.id}")
            except CloreAPIError as e:
                print(f"Failed to deploy on {server.id}: {e}")

asyncio.run(auto_scale())
```

***

## Prochaines étapes

* [Automatisation CLI](/guides/guides_v2-fr/avance/cli-automation.md) — Scripts Bash, CI/CD, opérations par lots
* [Traitement par lots](/guides/guides_v2-fr/avance/batch-processing.md) — Traitez de lourdes charges de travail sur les GPU Clore
* [Intégration API](/guides/guides_v2-fr/avance/api-integration.md) — Connectez les services d'IA à vos applications


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-fr/avance/python-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
