test / scripts /example.py
bilegentile's picture
Upload folder using huggingface_hub
c19ca42 verified
import gradio as gr
from diffusers.pipelines import StableDiffusionPipeline, StableDiffusionXLPipeline # pylint: disable=unused-import
from modules import shared, scripts, processing, sd_models, devices
"""
This is a simpler template for script for SD.Next that implements a custom pipeline
Items that can be added:
- Any pipeline already in diffusers
List of pipelines that can be directly used: <https://github.com/huggingface/diffusers/tree/main/src/diffusers/pipelines>
- Any pipeline for which diffusers definiotion exists and can be copied
List of pipelines with community definitions: <https://github.com/huggingface/diffusers/tree/main/examples/community>
- Any custom pipeline that you create
Author::
- Your details
Credits:
- Link to original implementation and author
Contributions:
- Submit a PR on SD.Next GitHub repo to be included in /scripts
- Before submitting a PR, make sure to test your script thoroughly and that it passes code quality checks
Lint rules are part of SD.Next CI/CD pipeline
> pip install ruff pylint
> ruff scripts/example.py
> pylint scriptts/example.py
"""
## Config
# script title
title = 'Example'
# is script available in txt2img tab
txt2img = False
# is script available in img2img tab
img2img = False
# is pipeline ok to run in pure latent mode without implicit conversions
# recommended so entire ecosystem can be used as-is, but requires that latent is in format that sdnext can understand
# some pipelines may not support this, in which case set to false and pipeline will implicitly do things like vae encode/decode on its own
latent = True
# base pipeline class from which this pipeline is derived, most commonly 'StableDiffusionPipeline' or 'StableDiffusionXLPipeline'
pipeline_base = 'StableDiffusionPipeline'
# class definition for this pipeline
# for built-in diffuser pipelines, simply import it from diffusers.pipelines above
# for example only, its set to same as base pipeline
# for community pipelines, copy class definition from community source code
# in which case only class definition code and required imports needs to be copied, not the entire source code
pipeline_class = StableDiffusionPipeline
# pipeline args values are defined in ui method below, here we need to define their exact names
# they also have to be in the exact order as they are defined in ui
# note: variable names should be exactly as defined in pipeline_class.__call__ method
# if pipeline requires a param and its not provided, it will result in runtime error
# if you provide param that is not defined by pipeline, sdnext will strip it
params = ['test1', 'test2', 'test3', 'test4']
### Script definition
class Script(scripts.Script):
def title(self):
return title
def show(self, is_img2img):
if shared.backend == shared.Backend.DIFFUSERS:
return img2img if is_img2img else txt2img
return False
# Define UI for pipeline
def ui(self, _is_img2img):
ui_controls = []
with gr.Row():
ui_controls.append(gr.Slider(minimum=0, maximum=1, step=0.1, value=0.5, label="Test1"))
ui_controls.append(gr.Slider(minimum=0, maximum=10, step=1, value=5, label="Test2"))
with gr.Row():
ui_controls.append(gr.Checkbox(label="Test3", value=True))
with gr.Row():
ui_controls.append(gr.Textbox(label="Test4", value="", placeholder="enter text here"))
with gr.Row():
gr.HTML('<a href="https://huggingface.co/docs/diffusers/api/pipelines/stable_diffusion/stable_diffusion_xl>Stable Diffusion SDXL pipeline docs</a>"')
return ui_controls
# Run pipeline
def run(self, p: processing.StableDiffusionProcessing, *args): # pylint: disable=arguments-differ
# prepare pipeline
c = shared.sd_model.__class__.__name__ if shared.sd_model is not None else ''
if c != pipeline_base:
shared.log.warning(f'{title}: pipeline={c} required={pipeline_base}')
return None
orig_pipeline = shared.sd_model # backup current pipeline definition
shared.sd_model = pipeline_class( # create new pipeline using currently loaded model which is always in `shared.sd_model`
# different pipelines may need different init params, so you may need to change this
# to see init params, see pipeline_class.__init__ method
# if init params are incorrect you will also see a runtime error with unrecognized or missing params
# for example:
# > TypeError: StableDiffusionPipeline.__init__() missing 2 required positional arguments: 'safety_checker' and 'feature_extractor'
vae = shared.sd_model.vae,
text_encoder=shared.sd_model.text_encoder,
tokenizer=shared.sd_model.tokenizer,
unet=shared.sd_model.unet,
scheduler=shared.sd_model.scheduler,
safety_checker=shared.sd_model.safety_checker,
feature_extractor=shared.sd_model.feature_extractor,
)
sd_models.copy_diffuser_options(shared.sd_model, orig_pipeline) # copy options from original pipeline
sd_models.set_diffuser_options(shared.sd_model) # set all model options such as fp16, offload, etc.
sd_models.move_model(shared.sd_model, devices.device) # move pipeline to device
shared.sd_model.to(dtype=devices.dtype)
# if pipeline also needs a specific type, you can set it here, but not commonly needed
# shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
# prepare params
# all pipeline params go into p.task_args and are automatically handled by sdnext from there
for i in range(len(args)):
p.task_args[params[i]] = args[i]
# you can also re-use existing params from `p` object if pipeline wants them, but under a different name
# for example, if pipeline expects 'image' param, but you want to use 'init_images' instead which is what img2img tab uses
# p.task_args['image'] = p.init_images[0]
if not latent:
p.task_args['output_type'] = 'np'
shared.log.debug(f'{c}: args={p.task_args}')
# if you need to run any preprocessing, this is the place to do it
# run processing
processed: processing.Processed = processing.process_images(p)
# if you need to run any postprocessing, this is the place to do it
# you dont need to handle saving, metadata, etc - sdnext will do it for you
# restore original pipeline
shared.sd_model = orig_pipeline
return processed