> ## Documentation Index
> Fetch the complete documentation index at: https://novita.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Guide d’utilisation du SDK GPUs

Ce guide explique comment utiliser le SDK `novita-gpus` pour appeler un Endpoint serverless asynchrone et comment personnaliser un handler de worker.

## 1. Installer le SDK

Installez le SDK dans votre environnement client ou dans l’environnement d’exécution du worker :

```bash theme={"system"}
pip install novita-gpus
```

## 2. Soumettre des jobs avec le SDK

L’URL de requête par défaut du SDK `novita-gpus` est `https://async-public.serverless.novita.ai/v1`. Pour appeler un Endpoint, définissez votre API Key et créez un client avec le nom de l’Endpoint.

```python theme={"system"}
import novita_gpus

novita_gpus.api_key = "sk_xxxx"

endpoint = novita_gpus.Endpoint("0f43a6867e05fddd")
job = endpoint.run({
    "prompt": "a red apple on a table"
})

print(job.status())
output = job.output(timeout=300)
print(output)
```

## 3. Exemple de job ComfyUI

Pour `novitalabs/comfyui-worker:v0.0.1`, l’entrée du job doit inclure un workflow ComfyUI. L’exemple minimal suivant correspond au cas testé :

```python theme={"system"}
import novita_gpus

novita_gpus.api_key = "sk_xxxx"

endpoint = novita_gpus.Endpoint("0f43a6867e05fddd")

job = endpoint.run({
    "workflow": {
        "4": {
            "class_type": "CheckpointLoaderSimple",
            "inputs": {"ckpt_name": "flux1-dev-fp8.safetensors"},
        },
        "5": {
            "class_type": "EmptyLatentImage",
            "inputs": {"width": 512, "height": 512, "batch_size": 1},
        },
        "6": {
            "class_type": "CLIPTextEncode",
            "inputs": {"clip": ["4", 1], "text": "a red apple on a table"},
        },
        "7": {
            "class_type": "CLIPTextEncode",
            "inputs": {"clip": ["4", 1], "text": "blurry, low quality"},
        },
        "3": {
            "class_type": "KSampler",
            "inputs": {
                "model": ["4", 0],
                "positive": ["6", 0],
                "negative": ["7", 0],
                "latent_image": ["5", 0],
                "seed": 42,
                "steps": 10,
                "cfg": 7,
                "sampler_name": "euler",
                "scheduler": "normal",
                "denoise": 1,
            },
        },
        "8": {
            "class_type": "VAEDecode",
            "inputs": {"samples": ["3", 0], "vae": ["4", 2]},
        },
        "9": {
            "class_type": "SaveImage",
            "inputs": {"filename_prefix": "test", "images": ["8", 0]},
        },
    },
    "output_node_id": "9",
})

print(job.status())
print(job.output(timeout=300))
```

## 4. Handler personnalisé

Côté worker, appelez `novita_gpus.start({"handler": handler})` pour démarrer la boucle de tâches. La plateforme transmet les données de tâche à `handler(job)` :

* `job["id"]` : id du job actuel
* `job["input"]` : contenu d’entrée soumis par le client
* La valeur de retour du handler est utilisée comme sortie du job
* Si le dict retourné contient un champ `error`, le job est marqué comme échoué

Exemple minimal de handler :

```python theme={"system"}
import time
import novita_gpus


def handler(job: dict) -> dict:
    job_id = job["id"]
    job_input = job.get("input", {})
    prompt = job_input.get("prompt", "hello")

    novita_gpus.progress_update(job, {
        "status": "running",
        "message": "job accepted",
    })

    time.sleep(1)

    return {
        "job_id": job_id,
        "prompt": prompt,
        "result": "ok",
    }


if __name__ == "__main__":
    novita_gpus.start({"handler": handler})
```

## 5. Exemples complets de workers

Pour le code source complet des workers, les instructions de build d’image Docker et les scripts de soumission de tâches, consultez les <Link href="https://github.com/novitalabs/gpus-python-example" target="_blank">exemples Python Novita GPUs</Link>.

