Al incorporar funciones de generación de imágenes y repintado por zonas (inpainting) en aplicaciones web modernas, los desarrolladores independientes y los equipos reducidos a menudo se enfrentan a un dilema técnico y financiero. Por un lado, alojar modelos de difusión de código abierto en instancias de GPU dedicadas (como AWS EC2 G5, RunPod o Modal) acarrea una carga operativa considerable: mantenimiento de controladores CUDA, actualizaciones de librerías vLLM/Diffusers, gestión de arranques en frío y un coste base fijo que oscila fácilmente entre 150 y 400 dólares mensuales por recursos inactivos. Por otro lado, las plataformas comerciales de SaaS (como Midjourney o Leonardo) imponen suscripciones mensuales obligatorias, cuotas rígidas y créditos que caducan, lo que resulta ineficiente para productos con volumen de tráfico fluctuante.
Dezgo resuelve este conflicto mediante una API REST sin servidor basada en un esquema auténtico de pago por uso (pay-as-you-go). Con una recarga inicial mínima de 10 dólares cuyos créditos nunca caducan, los desarrolladores pueden generar imágenes estándar de Stable Diffusion de 512x512 píxeles por aproximadamente 0,0019 dólares cada una, escalando de manera predecible según las dimensiones y el número de pasos de muestreo.
Esta guía técnica explica paso a paso cómo integrar la API oficial de Dezgo en una arquitectura web para producción: el mecanismo de autenticación mediante X-Dezgo-Key, la gestión de llamadas a los extremos /text2image e /inpainting_sdxl, la supervisión en tiempo real del saldo a través de las cabeceras HTTP y la implementación de colas asíncronas para mitigar tiempos de espera.
Comparativa de arquitectura: GPUs autogestionadas frente a SaaS tradicional y Dezgo
Antes de comenzar la implementación, conviene analizar las ventajas operativas y económicas de cada opción:
| Parámetro | Clúster GPU propio (EC2 / RunPod) | SaaS comercial tradicional (Midjourney) | API REST de Dezgo |
|---|---|---|---|
| Coste mínimo mensual | Elevado ($150–$500+ al mes en reposo) | Medio-Alto ($10–$60+ al mes por usuario) | Cero ($10 de prepago inicial sin suscripción) |
| Coste unitario | Variable; muy ineficiente en valles de tráfico | Planes fijos; créditos no consumidos expiran | ~$0,0019 por imagen 512px; cálculo por píxel y paso |
| Carga de mantenimiento | Crítica (drivers CUDA, autoescalado, memoria) | Mínima (caja negra sin control de infraestructura) | Mínima (llamadas HTTP REST estándar; cero ops GPU) |
| Flexibilidad de modelos | Total (cualquier peso HuggingFace o LoRA propio) | Baja (modelos cerrados y propietarios) | Alta (SD 1.5, SD 2.1, SDXL, Lightning y LoRAs) |
| Contrato de respuesta | Requiere desarrollo propio de la interfaz API | Bots de Discord o sondeos no estándares | Flujo binario directo (image/png) en la respuesta |
Dezgo destaca porque entrega el archivo de imagen directamente en el cuerpo de la respuesta HTTP y transmite la contabilidad exacta de cada llamada en las cabeceras de respuesta.
Autenticación y arquitectura de seguridad
Todas las solicitudes dirigidas a la API de Dezgo requieren autenticación mediante la cabecera HTTP X-Dezgo-Key. Esta clave se genera en la consola de usuario en dezgo.com/account.
La regla fundamental: No invocar a Dezgo desde el navegador del cliente
La clave de API de Dezgo debita fondos directamente de tu saldo prepagado y no ofrece permisos granulares para usuarios finales. Si expones X-Dezgo-Key en el código de frontend o en solicitudes de red del navegador, cualquier usuario malintencionado podrá extraer la clave y agotar tu saldo en pocos minutos.
La arquitectura de una aplicación web segura debe canalizar siempre las solicitudes a través de un servidor backend o un proxy de API de confianza:
[Navegador del cliente]
│
│ 1. POST /api/generate (Sesión de usuario / Token / Cuota interna)
▼
[Backend de tu aplicación]
│
│ 2. Validar entrada, descontar créditos internos
│ 3. Inyectar cabecera secreta "X-Dezgo-Key"
│ 4. POST https://api.dezgo.com/text2image
▼
[Motor REST de Dezgo]
│
│ 5. Devuelve flujo binario PNG + cabeceras de facturación
▼
[Backend de tu aplicación]
│
│ 6. Leer x-dezgo-job-amount-usd y x-dezgo-balance-total-usd
│ 7. Guardar en almacenamiento de objetos (S3 / R2) o transmitir al cliente
▼
[Navegador del cliente]
Paso 1: Implementación de Text-to-Image (/text2image)
El extremo de generación de texto a imagen admite peticiones formateadas como multipart/form-data o application/json (con cargas codificadas en base64) y devuelve directamente el flujo binario de la imagen renderizada (image/png o image/jpeg).
Parámetros clave de la solicitud
prompt(cadena, obligatorio): Descripción detallada de la imagen que se desea generar.negative_prompt(cadena, opcional): Elementos que se deben excluir de la composición.model(cadena, opcional): Identificador del modelo deseado. Es posible consultar la lista actualizada en tiempo real medianteGET https://api.dezgo.com/info(por ejemplo,stablediffusion_1_5,stablediffusion_2_1_768px, etc.).guidance(número, opcional): Escala de Classifier-Free Guidance (CFG), habitualmente entre 6.0 y 9.0 (predeterminado: 7.5).steps(entero, opcional): Pasos de muestreo (generalmente 20–50). Más pasos mejoran el detalle, pero aumentan linealmente el coste y el tiempo.sampler(cadena, opcional): Algoritmo de muestreo (por ejemplo,euler_a,ddim,dpmpp_2m).width/height(entero, opcional): Dimensiones en píxeles (predeterminado: 512x512).
Implementación en el backend con 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 de entorno DEZGO_API_KEY no está configurada.");
}
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);
}
// Extracción de datos de facturación desde las cabeceras HTTP de respuesta
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(`Error en los parámetros de Dezgo (400): ${message}`);
case 401:
throw new Error("Autenticación fallida en Dezgo (401): Verifique X-Dezgo-Key.");
case 402:
throw new Error("Saldo insuficiente en Dezgo (402): Cuenta prepago agotada.");
case 429:
throw new Error("Límite de tasa excedido en Dezgo (429): Demasiadas peticiones.");
default:
throw new Error(`Error de servidor en Dezgo (${status}): ${message}`);
}
}
Paso 2: Implementación de Inpainting con SDXL (/inpainting_sdxl)
El repintado por zonas (inpainting) permite modificar partes específicas de una imagen existente conservando el resto intacto. Dezgo ofrece dos extremos principales: /inpainting (para arquitecturas SD 1.5 y 2.x) e /inpainting_sdxl (para Stable Diffusion XL en resoluciones altas con mayor definición).
Requisitos de las imágenes de entrada
Para ejecutar el repintado se requieren dos archivos:
init_image: La imagen original de base que se desea alterar (PNG o JPEG).mask_image: Una máscara en blanco y negro con exactamente las mismas dimensiones queinit_image. Las zonas blancas (#FFFFFF) delimitan el área que la IA debe repintar, mientras que las zonas negras (#000000) protegen los píxeles originales que no deben alterarse.
Implementación en backend con 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]]:
"""
Envía una tarea de inpainting a Dezgo SDXL mediante multipart/form-data.
"""
if not DEZGO_API_KEY:
raise ValueError("DEZGO_API_KEY no está configurada en las variables de entorno.")
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("Saldo prepagado de Dezgo agotado. Se requiere recarga.")
elif response.status_code != 200:
raise RuntimeError(f"Fallo en inpainting de 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
Paso 3: Flujos asíncronos y prevención de tiempos de espera
La API de Dezgo es síncrona: mantiene la conexión HTTP abierta hasta que el modelo termina de procesar la imagen (entre 2 y 8 segundos de media). En entornos serverless con límites estrictos de ejecución (como los 10 segundos predeterminados en capas gratuitas de Vercel), esto puede generar errores de tiempo de espera (Gateway Timeout).
Patrón recomendado: Cola de tareas en segundo plano con Redis y SSE
Para garantizar la estabilidad en producción, desacopla la recepción de la petición del proceso de renderizado utilizando una cola como BullMQ o Celery:
[Cliente Web] ── 1. POST /api/jobs (prompt y máscara) ──► [Servidor Web API]
│
▼
[Cliente Web] ◄─ 3. Retorna 202 Accepted { jobId } ─── 2. Añade a cola Redis
│ │
│ ▼
│ 4. Escucha por SSE / WebSocket o sondeo [Redis / BullMQ]
│ │
│ ▼ 5. Procesa tarea
│ [Worker en segundo plano]
│ │
│ ├── 6. Invoca API de Dezgo
│ ├── 7. Sube imagen a S3 / R2
│ └── 8. Actualiza estado en DB
◄── 9. Notifica evento COMPLETED con URL del CDN ────────┘
Ejemplo de Worker con 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. Invocar el servicio de Dezgo
const { imageBuffer, contentType, jobCostUsd, remainingBalanceUsd } =
await generateTextToImage({ prompt, steps: 30 });
// 2. Almacenar la imagen binaria en un bucket S3 o R2
const cdnUrl = await uploadToS3({
key: `renders/${userId}/${jobId}.png`,
body: imageBuffer,
contentType,
});
// 3. Registrar el resultado y el coste en base de datos
await db.jobs.update({
where: { id: jobId },
data: {
status: "COMPLETED",
outputUrl: cdnUrl,
costUsd: jobCostUsd,
},
});
// 4. Alerta preventiva si el saldo restante es bajo
if (remainingBalanceUsd < 5.0) {
console.warn(`[Alerta Saldo] Saldo bajo en Dezgo: restan $${remainingBalanceUsd.toFixed(2)}.`);
}
return { cdnUrl, jobCostUsd };
});
Gestión de saldo y salvaguardas para producción
Dezgo no dispone de cobro automático recurrente en tarjeta; las recargas se efectúan manualmente en el panel de control. Por este motivo, supervisar las cabeceras de respuesta en cada petición es esencial para evitar interrupciones no programadas del servicio.
Telemetría en cabeceras HTTP
Cada respuesta satisfactoria incluye los siguientes datos contables:
x-dezgo-job-amount-usd: Importe exacto deducido por la generación actual (en USD).x-dezgo-balance-total-usd: Saldo disponible restante en la cuenta tras la operación.x-dezgo-balance-credits-usd: Suma histórica de recargas efectuadas.x-dezgo-balance-debits-usd: Suma histórica de consumo acumulado.x-dezgo-balance-index: Identificador secuencial de la transacción.
Consulta de saldo sin renderizado
Para verificar el estado contable de la cuenta sin incurrir en costes de generación, se puede consultar el extremo de transacciones:
curl -s -H "X-Dezgo-Key: YOUR_API_KEY" https://api.dezgo.com/account/tx/last
Este comando devuelve un objeto JSON con el índice más reciente y el valor actual del campo balance.
Estrategia de gestión de errores
- HTTP 402 (Payment Required): Indica que el saldo prepagado se ha terminado. Captura este código explícitamente en el backend para emitir una alerta crítica al equipo técnico y mostrar al usuario un mensaje adecuado ("Procesando en cola por mantenimiento") en lugar de un error 500 genérico.
- HTTP 429 (Too Many Requests): Límite de concurrencia alcanzado. Configura reintentos con retroceso exponencial (por ejemplo, tras 1s, 2s y 4s).
- HTTP 400 (Bad Request): Ocurre habitualmente cuando las dimensiones de la máscara y de la imagen original no coinciden. Valida siempre la geometría en píxeles antes de realizar el envío a Dezgo.
Conclusión
Para desarrolladores independientes y aplicaciones web con requisitos de generación bajo demanda, Dezgo ofrece un equilibrio óptimo entre el coste fijo de mantener infraestructura propia de GPU y las restricciones comerciales de las suscripciones mensuales. Mediante un proxy seguro en el backend, una cola asíncrona de tareas y la monitorización activa de las cabeceras de saldo, es posible desplegar una solución de IA visual escalable y rentable con costes por imagen inferiores a un céntimo de dólar.