> 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-de/fortgeschritten/python-sdk.md).

# Python SDK-Leitfaden

Vollständiger Python-SDK-Leitfaden — synchrone/asynchrone Clients, Marketplace-Filterung, Order-Lebenszyklus, Spot-Markt, Wallet-Operationen und Fehlerbehandlung

{% hint style="success" %}
**Neu im SDK?** Beginnen Sie mit dem [5-Minuten-Schnellstart](/guides/guides_v2-de/erste-schritte/python-quickstart.md) zuerst.
{% endhint %}

Für ein Schnellstart-Tutorial mit echten Beispielen siehe [Clore.ai Python SDK — Automatisieren Sie Ihre GPU-Workflows in 5 Minuten](https://blog.clore.ai/cloreai-python-sdk-automate-your-gpu-workflows-in-5-minutes/)

## Installation

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

Das SDK stellt zwei Clients bereit:

* **`CloreAI`** — synchron (einfacher, gut für Skripte)
* **`AsyncCloreAI`** — asynchron (schneller für gleichzeitige Operationen)

Beide verwenden dieselben Methoden und geben dieselben Pydantic-Modelle zurück.

***

## Sync vs. Async — Wann man was verwendet

| Anwendungsfall                       | Client         | Warum                                    |
| ------------------------------------ | -------------- | ---------------------------------------- |
| Einfache Skripte, einmalige Aufgaben | `CloreAI`      | Einfacherer Code, kein `async/await`     |
| Überwachungsschleifen                | `CloreAI`      | Sequenzielle Prüfungen funktionieren gut |
| Massenabfragen des Marktplatzes      | `AsyncCloreAI` | Gleichzeitige Anfragen = schneller       |
| Stapelweise Auftragserstellung       | `AsyncCloreAI` | Mehrere Aufträge parallel erstellen      |
| Webanwendungen                       | `AsyncCloreAI` | Nicht blockierendes I/O                  |

### Sync-Beispiel

```python
from clore_ai import CloreAI

client = CloreAI()  # Verwendet die Umgebungsvariable CLORE_API_KEY

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

client.close()  # Oder verwenden Sie einen Kontextmanager
```

### Async-Beispiel

```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"Gefundene Server: {len(servers)}")

asyncio.run(main())
```

### Kontextmanager (empfohlen)

Beide Clients unterstützen Kontextmanager für die automatische Bereinigung:

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

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

***

## Client-Konfiguration

```python
client = CloreAI(
    api_key="your_key",      # Oder CLORE_API_KEY als Umgebungsvariable setzen
    base_url="https://api.clore.ai/v1",  # Benutzerdefinierter API-Endpunkt
    timeout=30.0,            # Anfragetimeout in Sekunden
    max_retries=3            # Wiederholungen bei Ratenbegrenzung / Netzwerkfehlern
)
```

Das SDK enthält eine integrierte Ratenbegrenzung:

* **Allgemeine Anfragen:** 1 Anfrage/Sekunde
* **`create_order`:** 5-sekündige Pause zwischen Aufrufen
* **Ratenbegrenzungsfehler (Code 5):** Automatischer exponentieller Backoff

***

## Marktplatzfilterung

Der `marketplace()` Methode ruft alle verfügbaren Server ab und filtert clientseitig:

```python
from clore_ai import CloreAI

client = CloreAI()

# Alle verfügbaren Server
all_servers = client.marketplace()

# Nach GPU-Modell filtern (Groß-/Kleinschreibung wird ignoriert, Teilzeichenfolgenabgleich)
rtx_4090s = client.marketplace(gpu="RTX 4090")

# Nach mehreren Kriterien filtern
budget_gpus = client.marketplace(
    gpu="RTX 4090",
    max_price_usd=1.0,       # Max. 1,00 $/Stunde
    min_gpu_count=2,          # Mindestens 2 GPUs
    min_ram_gb=64.0,          # Mindestens 64 GB Systemspeicher
    available_only=True       # Nur verfügbare Server (Standard)
)
```

### Erweiterte Filterung (clientseitig)

Für Filter, die nicht in der Methode integriert sind, filtern Sie die zurückgegebenen `Server` Objekte selbst:

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

# Server in der EU mit hoher Zuverlässigkeit
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
]

