sd-backend-client 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sd_backend_client-0.2.1/LICENSE +24 -0
- sd_backend_client-0.2.1/PKG-INFO +186 -0
- sd_backend_client-0.2.1/README.md +154 -0
- sd_backend_client-0.2.1/pyproject.toml +56 -0
- sd_backend_client-0.2.1/sd_backend_client/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/a1111_webservice.py +646 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/basic_upscale_workflow_builder.py +40 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_diffusion_params.py +20 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_generation_handle.py +138 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_types.py +265 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/controlnet_comfyui_utils.py +179 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/diffusion_workflow_builder.py +620 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/latent_upscale_workflow_builder.py +300 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/apply_upscaler_node.py +28 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/basic_scaling_node.py +35 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/clip_skip_node.py +32 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/comfy_node.py +68 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/comfy_node_graph.py +51 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/apply_controlnet_node.py +53 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/dynamic_preprocessor_node.py +40 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/load_controlnet_node.py +31 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/image_scale_node.py +39 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/inpaint_model_conditioning_node.py +45 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/checkpoint_loader_node.py +32 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/clip_text_encode_node.py +29 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/empty_latent_image_node.py +31 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_image_mask_node.py +29 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_image_node.py +27 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_upscaler_node.py +23 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/simple_checkpoint_loader_node.py +25 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/ksampler_node.py +52 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/latent_mask_node.py +28 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/hypernet_loader_node.py +34 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/lora_loader_node.py +41 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/repeat_latent_node.py +30 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/save_image_node.py +26 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/ultimate_upscale_node.py +107 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/upscale_latent_node.py +39 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_decode_node.py +31 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_decode_tiled_node.py +44 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_encode_node.py +31 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_encode_tiled_node.py +42 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/preprocessor_preview_workflow_builder.py +46 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui/workflow_builder_utils.py +21 -0
- sd_backend_client-0.2.1/sd_backend_client/api/comfyui_webservice.py +686 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/api_datatypes.py +104 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/__init__.py +5 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_category_builder.py +86 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_constants.py +198 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_model.py +74 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_preprocessor.py +120 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_unit.py +37 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/diffusion_params.py +82 -0
- sd_backend_client-0.2.1/sd_backend_client/api/shared_data/generation_handle.py +176 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webservice.py +215 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/controlnet_webui_constants.py +248 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/controlnet_webui_utils.py +113 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/diffusion_request_body.py +254 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/request_formats.py +161 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/response_formats.py +151 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/script_info_types.py +35 -0
- sd_backend_client-0.2.1/sd_backend_client/api/webui/webui_generation_handle.py +339 -0
- sd_backend_client-0.2.1/sd_backend_client/py.typed +0 -0
- sd_backend_client-0.2.1/sd_backend_client/util/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/util/api_defaults.py +6 -0
- sd_backend_client-0.2.1/sd_backend_client/util/geometry.py +60 -0
- sd_backend_client-0.2.1/sd_backend_client/util/visual/__init__.py +1 -0
- sd_backend_client-0.2.1/sd_backend_client/util/visual/image_utils.py +83 -0
- sd_backend_client-0.2.1/sd_backend_client.egg-info/PKG-INFO +186 -0
- sd_backend_client-0.2.1/sd_backend_client.egg-info/SOURCES.txt +91 -0
- sd_backend_client-0.2.1/sd_backend_client.egg-info/dependency_links.txt +1 -0
- sd_backend_client-0.2.1/sd_backend_client.egg-info/requires.txt +5 -0
- sd_backend_client-0.2.1/sd_backend_client.egg-info/top_level.txt +1 -0
- sd_backend_client-0.2.1/setup.cfg +4 -0
- sd_backend_client-0.2.1/tests/test_a1111_async.py +258 -0
- sd_backend_client-0.2.1/tests/test_a1111_auth.py +80 -0
- sd_backend_client-0.2.1/tests/test_a1111_controlnet.py +68 -0
- sd_backend_client-0.2.1/tests/test_a1111_controlnet_generation.py +69 -0
- sd_backend_client-0.2.1/tests/test_a1111_generation.py +123 -0
- sd_backend_client-0.2.1/tests/test_a1111_metadata.py +101 -0
- sd_backend_client-0.2.1/tests/test_comfyui_async.py +174 -0
- sd_backend_client-0.2.1/tests/test_comfyui_controlnet_generation.py +95 -0
- sd_backend_client-0.2.1/tests/test_comfyui_generation.py +121 -0
- sd_backend_client-0.2.1/tests/test_comfyui_metadata.py +103 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sd-backend-client
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Standalone, headless Stable Diffusion backend client (ComfyUI / Forge / A1111 WebUI, ControlNet)
|
|
5
|
+
Author: Anthony Brown
|
|
6
|
+
License-Expression: Unlicense
|
|
7
|
+
Project-URL: Homepage, https://github.com/centuryglass/sd-backend-client
|
|
8
|
+
Project-URL: Issues, https://github.com/centuryglass/sd-backend-client/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/centuryglass/sd-backend-client/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: stable-diffusion,comfyui,automatic1111,forge,webui,controlnet,api-client
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: pillow>=9.2
|
|
27
|
+
Requires-Dist: requests>=2.20
|
|
28
|
+
Requires-Dist: websocket-client>=1.0
|
|
29
|
+
Requires-Dist: pydantic>=2.1
|
|
30
|
+
Requires-Dist: typing-extensions>=4.6.1
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# sd-backend-client
|
|
34
|
+
|
|
35
|
+
[](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml)
|
|
36
|
+
[](.github/workflows/ci.yml)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
A standalone, self-contained copy of IntraPaint's Stable Diffusion backend client
|
|
40
|
+
(`src/api`). It talks to **ComfyUI**, **Forge/Automatic1111 WebUI**, and their
|
|
41
|
+
**ControlNet** extensions, and builds the request bodies / node graphs those backends expect.
|
|
42
|
+
|
|
43
|
+
This package was extracted from [IntraPaint](https://github.com/centuryglass/IntraPaint) so it can
|
|
44
|
+
be dropped into other projects without pulling in the rest of the editor. Everything lives under the
|
|
45
|
+
`sd_backend_client` package and imports only from within it (plus third-party libraries).
|
|
46
|
+
|
|
47
|
+
**No Qt / PySide6 dependency.** Images are plain [Pillow](https://python-pillow.org/) `PIL.Image`
|
|
48
|
+
objects and the package has no GUI requirements — it runs headless.
|
|
49
|
+
|
|
50
|
+
## Status
|
|
51
|
+
|
|
52
|
+
This package is under active refactoring. The core txt2img / img2img / inpainting / ControlNet paths
|
|
53
|
+
work end-to-end against both backends (covered by the integration tests), but some areas — notably the
|
|
54
|
+
ComfyUI node classes' migration to pydantic and the tiled-upscaling workflow — are still in progress.
|
|
55
|
+
|
|
56
|
+
My eventual goal is to provide an API-agnostic interface, allowing complex image generation requests
|
|
57
|
+
to pass to either ComfyUI or Stable-Diffusion-WebUI without needing to care which interface is
|
|
58
|
+
actually available. To accomplish this, response data formats still need to be unified, and work
|
|
59
|
+
towards queued vs. blocking request handling still needs to be fully completed and tested.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
pip install -e .
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This installs the package (and its dependencies) in editable mode, so `sd_backend_client` is importable
|
|
68
|
+
from anywhere without manually managing `sys.path`.
|
|
69
|
+
|
|
70
|
+
Requires **Python 3.11+** (uses `match` statements and PEP 604 / `X | Y` type aliases).
|
|
71
|
+
Runtime dependencies: `pillow`, `requests`, `websocket-client`, `pydantic`, `typing-extensions`.
|
|
72
|
+
|
|
73
|
+
## Layout
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
sd_backend_client/
|
|
77
|
+
api/
|
|
78
|
+
webservice.py # base HTTP/session helper
|
|
79
|
+
a1111_webservice.py # Forge / A1111 WebUI client (synchronous)
|
|
80
|
+
comfyui_webservice.py # ComfyUI client (async queue + polling)
|
|
81
|
+
shared_data/ # backend-agnostic pydantic models
|
|
82
|
+
diffusion_params.py # DiffusionParams: shared generation parameters
|
|
83
|
+
api_datatypes.py # DiffusionUpscalingParams and friends
|
|
84
|
+
controlnet/ # ControlNetUnit / PreprocessorParams / ControlNet model
|
|
85
|
+
comfyui/ # ComfyUI node-graph + workflow builders (+ ComfyUIDiffusionParams)
|
|
86
|
+
webui/ # WebUI request/response formats (+ DiffusionRequestBody)
|
|
87
|
+
util/ # shared constants, Size, PIL image helpers
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
Generation parameters are passed explicitly as [pydantic](https://docs.pydantic.dev/) models — there
|
|
93
|
+
is no hidden config/cache layer. Images passed in and returned are `PIL.Image` objects; no
|
|
94
|
+
`QApplication` or event loop is needed.
|
|
95
|
+
|
|
96
|
+
`DiffusionParams` (in `shared_data`) holds the parameters common to both backends. Each backend
|
|
97
|
+
extends it: `DiffusionRequestBody` (WebUI) and `ComfyUIDiffusionParams` (ComfyUI) add
|
|
98
|
+
backend-specific fields.
|
|
99
|
+
|
|
100
|
+
### Forge / A1111 WebUI (synchronous)
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from sd_backend_client.api.a1111_webservice import A1111Webservice
|
|
104
|
+
from sd_backend_client.api.webui.diffusion_request_body import DiffusionRequestBody
|
|
105
|
+
|
|
106
|
+
service = A1111Webservice('http://localhost:7860')
|
|
107
|
+
body = DiffusionRequestBody(prompt='a corgi astronaut, detailed',
|
|
108
|
+
steps=30, cfg_scale=7.0, width=512, height=512)
|
|
109
|
+
result = service.txt2img(body) # blocks until the image is generated
|
|
110
|
+
images = result['images'] # list[PIL.Image]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For img2img / inpainting, pass the source image (and, for inpainting, a mask) to
|
|
114
|
+
`service.img2img(image, mask, body)`.
|
|
115
|
+
|
|
116
|
+
### ComfyUI (asynchronous)
|
|
117
|
+
|
|
118
|
+
ComfyUI generation is queued: the call returns immediately with a prompt id, and you poll for
|
|
119
|
+
completion, then download the results.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from sd_backend_client.api.comfyui_webservice import ComfyUiWebservice
|
|
123
|
+
from sd_backend_client.api.comfyui.comfyui_diffusion_params import ComfyUIDiffusionParams
|
|
124
|
+
|
|
125
|
+
service = ComfyUiWebservice('http://localhost:8188')
|
|
126
|
+
params = ComfyUIDiffusionParams(sd_model_name='deliberate_v3.safetensors',
|
|
127
|
+
prompt='a corgi astronaut, detailed',
|
|
128
|
+
steps=20, sampler='euler', scheduler='karras')
|
|
129
|
+
response = service.txt2img(params) # queues a job
|
|
130
|
+
# poll service.check_queue_entry(response.prompt_id, response.number) until it reports FINISHED,
|
|
131
|
+
# then service.download_images(progress.outputs.images) to get the PIL images.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Set `init_images` (and `mask`) on the params for img2img / inpainting.
|
|
135
|
+
|
|
136
|
+
### ControlNet
|
|
137
|
+
|
|
138
|
+
ControlNet units are backend-agnostic: build a `ControlNetUnit` (with an optional `ControlNetModel`
|
|
139
|
+
and a `PreprocessorParams`) and add it to `diffusion_params.controlnet_units`. Each backend serializes
|
|
140
|
+
them into the form it expects — WebUI's `alwayson_scripts` ControlNet args, or ComfyUI ControlNet
|
|
141
|
+
nodes.
|
|
142
|
+
|
|
143
|
+
### Authentication (A1111 / Forge)
|
|
144
|
+
|
|
145
|
+
IntraPaint prompted for credentials with a Qt login dialog. The standalone client instead accepts a
|
|
146
|
+
`credentials_provider` callback, invoked when the server requires auth; it returns a
|
|
147
|
+
`(username, password)` pair to try, or `None` to abort:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from sd_backend_client.api.a1111_webservice import A1111Webservice
|
|
151
|
+
|
|
152
|
+
service = A1111Webservice('http://localhost:7860',
|
|
153
|
+
credentials_provider=lambda: ('user', 'password'))
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Design notes
|
|
157
|
+
|
|
158
|
+
Extracted from IntraPaint's `src/api` and then decoupled in two ways:
|
|
159
|
+
|
|
160
|
+
- **No Qt.** `QImage` → `PIL.Image` (via the small helpers in `util/visual/image_utils.py`; decoded
|
|
161
|
+
images are normalized to RGBA), `QSize` → the minimal `Size` value class in `util/geometry.py`, and
|
|
162
|
+
the UI strings and `_tr()` translation helpers are removed.
|
|
163
|
+
Dropping Qt also dropped `cv2` / `numpy`, which were only used by the old image helpers.
|
|
164
|
+
- **No config layer.** The original client read generation parameters out of JSON-backed `Cache` /
|
|
165
|
+
`AppConfig` singletons. That whole system (and the `resources/config/*.json` definitions behind it)
|
|
166
|
+
has been removed; parameters are now passed explicitly as the pydantic models described above.
|
|
167
|
+
Moving to pydantic also replaced the hand-rolled request/response typing with validated models.
|
|
168
|
+
|
|
169
|
+
## Verifying against a live backend
|
|
170
|
+
|
|
171
|
+
The client's wire behavior is exercised by an integration test suite under `tests/` that runs against
|
|
172
|
+
real ComfyUI and A1111/Forge servers (see `tests/README.md`). If you rely on img2img / inpainting /
|
|
173
|
+
ControlNet, a real round-trip is worth more than trusting imports alone.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
`pip install -r requirements-dev.txt` adds the test, lint and type-check tools. CI (`.github/workflows/ci.yml`) runs
|
|
178
|
+
the unit tests on Python 3.11-3.14, a pylint check and a mypy check on every pull request into `main`. Releases are
|
|
179
|
+
cut by [release-please](https://github.com/googleapis/release-please) from Conventional Commits pull request titles;
|
|
180
|
+
see `CHANGELOG.md` once the first release lands. Rules for coding agents are in `AGENTS.md`.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
Public domain, dedicated under [The Unlicense](https://unlicense.org) — see `LICENSE`. Use it for
|
|
185
|
+
anything, with no attribution or other obligations.
|
|
186
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# sd-backend-client
|
|
2
|
+
|
|
3
|
+
[](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml)
|
|
4
|
+
[](.github/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A standalone, self-contained copy of IntraPaint's Stable Diffusion backend client
|
|
8
|
+
(`src/api`). It talks to **ComfyUI**, **Forge/Automatic1111 WebUI**, and their
|
|
9
|
+
**ControlNet** extensions, and builds the request bodies / node graphs those backends expect.
|
|
10
|
+
|
|
11
|
+
This package was extracted from [IntraPaint](https://github.com/centuryglass/IntraPaint) so it can
|
|
12
|
+
be dropped into other projects without pulling in the rest of the editor. Everything lives under the
|
|
13
|
+
`sd_backend_client` package and imports only from within it (plus third-party libraries).
|
|
14
|
+
|
|
15
|
+
**No Qt / PySide6 dependency.** Images are plain [Pillow](https://python-pillow.org/) `PIL.Image`
|
|
16
|
+
objects and the package has no GUI requirements — it runs headless.
|
|
17
|
+
|
|
18
|
+
## Status
|
|
19
|
+
|
|
20
|
+
This package is under active refactoring. The core txt2img / img2img / inpainting / ControlNet paths
|
|
21
|
+
work end-to-end against both backends (covered by the integration tests), but some areas — notably the
|
|
22
|
+
ComfyUI node classes' migration to pydantic and the tiled-upscaling workflow — are still in progress.
|
|
23
|
+
|
|
24
|
+
My eventual goal is to provide an API-agnostic interface, allowing complex image generation requests
|
|
25
|
+
to pass to either ComfyUI or Stable-Diffusion-WebUI without needing to care which interface is
|
|
26
|
+
actually available. To accomplish this, response data formats still need to be unified, and work
|
|
27
|
+
towards queued vs. blocking request handling still needs to be fully completed and tested.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This installs the package (and its dependencies) in editable mode, so `sd_backend_client` is importable
|
|
36
|
+
from anywhere without manually managing `sys.path`.
|
|
37
|
+
|
|
38
|
+
Requires **Python 3.11+** (uses `match` statements and PEP 604 / `X | Y` type aliases).
|
|
39
|
+
Runtime dependencies: `pillow`, `requests`, `websocket-client`, `pydantic`, `typing-extensions`.
|
|
40
|
+
|
|
41
|
+
## Layout
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
sd_backend_client/
|
|
45
|
+
api/
|
|
46
|
+
webservice.py # base HTTP/session helper
|
|
47
|
+
a1111_webservice.py # Forge / A1111 WebUI client (synchronous)
|
|
48
|
+
comfyui_webservice.py # ComfyUI client (async queue + polling)
|
|
49
|
+
shared_data/ # backend-agnostic pydantic models
|
|
50
|
+
diffusion_params.py # DiffusionParams: shared generation parameters
|
|
51
|
+
api_datatypes.py # DiffusionUpscalingParams and friends
|
|
52
|
+
controlnet/ # ControlNetUnit / PreprocessorParams / ControlNet model
|
|
53
|
+
comfyui/ # ComfyUI node-graph + workflow builders (+ ComfyUIDiffusionParams)
|
|
54
|
+
webui/ # WebUI request/response formats (+ DiffusionRequestBody)
|
|
55
|
+
util/ # shared constants, Size, PIL image helpers
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
Generation parameters are passed explicitly as [pydantic](https://docs.pydantic.dev/) models — there
|
|
61
|
+
is no hidden config/cache layer. Images passed in and returned are `PIL.Image` objects; no
|
|
62
|
+
`QApplication` or event loop is needed.
|
|
63
|
+
|
|
64
|
+
`DiffusionParams` (in `shared_data`) holds the parameters common to both backends. Each backend
|
|
65
|
+
extends it: `DiffusionRequestBody` (WebUI) and `ComfyUIDiffusionParams` (ComfyUI) add
|
|
66
|
+
backend-specific fields.
|
|
67
|
+
|
|
68
|
+
### Forge / A1111 WebUI (synchronous)
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from sd_backend_client.api.a1111_webservice import A1111Webservice
|
|
72
|
+
from sd_backend_client.api.webui.diffusion_request_body import DiffusionRequestBody
|
|
73
|
+
|
|
74
|
+
service = A1111Webservice('http://localhost:7860')
|
|
75
|
+
body = DiffusionRequestBody(prompt='a corgi astronaut, detailed',
|
|
76
|
+
steps=30, cfg_scale=7.0, width=512, height=512)
|
|
77
|
+
result = service.txt2img(body) # blocks until the image is generated
|
|
78
|
+
images = result['images'] # list[PIL.Image]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For img2img / inpainting, pass the source image (and, for inpainting, a mask) to
|
|
82
|
+
`service.img2img(image, mask, body)`.
|
|
83
|
+
|
|
84
|
+
### ComfyUI (asynchronous)
|
|
85
|
+
|
|
86
|
+
ComfyUI generation is queued: the call returns immediately with a prompt id, and you poll for
|
|
87
|
+
completion, then download the results.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from sd_backend_client.api.comfyui_webservice import ComfyUiWebservice
|
|
91
|
+
from sd_backend_client.api.comfyui.comfyui_diffusion_params import ComfyUIDiffusionParams
|
|
92
|
+
|
|
93
|
+
service = ComfyUiWebservice('http://localhost:8188')
|
|
94
|
+
params = ComfyUIDiffusionParams(sd_model_name='deliberate_v3.safetensors',
|
|
95
|
+
prompt='a corgi astronaut, detailed',
|
|
96
|
+
steps=20, sampler='euler', scheduler='karras')
|
|
97
|
+
response = service.txt2img(params) # queues a job
|
|
98
|
+
# poll service.check_queue_entry(response.prompt_id, response.number) until it reports FINISHED,
|
|
99
|
+
# then service.download_images(progress.outputs.images) to get the PIL images.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Set `init_images` (and `mask`) on the params for img2img / inpainting.
|
|
103
|
+
|
|
104
|
+
### ControlNet
|
|
105
|
+
|
|
106
|
+
ControlNet units are backend-agnostic: build a `ControlNetUnit` (with an optional `ControlNetModel`
|
|
107
|
+
and a `PreprocessorParams`) and add it to `diffusion_params.controlnet_units`. Each backend serializes
|
|
108
|
+
them into the form it expects — WebUI's `alwayson_scripts` ControlNet args, or ComfyUI ControlNet
|
|
109
|
+
nodes.
|
|
110
|
+
|
|
111
|
+
### Authentication (A1111 / Forge)
|
|
112
|
+
|
|
113
|
+
IntraPaint prompted for credentials with a Qt login dialog. The standalone client instead accepts a
|
|
114
|
+
`credentials_provider` callback, invoked when the server requires auth; it returns a
|
|
115
|
+
`(username, password)` pair to try, or `None` to abort:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from sd_backend_client.api.a1111_webservice import A1111Webservice
|
|
119
|
+
|
|
120
|
+
service = A1111Webservice('http://localhost:7860',
|
|
121
|
+
credentials_provider=lambda: ('user', 'password'))
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Design notes
|
|
125
|
+
|
|
126
|
+
Extracted from IntraPaint's `src/api` and then decoupled in two ways:
|
|
127
|
+
|
|
128
|
+
- **No Qt.** `QImage` → `PIL.Image` (via the small helpers in `util/visual/image_utils.py`; decoded
|
|
129
|
+
images are normalized to RGBA), `QSize` → the minimal `Size` value class in `util/geometry.py`, and
|
|
130
|
+
the UI strings and `_tr()` translation helpers are removed.
|
|
131
|
+
Dropping Qt also dropped `cv2` / `numpy`, which were only used by the old image helpers.
|
|
132
|
+
- **No config layer.** The original client read generation parameters out of JSON-backed `Cache` /
|
|
133
|
+
`AppConfig` singletons. That whole system (and the `resources/config/*.json` definitions behind it)
|
|
134
|
+
has been removed; parameters are now passed explicitly as the pydantic models described above.
|
|
135
|
+
Moving to pydantic also replaced the hand-rolled request/response typing with validated models.
|
|
136
|
+
|
|
137
|
+
## Verifying against a live backend
|
|
138
|
+
|
|
139
|
+
The client's wire behavior is exercised by an integration test suite under `tests/` that runs against
|
|
140
|
+
real ComfyUI and A1111/Forge servers (see `tests/README.md`). If you rely on img2img / inpainting /
|
|
141
|
+
ControlNet, a real round-trip is worth more than trusting imports alone.
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
`pip install -r requirements-dev.txt` adds the test, lint and type-check tools. CI (`.github/workflows/ci.yml`) runs
|
|
146
|
+
the unit tests on Python 3.11-3.14, a pylint check and a mypy check on every pull request into `main`. Releases are
|
|
147
|
+
cut by [release-please](https://github.com/googleapis/release-please) from Conventional Commits pull request titles;
|
|
148
|
+
see `CHANGELOG.md` once the first release lands. Rules for coding agents are in `AGENTS.md`.
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
Public domain, dedicated under [The Unlicense](https://unlicense.org) — see `LICENSE`. Use it for
|
|
153
|
+
anything, with no attribution or other obligations.
|
|
154
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# 77 is the first release that reads the PEP 639 `license` expression and `license-files`.
|
|
3
|
+
requires = ["setuptools>=77"]
|
|
4
|
+
build-backend = "setuptools.build_meta"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "sd-backend-client"
|
|
8
|
+
version = "0.2.1"
|
|
9
|
+
description = "Standalone, headless Stable Diffusion backend client (ComfyUI / Forge / A1111 WebUI, ControlNet)"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
license = "Unlicense"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
authors = [{ name = "Anthony Brown" }]
|
|
15
|
+
keywords = ["stable-diffusion", "comfyui", "automatic1111", "forge", "webui", "controlnet", "api-client"]
|
|
16
|
+
# Keep the Python versions in step with CI's test matrix (.github/workflows/ci.yml).
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Programming Language :: Python :: 3.14",
|
|
27
|
+
"Topic :: Multimedia :: Graphics",
|
|
28
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
# Each floor is the oldest release the unit tests pass against on Python 3.11, checked by CI's test-minimum-deps job.
|
|
32
|
+
# Keep the list in sync with requirements.txt.
|
|
33
|
+
dependencies = [
|
|
34
|
+
"pillow>=9.2",
|
|
35
|
+
"requests>=2.20",
|
|
36
|
+
"websocket-client>=1.0",
|
|
37
|
+
"pydantic>=2.1",
|
|
38
|
+
"typing-extensions>=4.6.1",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/centuryglass/sd-backend-client"
|
|
43
|
+
Issues = "https://github.com/centuryglass/sd-backend-client/issues"
|
|
44
|
+
Changelog = "https://github.com/centuryglass/sd-backend-client/blob/main/CHANGELOG.md"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
include = ["sd_backend_client*"]
|
|
48
|
+
|
|
49
|
+
# PEP 561 marker: type checkers read the installed package's annotations only when it is in the wheel.
|
|
50
|
+
[tool.setuptools.package-data]
|
|
51
|
+
sd_backend_client = ["py.typed"]
|
|
52
|
+
|
|
53
|
+
# CI's typecheck job runs `mypy` with these settings (AGENTS.md, "Type checking").
|
|
54
|
+
[tool.mypy]
|
|
55
|
+
files = ["sd_backend_client"]
|
|
56
|
+
python_version = "3.11"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""IntraPaint standalone API package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""api provides modules handling remote REST APIs."""
|