L'ajout de fonctionnalités de génération d'images et de retouche ciblée (inpainting) au sein d'applications web modernes confronte souvent les développeurs indépendants et les équipes techniques réduites à un arbitrage architectural délicat. D'un côté, l'hébergement de modèles de diffusion open source sur des instances GPU dédiées (comme AWS EC2 G5, RunPod ou Modal) engendre de lourdes contraintes d'exploitation : maintenance des pilotes CUDA, gestion des montées de version vLLM/Diffusers, latence de démarrage à froid et un plancher de coûts fixes oscillant facilement entre 150 et 400 dollars par mois pour des ressources inactives. De l'autre côté, les plateformes SaaS grand public (telles que Midjourney ou Leonardo) imposent des abonnements mensuels récurrents avec des crédits non reportables et des quotas rigides peu adaptés à un trafic utilisateur intermittent.
Dezgo résout ce compromis grâce à une API REST sans serveur adossée à une véritable tarification à l'usage (pay-as-you-go). Avec un dépôt initial prépayé dès 10 dollars (sans date d'expiration), les développeurs peuvent générer des rendus Stable Diffusion standard en 512x512 pixels pour environ 0,0019 dollar l'unité, le tarif évoluant de manière transparente et prévisible en fonction de la résolution et du nombre d'étapes d'échantillonnage.
Ce guide technique accompagne les ingénieurs full-stack dans l'intégration de l'API officielle de Dezgo : méthode d'authentification via X-Dezgo-Key, consommation des points de terminaison /text2image et /inpainting_sdxl, suivi en temps réel du solde grâce aux en-têtes de réponse HTTP et mise en place d'une file d'attente asynchrone pour parer aux risques d'expiration de requêtes.
Comparatif d'architecture : GPU autogérés vs SaaS récurrents vs Dezgo
Avant d'aborder l'implémentation du code, comparons les trois approches :
| Critère | Cluster GPU dédié (EC2 / RunPod) | SaaS commercial classique (Midjourney) | API REST de Dezgo |
|---|---|---|---|
| Coût plancher mensuel | Élevé ($150–$500+/mois de base inactive) | Moyen-Élevé ($10–$60+/utilisateur/mois) | Nul (recharge prépayée unique de $10; sans abonnement) |
| Coût unitaire | Variable; très défavorable en creux de trafic | Forfaits fixes; crédits non consommés perdus | ~$0,0019 par image 512px; coût calculé au pixel et à l'étape |
| Charge d'exploitation | Complexe (drivers CUDA, auto-scaling, mémoire) | Nulle (boîte noire entièrement infogérée) | Nulle (appels HTTP REST standards; aucune gestion de GPU) |
| Choix des modèles | Total (n'importe quel checkpoint HuggingFace/LoRA) | Restreint (modèles propriétaires fermés) | Élevé (SD 1.5, SD 2.1, SDXL, Lightning et LoRAs) |
| Contrat d'échange | Conception d'API personnalisée obligatoire | Bots Discord ou mécanismes asynchrones rigides | Flux binaire direct (image/png) dans la réponse HTTP |
La force de Dezgo réside dans la restitution immédiate de l'image binaire dans le corps de la réponse HTTP, combinée à l'envoi des métadonnées de facturation dans les en-têtes HTTP.
Authentification et architecture de sécurité
Toutes les requêtes adressées à l'API de Dezgo exigent la transmission d'une clé d'accès dans l'en-tête HTTP X-Dezgo-Key. Cette clé se génère depuis le tableau de bord de votre compte sur dezgo.com/account.
Règle impérative : Ne jamais appeler Dezgo depuis le navigateur client
Les clés Dezgo débitant directement le solde financier prépayé de votre compte sans système de permissions restreintes pour les utilisateurs finaux, exposer X-Dezgo-Key dans le code front-end ou les échanges réseau du navigateur présente un risque financier critique. Un utilisateur malveillant pourrait s'en emparer et épuiser vos fonds en quelques minutes.
Une architecture sécurisée doit toujours intercaler un serveur backend ou un proxy d'API de confiance :
[Navigateur Client]
│
│ 1. POST /api/generate (Session utilisateur / Quota applicatif)
▼
[Backend Applicatif]
│
│ 2. Validation des entrées, déduction des crédits internes
│ 3. Injection de l'en-tête secret "X-Dezgo-Key"
│ 4. POST https://api.dezgo.com/text2image
▼
[Cluster REST Dezgo]
│
│ 5. Flux binaire PNG + en-têtes de tarification
▼
[Backend Applicatif]
│
│ 6. Lecture de x-dezgo-job-amount-usd et x-dezgo-balance-total-usd
│ 7. Sauvegarde sur stockage objet (S3 / R2) ou relais vers le client
▼
[Navigateur Client]
Étape 1 : Implémentation du Text-to-Image (/text2image)
Le point de terminaison text-to-image prend en charge les requêtes au format multipart/form-data ou application/json (avec données encodées en base64) et renvoie directement l'image binaire générée (image/png ou image/jpeg).
Paramètres de requête essentiels
prompt(chaîne, obligatoire) : Description textuelle de la composition souhaitée.negative_prompt(chaîne, facultatif) : Éléments indésirables à exclure du rendu.model(chaîne, facultatif) : Identifiant du modèle utilisé. La liste à jour peut être consultée dynamiquement viaGET https://api.dezgo.com/info(par exemplestablediffusion_1_5,stablediffusion_2_1_768px).guidance(nombre, facultatif) : Échelle de guidage sans classificateur (CFG Scale), généralement comprise entre 6.0 et 9.0 (valeur par défaut : 7.5).steps(entier, facultatif) : Nombre d'étapes d'échantillonnage (communément 20 à 50). Un nombre élevé affine les détails, mais augmente proportionnellement le coût et la durée de calcul.sampler(chaîne, facultatif) : Algorithme d'échantillonnage (tel queeuler_a,ddim,dpmpp_2m).width/height(entier, facultatif) : Dimensions en pixels (par défaut 512x512).
Implémentation backend en Node.js / TypeScript
// server/services/dezgoService.ts
import { Buffer } from "node:buffer";
interface TextToImageOptions {
prompt: string;
negativePrompt?: string;
model?: string;
guidance?: number;
steps?: number;
width?: number;
height?: number;
}
interface GenerationResult {
imageBuffer: Buffer;
contentType: string;
jobCostUsd: number;
remainingBalanceUsd: number;
}
export async function generateTextToImage(
options: TextToImageOptions
): Promise<GenerationResult> {
const apiKey = process.env.DEZGO_API_KEY;
if (!apiKey) {
throw new Error("La variable d'environnement DEZGO_API_KEY n'est pas configurée.");
}
const formData = new FormData();
formData.append("prompt", options.prompt);
if (options.negativePrompt) {
formData.append("negative_prompt", options.negativePrompt);
}
if (options.model) {
formData.append("model", options.model);
}
if (options.guidance) {
formData.append("guidance", options.guidance.toString());
}
if (options.steps) {
formData.append("steps", options.steps.toString());
}
if (options.width) {
formData.append("width", options.width.toString());
}
if (options.height) {
formData.append("height", options.height.toString());
}
const response = await fetch("https://api.dezgo.com/text2image", {
method: "POST",
headers: {
"X-Dezgo-Key": apiKey,
},
body: formData,
});
if (!response.ok) {
const errorBody = await response.text();
handleDezgoError(response.status, errorBody);
}
// Extraction des métadonnées de coût et de solde dans les en-têtes HTTP
const jobCostUsd = parseFloat(
response.headers.get("x-dezgo-job-amount-usd") || "0"
);
const remainingBalanceUsd = parseFloat(
response.headers.get("x-dezgo-balance-total-usd") || "0"
);
const arrayBuffer = await response.arrayBuffer();
const imageBuffer = Buffer.from(arrayBuffer);
const contentType = response.headers.get("content-type") || "image/png";
return {
imageBuffer,
contentType,
jobCostUsd,
remainingBalanceUsd,
};
}
function handleDezgoError(status: number, message: string): never {
switch (status) {
case 400:
throw new Error(`Paramètres Dezgo invalides (400) : ${message}`);
case 401:
throw new Error("Échec d'authentification Dezgo (401) : Vérifiez X-Dezgo-Key.");
case 402:
throw new Error("Paiement requis Dezgo (402) : Solde prépayé épuisé.");
case 429:
throw new Error("Limite de requêtes Dezgo atteinte (429) : Trop d'appels simultanés.");
default:
throw new Error(`Erreur serveur Dezgo (${status}) : ${message}`);
}
}
Étape 2 : Implémentation de l'Inpainting avec SDXL (/inpainting_sdxl)
L'inpainting permet de modifier des portions ciblées d'une image existante au moyen d'un masque tout en conservant le contexte environnant. Dezgo propose deux points d'accès majeurs : /inpainting pour les modèles Stable Diffusion classiques et /inpainting_sdxl pour l'architecture SDXL en haute résolution.
Exigences relatives aux images d'entrée
L'opération d'inpainting nécessite obligatoirement deux fichiers :
init_image: L'image source originale à modifier (PNG ou JPEG).mask_image: Un masque monochrome ayant très exactement les mêmes dimensions en pixels queinit_image. Les zones blanches (#FFFFFF) indiquent la zone à repeindre par l'IA ; les zones noires (#000000) désignent les pixels originaux à protéger sans altération.
Implémentation backend en Python (FastAPI / Requests)
# app/services/dezgo_inpainting.py
import os
import requests
from typing import Dict, Any, Tuple
DEZGO_API_KEY = os.environ.get("DEZGO_API_KEY")
INPAINTING_SDXL_URL = "https://api.dezgo.com/inpainting_sdxl"
def execute_sdxl_inpainting(
prompt: str,
init_image_bytes: bytes,
mask_image_bytes: bytes,
negative_prompt: str = "",
guidance: float = 7.5,
steps: int = 30,
) -> Tuple[bytes, Dict[str, Any]]:
"""
Transmet une requête d'inpainting SDXL à Dezgo via multipart/form-data.
"""
if not DEZGO_API_KEY:
raise ValueError("La variable d'environnement DEZGO_API_KEY n'est pas définie.")
headers = {
"X-Dezgo-Key": DEZGO_API_KEY
}
files = {
"init_image": ("init.png", init_image_bytes, "image/png"),
"mask_image": ("mask.png", mask_image_bytes, "image/png"),
}
data = {
"prompt": prompt,
"negative_prompt": negative_prompt,
"guidance": str(guidance),
"steps": str(steps),
}
response = requests.post(
INPAINTING_SDXL_URL,
headers=headers,
files=files,
data=data,
timeout=60
)
if response.status_code == 402:
raise RuntimeError("Solde Dezgo insuffisant. Veuillez recharger votre compte.")
elif response.status_code != 200:
raise RuntimeError(f"Échec de l'inpainting Dezgo [{response.status_code}] : {response.text}")
metadata = {
"job_cost_usd": float(response.headers.get("x-dezgo-job-amount-usd", "0")),
"remaining_balance_usd": float(response.headers.get("x-dezgo-balance-total-usd", "0")),
"content_type": response.headers.get("Content-Type", "image/png"),
}
return response.content, metadata
Étape 3 : Traitement asynchrone et prévention des délais d'expiration
L'API de Dezgo fonctionne de manière synchrone : la connexion HTTP reste active jusqu'à la fin de la génération par le modèle (généralement 2 à 8 secondes). Dans des architectures sans serveur (comme le palier gratuit de Vercel avec sa limite stricte de 10 secondes), cette latence peut provoquer des erreurs d'expiration de passerelle (Gateway Timeout).
Schéma recommandé : File d'attente Redis avec SSE
En production, il est recommandé de séparer la réception de la requête du processus de rendu à l'aide d'une file d'attente Redis (BullMQ ou Celery) :
[Navigateur Client] ── 1. POST /api/jobs (prompt et masque) ──► [Serveur Web API]
│
▼
[Navigateur Client] ◄─ 3. Réponse 202 Accepted { jobId } ─── 2. Ajout dans Redis
│ │
│ ▼
│ 4. Écoute via SSE / WebSocket ou scrutation [File Redis / BullMQ]
│ │
│ ▼ 5. Prise en charge
│ [Worker en arrière-plan]
│ │
│ ├── 6. Appel API Dezgo
│ ├── 7. Dépôt sur S3 / R2
│ └── 8. Mise à jour DB
◄── 9. Notification d'achèvement avec lien CDN image ────────────┘
Exemple de Worker BullMQ
// workers/renderWorker.ts
import { Worker, Job } from "bullmq";
import { generateTextToImage } from "../services/dezgoService";
import { uploadToS3 } from "../services/storageService";
import { db } from "../services/db";
export const renderWorker = new Worker("image-generation-queue", async (job: Job) => {
const { prompt, userId, jobId } = job.data;
// 1. Appel du service Dezgo
const { imageBuffer, contentType, jobCostUsd, remainingBalanceUsd } =
await generateTextToImage({ prompt, steps: 30 });
// 2. Persistance dans le stockage d'objets (S3 ou R2)
const cdnUrl = await uploadToS3({
key: `renders/${userId}/${jobId}.png`,
body: imageBuffer,
contentType,
});
// 3. Mise à jour du statut en base de données et enregistrement financier
await db.jobs.update({
where: { id: jobId },
data: {
status: "COMPLETED",
outputUrl: cdnUrl,
costUsd: jobCostUsd,
},
});
// 4. Déclenchement d'une alerte si le solde restant passe sous les 5 dollars
if (remainingBalanceUsd < 5.0) {
console.warn(`[Alerte Solde] Solde Dezgo faible : $${remainingBalanceUsd.toFixed(2)} restant.`);
}
return { cdnUrl, jobCostUsd };
});
Gestion du solde financier et bonnes pratiques de production
Dezgo ne disposant pas de rechargement automatique par prélèvement bancaire, les crédits doivent être renouvelés manuellement avant d'atteindre zéro. La surveillance continue des en-têtes de réponse est donc indispensable pour éviter toute interruption de service.
Indicateurs de télémétrie dans les en-têtes HTTP
Chaque réponse validée retourne les indicateurs suivants :
x-dezgo-job-amount-usd: Montant exact facturé pour l'opération en cours (USD).x-dezgo-balance-total-usd: Solde disponible restant sur le compte après déduction (USD).x-dezgo-balance-credits-usd: Montant cumulé total des dépôts effectués.x-dezgo-balance-debits-usd: Montant cumulé total des dépenses enregistrées.x-dezgo-balance-index: Numéro de séquence de la transaction comptable.
Consultation du solde sans génération d'image
Pour contrôler l'état financier du compte sans générer d'image ni consommer de crédits, interrogez le point d'accès des transactions :
curl -s -H "X-Dezgo-Key: YOUR_API_KEY" https://api.dezgo.com/account/tx/last
Cet appel renvoie un objet JSON contenant le dernier enregistrement comptable ainsi que la valeur du champ balance.
Gestion des erreurs opérationnelles
- HTTP 402 (Payment Required) : Le solde prépayé est épuisé. Interceptez ce code au niveau du backend pour alerter immédiatement l'équipe technique via Slack ou PagerDuty, tout en affichant un message rassurant à l'utilisateur (« Traitement temporairement différé pour maintenance ») au lieu d'une erreur 500 générique.
- HTTP 429 (Too Many Requests) : Seuil de requêtes simultanées dépassé. Implémentez un mécanisme d'attente exponentielle avec gigue (jitter) au niveau du worker (ex. nouvelle tentative après 1s, 2s, 4s).
- HTTP 400 (Bad Request) : Survient généralement lors d'une inadéquation de dimensions entre le masque et l'image d'origine. Validez systématiquement la géométrie en pixels avant l'envoi vers Dezgo.
Conclusion
Pour les développeurs indépendants et les produits numériques nécessitant de la création visuelle à la demande, Dezgo constitue une alternative particulièrement efficace face aux coûts fixes des clusters GPU et aux forfaits mensuels contraignants des SaaS traditionnels. En combinant un proxy backend sécurisé, une file d'attente asynchrone et un monitoring rigoureux des soldes via les en-têtes HTTP, il devient possible de déployer un service d'image IA hautement évolutif avec des coûts unitaires inférieurs au centime d'euro.