# Nach Preis sortieren
cheapest = sorted(servers, key=lambda s: s.price_usd or float("inf"))
print(f"Günstigster: Server {cheapest[0].id} — ${cheapest[0].price_usd:.4f}/h")
```

### Felder des Servermodells

Jedes `MarketplaceServer` Objekt hat diese Attribute und praktischen Eigenschaften:

| Feld             | Typ                   | Beschreibung                                                        |
| ---------------- | --------------------- | ------------------------------------------------------------------- |
| `id`             | `int`                 | Server-ID (verwenden Sie diese in `create_order`)                   |
| `gpu_model`      | `str \| None`         | GPU-Beschreibung aus den Spezifikationen (Eigenschaft)              |
| `gpu_count`      | `int`                 | Anzahl der GPUs aus `gpu_array` (Eigenschaft)                       |
| `ram_gb`         | `float \| None`       | System-RAM in GB (Eigenschaft, aus `specs.ram`)                     |
| `price_usd`      | `float \| None`       | On-Demand-Preis in USD (Eigenschaft, aus `price.usd.on_demand_usd`) |
| `spot_price_usd` | `float \| None`       | Spot-Preis in USD (Eigenschaft)                                     |
| `verfügbar`      | `bool`                | Ob der Server nicht vermietet ist (Eigenschaft)                     |
| `location`       | `str \| None`         | Ländercode aus den Netzwerkspezifikationen (Eigenschaft)            |
| `specs`          | `ServerSpecs \| None` | Hardware-Spezifikationen (CPU, RAM, Festplatte, GPU, Netzwerk)      |
| `price`          | `ServerPrice \| None` | Vollständige Preisstruktur                                          |
| `rented`         | `bool \| None`        | Ob der Server derzeit vermietet ist                                 |

***

## Auftragsverwaltung

### Aufträge erstellen

```python
order = client.create_order(
    server_id=142,
    image="cloreai/ubuntu22.04-cuda12",
    type="on-demand",               # "on-demand" oder "spot"
    currency="bitcoin",             # Zahlungsmwährung
    ssh_password="MySecurePass",    # SSH-Zugriff
    ports={"22": "tcp", "8888": "http"},  # Portzuordnungen
    env={"HF_TOKEN": "hf_xxx"},    # Umgebungsvariablen
    command="bash /start.sh",       # Benutzerdefinierter Startbefehl
    jupyter_token="my_token"        # Jupyter-Notebook-Token
)

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

### Vollständige `create_order` Parameter

| Parameter            | Typ     | Erforderlich | Beschreibung                        |
| -------------------- | ------- | ------------ | ----------------------------------- |
| `server_id`          | `int`   | ✅            | Zu mietender Server                 |
| `image`              | `str`   | ✅            | Docker-Image                        |
| `type`               | `str`   | ✅            | `"on-demand"` oder `"spot"`         |
| `currency`           | `str`   | ✅            | Zahlungswährung (z. B. `"bitcoin"`) |
| `ssh_password`       | `str`   | —            | SSH-Passwort                        |
| `ssh_key`            | `str`   | —            | Öffentlicher SSH-Schlüssel          |
| `ports`              | `dict`  | —            | Portzuordnungen (`{"22": "tcp"}`)   |
| `env`                | `dict`  | —            | Umgebungsvariablen                  |
| `jupyter_token`      | `str`   | —            | Jupyter-Notebook-Token              |
| `command`            | `str`   | —            | Startbefehl                         |
| `spot_price`         | `float` | —            | Spot-Gebotspreis                    |
| `required_price`     | `float` | —            | Erforderlicher Preis                |
| `autossh_entrypoint` | `str`   | —            | Automatischer SSH-Einstiegspunkt    |

### Aufträge auflisten

```python
# Nur aktive Aufträge
active = client.my_orders()
for o in active:
    print(f"Auftrag {o.id}: Typ={o.type}, IP={o.pub_cluster}, Status={o.status}")

# Abgeschlossene Aufträge einschließen
all_orders = client.my_orders(include_completed=True)
```

### Felder des Auftragsmodells

| Feld          | Typ             | Beschreibung                            |
| ------------- | --------------- | --------------------------------------- |
| `id`          | `int`           | Auftrags-ID                             |
| `server_id`   | `int \| None`   | ID des gemieteten Servers               |
| `type`        | `str`           | `"on-demand"` oder `"spot"`             |
| `status`      | `str \| None`   | Auftragsstatus                          |
| `image`       | `str \| None`   | Docker-Image                            |
| `currency`    | `str \| None`   | Zahlungsmwährung                        |
| `price`       | `float \| None` | Preis                                   |
| `pub_cluster` | `str \| None`   | Öffentliche IP / Hostname               |
| `tcp_ports`   | `dict \| None`  | Portzuordnungen (z. B. `{"22": 50022}`) |
| `created_at`  | `str \| None`   | Erstellungszeitstempel                  |

