Comfy API v2 tiene versionado. Los cambios dentro de v2 son aditivos; los cambios disruptivos se publican como v3. Reporta problemas a través de Feedback.
comfy-sdk (PyPI) y @comfyorg/sdk (npm) incluyen dos clientes que hablan con dos servicios diferentes. Los nombres de los métodos se repiten entre ambos (run, submit, events) y significan cosas distintas en cada uno, así que revisa qué cliente construye un fragmento de código antes de copiarlo.
Ninguna superficie envuelve a la otra, y una misma clave API creada en tu espacio de trabajo de Comfy funciona para ambas.
Los dos lenguajes exponen la superficie del Router de manera distinta. En Python,
Comfy() incluye ambas: client.models.run(...) para el Router y client.workflows / client.assets / client.jobs para Cloud. En TypeScript son exportaciones separadas con nombres deliberadamente similares: comfy (en minúsculas, el espacio de nombres a nivel de módulo) contiene comfy.models, mientras que Comfy (la clase) es el cliente de Cloud y no tiene .models.- Plugins que generan contenido dentro de otra aplicación, como Blender o Krita
- Aplicaciones de consumo que ejecutan la generación en nombre de sus usuarios
- Pipelines por lotes, por ejemplo, ejecutar un flujo de trabajo sobre cada fotograma de un video
- Servicios de backend que necesitan muchos flujos de trabajo en ejecución a la vez
Estos SDK controlan ComfyUI desde fuera. Si escribes nodos personalizados o extensiones de frontend que se ejecutan dentro de ComfyUI, lo que buscas es Desarrollar Nodos personalizados. Esas son un conjunto de APIs aparte.
Instalar
Versión actual: 0.5.0.
comfy-sdk en PyPI y @comfyorg/sdk en npm se publican juntos y comparten un número de versión. Instala la última versión (pip install comfy-sdk, npm install @comfyorg/sdk) o indica un rango en lugar de anclar una versión exacta. Los dos ecosistemas lo expresan de forma distinta: comfy-sdk>=0.5 es un límite inferior y acepta versiones menores posteriores, mientras que @comfyorg/sdk@^0.5 es el rango compatible de npm para 0.5.x y no llega hasta 0.6.0, así que hay que elevar el rango con circunflejo cuando se publica una nueva versión menor. Usa @comfyorg/sdk@>=0.5.0 si quieres que el lado de npm también siga las versiones menores posteriores. Las páginas del registro son la fuente autoritativa si esta nota se queda desactualizada.Inicio rápido
Sube una imagen de entrada, ejecuta un flujo de trabajo y escribe los resultados en disco.workflow_api.json es un flujo de trabajo guardado en formato API. "10" y "9" son IDs de nodo de ese archivo: el nodo al que llega la imagen de entrada y el nodo de salida cuyos resultados quieres.
Los manejadores de recursos son diferidos. photo.png se hashea localmente y solo se sube si el servidor no tiene ya esos bytes, así que volver a ejecutar con la misma entrada no cuesta nada.
run() envía la tarea y espera a que llegue a un estado terminal. Para trabajar mientras se ejecuta, usa submit() en su lugar y observa el flujo de eventos.
Para ejecutar contra tu propio ComfyUI, configura COMFY_BASE_URL y quita la clave. Consulta más abajo.
Elegir una URL base
La URL base proviene de la variable de entorno
COMFY_BASE_URL, no de un argumento del constructor:
http(s) y, si no está definida o está vacía, se usa Comfy Cloud. Por eso el cliente es el mismo en todas partes:
¿Actualizas desde una versión temprana?
Comfy("<url>", "<key>") ahora es Comfy(api_key="<key>") con COMFY_BASE_URL configurada. api_key solo se puede pasar por nombre, así que la llamada posicional anterior lanza TypeError en lugar de leer silenciosamente una URL como clave.Comfy Cloud
Funciona sin configuración adicional. Crea una clave API y pásala al cliente.El acceso a la API requiere una suscripción de pago a Comfy Cloud. El plan gratuito no lo incluye. Cuántas tareas puedes ejecutar a la vez depende de tu plan. Consulta Límites de simultaneidad.
Despliegue de Comfy API
Un flujo de trabajo que desplegaste mediante la plataforma para desarrolladores obtiene su propio endpoint. ApuntaCOMFY_BASE_URL a ese endpoint y usa tu clave API, exactamente igual que con Comfy Cloud. Todo en esta guía funciona de la misma manera, excepto las etiquetas de tareas y la lista de tareas, que Comfy Cloud todavía no admite.
Un despliegue de Comfy API puede ejecutar varios flujos de trabajo con los modelos y nodos personalizados incluidos en su Build. Para cada tarea, get_workflow() devuelve una respuesta de flujo de trabajo con format: "api" y el gráfico ejecutado en su propiedad .graph.
Tu propio ComfyUI
La API v2 se sirve en ComfyUI autoalojado mediante comfy-api-proxy, un pequeño servicio de código abierto que se ejecuta junto a tu ComfyUI. Instálalo, ejecútalo y configuraCOMFY_BASE_URL="http://127.0.0.1:8189":
Reintentar un envío: la clave de idempotencia
submit() y run() envían una Idempotency-Key en cada envío, y el contrato de Comfy API v2 para esa clave es rechazar el duplicado, no grabar y reproducir. Lee esto antes de envolver un envío en un bucle de reintentos.
- Cada llamada genera una clave nueva. Llamar a
submit()dos veces con el mismo flujo de trabajo son dos envíos, dos tareas y dos cobros. Unfor attempt in range(3)ingenuo alrededor desubmit()es un doble cobro, no un reintento. - Una clave reutilizada se rechaza, no se reproduce. Pasa tu propia
idempotency_key(idempotencyKeyen TypeScript) para hacer idempotente un reintento, y la segunda solicitud con esa clave falla con422 idempotency_key_reuseen lugar de devolver la primera tarea. Los SDK lanzanIdempotencyKeyReuse. Eso es lo contrario de lo que suele significar “reintento idempotente”, así que manéjalo de forma explícita. - La recuperación consiste en ir a buscar la tarea, no en reenviar. Ante
IdempotencyKeyReuse, es muy posible que el primer intento ya haya creado una tarea. Recupérala conclient.jobs.get(job_id). Esa consulta necesita un id que ya hayas guardado, así que solo recupera el caso en que el envío devolvió y persististe el id antes del fallo. Si la conexión se cortó antes de registrar el id, no hay nada que buscar ni recuperación automática: los ejemplos siguientes vuelven a lanzar la excepción para manejarla a mano en lugar de reenviar con una clave reclamada. - La clave se libera cuando el envío falló de forma definitiva. Un error de validación, un rechazo por falta de créditos o un rechazo por cola llena no crean ninguna tarea y liberan la clave, así que reenviar con ella es válido. Tras un fallo ambiguo (un timeout de lectura, una conexión cortada a mitad de la solicitud) la clave sigue reclamada: busca la tarea en lugar de reenviar.
- Las claves caducan a las 24 horas y deben ser ASCII imprimible no vacío y respetar el límite de longitud. Una clave inválida lanza
ValueErrorantes de realizar ninguna solicitud, así que un""explícito nunca recurre en silencio a una clave generada.
client.jobs.get(job_id) es la ruta de rehidratación del SDK y necesita un id, y por eso grabar el id en el momento en que un envío devuelve es lo que hace que esto sea recuperable. Consulta Comfy API v2 para ver el contrato completo de la clave en POST /api/v2/jobs.
La
Idempotency-Key de Comfy Router se comporta de forma diferente. En Router la clave es un identificador de reproducción en lugar de un token de un solo uso: reenviar un envío en cola con la misma clave devuelve la solicitud original en lugar de encolar una segunda. Consulta idempotencia y facturación en cola y resultados de reintento en Router. Ambas superficies comparten el nombre de una cabecera, no un contrato.Observar la ejecución de una tarea
job.events() te ofrece una transmisión en vivo del estado de la tarea: progreso de nodos y pasos, fotogramas de vista previa y cada salida en el momento en que se confirma. Se reconecta por su cuenta si la conexión se cae.
Preview.to_pil() requiere el extra opcional de Pillow: pip install "comfy-sdk[pil]".
result() devuelve la tarea finalizada o lanza JobFailed con el detalle a nivel de nodo si la ejecución falla. Consulta el SDK README de tu idioma para ver el catálogo completo de eventos.
events() no es subscribe()
Existen tres cosas con nombres parecidos en las dos superficies, y solo una de ellas aparece en esta página:
No existe
subscribe() en el cliente de Comfy Cloud, ni job.subscribe() en ningún lado. El equivalente de subscribe en Cloud es run(): envía y espera un estado terminal.
La transmisión es un feed en vivo, no un registro reproducible. Existe para que puedas mostrar el progreso, no para que dependas de ella para obtener resultados. Lo que manda es el sondeo de la tarea, y run(), wait() y result() recurren al sondeo de forma automática. Consulta las Notas de diseño para saber por qué.
Rastrear una salida hasta su flujo de trabajo
Las salidas llevan el id de la tarea que las produjo, así que puedes partir de un archivo y trabajar hacia atrás sin mantener una tabla aparte.None (en TypeScript: undefined) para un recurso que subiste, ya que no tiene una tarea que lo haya producido.
Desde la tarea puedes pedir el flujo de trabajo que está detrás. Esto funciona para una tarea que no enviaste en este proceso, rehidratada por id:
format. La forma que devuelve depende de cómo se envió la tarea, no de nada que controles por solicitud:
Las tareas que envías a través del SDK siempre devuelven
api, porque el envío v2 todavía no tiene campos para fijar la versión. Eso cambiará; el discriminador está ahí para que tu código no tenga que ocuparse de ello.
Etiquetar tareas y encontrarlas más tarde
Una etiqueta es una clave y un valor que adjuntas a una tarea al enviarla, comoclient: acme o project: spring. Usa las etiquetas para registrar para cuál de tus clientes o proyectos se ejecutó una tarea. Después puedes listar las tareas de un cliente sin mantener tu propia tabla de ids de tareas. Las etiquetas y la lista de tareas necesitan la versión actual del SDK, la que se indica en la nota de versión en Instalar.
Las etiquetas funcionan en tareas enviadas a un despliegue de Comfy API, así que configura COMFY_BASE_URL con la dirección del despliegue como se muestra en Elegir una URL base. Comfy Cloud las rechaza por ahora y responde a la lista de tareas con 501 y el código not_implemented. Un comfy-api-proxy autoalojado tampoco las guarda: su propio campo metadata es una sola cadena de texto, así que rechaza un mapa de etiquetas. Su lista de tareas ignora los filtros de etiquetas, por lo que una llamada de lista del SDK con etiquetas no devuelve ninguna tarea allí, y los mismos filtros por HTTP devuelven todas las tareas.
Los límites:
- Hasta 16 etiquetas por tarea.
- Una clave tiene de 1 a 40 caracteres: letras, dígitos,
_,-y.. - Un valor es una cadena de hasta 256 bytes (UTF-8).
- Las etiquetas se establecen al enviar la tarea y no se pueden cambiar después.
422 y el código metadata_invalid, y no se crea ninguna tarea. El mensaje de error indica la clave que incumplió la regla, o da la cuenta cuando hay más de 16 etiquetas. Los SDK no comprueban los límites por sí mismos. Lanzan un error que lleva el código y el mensaje del servidor.
Pasa metadata al enviar. La tarea lleva las etiquetas cuando la vuelves a leer:
metadata vacío.
Para encontrar las tareas de un cliente, lista las tareas filtrando por etiqueta. La lista cubre solo las tareas enviadas al despliegue de tu URL base. Los resultados llegan con las más recientes primero, y el SDK obtiene la página siguiente por ti mientras iteras:
client.jobs.get(job.id).
Por HTTP
Envíametadata en el cuerpo de POST /api/v2/jobs:
GET /api/v2/jobs con un parámetro de consulta metadata[<key>]=<value> por etiqueta. La opción -g evita que curl interprete los corchetes como un patrón:
next_cursor. Pásalo de vuelta como cursor, junto con los mismos filtros metadata[...], para obtener la página siguiente. Un cursor enviado sin sus filtros devuelve tareas sin filtrar. Usa limit para establecer el tamaño de página (como máximo 500).
400 y el código invalid_metadata_filter. Consulta la referencia de Comfy API v2 para ver todos los campos de la tarea y de la lista.
Qué cubren los SDK hoy
La primera versión hace una cosa bien: ejecutar un flujo de trabajo y devolver los resultados.- Recursos. Crea handles de entrada a partir de un archivo, bytes, un stream o una URL. Los handles son perezosos y se direccionan por contenido, así que volver a ejecutar con la misma entrada no la vuelve a subir.
- Envío. Envía un gráfico en formato API. El envío es idempotente, y si la cola está llena se reintenta por ti dentro de un presupuesto acotado.
- Ejecución. Consulta con
wait()o sigueevents()para ver el progreso en vivo. - Salidas. Escribe en disco, acumula en memoria, obtén un rango de bytes o consigue una URL de descarga de corta duración.
getDownloadUrl()devuelve una URL firmada que cualquiera puede leer sin una clave API, válida durante unas 6 horas. Lee URLs de salida y cuánto duran antes de guardar una: para seguir mostrando una salida más tarde, vuelve a alojar los bytes o genera de nuevo la URL bajo demanda. - Trazabilidad. Cada salida lleva el id de la tarea que la produjo, y una tarea puede devolver el flujo de trabajo que tiene detrás.
- Eliminar recursos. Elimina un recurso que hayas subido, por handle o por id.
- Errores. Excepciones tipadas como
JobFailed,Unauthorized,InsufficientCreditsyQueueFull, en lugar de códigos de estado en bruto. - Cancelación. Las tareas se pueden cancelar mientras se ejecutan. TypeScript además acepta un
AbortSignalen cualquier llamada.
Comfy síncrono y un cliente AsyncComfy con la misma superficie. TypeScript es solo asíncrono.
No están en esta versión: la gestión de flujos de trabajo guardados, la biblioteca de modelos, la introspección de nodos y los parámetros con nombre de los flujos de trabajo. Notas de diseño explica por qué la superficie empieza siendo tan pequeña.
Referencia
Los README de los SDK son la referencia completa para cada idioma, e incluyen autenticación, recursos, errores y los mecanismos de escape de bajo nivel.SDK de Python
comfy-sdk en PyPI. Clientes síncronos y asíncronos.SDK de TypeScript
@comfyorg/sdk en npm. Tipado, asíncrono y con un cliente de bajo nivel.Referencia de Comfy API v2
La API HTTP que sustenta ambos SDK. Úsala directamente desde cualquier idioma.
Notas de diseño
Por qué existe esta API, cómo se relaciona con las API de ComfyUI existentes y qué viene después.
Comfy Router
La otra interfaz del mismo paquete:
comfy.models.run para modelos de socios como Flux, Veo y Gemini.Retroalimentación
Reporta lo que resulte incómodo, lo que esperabas encontrar y no encontraste, y lo que tuviste que sortear. El canal#developer-platform en nuestro Discord es el lugar para hacerlo.
Si quieres un SDK de primera mano en otro idioma, dilo ahí. Ambos SDK se apoyan en el mismo contrato HTTP documentado, así que hoy cualquier idioma puede comunicarse con la API, pero preferimos saber dónde está la demanda.