stable-diffusion-webui
stable-diffusion-webui copied to clipboard
[Feature Request]: request API to save local image
Is there an existing issue for this?
- [X] I have searched the existing issues and checked the recent builds/commits
What would your feature do ?
When sending a request to API to run txtimg, img2img, etc,, I would like the ability to tell it to save the image locally. The Web UI already has a robust, customizable file saving feature. The problem this solves is someone handling a frontend doesn't need to do extra work creating code that already exists on the backend.
Proposed workflow
The frontend can send a payload to /sdapi/v1/txt2img
or wherever, which can optionally contain an additional key. Something like "save_local_image": True/False
If set to True
, the API will save an image as per the user's Web UI settings in addition to sending the normal API response back for frontend to do what they want with it.
Additional information
If this already exists in the API, could someone kindly point me to it?
Auto purposely wanted to not have the API save any images
Auto purposely wanted to not have the API save any images
How about adding an option "--api-save-images" so the server can choose to do it
Well the API is purposefully preventing the SD processing pipelines from saving the images, as you can see in the api module for txt2img : https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/3715ece0adce7bf7c5e9c5ab3710b2fdc3848f39/modules/api/api.py#L183-L184 or img2img : https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/3715ece0adce7bf7c5e9c5ab3710b2fdc3848f39/modules/api/api.py#L223-L224
So if you wanna make it save them set the to false:
"do_not_save_samples": False,
"do_not_save_grid": False
that's a quick work around, but of course you can go further and add a flag and so on.
So if you wanna make it save them set the to false:
"do_not_save_samples": False,
"do_not_save_grid": False
It doesn't work. After I changed to False and completed txt2img by api, the error was appeared:
ERROR: Exception in ASGI application████████████████████████████████████████████████| 70/70 [01:16<00:00, 1.89s/it]
Traceback (most recent call last):
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\streams\memory.py", line 94, in receive
return self.receive_nowait()
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\streams\memory.py", line 89, in receive_nowait
raise WouldBlock
anyio.WouldBlock
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\base.py", line 77, in call_next
message = await recv_stream.receive()
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\streams\memory.py", line 114, in receive
raise EndOfStream
anyio.EndOfStream
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 407, in run_asgi
result = await app( # type: ignore[func-returns-value]
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 78, in __call__
return await self.app(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\fastapi\applications.py", line 270, in __call__
await super().__call__(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\applications.py", line 124, in __call__
await self.middleware_stack(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
raise exc
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\base.py", line 106, in __call__
response = await self.dispatch_func(request, call_next)
File "C:\repos\stable-diffusion-webui\modules\api\api.py", line 96, in log_and_time
res: Response = await call_next(req)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\base.py", line 80, in call_next
raise app_exc
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\base.py", line 69, in coro
await self.app(scope, receive_or_disconnect, send_no_error)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\gzip.py", line 24, in __call__
await responder(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\gzip.py", line 44, in __call__
await self.app(scope, receive, self.send_with_gzip)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\exceptions.py", line 79, in __call__
raise exc
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__
await self.app(scope, receive, sender)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__
raise e
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\routing.py", line 706, in __call__
await route.handle(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\routing.py", line 276, in handle
await self.app(scope, receive, send)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\routing.py", line 66, in app
response = await func(request)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\fastapi\routing.py", line 237, in app
raw_response = await run_endpoint_function(
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\fastapi\routing.py", line 165, in run_endpoint_function
return await run_in_threadpool(dependant.call, **values)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\starlette\concurrency.py", line 41, in run_in_threadpool
return await anyio.to_thread.run_sync(func, *args)
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\to_thread.py", line 31, in run_sync
return await get_asynclib().run_sync_in_worker_thread(
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 937, in run_sync_in_worker_thread
return await future
File "C:\repos\stable-diffusion-webui\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 867, in run
result = context.run(func, *args)
File "C:\repos\stable-diffusion-webui\modules\api\api.py", line 203, in text2imgapi
processed = process_images(p)
File "C:\repos\stable-diffusion-webui\modules\processing.py", line 485, in process_images
res = process_images_inner(p)
File "C:\repos\stable-diffusion-webui\modules\processing.py", line 675, in process_images_inner
images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p)
File "C:\repos\stable-diffusion-webui\modules\images.py", line 494, in save_image
os.makedirs(path, exist_ok=True)
File "C:\Programs\Python\Python310\lib\os.py", line 210, in makedirs
head, tail = path.split(name)
File "C:\Programs\Python\Python310\lib\ntpath.py", line 211, in split
p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not NoneType
😃, sorry, my bad, you see I did this weeks, ago, and I forget some, stuff, this errors is linked to the saving path, well, you have to include the saving folder for the pipelines, in my case, I just saved them to the default folders as the GUI, so the code should looks like this :
for tzt2img pipeline : https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/3715ece0adce7bf7c5e9c5ab3710b2fdc3848f39/modules/api/api.py#L181-L186
it becomes
populate = txt2imgreq.copy(update={ # Override __init__ params
"sampler_name": validate_sampler_name(txt2imgreq.sampler_name or txt2imgreq.sampler_index),
"do_not_save_samples": False,
"do_not_save_grid": False,
"outpath_samples": opts.outdir_txt2img_samples, #you can set another folder if you want, I didn't test it though
"outpath_grids": opts.outdir_txt2img_grids,
}
)
for the im2img : https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/3715ece0adce7bf7c5e9c5ab3710b2fdc3848f39/modules/api/api.py#L221-L227
same :
populate = img2imgreq.copy(update={ # Override __init__ params
"sampler_name": validate_sampler_name(img2imgreq.sampler_name or img2imgreq.sampler_index),
"do_not_save_samples": False,
"do_not_save_grid": False,
"outpath_samples": opts.outdir_txt2img_samples, # put another path if you want,
"outpath_grids": opts.outdir_txt2img_grids,
"mask": mask
}
)
try again, with this, I might try later, when I can and share if there is a error.
do_not_save_samples
is there any way to save it in a different folder like /api or something
do_not_save_samples
is there any way to save it in a different folder like /api or something
I managed to save a generated image in a custom path. Not sure if you want something like this:
# Send the payload to the API and process the response
response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
r = response.json()
image = Image.open(io.BytesIO(base64.b64decode(r['images'][0])))
# Save the image with the specified suffix
output_filename = f"{model_name}.{suffix}.png"
output_path = output_directory / output_filename
image.save(output_path)
print(f"Thumbnail generated and saved as {output_path}")