### Aufträge überwachen

```python
import time

def wait_for_ready(client, order_id, timeout=120):
    """Warten, bis ein Auftrag eine öffentliche IP erhält."""
    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"Auftrag {order_id} nach {timeout}s noch nicht bereit")

# Verwendung
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)}")
```

### Aufträge stornieren

```python
# Mit optionalem Grund stornieren
client.cancel_order(order_id=38, issue="Job abgeschlossen")

# Alle aktiven Aufträge stornieren
orders = client.my_orders()
for order in orders:
    client.cancel_order(order.id, issue="Bereinigung")
    print(f"Stornierter Auftrag {order.id}")
```

***

## Serververwaltung (für Hoster)

Wenn Sie GPUs auf Clore hosten, können Sie mit dem SDK Ihre Server verwalten:

### Ihre Server auflisten

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

### Server-Konfiguration abrufen

```python
config = client.server_config("MyGPU-Rig")
print(f"Name: {config.name}")
print(f"Sichtbarkeit: {config.visibility}")
print(f"Online: {config.online}")
print(f"Mindestmiete: {config.mrl}h")
print(f"On-Demand-Preis: {config.on_demand_price}")
print(f"Spot-Preis: {config.spot_price}")
```

### Servereinstellungen aktualisieren

```python
client.set_server_settings(
    name="MyGPU-Rig",
    availability=True,       # Server verfügbar machen
    mrl=24,                  # Mindestmietdauer 24h
    on_demand=0.0001,        # On-Demand-Preis in BTC
    spot=0.00000113          # Spot-Preis in BTC
)
print("Einstellungen aktualisiert")
```

***

## Spot-Markt

Spot-Aufträge können unterbrochen werden, wenn jemand Ihr Gebot überbietet. Etwa ein Drittel der Server bietet Spot unterhalb des On-Demand-Preises an (Median \~13 % Rabatt); der Rest listet Spot zum On-Demand-Preis.

### Spot-Angebote anzeigen

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

### Einen Spot-Auftrag erstellen

```python
order = client.create_order(
    server_id=142,
    image="cloreai/ubuntu22.04-cuda12",
    type="spot",
    currency="bitcoin",
    spot_price=0.0001,       # Ihr Gebotspreis
    ssh_password="MyPass"
)
print(f"Spot-Auftrag {order.id} erstellt")
```

### Spot-Preis anpassen

```python
# Erhöhen Sie Ihr Gebot, um nicht überboten zu werden
client.set_spot_price(order_id=39, price=0.000003)
```

### Spot-Gebotsstrategie

```python
from clore_ai import CloreAI

client = CloreAI()

def smart_spot_bid(server_id, premium_pct=5):
    """Bieten Sie leicht über dem aktuellen minimalen Spot-Preis."""
    offers = client.spot_marketplace(server_id=server_id)
    if not offers:
        print("Keine Spot-Angebote — den On-Demand-Preis als Basis verwenden")
        return None

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

# Verwendung
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
    )
```

***

## Wallet-Operationen

### Guthaben prüfen

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

### Warnung bei niedrigem Guthaben

```python
from clore_ai import CloreAI

def check_balance(min_btc=0.001):
    """Warnen, wenn das BTC-Guthaben unter dem Schwellenwert liegt."""
    client = CloreAI()
    wallets = client.wallets()

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

    print("✅ Guthaben in Ordnung")
    return True

check_balance(min_btc=0.001)
```

***

## Bewährte Methoden zur Fehlerbehandlung

### Ausnahmearchitektur

```
CloreAPIError (Basisklasse)
├── DBError           (Code 1) — Datenbankfehler
├── InvalidInputError (Code 2) — Ungültige Eingabe
├── AuthError         (Code 3) — Ungültiger API-Schlüssel
├── InvalidEndpointError (Code 4) — Falscher Endpunkt
├── RateLimitError    (Code 5) — Ratenbegrenzung (automatisch erneut versucht)
└── FieldError        (Code 6) — feldspezifischer Fehler
```

### Grundlegende Fehlerbehandlung

