# hordelib

`hordelib` is a thin wrapper around [ComfyUI](https://github.com/comfyanonymous/ComfyUI) primarily to enable the [AI Horde](https://aihorde.net/) to run inference pipelines designed in ComfyUI. `hordelib` and ComfyUI is are licensed under the terms of the GNU General Public License.

## Purpose

The goal here is to be able to design inference pipelines in the excellent ComfyUI, and then call those inference pipelines programmatically, in a manner ultimately suitable for use in stable horde.

## Usage

Horde payloads can be processed simply with (for example):

```python
    from hordelib.horde import HordeLib

    generate = HordeLib()

    data = {
        "sampler_name": "k_dpmpp_2m",
        "cfg_scale": 7.5,
        "denoising_strength": 1.0,
        "seed": 123456789,
        "height": 512,
        "width": 512,
        "karras": True,
        "tiling": False,
        "hires_fix": False,
        "clip_skip": 1,
        "control_type": "canny",
        "image_is_control": False,
        "return_control_map": False,
        "prompt": "an ancient llamia monster, seductive, greek",
        "ddim_steps": 25,
        "n_iter": 1,
        "model": "model.ckpt",
    }
    pil_image = generate.text_to_image(data)
    pil_image.save("horde_text_to_image_text.png")
```

## Development

Requirements:
- `git` (install git)
- `tox` (`pip install tox`)
- Copy _any_ checkpoint model into the project root named `model.ckpt`

### Running the Tests

Simply execute: `tox` (or `tox -q` for less noisy output)

This will take a while the first time as it installs all the dependencies.

If the tests run successfully images will be produced in the project with the name of each pipeline, for example, `pipeline_stable_diffusion.png`.

### Directory Structure

`hordelib/pipeline_designs/`
Contains ComfyUI pipelines in a format that can be opened by the ComfyUI web app. These saved directly from the web app.

`hordelib/pipelines/`
Contains the above pipeline JSON files converted to the format required by the backend pipeline processor. These are converted from the web app, see _Converting ComfyUI pipelines_ below.

`hordelib/nodes/` These are the custom ComfyUI nodes we use for `hordelib` specific processing.

### Designing ComfyUI Pipelines

Use the standard ComfyUI web app. Use the "title" attribute to name the nodes, these names become parameter names in the `hordelib`. For example, a KSampler with the "title" of "sampler2" would become a parameter `sampler2.seed`, `sampler2.cfg`, etc. Load the pipeline `hordelib/pipeline_designs/pipeline_stable_diffusion.json` in the ComfyUI web app for an example.

Save any new pipeline in `hordelib/pipeline_designs` using the naming convention "pipeline_\<name\>.json".

Convert the JSON for the model (see _Converting ComfyUI pipelines_ below) and save the resulting JSON in `hordelib/pipelines` using the same filename as the previous JSON file.

That is all. This can then be called from `hordelib` using the `run_image_pipeline()` method in `hordelib.comfy.Comfy()`

### Converting ComfyUI pipelines

The quickest way to get from a pipeline diagram in the ComfyUI web app to a usable JSON file is to simply patch the ComfyUI backend to save the JSON we require when the web app submits the inference pipeline for rendering.

Patch `ComfyUI/execution.py:validate_prompt()` to include the following just before the final `return` statement:
```python
    with open("prompt.json", "wt", encoding="utf-8") as f:
        f.write(json.dumps(prompt, indent=4))
```

This will create the file `prompt.json` in the root of the ComfyUI project for the submitted pipeline job.

### Build Configuration

The main config files for the project are: `pyproject.toml`, `tox.ini` and `requirements.txt`

### PyPi Publishing

Three steps:
1. Bump the version in `hordelib/__init__.py`
1. `python -m build`
1. `twine upload -r pypi dist/*`

### Updating the embedded version of ComfyUI

We use a ComfyUI version pinned to a specific commit, see `hordelib/__init__.py:COMFYUI_VERSION`

To test if the latest version works and upgrade to it, from the project root simply:

1. `cd hordelib/Comfy` _Change CWD to the embedded comfy_
1. `git checkout master` _Switch to master branch_
1. `git pull` _Get the latest comfyui code_
1. `git rev-parse HEAD` _Print the commit hash we'll need this_
1. `cd ../../` _Get back to the hordelib project root_
1. `tox` _See if everything still works_

If everything still works. Take the commit hash printed above and put it in `hordelib/__init__.py:COMFYUI_VERSION`

Now ComfyUI is pinned to a new version.
