高质量sd webui api模式使用教程大全
讯飞摸鱼躺平王 2024-10-01 14:33:02 阅读 95
sd webui api模式使用教程大全
简介:
这是我亲自探索的能跑通的sd webui api模式的python调用记录,我将尽我最大的力量来做好/维护好本教程。
当然啦,有些我也没有探索成功,希望各位有成功经历的小伙伴在评论区告诉我怎么调用哈~
<code>注:未经同意,禁止转载
知识是属于全人类的。
拒绝野鸡收费教程,从我做起。
📋TODO:
文生图 图生图 底模的获取/重载/切换🔥🔥🔥 控制网络(controlnet)🔥🔥🔥 分割(SAM)🔥🔥🔥 获取png_info 扩图(outpainting) 叠图 人像修复(Adetailer) 融图
前排提示:在使用API模式启动好服务后,填你的地址:端口+/docs#/就能找到对应的API文档,例如我的在 http://127.0.0.1:7860/docs#/
文生图示例
注意端口和地址填你自己对应的哈!
<code>from datetime import datetime
import urllib.request
import base64
import json
import time
import os
webui_server_url = 'http://127.0.0.1:7861'
out_dir_t2i = os.path.join('api_out', 'txt2img') #图片保存路径
os.makedirs(out_dir_t2i, exist_ok=True)
def timestamp():
'''时间戳'''
return datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S")
def decode_and_save_base64(base64_str, save_path):
'''base64→图片'''
with open(save_path, "wb") as file:
file.write(base64.b64decode(base64_str))
def call_api(api_endpoint, **payload):
data = json.dumps(payload).encode('utf-8')
request = urllib.request.Request(f'{ webui_server_url}/{ api_endpoint}',headers={ 'Content-Type': 'application/json'},data=data,)
response = urllib.request.urlopen(request)
return json.loads(response.read().decode('utf-8'))
def call_txt2img_api(**payload):
response = call_api('sdapi/v1/txt2img', **payload)
for index, image in enumerate(response.get('images')):
save_path = os.path.join(out_dir_t2i, f'txt2img-{ timestamp()}-{ index}.png')
decode_and_save_base64(image, save_path)
if __name__ == '__main__':
payload = {
"prompt": "masterpiece, (best quality:1.1)",
"negative_prompt": "",
"seed": 1,
"steps": 20,
"width": 512,
"height": 512,
"cfg_scale": 7,
"sampler_name": "DPM++ 2M",
"n_iter": 1,
"batch_size": 1,}
call_txt2img_api(**payload)
图生图示例
from datetime import datetime
import urllib.request
import base64
import json
import time
import os
webui_server_url = 'http://127.0.0.1:7861'
out_dir_i2i = os.path.join('api_out', 'img2img') #图片保存路径
os.makedirs(out_dir_i2i, exist_ok=True)
def timestamp():
'''时间戳'''
return datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S")
def encode_file_to_base64(path):
'''图片→base64'''
with open(path, 'rb') as file:
return base64.b64encode(file.read()).decode('utf-8')
def decode_and_save_base64(base64_str, save_path):
'''base64→图片'''
with open(save_path, "wb") as file:
file.write(base64.b64decode(base64_str))
def call_api(api_endpoint, **payload):
data = json.dumps(payload).encode('utf-8')
request = urllib.request.Request(f'{ webui_server_url}/{ api_endpoint}',headers={ 'Content-Type': 'application/json'},data=data,)
response = urllib.request.urlopen(request)
return json.loads(response.read().decode('utf-8'))
def call_img2img_api(**payload):
response = call_api('sdapi/v1/img2img', **payload)
for index, image in enumerate(response.get('images')):
save_path = os.path.join(out_dir_i2i, f'img2img-{ timestamp()}-{ index}.png')
decode_and_save_base64(image, save_path)
if __name__ == '__main__':
init_images = [encode_file_to_base64(r"api_out/txt2img/0.png"),]
batch_size = 2
payload = {
"prompt": "1girl, blue hair",
"seed": 1,
"steps": 20,
"width": 512,
"height": 512,
"denoising_strength": 0.5,
"n_iter": 1,
"init_images": init_images,
"batch_size": batch_size if len(init_images) == 1 else len(init_images),}
call_img2img_api(**payload)
底模操作
1、底模获取
获取当前服务所用的底模,返回一个字典,可自行打印根据需求查看对应字段。
import base64
import requests
from PIL import Image
from io import BytesIO
url = "http://127.0.0.1:7861/sdapi/v1/sd-models"
res = requests.get(url)
print(res.json())
2、底模重载
import base64
import requests
from PIL import Image
from io import BytesIO
url = "http://127.0.0.1:7861/sdapi/v1/refresh-checkpoints"
res = requests.post(url)
注:我运行完后返回了200,但是时间过的特别快,感觉不像是重载而是那个♻️按钮。
3、底模切换🔥🔥🔥
直接在data字段里加入"override_settings"字段,如下所示:
data = {
"prompt": "a girl",
"negative_prompt": "boy",
"seed": -1, # 随机种子
"sampler_name": "取样器(之间复制webui的名字就行)",
"cfg_scale": 7, # 提示词相关性 越大越接近提示词
"width": 512, # 宽 (注意要被16整除)
"height": 512, # 高 (注意要被16整除)
"override_settings": {
"sd_model_checkpoint": "sd_xl_base_1.0.safetensors [31e35c80fc]", # 指定大模型
"sd_vae": "Automatic", # 指定vae 默认自动
},
"override_settings_restore_afterwards": True # override_settings 是否在之后恢复覆盖的设置 默认是True
}
然后运行,观察后台有没有打印换底模的log,一般情况下都能成功。
假如以上步骤切换失败了,这就涉及到改代码了,建议有代码基础的尝试以下步骤:
①修改modules\api\models.py增加一个"model_name"的key:
StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator(
"StableDiffusionProcessingTxt2Img",
StableDiffusionProcessingTxt2Img,
[
{ "key": "sampler_index", "type": str, "default": "Euler"},
{ "key": "script_name", "type": str, "default": None},
{ "key": "script_args", "type": list, "default": []},
{ "key": "send_images", "type": bool, "default": True},
{ "key": "save_images", "type": bool, "default": False},
{ "key": "alwayson_scripts", "type": dict, "default": { }},
{ "key": "model_name", "type": str, "default": None}, # 新增此代码
]
).generate_model()
StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(
"StableDiffusionProcessingImg2Img",
StableDiffusionProcessingImg2Img,
[
{ "key": "sampler_index", "type": str, "default": "Euler"},
{ "key": "init_images", "type": list, "default": None},
{ "key": "denoising_strength", "type": float, "default": 0.75},
{ "key": "mask", "type": str, "default": None},
{ "key": "include_init_images", "type": bool, "default": False, "exclude" : True},
{ "key": "script_name", "type": str, "default": None},
{ "key": "script_args", "type": list, "default": []},
{ "key": "send_images", "type": bool, "default": True},
{ "key": "save_images", "type": bool, "default": False},
{ "key": "alwayson_scripts", "type": dict, "default": { }},
{ "key": "model_name", "type": str, "default": None}, # 新增此代码
]
).generate_model()
②修改modules\processing.py
在StableDiffusionProcessingTxt2Img和StableDiffusionProcessingImg2Img两个类里加上model_name: str = None,假如你的版本比较老,就加到这两个类的def __init__
里,否则就直接建一个类的属性。例如我的:
class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
enable_hr: bool = False
denoising_strength: float = 0.75
firstphase_width: int = 0
firstphase_height: int = 0
hr_scale: float = 2.0
hr_upscaler: str = None
hr_second_pass_steps: int = 0
hr_resize_x: int = 0
hr_resize_y: int = 0
hr_checkpoint_name: str = None
hr_sampler_name: str = None
hr_prompt: str = ''
hr_negative_prompt: str = ''
model_name: str = None# 新增此代码
③修改modules\api\api.py text2imgapi和img2imgapi两个函数
def text2imgapi(self,txt2imgreq: models.StableDiffusionTxt2ImgProcessingAPI):
...
model_name = txt2imgreq.model_name# 新增此代码
with self.queue_lock:
if model_name is not None:
w_info = sd_models.CheckpointInfo(os.path.join('models/Stable-diffusion'.model_name))# 新增此代码
sd_models.reload_model_weights(info=w_info)# 新增此代码
with closing(StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)) as p:
...
def img2imgapi(self, img2imgreq: models.StableDiffusionImg2ImgProcessingAPI):
...
model_name = img2imgreq.model_name# 新增此代码
with self.queue_lock:
if model_name is not None:
w_info = sd_models.CheckpointInfo(os.path.join('models/Stable-diffusion'.model_name))# 新增此代码
sd_models.reload_model_weights(info=w_info)# 新增此代码
with closing(StableDiffusionProcessingImg2Img(sd_model=shared.sd_model, **args)) as p:
...
④🏃♂️调用
在传入的data里加上model_name字段就能换模型了。
payload = {
"prompt": "masterpiece, (best quality:1.1)",
"negative_prompt": "",
"seed": 1,
"steps": 2,
"width": 512,
"height": 512,
"cfg_scale": 7,
"sampler_name": "DPM++ 2M",
"model_name": "sd_xl_base_1.0.safetensors",}# 新增的字段
controlnet
首先,我假设您的webui已经安装好了controlnet并下载好相关权重。
文生图和图生图都是在data字段里加入一个"alwayson_scripts"字段,如下所示:
from datetime import datetime
import urllib.request
import base64
import json
import time
import os
webui_server_url = 'http://127.0.0.1:7861'
out_dir_t2i = os.path.join('api_out', 'txt2img') #图片保存路径
os.makedirs(out_dir_t2i, exist_ok=True)
def timestamp():
'''时间戳'''
return datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S")
def decode_and_save_base64(base64_str, save_path):
'''base64→图片'''
with open(save_path, "wb") as file:
file.write(base64.b64decode(base64_str))
def call_api(api_endpoint, **payload):
data = json.dumps(payload).encode('utf-8')
request = urllib.request.Request(f'{ webui_server_url}/{ api_endpoint}',headers={ 'Content-Type': 'application/json'},data=data,)
response = urllib.request.urlopen(request)
return json.loads(response.read().decode('utf-8'))
def call_txt2img_api(**payload):
response = call_api('sdapi/v1/txt2img', **payload)
for index, image in enumerate(response.get('images')):
save_path = os.path.join(out_dir_t2i, f'txt2img-{ timestamp()}-{ index}.png')
decode_and_save_base64(image, save_path)
if __name__ == '__main__':
payload = {
"prompt": "masterpiece, (best quality:1.1)",
"negative_prompt": "",
"seed": 1,
"steps": 20,
"width": 512,
"height": 512,
"cfg_scale": 7,
"sampler_name": "DPM++ 2M",
"n_iter": 1,
"batch_size": 1,
"alwayson_scripts": {
"controlnet":{
"args": [
{
"enabled": True, # 启用
"control_mode": 0, # 对应webui 的 Control Mode 可以直接填字符串 推荐使用下标 0 1 2
"model": "t2i-adapter_diffusers_xl_lineart [bae0efef]", # 对应webui 的 Model
"module": "lineart_standard (from white bg & black line)", # 对应webui 的 Preprocessor
"weight": 0.45, # 对应webui 的Control Weight
"resize_mode": "Crop and Resize",
"threshold_a": 200, # 阈值a 部分control module会用上
"threshold_b": 245, # 阈值b
"guidance_start": 0, # 什么时候介入 对应webui 的 Starting Control Step
"guidance_end": 0.7, # 什么时候退出 对应webui 的 Ending Control Step
"pixel_perfect": True, # 像素完美
"processor_res": 512, # 预处理器分辨率
"save_detected_map": False, # 因为使用了 controlnet API会返回生成controlnet的效果图,默认是True,如何不需要,改成False
"input_image": "", # 图片 格式为base64
}# 多个controlnet 在复制上面一个字典下来就行
]
}
}
call_txt2img_api(**payload)
SAM
首先,我假设您的webui已经安装好了SAM并下载好相关权重。
import base64
import requests
from PIL import Image
from io import BytesIO
def image_to_base64(img_path: str) -> str:
with open(img_path, "rb") as img_file:
img_base64 = base64.b64encode(img_file.read()).decode()
return img_base64
def save_image(b64_img:str, p_out:str) -> None:
with open(p_out,'wb') as f:
f.write(base64.b64decode(b64_img))
url = "http://127.0.0.1:7861/sam/sam-predict"
data = {
"sam_model_name": "sam_hq_vit_b.pth",
"input_image": image_to_base64("api_out/txt2img/txt2img-20240716-162233-0.png"),
"sam_positive_points": [[100.25,100.25]],
"sam_negative_points": [],
"dino_enabled": False,
"dino_model_name": "GroundingDINO_SwinT_OGC (694MB)",
"dino_text_prompt": "string",
"dino_box_threshold": 0.3,
"dino_preview_checkbox": False,
"dino_preview_boxes_selection": [0]
}
res = requests.post(url, json=data)
save_image(res.json()['masks'][0], 'oup_mask.png')
获取png_info
这是一个非常实用的功能,可以获取png图片的一些信息。
import base64
import requests
def image_to_base64(img_path: str) -> str:
with open(img_path, "rb") as img_file:
img_base64 = base64.b64encode(img_file.read()).decode()
return img_base64
url = "http://127.0.0.1:7861/sdapi/v1/png-info"
data = { "image": image_to_base64("api_out/txt2img/txt2img-20240716-162233-0.png")}#要传入的图片路径
res = requests.post(url, json=data)
print(res.json())
扩图
基于controlnet实现叠图功能,首先按网上教程把controlnet和LAMA装好,然后下载一个扩图的controlnet权重:control_v11p_sd15_inpaint.pth,放入相应的目录后按照以下步骤即可。
import json
import base64
import requests
def submit_post(url,data):
return requests.post(url,data=json.dumps(data))
def save_encoded_image(b64_image: str, output_path: str):
with open(output_path, 'wb') as image_file:
image_file.write(base64.b64decode(b64_image))
def encode_file_to_base64(path):
with open(path, 'rb') as file:
return base64.b64encode(file.read()).decode('utf-8')
if __name__ == '__main__':
img2img_url = r'http://127.0.0.1:1245/sdapi/v1/img2img'
init_images = [encode_file_to_base64(r"IP-Adapter1.png"),]
data = {
"seed": -1,
"steps": 20,
"width": 1024,
"height": 512,
'sampler_index': 'DPM++ 2M Karras',
"denoising_strength": 0.5,
"n_iter": 1,
"init_images": init_images,
# "batch_size": batch_size if len(init_images) == 1 else len(init_images),
"alwayson_scripts":{
"controlnet":
{
"args": [
{
"enabled": True, # 是否启用
"control_mode": 2, # 对应webui 的 Control Mode 可以直接填字符串 推荐使用下标 0 1 2
"model": "control_v11p_sd15_inpaint [ebff9138]", # 对应webui 的 Model
"module": "inpaint_only+lama", # 对应webui 的 Preprocessor
"weight": 1, # 对应webui 的Control Weight
"resize_mode": "Resize and Fill",
"threshold_a": 200, # 阈值a 部分control module会用上
"threshold_b": 245, # 阈值b
"guidance_start": 0, # 什么时候介入 对应webui 的 Starting Control Step
"guidance_end": 0.7, # 什么时候退出 对应webui 的 Ending Control Step
"pixel_perfect": True, # 像素完美
"processor_res": 512, # 预处理器分辨率
"save_detected_map": False, # 因为使用了 controlnet API会返回生成controlnet的效果图,默认是True,如何不需要,改成False
"input_image": encode_file_to_base64(r"IP-Adapter1.png"), # 图片 格式为base64
}
# 多个controlnet 在复制上面一个字典下来就行
]
}
}
}
response = submit_post(img2img_url, data)
save_image_path = r'outpainting.png'
save_encoded_image(response.json()['images'][0], save_image_path)
叠图
基于ipadapter实现叠图功能,先按网上教程把ipadapter装好,按照以下步骤即可实现叠图:
import json
import base64
import requests
def submit_post(url,data):
return requests.post(url,data=json.dumps(data))
def save_encoded_image(b64_image: str, output_path: str):
with open(output_path, 'wb') as image_file:
image_file.write(base64.b64decode(b64_image))
def encode_file_to_base64(path):
with open(path, 'rb') as file:
return base64.b64encode(file.read()).decode('utf-8')
if __name__ == '__main__':
img2img_url = r'http://172.0.0.1:4524/sdapi/v1/img2img'
input_image = encode_file_to_base64(r"/data/zkzou2/wwj/image_generation/stable-diffusion-webui/Canny.jpg")
style_image = encode_file_to_base64(r"/data/zkzou2/wwj/image_generation/stable-diffusion-webui/IP-Adapter1.png")
data = {
"seed": -1,
"steps": 20,
"width": 512,
"height": 512,
'sampler_index': 'DPM++ 2M Karras',
"denoising_strength": 0.5,
"n_iter": 1,
"init_images": [input_image],
# "batch_size": batch_size if len(init_images) == 1 else len(init_images),
"alwayson_scripts":{
"controlnet":
{
"args": [
{
"enabled": True, # 是否启用
"control_mode": 0, # 对应webui 的 Control Mode 可以直接填字符串 推荐使用下标 0 1 2
"model": "ip-adapter_sd15_plus [32cd8f7f]", # 对应webui 的 Model
"module": "ip-adapter_clip_sd15", # 对应webui 的 Preprocessor
"weight": 1, # 对应webui 的Control Weight
"resize_mode": "Crop and Resize",
"threshold_a": 200, # 阈值a 部分control module会用上
"threshold_b": 245, # 阈值b
"guidance_start": 0, # 什么时候介入 对应webui 的 Starting Control Step
"guidance_end": 0.7, # 什么时候退出 对应webui 的 Ending Control Step
"pixel_perfect": True, # 像素完美
"processor_res": 512, # 预处理器分辨率
"save_detected_map": False, # 因为使用了 controlnet API会返回生成controlnet的效果图,默认是True,如何不需要,改成False
"input_image": style_image, # 图片 格式为base64
},
{
"enabled": True, # 是否启用
"control_mode": 0, # 对应webui 的 Control Mode 可以直接填字符串 推荐使用下标 0 1 2
"model": "control_v11p_sd15_canny [d14c016b]", # 对应webui 的 Model, 叠图可以更换 Model 和 Preprocessor
"module": "canny", # 对应webui 的 Preprocessor
"weight": 1, # 对应webui 的Control Weight
"resize_mode": "Crop and Resize",
"threshold_a": 200, # 阈值a 部分control module会用上
"threshold_b": 245, # 阈值b
"guidance_start": 0, # 什么时候介入 对应webui 的 Starting Control Step
"guidance_end": 0.7, # 什么时候退出 对应webui 的 Ending Control Step
"pixel_perfect": True, # 像素完美
"processor_res": 512, # 预处理器分辨率
"save_detected_map": False, # 因为使用了 controlnet API会返回生成controlnet的效果图,默认是True,如何不需要,改成False
"input_image": input_image, # 图片 格式为base64
}
]
}
},
"override_settings": {
"sd_model_checkpoint": "v1-5-pruned-emaonly.safetensors [6ce0161689]", # 指定大模型
"sd_vae": "Automatic", # 指定vae 默认自动
},
"override_settings_restore_afterwards": True # override_settings 是否在之后恢复覆盖的设置 默认是True
}
response = submit_post(img2img_url, data)
save_image_path = r'stacked.png'
save_encoded_image(response.json()['images'][0], save_image_path)
人像修复(Adetailer)
评论区有人问我能不能调Adetailer,那必须安排呀!
首先,你先按网上教程把Adetailer装好,该下的权重下好,参考以下代码调用:
import json
import base64
import requests
import os
def submit_post(url,data):
return requests.post(url,data=json.dumps(data))
def save_encoded_image(b64_image: str, output_path: str):
with open(output_path, 'wb') as image_file:
image_file.write(base64.b64decode(b64_image))
def encode_file_to_base64(path):
with open(path, 'rb') as file:
return base64.b64encode(file.read()).decode('utf-8')
if __name__ == '__main__':
img2img_url = r'http://127.0.0.1:1245/sdapi/v1/img2img'
image = [encode_file_to_base64("/data/zkzou2/wwj/image_generation/stable-diffusion-webui/Ad2.png"),]
data = {
"prompt": "a beautiful girl, full body",
"seed": 816743407,
"steps": 20,
"width": 512,
"height": 512,
'sampler_index': 'DPM++ 2M SDE Karras',
"denoising_strength": 0.55,
"n_iter": 1,
"init_images": image,
"model_name": "v1-5-pruned-emaonly.safetensors",
# "batch_size": batch_size if len(init_images) == 1 else len(init_images),
"alwayson_scripts":{
"ADetailer":{
"args":[
True, # ad_enable
True, # 是否启用skip_img2img
{
"ad_model": "face_yolov8n.pt",
"ad_prompt": "detailed face"
}
# 添加多个ad_model
]
}
}
}
response = submit_post(img2img_url, data)
save_image_path = r"Ad_output.png"
save_encoded_image(response.json()['images'][0], save_image_path)
融图
探索中。。。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。