storytellurx/scripts/image-generation/README.md
Elias Rhouzlane 7d4017039b fix: design
2026-09-09 13:18:14 +02:00

125 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Generate local images
From the project root:
```sh
vp run generate:image --prompt "Fluorescent punk comic collage, acid yellow and hot pink, thick black ink" --name "cybelle"
```
Images are written directly to `public/assets/generations/`:
```text
# Default
public/assets/generations/<name>.<preset>.webp
# With --with-hash
public/assets/generations/<name>.<preset>.<prompt-hash>.webp
```
```sh
vp run generate:image --prompt "A ceramic teapot" --name "teapot"
vp run generate:image --prompt "A ceramic teapot" --name "teapot" --with-hash
```
The preset is its canonical lowercase ID (default: `dreamshaper-8-lcm`). The optional prompt hash is the first eight hexadecimal characters of the prompt's SHA-256 hash. Images are served at `/assets/generations/<filename>`.
Other generated files live in `.cache/generations/<hash>/`, where `<hash>` is the full SHA-256 hash of the output filename. The `<filename>.json` sidecar records the settings, settings hash, prompt, prompt hash, reference path, date, and generation time. Engine logs are saved as `<filename>.server.log`. Temporary files and the exclusive reservation are removed when the command finishes or is interrupted.
Existing images are rejected unless `--force` is provided. With `--force`, successful generation replaces the image and updates its cached metadata and log; a generation failure preserves the existing image. Concurrent writes remain blocked by the output reservation. Alternatively, choose another `--name`, or use `--with-hash` with a different prompt. Changing only the seed or settings does not change the output filename. Earlier images under `assets/generations/` are retained in place.
## Prompt prefix
Set `defaultPromptPrefix` at the top of `presets.ts` to share a prefix across every preset. It starts empty. The prefix is prepended to `--prompt` with a space. Override it per run with `--prompt-prefix`, or pass `--prompt-prefix ""` to disable it:
```sh
vp run generate:image --name teapot --prompt "A ceramic teapot" --prompt-prefix "Watercolor illustration,"
```
`--with-hash` hashes the complete prompt including the prefix. Cached metadata records the original input, effective prompt, and prefix.
## Preset registry
```sh
vp run generate:image --preset cyberrealistic --prompt "A ceramic teapot, soft window light" --name "teapot"
vp run generate:image --preset dreamshaper-8-lcm --prompt "Fluorescent punk comic collage" --name "draft"
vp run generate:image --list-presets
```
Omitting `--preset` selects **dreamshaper-8-lcm**. Names are case-insensitive (`CyberRealistic` works).
| Preset | Checkpoint | Steps | CFG | Sampler / scheduler | Cache |
| ----------------------------- | -------------------------------- | ----: | --: | --------------------- | ------ |
| `cyberrealistic` | CyberRealistic v5 FP16, SD 1.5 | 20 | 7 | DPM++ 2M / Karras | UCache |
| `cyberrealistic-no-cache` | Same checkpoint | 20 | 7 | DPM++ 2M / Karras | Off |
| `realistic-vision-hyper` | Realistic Vision v5.1 Hyper FP16 | 4 | 1.8 | DPM++ 2M / Discrete | Off |
| `dreamshaper-8-lcm` (default) | DreamShaper 8 LCM, SD 1.5 | 8 | 2 | LCM / LCM | Off |
| `juggernaut-xi-lightning` | Juggernaut XI Lightning, SDXL | 6 | 1.5 | DPM++ 2M SDE / Karras | Off |
Every preset owns a `negativePrompt` setting. Realistic Vision Hyper defaults to `ugly, deformed, bad anatomy, blurry, cartoon`; the other current presets default to an empty negative prompt.
```sh
vp run generate:image --preset realistic-vision-hyper --prompt "A ceramic teapot, soft window light" --name "teapot"
vp run generate:image --preset realistic-vision-hyper --prompt "A ceramic teapot" --name "teapot" --negative-prompt "blurry, low resolution"
vp run generate:image --preset realistic-vision-hyper --prompt "A ceramic teapot" --name "teapot" --negative-prompt ""
```
The effective negative prompt (preset default or CLI override) is included in the cached JSON sidecar and its settings hash. Overriding it changes the recorded settings hash; choose a different name to retain both images. The filename suffix remains the positive-prompt hash. Realistic Vision uses the CLI-equivalent default discrete scheduler and no UCache, matching the supplied four-step recipe. DreamShaper 8 LCM is the default preset (8 steps, 512×512).
SD 1.5 presets use the existing **TAESD** decoder. Juggernaut uses its embedded SDXL VAE and defaults to 1024×1024. CyberRealistic's UCache explicitly records threshold 1.0, start 0.15, end 0.95, decay 1.0, relative 1 and reset 1.
Add model/config combinations in [`presets.ts`](presets.ts); change `defaultPreset` there to change the default. CLI `--steps` overrides the selected preset's step count. Checkpoints and decoder paths are relative to `--tools`. This registry deliberately pairs architectures and settings rather than guessing settings from arbitrary filenames.
The installed checkpoints were checked on 2026-09-08. SD-Turbo has been removed from the registry because its checkpoint is no longer installed. Old generation history is preserved. `klein-4bit/` is an MFLUX model bundle, and `loras/lcm-sd15.safetensors` is an adapter, so neither is exposed as a standalone checkpoint in this sd-server runner.
DreamShaper uses an eight-step LCM starting configuration with CFG 2; its [author's example](https://huggingface.co/Lykon/dreamshaper-8-lcm) uses 15 steps, which you can select with `--steps 15`. Juggernaut follows its [model card](https://huggingface.co/RunDiffusion/Juggernaut-XI-Lightning) for resolution, low CFG and step count. The installed engine does not expose DPM++ SDE, so its preset uses the supported DPM++ **2M** SDE variant with Karras. These new presets have not been performance-benchmarked on this Mac; SDXL is substantially larger than the SD 1.5 checkpoints.
## Reference images
```sh
vp run generate:image --preset dreamshaper-8-lcm \
--prompt "Fluorescent punk comic collage, thick black ink" \
--name "cybelle-remix" \
--reference assets/backgrounds/cybelle-punk-v1/reference-sized.png \
--seed 73 --strength 0.5 --width 512 --height 896
```
This uses DreamShaper and does not reproduce the historical SD-Turbo remix. Defaults are 512×512 for SD 1.5 or 1024×1024 for Juggernaut, a random seed on each run and reference strength 0.5. `--width` and `--height` override preset dimensions. Use `--seed 73` to fix the seed for reproducible generation. The chosen seed is recorded in the cached metadata.
## Server lifecycle
No server command is necessary. The runner starts a private server on an available loopback port, generates one image, converts it to WebP, and shuts down the server on success, failure, Ctrl+C, SIGTERM or SIGHUP. It escalates to SIGKILL if its child does not stop within three seconds. As with any process, uncatchable termination of the runner itself (SIGKILL or power loss) cannot execute cleanup.
To reuse a server you already keep running:
```sh
vp run generate:image --prompt "..." --name "cybelle" --server http://127.0.0.1:18792
```
The runner verifies the exposed model name and leaves a borrowed server running. That API cannot verify the server's decoder, weights or backend; external mode is identified separately in the saved settings. Use the default owned-server mode for the recorded local configuration and predictable cleanup.
## Local prerequisites
The script is TypeScript, executed directly by the project's Node 26. It uses built-in Node APIs and the already installed `cwebp` executable; no Python server or Python environment is required.
The existing generator installation is expected at `~/code/image-generation-benchmark`, containing:
```text
stable-diffusion.cpp/build/bin/sd-server
models/cyberrealistic_v5_fp16.safetensors
models/realisticVision_v51_hyper.safetensors
models/dreamshaper_8_lcm.safetensors
models/juggernaut_xi_lightning.safetensors
models/taesd.safetensors
```
Override with `--tools /path/to/installation`. Models stay outside the application. File fingerprints are cached under `.cache/image-generation` using file path, size and modification/change times; first use hashes the model files. Images are generated locally. `--help` lists arguments.
## Verification
```sh
node --test scripts/image-generation/generate.test.ts
node_modules/.bin/tsc --ignoreConfig --noEmit --allowImportingTsExtensions --target esnext --module nodenext --moduleResolution nodenext --strict --skipLibCheck --types node scripts/image-generation/generate.ts scripts/image-generation/generate.test.ts
```
Tests cover WebP conversion, preset selection, model-specific request/cache settings, filename/settings hashing, overwrite protection, owned-server cleanup on errors and Ctrl+C, traversal rejection, and borrowed-server preservation. Tests use a tiny fake image server and the real local `cwebp` converter; a real Metal generation is verified separately through `vp run generate:image`.
Earlier real validation: the CyberRealistic preset produced a still-life WebP and stopped its server. Engine logs confirmed UCache skipped 9/20 steps; generation was 22.87 s with 1.02 s decode (23.32 s runner timing). This is a single run, not a controlled cached-versus-uncached speed comparison. Successful engine logs are retained in `.cache/generations/<hash>/`.