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.
Files changed (93) hide show
  1. sd_backend_client-0.2.1/LICENSE +24 -0
  2. sd_backend_client-0.2.1/PKG-INFO +186 -0
  3. sd_backend_client-0.2.1/README.md +154 -0
  4. sd_backend_client-0.2.1/pyproject.toml +56 -0
  5. sd_backend_client-0.2.1/sd_backend_client/__init__.py +1 -0
  6. sd_backend_client-0.2.1/sd_backend_client/api/__init__.py +1 -0
  7. sd_backend_client-0.2.1/sd_backend_client/api/a1111_webservice.py +646 -0
  8. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/__init__.py +1 -0
  9. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/basic_upscale_workflow_builder.py +40 -0
  10. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_diffusion_params.py +20 -0
  11. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_generation_handle.py +138 -0
  12. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/comfyui_types.py +265 -0
  13. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/controlnet_comfyui_utils.py +179 -0
  14. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/diffusion_workflow_builder.py +620 -0
  15. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/latent_upscale_workflow_builder.py +300 -0
  16. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/__init__.py +1 -0
  17. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/apply_upscaler_node.py +28 -0
  18. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/basic_scaling_node.py +35 -0
  19. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/clip_skip_node.py +32 -0
  20. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/comfy_node.py +68 -0
  21. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/comfy_node_graph.py +51 -0
  22. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/__init__.py +1 -0
  23. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/apply_controlnet_node.py +53 -0
  24. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/dynamic_preprocessor_node.py +40 -0
  25. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/controlnet/load_controlnet_node.py +31 -0
  26. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/image_scale_node.py +39 -0
  27. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/inpaint_model_conditioning_node.py +45 -0
  28. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/__init__.py +1 -0
  29. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/checkpoint_loader_node.py +32 -0
  30. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/clip_text_encode_node.py +29 -0
  31. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/empty_latent_image_node.py +31 -0
  32. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_image_mask_node.py +29 -0
  33. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_image_node.py +27 -0
  34. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/load_upscaler_node.py +23 -0
  35. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/input/simple_checkpoint_loader_node.py +25 -0
  36. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/ksampler_node.py +52 -0
  37. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/latent_mask_node.py +28 -0
  38. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/__init__.py +1 -0
  39. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/hypernet_loader_node.py +34 -0
  40. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/model_extensions/lora_loader_node.py +41 -0
  41. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/repeat_latent_node.py +30 -0
  42. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/save_image_node.py +26 -0
  43. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/ultimate_upscale_node.py +107 -0
  44. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/upscale_latent_node.py +39 -0
  45. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/__init__.py +1 -0
  46. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_decode_node.py +31 -0
  47. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_decode_tiled_node.py +44 -0
  48. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_encode_node.py +31 -0
  49. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/nodes/vae/vae_encode_tiled_node.py +42 -0
  50. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/preprocessor_preview_workflow_builder.py +46 -0
  51. sd_backend_client-0.2.1/sd_backend_client/api/comfyui/workflow_builder_utils.py +21 -0
  52. sd_backend_client-0.2.1/sd_backend_client/api/comfyui_webservice.py +686 -0
  53. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/__init__.py +1 -0
  54. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/api_datatypes.py +104 -0
  55. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/__init__.py +5 -0
  56. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_category_builder.py +86 -0
  57. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_constants.py +198 -0
  58. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_model.py +74 -0
  59. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_preprocessor.py +120 -0
  60. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/controlnet/controlnet_unit.py +37 -0
  61. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/diffusion_params.py +82 -0
  62. sd_backend_client-0.2.1/sd_backend_client/api/shared_data/generation_handle.py +176 -0
  63. sd_backend_client-0.2.1/sd_backend_client/api/webservice.py +215 -0
  64. sd_backend_client-0.2.1/sd_backend_client/api/webui/__init__.py +1 -0
  65. sd_backend_client-0.2.1/sd_backend_client/api/webui/controlnet_webui_constants.py +248 -0
  66. sd_backend_client-0.2.1/sd_backend_client/api/webui/controlnet_webui_utils.py +113 -0
  67. sd_backend_client-0.2.1/sd_backend_client/api/webui/diffusion_request_body.py +254 -0
  68. sd_backend_client-0.2.1/sd_backend_client/api/webui/request_formats.py +161 -0
  69. sd_backend_client-0.2.1/sd_backend_client/api/webui/response_formats.py +151 -0
  70. sd_backend_client-0.2.1/sd_backend_client/api/webui/script_info_types.py +35 -0
  71. sd_backend_client-0.2.1/sd_backend_client/api/webui/webui_generation_handle.py +339 -0
  72. sd_backend_client-0.2.1/sd_backend_client/py.typed +0 -0
  73. sd_backend_client-0.2.1/sd_backend_client/util/__init__.py +1 -0
  74. sd_backend_client-0.2.1/sd_backend_client/util/api_defaults.py +6 -0
  75. sd_backend_client-0.2.1/sd_backend_client/util/geometry.py +60 -0
  76. sd_backend_client-0.2.1/sd_backend_client/util/visual/__init__.py +1 -0
  77. sd_backend_client-0.2.1/sd_backend_client/util/visual/image_utils.py +83 -0
  78. sd_backend_client-0.2.1/sd_backend_client.egg-info/PKG-INFO +186 -0
  79. sd_backend_client-0.2.1/sd_backend_client.egg-info/SOURCES.txt +91 -0
  80. sd_backend_client-0.2.1/sd_backend_client.egg-info/dependency_links.txt +1 -0
  81. sd_backend_client-0.2.1/sd_backend_client.egg-info/requires.txt +5 -0
  82. sd_backend_client-0.2.1/sd_backend_client.egg-info/top_level.txt +1 -0
  83. sd_backend_client-0.2.1/setup.cfg +4 -0
  84. sd_backend_client-0.2.1/tests/test_a1111_async.py +258 -0
  85. sd_backend_client-0.2.1/tests/test_a1111_auth.py +80 -0
  86. sd_backend_client-0.2.1/tests/test_a1111_controlnet.py +68 -0
  87. sd_backend_client-0.2.1/tests/test_a1111_controlnet_generation.py +69 -0
  88. sd_backend_client-0.2.1/tests/test_a1111_generation.py +123 -0
  89. sd_backend_client-0.2.1/tests/test_a1111_metadata.py +101 -0
  90. sd_backend_client-0.2.1/tests/test_comfyui_async.py +174 -0
  91. sd_backend_client-0.2.1/tests/test_comfyui_controlnet_generation.py +95 -0
  92. sd_backend_client-0.2.1/tests/test_comfyui_generation.py +121 -0
  93. 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
+ [![CI](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml)
36
+ [![Python 3.11 | 3.12 | 3.13 | 3.14](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](.github/workflows/ci.yml)
37
+ [![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue)](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
+ [![CI](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/centuryglass/sd-backend-client/actions/workflows/ci.yml)
4
+ [![Python 3.11 | 3.12 | 3.13 | 3.14](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](.github/workflows/ci.yml)
5
+ [![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue)](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."""