```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("Ungültiger API-Schlüssel — CLORE_API_KEY prüfen")
except InvalidInputError as e:
    print(f"Ungültige Eingabe: {e}")
except RateLimitError:
    print("Ratenbegrenzung — das SDK versucht es automatisch erneut, aber die maximale Anzahl an Wiederholungen wurde überschritten")
except CloreAPIError as e:
    print(f"API-Fehler (Code {e.code}): {e}")
```

### Retry-Muster mit Backoff

Das SDK hat integrierte Wiederholungsversuche für Ratenlimits und Netzwerkfehler (`max_retries=3`). Für Wiederholungsversuche auf Anwendungsebene:

```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):
    """Einen Clore-API-Vorgang mit exponentiellem Backoff erneut versuchen."""
    for attempt in range(max_attempts):
        try:
            return func()
        except RateLimitError:
            if attempt < max_attempts - 1:
                delay = base_delay * (2 ** attempt)
                print(f"Ratenlimit erreicht, erneuter Versuch in {delay}s...")
                time.sleep(delay)
            else:
                raise
        except CloreAPIError as e:
            if e.code in (1,):  # DB-Fehler können vorübergehend sein
                if attempt < max_attempts - 1:
                    time.sleep(base_delay)
                    continue
            raise

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

***

## Leistungstipps

### 1. Den Client wiederverwenden

```python
# ❌ Schlecht — erstellt jedes Mal eine neue HTTP-Verbindung
for _ in range(10):
    client = CloreAI()
    client.marketplace()
    client.close()

# ✅ Gut — verwendet die HTTP-Verbindung wieder
client = CloreAI()
for _ in range(10):
    client.marketplace()
client.close()
```

### 2. Async für gleichzeitige Operationen verwenden

```python
import asyncio
from clore_ai import AsyncCloreAI

async def compare_gpus():
    async with AsyncCloreAI() as client:
        # 3 Suchen gleichzeitig ausführen
        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)} Server")
        print(f"RTX 3090: {len(rtx3090)} Server")
        print(f"A100: {len(a100)} Server")

asyncio.run(compare_gpus())
```

### 3. Asynchrone Stapel-Bestellerstellung

```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}: FEHLGESCHLAGEN — {result}")
            else:
                print(f"Server {sid}: Bestellung {result.id} erstellt")

        return orders

# Auf 3 Servern gleichzeitig bereitstellen
asyncio.run(batch_deploy([142, 305, 891]))
```

{% hint style="warning" %}
**Hinweis:** Das SDK erzwingt eine 5-Sekunden-Abkühlzeit zwischen `create_order` Aufrufen. Selbst im Async-Modus werden Bestellungen zeitlich versetzt, um Ratenlimits einzuhalten.
{% endhint %}

### 4. Clients bei Fertigstellung schließen

```python
# Der Kontextmanager übernimmt dies automatisch
with CloreAI() as client:
    # Arbeit...
    pass  # client.close() wird automatisch aufgerufen

# Oder manuell schließen
client = CloreAI()
try:
    # Arbeit...
    pass
finally:
    client.close()
```

***

## Vollständiges Beispiel: GPU-Worker automatisch skalieren

```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"
):
    """Einen Pool von GPU-Workern aufrechterhalten."""
    async with AsyncCloreAI() as client:
        # 1. Aktuelle Bestellungen prüfen
        current_orders = await client.my_orders()
        active_count = len(current_orders)
        print(f"Aktive Worker: {active_count}/{target_workers}")

        if active_count >= target_workers:
            print("Bereits am Ziel. Nichts zu tun.")
            return

        # 2. Verfügbare Server finden
        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"Nur {len(candidates)} Server verfügbar (benötigt werden {needed})")

        # 3. Bereitstellen
        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"Auf Server {server.id} bereitgestellt → Bestellung {order.id}")
            except CloreAPIError as e:
                print(f"Bereitstellung auf {server.id} fehlgeschlagen: {e}")

asyncio.run(auto_scale())
```

***

## Nächste Schritte

* [CLI-Automatisierung](/guides/guides_v2-de/fortgeschritten/cli-automation.md) — Bash-Skripte, CI/CD, Batch-Operationen
* [Batch-Verarbeitung](/guides/guides_v2-de/fortgeschritten/batch-processing.md) — Große Workloads auf Clore-GPUs verarbeiten
* [API-Integration](/guides/guides_v2-de/fortgeschritten/api-integration.md) — KI-Services mit Ihren Apps verbinden


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-de/fortgeschritten/python-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