Le dépôt inclut deux exemples :

* <Link href="https://github.com/novitalabs/gpus-python-example/tree/main/workers/comfyui-worker" target="_blank">comfyui-worker</Link> : exécute ComfyUI depuis `handler.py` et retourne les images générées.
* <Link href="https://github.com/novitalabs/gpus-python-example/tree/main/workers/sleep-worker" target="_blank">sleep-worker</Link> : un `handler.py` minimal qui attend pendant une durée demandée et retourne un résultat JSON.

Chaque répertoire d’exemple contient :

* `handler.py` : définit `handler(job)` et démarre le worker avec `novita_gpus.start({"handler": handler})`.
* `Dockerfile` : construit l’image du worker.
* `requirements.txt` : installe `novita-gpus`.
* `submit_task.py` : soumet une tâche avec le SDK client `novita-gpus`.

Construisez et poussez votre image de worker vers votre propre registre :

```bash theme={"system"}
IMAGE=<your-registry>/comfyui-worker:v0.0.1

docker buildx build --platform linux/amd64 \
  -t "$IMAGE" \
  --push .
```

La soumission de tâche utilise le format de nom d’Endpoint `<endpoint-id>-<app-name>`.
Par exemple, l’Endpoint ID `o8UJWkag5WTn` et le nom d’application `async` produisent :

```text theme={"system"}
o8UJWkag5WTn-async
```

Les exemples `submit_task.py` acceptent l’Endpoint ID et le nom d’application séparément, puis composent le nom d’Endpoint final :

```bash theme={"system"}
export NOVITA_API_KEY="sk_xxxx"
export NOVITA_ENDPOINT_ID="o8UJWkag5WTn"
export NOVITA_APP_NAME="async"

python submit_task.py \
  --endpoint "$NOVITA_ENDPOINT_ID" \
  --app-name "$NOVITA_APP_NAME" \
  --api-key "$NOVITA_API_KEY"
```

Dans le script, le client SDK est créé avec le nom d’Endpoint composé :

```python theme={"system"}
endpoint_name = f"{args.endpoint}-{args.app_name}"
endpoint = novita_gpus.Endpoint(endpoint_name, api_key=args.api_key)
```

## 6. Retourner des images ou des fichiers

L’API `status` de l’Endpoint serverless asynchrone a une limite de taille de sortie. Pour les fichiers volumineux tels que les images et les vidéos, téléversez-les d’abord vers un stockage d’objets et retournez les URL dans la sortie.

Configurez les variables d’environnement du stockage d’objets dans l’Endpoint :

```bash theme={"system"}
BUCKET_ENDPOINT_URL=https://<your-bucket-endpoint>
BUCKET_ACCESS_KEY_ID=<your-access-key-id>
BUCKET_SECRET_ACCESS_KEY=<your-secret-access-key>
BUCKET_NAME=<your-bucket-name>
```

Téléversez une image dans le handler :

```python theme={"system"}
import novita_gpus


def handler(job: dict) -> dict:
    image_url = novita_gpus.upload_image(job["id"], "/tmp/output.png")

    return {
        "images": [
            {
                "filename": "output.png",
                "url": image_url,
            }
        ]
    }


if __name__ == "__main__":
    novita_gpus.start({"handler": handler})
```

Vous pouvez également téléverser des fichiers ordinaires ou des bytes :

```python theme={"system"}
import novita_gpus

file_url = novita_gpus.upload_file("result.json", "/tmp/result.json")
bytes_url = novita_gpus.upload_bytes("result.txt", b"hello")
```

## 7. FAQ

### Dois-je configurer une API Key dans le worker ?

Généralement non. Les API Keys sont principalement utilisées par les clients pour soumettre, interroger et annuler des jobs.

### Quelle valeur de retour du handler marque un job comme échoué ?

Si le handler retourne un dict qui contient un champ `error`, le job est marqué comme échoué :

```python theme={"system"}
return {"error": "invalid input"}
```
