
Image Generator Sd Webui
- 41 installs
- 21 repo stars
- Updated July 31, 2026
- jim60105/copilot-prompt
Drive a Stable Diffusion WebUI / Forge server through its REST API to list models, run txt2img, poll progress, and interrupt jobs.
About
Wraps the AUTOMATIC1111-compatible sd-webui REST API with curl scripts to enumerate resources, generate images, track progress, and cancel jobs. A developer uses it to produce images from a running local or remote SD server.
- Thin scripts/*.sh curl wrappers over /sdapi/v1/* endpoints
- Probe, enumerate, generate, progress, and cancel workflow
Image Generator Sd Webui by the numbers
- 41 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #921 of 1,335 Generative Media skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jim60105/copilot-prompt --skill image-generator-sd-webuiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 41 |
|---|---|
| repo stars | ★ 21 |
| Last updated | July 31, 2026 |
| Repository | jim60105/copilot-prompt ↗ |
What it does
Drive a Stable Diffusion WebUI / Forge server through its REST API to list models, run txt2img, poll progress, and interrupt jobs.
Files
Image Generator (sd-webui API)
Overview
Drive a Stable Diffusion WebUI / Forge server through its REST API to enumerate available resources, run txt2img, poll progress, and interrupt jobs. All scripts under scripts/ are thin curl wrappers; they print JSON or extracted fields to stdout so the agent can pipe / parse them.
Server connection
Before doing anything, confirm the server URL (and optional HTTP Basic Auth) with the user. Pass them as environment variables to every script:
export SD_WEBUI_URL="http://localhost:7860" # required, no trailing slash
export SD_WEBUI_USER="" # optional, HTTP Basic Auth
export SD_WEBUI_PASS="" # optionalIf unset, scripts default to http://localhost:7860 with no auth.
Quick connectivity test (returns OK <url> on success, exits non-zero on failure):
scripts/probe.shWorkflow
1. Probe — Verify the server is reachable (scripts/probe.sh). On failure, ask the user for the correct URL / credentials. 2. Enumerate & choose — List the resources to pick (models, modules, samplers, schedulers, styles) and ask the user to choose. Capture their choice verbatim in the API's English name / title / model_name — sd-webui matches exactly, do not translate or rename. 3. Prompt — Obtain the positive prompt, negative prompt, and any extra params (steps, CFG, size). See "Prompt engineering" for sourcing these. 4. Generate — Call scripts/generate.sh with a request JSON. It returns a JSON object containing the base64 PNG image and the generation info. 5. (Optional) Track progress — While generation is running (in another shell / background), call scripts/progress.sh to print progress (0–1), eta_relative, and state. 6. (Optional) Cancel — Call scripts/cancel.sh to interrupt the current job.
Tasks
Listing available resources
| User wants | Command | API endpoint |
|---|---|---|
| Checkpoints (models) | scripts/list.sh models | GET /sdapi/v1/sd-models → array of {title, model_name, hash, ...} |
| Extra modules (TE / VAE, Forge-only) | scripts/list.sh modules | GET /sdapi/v1/sd-modules → array of {model_name, ...} |
| Samplers | scripts/list.sh samplers | GET /sdapi/v1/samplers → array of {name, aliases} |
| Schedulers | scripts/list.sh schedulers | GET /sdapi/v1/schedulers → array of {name, label} |
| Style presets | scripts/list.sh styles | GET /sdapi/v1/prompt-styles → array of {name, prompt, negative_prompt} |
| Upscalers | scripts/list.sh upscalers | GET /sdapi/v1/upscalers |
| LoRAs | scripts/list.sh loras | GET /sdapi/v1/loras |
| Embeddings | scripts/list.sh embeddings | GET /sdapi/v1/embeddings |
scripts/list.sh <kind> prints the canonical English identifier for each entry, one per line — pipe to column, fzf, etc. Add --json for the raw JSON.
After listing, present the options to the user (use ask_user with an enum if the list is short). For models, prefer the full title (which embeds the hash suffix, e.g. anima/animaika_v36.safetensors [d50fb5b9a0]) over model_name because the title is unambiguous — if the user supplies a bare filename without the hash, verify it via list.sh models and substitute the exact title before sending it to the API. For schedulers, list.sh schedulers prints the human-readable label (e.g. Beta); both label and the lowercase name (beta) are accepted by the txt2img scheduler field.
Generating an image (txt2img)
1. Build a JSON request. Required field: prompt. Recommended: negative_prompt, steps, cfg_scale, width, height, sampler_name, scheduler, styles (array of style names), and override_settings.sd_model_checkpoint (model title) / override_settings.forge_additional_modules (array of module names, Forge only). See references/txt2img-parameters.md for every field. 2. Run:
scripts/generate.sh request.json > result.json
# or pipe:
cat request.json | scripts/generate.sh - > result.json3. Extract the image (base64 PNG):
jq -r '.images[0]' result.json | base64 -d > out.png4. The info field is a JSON string with seed, all_prompts, sampler_name, etc. — parse with jq -r '.info | fromjson'.
Important behaviour notes:
- `samples_format` pre-pin: sd-webui/Forge validates
samples_formatbefore applyingoverride_settings, so if the server's persistent value is unsupported (e.g.avif), txt2img fails.generate.shpreemptivelyPOSTssamples_format=pngto/sdapi/v1/optionsand redundantly injectsoverride_settings.samples_format=png. ⚠️ The pre-pin mutates the server's persistent default to"png"—override_settings_restore_afterwardscannot undo it. If the user shares the server with clients expecting a different default, restore manually after:scripts/options.sh set samples_format '"webp"'. Convert locally if you need non-PNG output (see "Converting to another format" below). override_settings_restore_afterwards: trueis forced on bygenerate.shso the otheroverride_settingskeys (model checkpoint, modules, VAE) do not stick.- Generation is synchronous — the POST blocks until the image is ready. The script uses a 600s curl timeout; override with
SD_WEBUI_TIMEOUT=900 scripts/generate.sh ....
Converting to another format
If the user wants the output in a non-PNG format (WebP, AVIF, JPEG, etc.), do not try to re-enable a different samples_format on the server. Instead, convert locally while preserving the embedded sd-webui generation metadata:
1. Check whether both format-converter.sh and copy-info.sh are available on PATH (e.g. command -v format-converter.sh && command -v copy-info.sh). 2. If both are present, run format-converter.sh on the PNG — it calls copy-info.sh internally to carry the parameters over. Run format-converter.sh -h to see the current usage. 3. If either is missing, guide the user to install the helper project once: <https://github.com/jim60105/sd-image-format-converter>. It has system dependencies that must be set up manually, so it can't be auto-installed. After install, both scripts should be on PATH and -h will show usage.
Tracking progress
Call from another terminal (or background the generate.sh call with & first):
scripts/progress.sh # one-shot, prints JSON
scripts/progress.sh --watch # poll every 1s until progress reaches 1.0 or state.job is empty
scripts/progress.sh --watch --interval 2
scripts/progress.sh --field progress # just the numeric 0..1 value
scripts/progress.sh --field state.jobEndpoint: GET /sdapi/v1/progress?skip_current_image=true. Key response fields:
progress— float 0..1, fraction of current job complete.eta_relative— estimated seconds remaining.state.job— current job name (empty string when idle).state.sampling_step/state.sampling_steps— current step index / total.current_image— base64 PNG preview of the in-progress image (omitted by the script viaskip_current_image=trueto keep responses small; fetch raw withcurlif needed).
Cancelling
scripts/cancel.sh # POST /sdapi/v1/interrupt — stop current job, return current partial result
scripts/cancel.sh --skip # POST /sdapi/v1/skip — skip current job in a batchNote: interrupt is cooperative — it tells the sampler to stop at the next step. The pending generate.sh call will return with whatever the model produced so far (often a usable but partial image). It does not raise an HTTP error on the txt2img call.
Global options (advanced)
scripts/options.sh wraps GET /sdapi/v1/options and POST /sdapi/v1/options:
scripts/options.sh get # print all options as JSON
scripts/options.sh get sd_model_checkpoint # print one key
scripts/options.sh set sd_model_checkpoint '"<title>"' # set one key (value is JSON; string must be quoted)
scripts/options.sh set-json '{"k1":"v1","k2":"v2"}' # set multiple keys
scripts/options.sh refresh-checkpoints # POST /sdapi/v1/refresh-checkpointsPrefer override_settings inside the txt2img request over options set — override_settings is request-scoped and reverts after the call, while options set persists globally and affects every other client.
Prompt engineering
This skill does not generate or refine prompts. When the user asks for prompt help:
1. Check whether another agent skill is available for prompt engineering (search by name: e.g. sd-prompt-builder, danbooru-prompt, image-prompt-*). If so, delegate to it. 2. Otherwise, ask the user for the prompt explicitly, or accept a natural-language description and pass it through verbatim as the prompt field. Do not invent Danbooru tags or stylistic modifiers on your own.
References
references/api-endpoints.md— full sd-webui / Forge endpoint reference with request / response shapes for every endpoint this skill uses, plus useful adjacent ones (/sdapi/v1/memory,/sdapi/v1/png-info, etc.).references/txt2img-parameters.md— everytxt2imgrequest field including HiRes-fix, refiner, Forge-specific extensions (forge_additional_modules,forge_inference_memory,forge_preset), andoverride_settingskeys.
Read these only when constructing a non-trivial request or hitting an error that needs deeper investigation.
sd-webui / Forge API endpoint reference
All paths are relative to the server base URL (e.g. http://localhost:7860). Requests use Content-Type: application/json. Authentication, when enabled, is HTTP Basic (-u user:pass).
This document covers the endpoints actually used by this skill plus a few useful adjacent ones. The full surface area of the sd-webui API is larger — consult the running server's /docs (OpenAPI Swagger UI) for everything else.
Connectivity / health
GET /sdapi/v1/samplers
Lightweight "is the server up?" probe. Returns 200 OK with an array of {name, aliases, options} once the server has finished loading. Used by probe.sh.
Enumeration
GET /sdapi/v1/sd-models
Returns the installed checkpoints:
[
{
"title": "model.safetensors [a1b2c3d4]",
"model_name": "model",
"hash": "a1b2c3d4",
"sha256": "...",
"filename": "/path/to/model.safetensors",
"config": null
}
]Use title (includes the hash suffix) as the value of override_settings.sd_model_checkpoint — that is the unambiguous identifier the server matches against.
GET /sdapi/v1/sd-modules (Forge-only)
Forge-style extra modules (text encoders, VAE, etc.) that can be stacked at inference time:
[{"model_name": "ae.safetensors", "filename": "..."}]Pass an array of model_name strings as override_settings.forge_additional_modules. AUTOMATIC1111 vanilla returns 404 here.
GET /sdapi/v1/samplers
[{"name": "Euler a", "aliases": ["k_euler_a"], "options": {}}]Use name as sampler_name in the txt2img request.
GET /sdapi/v1/schedulers
[{"name": "automatic", "label": "Automatic"}]Use label (or name) as scheduler in the txt2img request. Vanilla AUTOMATIC1111 may not expose schedulers separately from samplers — in that case the endpoint returns an empty array and scheduler is ignored.
GET /sdapi/v1/prompt-styles
[{"name": "my-style", "prompt": "...", "negative_prompt": "..."}]Use name (as an array element) in the styles field of the txt2img request.
GET /sdapi/v1/upscalers
[{"name": "Lanczos", "model_name": null, "model_path": null, "model_url": null, "scale": 4}]
Used for extras API or hr_upscaler in HiRes-fix.
GET /sdapi/v1/loras
LoRAs installed on the server. Reference them inline in prompts as <lora:name:weight>.
GET /sdapi/v1/embeddings
{"loaded": {...}, "skipped": {...}} — textual inversion embeddings. Reference them in prompts by their key name.
Generation
POST /sdapi/v1/txt2img
Submits a text-to-image job. Synchronous: the request blocks until the image is generated. Body is the txt2img request JSON — see txt2img-parameters.md. Response:
{
"images": ["<base64 PNG>", "..."],
"parameters": { "...": "echoed request" },
"info": "<JSON-encoded string with seed, all_prompts, subseed, sampler_name, etc.>"
}To get the seed: jq -r '.info | fromjson | .seed'.
POST /sdapi/v1/img2img
Same structure as txt2img but additionally accepts init_images (array of base64-encoded source images) and denoising_strength. Not wrapped by a script in this skill — call directly with curl if needed.
Progress / control
GET /sdapi/v1/progress?skip_current_image=true
{
"progress": 0.42,
"eta_relative": 3.7,
"state": {
"skipped": false,
"interrupted": false,
"job": "txt2img",
"job_count": 1,
"job_timestamp": "20240101000000",
"job_no": 0,
"sampling_step": 12,
"sampling_steps": 28
},
"current_image": null,
"textinfo": "..."
}skip_current_image=true omits the base64 preview to keep responses small. Set to false to fetch the in-progress image.
state.job is the empty string when the server is idle.
POST /sdapi/v1/interrupt
Body {} (or empty). Returns {}. Cooperatively stops the current sampler — the in-flight txt2img call returns normally with the partial result. Use to cancel a job.
POST /sdapi/v1/skip
Body {}. Skips the current job in a batch (job_count > 1); subsequent jobs in the batch continue.
GET /queue/status
Not under /sdapi/v1/. Returns the underlying Gradio queue layer status as an EstimationMessage:
{
"event_id": "...",
"msg": "estimation",
"queue_size": 0,
"rank": null,
"rank_eta": null
}queue_size is the queue depth; rank / rank_eta are populated when the caller's request is queued behind others. Useful when multiple clients share the server. The reference plugin wraps this as getQueueStatus(). This skill does not provide a dedicated script — call directly:
curl -sS "${SD_WEBUI_URL}/queue/status"Options (global / persistent)
GET /sdapi/v1/options
Returns a large flat JSON object of every setting in the UI. Notable keys:
sd_model_checkpoint— active checkpointtitlesamples_format—"png"/"jpg"/"webp"etc.CLIP_stop_at_last_layers— clip-skip integersd_vae— active VAE name or"Automatic"eta_noise_seed_delta
POST /sdapi/v1/options
Body: a JSON object with one or more option keys to update. Returns {}. Persists across requests and affects every client connected to the server.
For request-scoped overrides, use override_settings inside the txt2img/img2img body together with override_settings_restore_afterwards: true (this skill does both).
POST /sdapi/v1/refresh-checkpoints
Body {}. Tells the server to rescan its models folder. Useful after dropping a new .safetensors file in.
Less-common but useful
| Method | Path | Purpose |
|---|---|---|
| GET | /sdapi/v1/cmd-flags | Server launch flags |
| GET | /sdapi/v1/memory | Free / used VRAM and RAM |
| POST | /sdapi/v1/refresh-vae | Rescan the VAE folder (there is no GET /sdapi/v1/sd-vae on Forge-classic; query active VAE via /sdapi/v1/options → sd_vae) |
| POST | /sdapi/v1/png-info | Read embedded generation parameters from a PNG |
| POST | /sdapi/v1/extra-single-image | Run an "extras" job (upscale / face restore) on one image |
| POST | /sdapi/v1/extra-batch-images | Same, for a batch |
| GET | /sdapi/v1/face-restorers | List face restorer models |
| GET | /sdapi/v1/latent-upscale-modes | List latent upscale modes (for HiRes-fix) |
| GET | /sdapi/v1/scripts / /sdapi/v1/script-info | List Always-On / Script-tab scripts + their argument schemas |
| POST | /sdapi/v1/unload-checkpoint | Free VRAM by unloading the current model |
| POST | /sdapi/v1/refresh-loras / /sdapi/v1/refresh-embeddings / /sdapi/v1/refresh-checkpoints | Rescan respective folders |
Note: vanilla AUTOMATIC1111 historically exposed /sdapi/v1/hypernetworks and /sdapi/v1/sd-vae (GET); both are absent on the current Forge-classic API surface. Always confirm against the running server:
curl -sS "${SD_WEBUI_URL}/openapi.json" | jq -r '.paths | keys[]'txt2img request parameters
Body of POST /sdapi/v1/txt2img. Only prompt is strictly required; everything else has a server-side default. Numeric defaults shown match AUTOMATIC1111 / Forge stock behaviour and may differ on your server depending on /sdapi/v1/options.
Core
| Field | Type | Default | Notes |
|---|---|---|---|
prompt | string | — | Positive prompt. Required. |
negative_prompt | string | "" | Negative prompt. |
seed | integer | -1 | -1 = random; otherwise a 64-bit signed seed. The actual seed used is echoed in the response info JSON. |
subseed | integer | -1 | Variation seed. |
subseed_strength | number | 0 | Variation strength, 0..1. |
seed_resize_from_h | integer | 0 | Resize-seed-from height. 0 to disable. |
seed_resize_from_w | integer | 0 | Resize-seed-from width. 0 to disable. |
sampler_name | string | "Euler" | Must match a name returned by GET /sdapi/v1/samplers. |
scheduler | string | "Automatic" | Must match a label/name from GET /sdapi/v1/schedulers. Forge-only; ignored on vanilla. |
steps | integer | 20 | Sampling steps. Quality plateaus quickly past 30–40 for most samplers. |
cfg_scale | number | 7.0 | Classifier-free-guidance scale. Higher = stronger prompt adherence, lower = more creative. SDXL works best around 4–7; SD1.5 around 7–12. |
distilled_cfg_scale | number | 3.5 | Distilled-CFG (Forge-classic, used by Flux and other distilled models). Ignored for non-distilled checkpoints. |
width | integer | 512 | Multiples of 8. SDXL native: 1024×1024 (or 832×1216 portrait). |
height | integer | 512 | Same constraints as width. |
batch_size | integer | 1 | Images generated in parallel per job. |
n_iter | integer | 1 | Number of jobs (sequential). Total images = batch_size * n_iter. |
styles | string[] | [] | Names from GET /sdapi/v1/prompt-styles. Server prepends/appends the matching prompt/negative. |
tiling | boolean | false | Generate a tileable texture. |
restore_faces | boolean | false | Run face-restoration post-processing. |
do_not_save_samples | boolean | false | Don't save the image to the server's output dir. |
do_not_save_grid | boolean | false | Don't save a grid image. |
HiRes-fix
| Field | Type | Default | Notes |
|---|---|---|---|
enable_hr | boolean | false | Enable HiRes-fix two-stage upscale. |
hr_scale | number | 2.0 | Upscale factor. |
hr_upscaler | string | "Latent" | Name from GET /sdapi/v1/upscalers. |
hr_second_pass_steps | integer | 0 | 0 = same as steps. |
denoising_strength | number | 0.7 | Denoising for the second pass. |
hr_resize_x / hr_resize_y | integer | 0 | Explicit target resolution. 0 = derived from hr_scale. |
hr_sampler_name | string | "" | Second-pass sampler. Empty = same as sampler_name. |
hr_scheduler | string | "" | Second-pass scheduler (Forge-classic). |
hr_prompt / hr_negative_prompt | string | "" | Optional override for the second pass. Empty = reuse the original. |
hr_checkpoint_name | string | "" | Second-pass model checkpoint (Forge-classic). Empty = same as first pass. |
hr_additional_modules | string[] | [] | Second-pass forge_additional_modules (Forge-classic). Empty = same as first pass. |
hr_cfg / hr_distilled_cfg | number | 0 | Second-pass CFG / distilled-CFG (Forge-classic). 0 = same as first pass. |
Refiner (SDXL)
| Field | Type | Default | Notes |
|---|---|---|---|
refiner_checkpoint | string | "" | Refiner checkpoint title. |
refiner_switch_at | number | 0 | 0..1 — fraction of total steps at which to swap to the refiner. |
override_settings
Object whose keys are entries from GET /sdapi/v1/options. Applied only for this request when override_settings_restore_afterwards: true (recommended — always set this).
Most commonly used keys:
| Key | Type | Notes |
|---|---|---|
sd_model_checkpoint | string | Active checkpoint. Must match a title from GET /sdapi/v1/sd-models. |
sd_vae | string | VAE name, or "Automatic", or "None". |
CLIP_stop_at_last_layers | integer | Clip-skip (1 = no skip; 2 = SD1.5 anime convention). |
samples_format | string | Server-side output format. Always force `"png"` for transport; convert locally afterwards. Forge validates this before applying overrides, so if the server's persistent value is unsupported (e.g. "avif"), the entire request fails. The generate.sh script in this skill pre-pins it via POST /sdapi/v1/options and sets it in override_settings as a redundant safeguard. |
eta_noise_seed_delta | integer | Anime-finetune convention often sets this to 31337. |
Forge-specific override_settings
These keys only exist on Forge / Forge-classic forks. Verify against your server with scripts/options.sh get | jq 'keys[] | select(startswith("forge_"))'.
| Key | Type | Notes |
|---|---|---|
forge_additional_modules | string[] | Array of model_name from GET /sdapi/v1/sd-modules. Stacks extra TE/VAE/etc. modules for this request. The currently-active list mirrors the active preset's forge_additional_modules_<preset> (e.g. _sd, _xl, _flux). |
forge_preset | string | Forge UI preset name ("sd", "xl", "flux", "qwen", "wan", "lumina", "klein", "anima", "zit" on Forge-classic). |
setting_allocated_vram | number | Reserved VRAM in GB for inference (Forge-classic). Not all Forge variants expose this — check first. |
sd_vae | string | Active VAE name, "Automatic", or "None". |
sd_vae_decode_method / sd_vae_encode_method | string | VAE precision / fallback strategy. |
override_settings_restore_afterwards
Boolean, default false. Always set to `true` unless you specifically intend to mutate the server's persistent settings.
Script-args fields (advanced)
| Field | Type | Notes |
|---|---|---|
script_name | string | Name of an Always-On / Script-tab script to invoke. |
script_args | array | Positional arguments for that script. |
alwayson_scripts | object | Map of { "ScriptName": { "args": [...] } } for ControlNet, ADetailer, etc. The shape of args is script-specific and undocumented — extract from the UI's network panel as a reference. |
Minimal request example
{
"prompt": "a watercolor portrait of a fox",
"negative_prompt": "lowres, jpeg artifacts",
"steps": 28,
"cfg_scale": 4.0,
"width": 832,
"height": 1216,
"sampler_name": "Euler a",
"scheduler": "Beta",
"styles": [],
"override_settings": {
"sd_model_checkpoint": "myModel.safetensors [a1b2c3d4]"
}
}Forge example with extra modules
{
"prompt": "1girl, looking at viewer, masterpiece",
"negative_prompt": "lowres, bad anatomy",
"steps": 32,
"cfg_scale": 4.0,
"width": 832,
"height": 1216,
"sampler_name": "ER SDE",
"scheduler": "Beta",
"styles": ["anime-detail"],
"override_settings": {
"sd_model_checkpoint": "illustriousXL.safetensors [deadbeef]",
"forge_additional_modules": ["clip_l.safetensors", "t5xxl_fp16.safetensors", "ae.safetensors"]
}
}#!/usr/bin/env bash
# Shared helpers for sd-webui API scripts.
# Source this file; do not execute directly.
set -euo pipefail
SD_WEBUI_URL="${SD_WEBUI_URL:-http://localhost:7860}"
SD_WEBUI_URL="${SD_WEBUI_URL%/}"
SD_WEBUI_USER="${SD_WEBUI_USER:-}"
SD_WEBUI_PASS="${SD_WEBUI_PASS:-}"
SD_WEBUI_TIMEOUT="${SD_WEBUI_TIMEOUT:-600}"
# sd_curl <path> [extra curl args...]
# Echoes response body to stdout. Exits non-zero on HTTP error or transport error,
# printing a diagnostic to stderr including HTTP status and the first 500 chars of
# the response body.
sd_curl() {
local path="$1"
shift
local url="${SD_WEBUI_URL}${path}"
local auth_args=()
if [[ -n "$SD_WEBUI_USER" ]]; then
auth_args=(-u "${SD_WEBUI_USER}:${SD_WEBUI_PASS}")
fi
local tmp
tmp="$(mktemp)"
trap 'rm -f "$tmp"' RETURN
local http_code
http_code="$(curl -sS \
--max-time "$SD_WEBUI_TIMEOUT" \
-o "$tmp" \
-w '%{http_code}' \
-H 'Content-Type: application/json' \
"${auth_args[@]}" \
"$@" \
"$url")" || {
echo "sd-webui request failed (transport error) at $path" >&2
return 1
}
if [[ "$http_code" -lt 200 || "$http_code" -ge 300 ]]; then
local body
body="$(head -c 500 "$tmp" || true)"
echo "sd-webui API error: HTTP $http_code at $path — $body" >&2
return 1
fi
cat "$tmp"
}
# Require jq for JSON parsing helpers.
require_jq() {
if ! command -v jq >/dev/null 2>&1; then
echo "jq is required but not installed. Install with: apt install jq" >&2
return 1
fi
}
#!/usr/bin/env bash
# Cancel the current sd-webui job.
#
# Usage:
# cancel.sh — POST /sdapi/v1/interrupt (stop current job at next sampler step)
# cancel.sh --skip — POST /sdapi/v1/skip (skip current job in a batch, continue with next)
#
# Note: interrupt is cooperative. The in-flight txt2img HTTP call will return
# normally with whatever partial result the sampler produced — it does NOT raise
# an HTTP error.
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
SD_WEBUI_TIMEOUT=10
action=interrupt
case "${1:-}" in
"") ;;
--skip) action=skip ;;
-h|--help) sed -n '2,12p' "$0"; exit 0 ;;
*) echo "Unknown argument: $1" >&2; exit 2 ;;
esac
sd_curl "/sdapi/v1/${action}" -X POST -d '{}' >/dev/null
echo "OK ${action}"
#!/usr/bin/env bash
# Submit a txt2img request to the sd-webui server.
#
# Usage:
# generate.sh <request.json> # read request from file
# generate.sh - # read request from stdin
#
# The request must be a JSON object matching the sd-webui txt2img schema:
# {
# "prompt": "...",
# "negative_prompt": "...",
# "steps": 28,
# "cfg_scale": 7.0,
# "width": 832,
# "height": 1216,
# "sampler_name": "Euler a",
# "scheduler": "Automatic",
# "styles": ["my style"],
# "override_settings": {
# "sd_model_checkpoint": "model.safetensors [hash]",
# "forge_additional_modules": ["vae.safetensors"]
# }
# }
#
# This script:
# 1. Pre-pins samples_format=png via /sdapi/v1/options (Forge validates this
# BEFORE applying override_settings; a persistent unsupported value like
# "avif" would otherwise reject the request).
# 2. Forces override_settings.samples_format=png and override_settings_restore_afterwards=true
# on the request body to keep the server's persistent options unchanged.
# 3. POSTs to /sdapi/v1/txt2img and prints the full JSON response to stdout.
#
# The response shape is:
# { "images": ["<base64 PNG>", ...], "parameters": {...}, "info": "<JSON string with seed, etc.>" }
#
# To extract the image:
# generate.sh req.json | jq -r '.images[0]' | base64 -d > out.png
#
# Override the curl timeout (default 600s):
# SD_WEBUI_TIMEOUT=900 generate.sh req.json
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
if [[ $# -ne 1 ]]; then
sed -n '2,30p' "$0" >&2
exit 2
fi
require_jq
src="$1"
if [[ "$src" == "-" ]]; then
request_raw="$(cat)"
else
request_raw="$(cat "$src")"
fi
# Validate JSON.
if ! echo "$request_raw" | jq -e . >/dev/null 2>&1; then
echo "generate.sh: request is not valid JSON" >&2
exit 2
fi
# Merge safety overrides into the request.
request_body="$(echo "$request_raw" | jq '
.override_settings = ((.override_settings // {}) + {samples_format: "png"})
| .override_settings_restore_afterwards = true
')"
# Step 1: pre-pin samples_format=png. Tolerate failure (legacy AUTOMATIC1111
# without this option, or auth restrictions) — the override_settings in the
# request body is a redundant safeguard.
if ! sd_curl /sdapi/v1/options -X POST -d '{"samples_format":"png"}' >/dev/null 2>&1; then
echo "generate.sh: warning — failed to pin samples_format via /sdapi/v1/options; relying on override_settings" >&2
fi
# Step 2: submit txt2img.
sd_curl /sdapi/v1/txt2img -X POST -d "$request_body"
#!/usr/bin/env bash
# List resources from the sd-webui server.
#
# Usage:
# list.sh <kind> [--json]
#
# Kinds:
# models — checkpoints (GET /sdapi/v1/sd-models)
# modules — Forge extra modules / TE / VAE (GET /sdapi/v1/sd-modules)
# samplers — (GET /sdapi/v1/samplers)
# schedulers — (GET /sdapi/v1/schedulers)
# styles — prompt style presets (GET /sdapi/v1/prompt-styles)
# upscalers — (GET /sdapi/v1/upscalers)
# loras — (GET /sdapi/v1/loras)
# embeddings — (GET /sdapi/v1/embeddings)
#
# By default prints the canonical English identifier, one per line.
# With --json, prints the raw API response.
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
if [[ $# -lt 1 ]]; then
sed -n '2,20p' "$0" >&2
exit 2
fi
kind="$1"
shift
raw_json=0
for arg in "$@"; do
case "$arg" in
--json) raw_json=1 ;;
*) echo "Unknown argument: $arg" >&2; exit 2 ;;
esac
done
case "$kind" in
models) path=/sdapi/v1/sd-models; filter='.[] | .title // .model_name // empty' ;;
modules) path=/sdapi/v1/sd-modules; filter='.[] | .model_name // .name // empty' ;;
samplers) path=/sdapi/v1/samplers; filter='.[] | .name // empty' ;;
schedulers) path=/sdapi/v1/schedulers; filter='.[] | .label // .name // empty' ;;
styles) path=/sdapi/v1/prompt-styles; filter='.[] | .name // empty' ;;
upscalers) path=/sdapi/v1/upscalers; filter='.[] | .name // empty' ;;
loras) path=/sdapi/v1/loras; filter='.[] | .name // .alias // empty' ;;
embeddings) path=/sdapi/v1/embeddings; filter='(.loaded // {}) | keys[]' ;;
*) echo "Unknown kind: $kind" >&2; exit 2 ;;
esac
response="$(sd_curl "$path")"
if [[ $raw_json -eq 1 ]]; then
echo "$response"
else
require_jq
echo "$response" | jq -r "$filter"
fi
#!/usr/bin/env bash
# Get / set global sd-webui options.
#
# Usage:
# options.sh get — print all options (large JSON)
# options.sh get <key> — print one option value
# options.sh set <key> <value> — set one option (value passed as JSON; strings must be quoted)
# options.sh set-json '<json-object>' — set multiple options at once
# options.sh refresh-checkpoints — POST /sdapi/v1/refresh-checkpoints (rescans the models folder)
#
# WARNING: `set` and `set-json` mutate the server's PERSISTENT options. Prefer
# `override_settings` inside a txt2img request body — that is request-scoped and
# reverts after the call. Use this script only when you genuinely need to change
# a global option (e.g. swap the active checkpoint for all clients).
#
# Common keys:
# sd_model_checkpoint — active checkpoint, must match a `title` from list.sh models
# samples_format — "png" / "jpg" / "webp" (Forge accepts subset; keep "png")
# CLIP_stop_at_last_layers — integer
# sd_vae — active VAE name or "Automatic"
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
SD_WEBUI_TIMEOUT=30
cmd="${1:-}"
shift || true
case "$cmd" in
get)
require_jq
response="$(sd_curl /sdapi/v1/options)"
if [[ $# -eq 0 ]]; then
echo "$response"
else
echo "$response" | jq -r --arg k "$1" '.[$k]'
fi
;;
set)
if [[ $# -ne 2 ]]; then
echo "Usage: options.sh set <key> <value-as-json>" >&2
exit 2
fi
require_jq
body="$(jq -nc --arg k "$1" --argjson v "$2" '{($k): $v}')"
sd_curl /sdapi/v1/options -X POST -d "$body" >/dev/null
echo "OK set $1"
;;
set-json)
if [[ $# -ne 1 ]]; then
echo "Usage: options.sh set-json '<json-object>'" >&2
exit 2
fi
sd_curl /sdapi/v1/options -X POST -d "$1" >/dev/null
echo "OK set-json"
;;
refresh-checkpoints)
sd_curl /sdapi/v1/refresh-checkpoints -X POST -d '{}' >/dev/null
echo "OK refresh-checkpoints"
;;
-h|--help|"")
sed -n '2,25p' "$0"
;;
*)
echo "Unknown subcommand: $cmd" >&2
sed -n '2,25p' "$0" >&2
exit 2
;;
esac
#!/usr/bin/env bash
# Probe the sd-webui server. Prints "OK <url>" on success, error to stderr on failure.
# Uses /sdapi/v1/samplers as a lightweight reachability check.
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
# Override timeout to a short value for probing (don't wait 10 minutes to find out
# the server is down).
SD_WEBUI_TIMEOUT="${SD_WEBUI_PROBE_TIMEOUT:-10}"
if sd_curl /sdapi/v1/samplers >/dev/null; then
echo "OK ${SD_WEBUI_URL}"
else
exit 1
fi
#!/usr/bin/env bash
# Get the progress of the current sd-webui job.
#
# Usage:
# progress.sh — one-shot, prints JSON
# progress.sh --watch [--interval N] — poll every N seconds (default 1) until idle
# progress.sh --field <key> — print just one field (progress, eta_relative, state.job, etc.)
#
# Endpoint: GET /sdapi/v1/progress?skip_current_image=true
#
# Key fields in response:
# progress — 0..1 (fraction of current job)
# eta_relative — estimated seconds remaining
# state.job — current job name; empty string when idle
# state.job_count — total jobs in current batch
# state.job_no — index of current job in batch
# state.sampling_step / state.sampling_steps — current step / total
# textinfo — human-readable status
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$DIR/_common.sh"
watch=0
interval=1
field=""
while [[ $# -gt 0 ]]; do
case "$1" in
--watch) watch=1; shift ;;
--interval) interval="$2"; shift 2 ;;
--field) field="$2"; shift 2 ;;
-h|--help) sed -n '2,20p' "$0"; exit 0 ;;
*) echo "Unknown argument: $1" >&2; exit 2 ;;
esac
done
# Use a short timeout for progress polling.
SD_WEBUI_TIMEOUT=10
fetch_and_print() {
local response
response="$(sd_curl '/sdapi/v1/progress?skip_current_image=true')"
if [[ -n "$field" ]]; then
require_jq
# Allow dotted paths like "state.job". Split on '.' and use getpath()
# so the user input never becomes part of the jq program text.
echo "$response" | jq -r --arg path "$field" '
($path | split(".")) as $p
| getpath($p)
| if . == null then "" else . end
'
else
echo "$response"
fi
}
if [[ $watch -eq 0 ]]; then
fetch_and_print
exit 0
fi
require_jq
while :; do
response="$(sd_curl '/sdapi/v1/progress?skip_current_image=true')"
progress="$(echo "$response" | jq -r '.progress // 0')"
eta="$(echo "$response" | jq -r '.eta_relative // 0')"
job="$(echo "$response" | jq -r '.state.job // ""')"
step="$(echo "$response" | jq -r '.state.sampling_step // 0')"
total="$(echo "$response" | jq -r '.state.sampling_steps // 0')"
interrupted="$(echo "$response" | jq -r '.state.interrupted // false')"
printf 'progress=%.3f step=%s/%s eta=%.1fs job=%s\n' "$progress" "$step" "$total" "$eta" "$job"
# Terminate when the server reports it's idle (job empty) or interrupted.
# NOTE: do NOT exit on progress>=1.0 alone — sd-webui/Forge may still be
# running post-processing (VAE decode, face restore, file save) while
# progress already reads 1.0.
if [[ -z "$job" || "$interrupted" == "true" ]]; then
break
fi
sleep "$interval"
done