Skip to content

Commit

Permalink
1.7.1 - Auto-restart, non-fatal file conversion errors (#16)
Browse files Browse the repository at this point in the history
* version bump, support frames for batchSize

* handle case of local image paths

* fix installation of sharp

* animatediff works

* zod hates to base64 validate huge stuff. fair enough

* start outlining tests

* ignore model files

* scaffolding tests

* controlnet frames

* ignore model directory

* rip out filewatcher, just use comfy apis

* first passing test

* fixes based on testing

* sync tests passing

* remove dependency on recipes repo

* create test utils, do webhook tests

* sd1.5 tests

* ltx video tests

* fix webhook test issue

* flux tests

* sd3.5 tests

* sdxl tests

* workaround testing race condition

* document required models

* remove unused

* hunyuan video

* add hunyuan to supported models

* more testing instructions

* make body size configurable, little cleanup in server

* remove commented out code in workflow loader

* shorten that test

* document location of all models used for testing

* cogvideo works

* cogvideox 2b works

* configurable restart policy

* document config change

* no longer treat image conversion as  a fatal error, just send the unconverted output

* fix

* mochi support

* remove .only

* build scripts for docker images for ghcr

* move more env into base

* specify mochi video in readme

* document cogvideox and mochi model sources

* version bump

* comments

* await workflow generation. allows for async prompt generations

* label the event in the webhook

* readme note about timeouts

* update workflows

* nah, didn't like that

* more readme update
  • Loading branch information
shawnrushefsky authored Jan 14, 2025
1 parent 37882e8 commit 82b70fa
Show file tree
Hide file tree
Showing 19 changed files with 581 additions and 76 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:

- name: Get the PR that was merged into main
id: pr-output
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
info=$(gh pr list --state merged --limit 1 --json title --json body)
echo "title=$(echo $info | jq -r '.title')" >> $GITHUB_OUTPUT
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ on:
branches:
- main
paths-ignore:
- ".github/**"
- "**.md"
- "**.png"
- ".gitignore"
- "generate-workflow"
- "**.yml"
- "test/**"
- "example-workflows/**"

Expand Down
35 changes: 29 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,26 @@ A simple wrapper that facilitates using ComfyUI as a stateless API, either by re
- [Generating New Workflow Endpoints](#generating-new-workflow-endpoints)
- [Automating with Claude 3.5 Sonnet](#automating-with-claude-35-sonnet)
- [Prebuilt Docker Images](#prebuilt-docker-images)
- [Considerations for Running on SaladCloud](#considerations-for-running-on-saladcloud)
- [Contributing](#contributing)
- [Testing](#testing)
- [Required Models](#required-models)
- [Running Tests](#running-tests)

## Download and Usage

Download the latest version from the release page, and copy it into your existing ComfyUI dockerfile. Then, you can use it like this:
Either use a [pre-built Docker image](#prebuilt-docker-images), or build your own.

Download the latest version from the release page, and copy it into your existing ComfyUI dockerfile.
You can find good base dockerfiles in the [docker](./docker) directory.
There are also example dockerfiles for popular models in the [SaladCloud Recipes Repo](https://github.com/SaladTechnologies/salad-recipes/tree/master/src).

If you have your own ComfyUI dockerfile, you can add the comfyui-api server to it like so:

```dockerfile
# Change this to the version you want to use
ARG api_version=1.7.0
ARG api_version=1.7.1


# Download the comfyui-api binary, and make it executable
ADD https://github.com/SaladTechnologies/comfyui-api/releases/download/${api_version}/comfyui-api .
Expand All @@ -41,7 +49,7 @@ The server hosts swagger docs at `/docs`, which can be used to interact with the
## Features

- **Full Power Of ComfyUI**: The server supports the full ComfyUI /prompt API, and can be used to execute any ComfyUI workflow.
- **Verified Model/Workflow Support**: Stable Diffusion 1.5, Stable Diffusion XL, Stable Diffusion 3.5, Flux, AnimateDiff, LTX Video, Hunyuan Video. My assumption is more model types are supported, but these are the ones I have verified.
- **Verified Model/Workflow Support**: Stable Diffusion 1.5, Stable Diffusion XL, Stable Diffusion 3.5, Flux, AnimateDiff, LTX Video, Hunyuan Video, CogVideoX, Mochi Video. My assumption is more model types are supported, but these are the ones I have verified.
- **Stateless API**: The server is stateless, and can be scaled horizontally to handle more requests.
- **Swagger Docs**: The server hosts swagger docs at `/docs`, which can be used to interact with the API.
- **"Synchronous" Support**: The server will return base64-encoded images directly in the response, if no webhook is provided.
Expand All @@ -60,8 +68,8 @@ The server hosts swagger docs at `/docs`, which can be used to interact with the

The server has two probes, `/health` and `/ready`.

- The `/health` probe will return a 200 status code once the warmup workflow has complete.
- The `/ready` probe will also return a 200 status code once the warmup workflow has completed, and the server is ready to accept requests.
- The `/health` probe will return a 200 status code once the warmup workflow has completed. It will stay healthy as long as the server is running, even if ComfyUI crashes.
- The `/ready` probe will also return a 200 status code once the warmup workflow has completed. It will return a 503 status code if ComfyUI is not running, such as in the case it has crashed, but is being automatically restarted.

Here's a markdown guide to configuring the application based on the provided config.ts file:

Expand Down Expand Up @@ -91,6 +99,7 @@ The default values mostly assume this will run on top of an [ai-dock](https://gi
| WARMUP_PROMPT_FILE | (not set) | Path to warmup prompt file (optional) |
| WORKFLOW_DIR | "/workflows" | Directory for workflow files |
| BASE | "ai-dock" | There are different ways to load the comfyui environment for determining config values that vary with the base image. Currently only "ai-dock" has preset values. Set to empty string to not use this. |
| ALWAYS_RESTART_COMFYUI | "false" | If set to "true", the ComfyUI process will be automatically restarted if it exits. Otherwise, the API server will exit when ComfyUI exits. |

### Configuration Details

Expand Down Expand Up @@ -155,10 +164,13 @@ const ComfyNodeSchema = z.object({
});

type ComfyNode = z.infer<typeof ComfyNodeSchema>;
type ComfyPrompt = Record<string, ComfyNode>;

interface Workflow {
RequestSchema: z.ZodObject<any, any>;
generateWorkflow: (input: any) => ComfyPrompt;
generateWorkflow: (input: any) => Promise<ComfyPrompt> | ComfyPrompt;
description?: string;
summary?: string;
}

// This defaults the checkpoint to whatever was used in the warmup workflow
Expand Down Expand Up @@ -374,6 +386,11 @@ The tag pattern is `saladtechnologies/comfyui:comfy<comfy-version>-api<api-versi
- `<api-version>` is the version of the comfyui-api server
- `<model|base>` is the model used. There is a `base` tag for an image that contains ComfyUI and the comfyui-api server, but no models. There are also tags for specific models, like `sdxl-with-refiner` or `flux-schnell-fp8`.

## Considerations for Running on SaladCloud

- **SaladCloud's Container Gateway has a 100s timeout.** It is possible to construct very long running workflows, such for video generation, with ComfyUI that would exceed this timeout. In this scenario, you will need to either use a webhook to receive the results, or integrate with SaladCloud's [Job Queues](https://docs.salad.com/products/sce/job-queues/job-queues#job-queues) to handle long-running workflows.
- **SaladCloud's maximum container image size is 35GB(compressed).** The base [comfyui-api image](https://hub.docker.com/r/saladtechnologies/comfyui/tags) is around 3.25GB(compressed), so any models and extensions must fit in the remaining space.

## Contributing

Contributions are welcome! Please open an issue or a pull request if you have any suggestions or improvements.
Expand Down Expand Up @@ -402,6 +419,9 @@ Automated tests for this project require model files to be present in the `./tes
- `llava_llama3_fp8_scaled.safetensors` - https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged/tree/main/split_files/text_encoders
- `hunyuan_video_vae_bf16.safetensors` - https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged/tree/main/split_files/vae
- `vae-ft-mse-840000-ema-pruned.ckpt` - https://huggingface.co/stabilityai/sd-vae-ft-mse-original/blob/main/vae-ft-mse-840000-ema-pruned.ckpt
- `THUDM/CogVideoX-2b` - https://huggingface.co/THUDM/CogVideoX-2b
- `mochi_preview_fp8_scaled.safetensors` - https://huggingface.co/Comfy-Org/mochi_preview_repackaged/blob/main/all_in_one/mochi_preview_fp8_scaled.safetensors


They should be in the correct comfyui directory structure, like so:

Expand All @@ -413,6 +433,7 @@ They should be in the correct comfyui directory structure, like so:
│ ├── dreamshaper_8.safetensors
│ ├── flux1-schnell-fp8.safetensors
│ ├── ltx-video-2b-v0.9.1.safetensors
| ├── mochi_preview_fp8_scaled.safetensors
│ ├── sd3.5_medium.safetensors
│ ├── sd_xl_base_1.0.safetensors
│ └── sd_xl_refiner_1.0.safetensors
Expand All @@ -421,6 +442,8 @@ They should be in the correct comfyui directory structure, like so:
│ ├── clip_l.safetensors
│ ├── t5xxl_fp16.safetensors
│ └── t5xxl_fp8_e4m3fn.safetensors
├── CogVideo
│ └── CogVideo2B/
├── controlnet
│ ├── openpose-sd1.5-1.1.safetensors
├── diffusion_models
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
comfyui:
image: saladtechnologies/comfyui:comfy0.3.10-test-image
image: ghcr.io/saladtechnologies/comfyui-api:comfy0.3.10-test-image
volumes:
- ./bin:/app/bin
- ./test/docker-image/models:/opt/ComfyUI/models
Expand Down
14 changes: 14 additions & 0 deletions docker/api.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ARG base=runtime
ARG comfy_version=0.3.10
ARG pytorch_version=2.5.0
ARG cuda_version=12.1
FROM ghcr.io/saladtechnologies/comfyui-api:comfy${comfy_version}-torch${pytorch_version}-cuda${cuda_version}-${base}

ENV WORKFLOW_DIR=/workflows
ENV STARTUP_CHECK_MAX_TRIES=30

ARG api_version=1.7.1
ADD https://github.com/SaladTechnologies/comfyui-api/releases/download/${api_version}/comfyui-api .
RUN chmod +x comfyui-api

CMD ["./comfyui-api"]
23 changes: 23 additions & 0 deletions docker/build-api-images
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#! /usr/bin/bash

usage="Usage: $0 [comfy_version] [torch_version] [cuda_version] [api_version]"

comfy_version=${1:-0.3.10}
torch_version=${2:-2.5.0}
cuda_version=${3:-12.1}

current_api_version=$(cat ../package.json | jq -r '.version')
api_version=${4:-$current_api_version}

bases=("runtime" "devel")

for base in "${bases[@]}"; do
docker build -t ghcr.io/saladtechnologies/comfyui-api:comfy$comfy_version-api$api_version-torch$torch_version-cuda$cuda_version-$base \
-f api.dockerfile \
--build-arg comfy_version=$comfy_version \
--build-arg base=$base \
--build-arg pytorch_version=$torch_version \
--build-arg cuda_version=$cuda_version \
--build-arg api_version=$api_version \
.
done
16 changes: 16 additions & 0 deletions docker/build-comfy-base-images
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#! /usr/bin/bash

comfy_version=${1:-0.3.10}
torch_version=${2:-2.5.0}
cuda_version=${3:-12.1}
bases=("runtime" "devel")

for base in "${bases[@]}"; do
docker build -t ghcr.io/saladtechnologies/comfyui-api:comfy$comfy_version-torch$torch_version-cuda$cuda_version-$base \
-f comfyui.dockerfile \
--build-arg comfy_version=$comfy_version \
--build-arg base=$base \
--build-arg pytorch_version=$torch_version \
--build-arg cuda_version=$cuda_version \
.
done
32 changes: 32 additions & 0 deletions docker/comfyui.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
ARG base=runtime
ARG pytorch_version=2.5.0
ARG cuda_version=12.1
FROM pytorch/pytorch:${pytorch_version}-cuda${cuda_version}-cudnn9-${base}
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
curl \
git \
unzip \
wget \
&& rm -rf /var/lib/apt/lists/*

# Install comfy-cli, which makes it easy to install custom nodes and other comfy specific functionality.
RUN pip install --upgrade pip
RUN pip install comfy-cli
WORKDIR /opt
ARG comfy_version=0.3.10
RUN git clone --depth 1 --branch v${comfy_version} https://github.com/comfyanonymous/ComfyUI.git
WORKDIR /opt/ComfyUI
RUN pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121
RUN pip install -r requirements.txt
ENV COMFY_HOME=/opt/ComfyUI
RUN comfy --skip-prompt tracking disable
RUN comfy --skip-prompt set-default ${COMFY_HOME}
ENV MODEL_DIR=${COMFY_HOME}/models
ENV OUTPUT_DIR=${COMFY_HOME}/output
ENV INPUT_DIR=${COMFY_HOME}/input
ENV CMD="comfy --workspace ${COMFY_HOME} launch -- --listen *"
ENV BASE=""

CMD ["comfy", "--workspace", "${COMFY_HOME}", "launch", "--", "--listen", "*"]
17 changes: 17 additions & 0 deletions docker/push-all
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /usr/bin/bash

usage="Usage: $0 [comfy_version] [torch_version] [cuda_version] [api_version]"

comfy_version=${1:-0.3.10}
torch_version=${2:-2.5.0}
cuda_version=${3:-12.1}

current_api_version=$(cat package.json | jq -r '.version')
api_version=${4:-$current_api_version}

bases=("runtime" "devel")

for base in "${bases[@]}"; do
docker push ghcr.io/saladtechnologies/comfyui-api:comfy$comfy_version-torch$torch_version-cuda$cuda_version-$base
docker push ghcr.io/saladtechnologies/comfyui-api:comfy$comfy_version-api$api_version-torch$torch_version-cuda$cuda_version-$base
done
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "comfyui-api",
"version": "1.7.0",
"version": "1.7.1",
"description": "Wraps comfyui to make it easier to use as a stateless web service",
"main": "dist/src/index.js",
"scripts": {
Expand Down
10 changes: 8 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const {
MARKDOWN_SCHEMA_DESCRIPTIONS = "true",
BASE = "ai-dock",
MAX_BODY_SIZE_MB = "100",
ALWAYS_RESTART_COMFYUI = "false",
} = process.env;

fs.mkdirSync(WORKFLOW_DIR, { recursive: true });
Expand All @@ -34,8 +35,7 @@ const port = parseInt(PORT, 10);
const startupCheckInterval = parseInt(STARTUP_CHECK_INTERVAL_S, 10) * 1000;
const startupCheckMaxTries = parseInt(STARTUP_CHECK_MAX_TRIES, 10);
const maxBodySize = parseInt(MAX_BODY_SIZE_MB, 10) * 1024 * 1024;

// type for {string: string}
const alwaysRestartComfyUI = ALWAYS_RESTART_COMFYUI.toLowerCase() === "true";

const loadEnvCommand: Record<string, string> = {
"ai-dock": `source /opt/ai-dock/etc/environment.sh \
Expand Down Expand Up @@ -71,6 +71,11 @@ interface ComfyDescription {
schedulers: string[];
}

/**
* This function uses python to import some of the ComfyUI code and get the
* description of the samplers and schedulers.
* @returns ComfyDescription
*/
function getComfyUIDescription(): ComfyDescription {
const temptComfyFilePath = path.join(comfyDir, "temp_comfy_description.json");
const pythonCode = `
Expand Down Expand Up @@ -131,6 +136,7 @@ const config = {
comfyHost: DIRECT_ADDRESS,
comfyPort: COMFYUI_PORT_HOST,
comfyURL,
alwaysRestartComfyUI,
wsClientId,
comfyWSURL,
startupCheckInterval,
Expand Down
Loading

0 comments on commit 82b70fa

Please sign in to comment.