ControlNeXt / app.py
Eugeoter's picture
update
76be739
import gradio as gr
import torch
import numpy as np
import spaces
from utils import utils, tools, preprocess
BASE_MODEL_REPO_ID = "neta-art/neta-xl-2.0"
BASE_MODEL_FILENAME = "neta-xl-v2.fp16.safetensors"
VAE_PATH = "madebyollin/sdxl-vae-fp16-fix"
CONTROLNEXT_REPO_ID = "Eugeoter/controlnext-sdxl-anime-canny"
CACHE_DIR = None
DEFAULT_PROMPT = ""
DEFAULT_NEGATIVE_PROMPT = "worst quality, abstract, clumsy pose, deformed hand, dynamic malformation, fused fingers, extra digits, fewer digits, fewer fingers, extra fingers, extra arm, missing arm, extra leg, missing leg, signature, artist name, multi views, disfigured, ugly"
def ui():
device = "cuda" if torch.cuda.is_available() else "cpu"
pipeline = tools.get_pipeline(
pretrained_model_name_or_path=BASE_MODEL_REPO_ID,
unet_model_name_or_path=CONTROLNEXT_REPO_ID,
controlnet_model_name_or_path=CONTROLNEXT_REPO_ID,
vae_model_name_or_path=VAE_PATH,
load_weight_increasement=True,
device=device,
hf_cache_dir=CACHE_DIR,
use_safetensors=True,
)
schedulers = ['Euler A', 'UniPC', 'Euler', 'DDIM', 'DDPM']
css = """
#col-container {
margin: 0 auto;
max-width: 520px;
}
"""
with gr.Blocks(css=css) as demo:
gr.Markdown(f"""
# [ControlNeXt-SDXL](https://github.com/dvlab-research/ControlNeXt) Demo (Anime Canny)
Base model: [Neta-Art-XL-2.0](https://civitai.com/models/410737/neta-art-xl)
""")
with gr.Row():
with gr.Column(scale=9):
prompt = gr.Textbox(label='Prompt', value=DEFAULT_PROMPT, lines=3, placeholder='prompt', container=False)
negative_prompt = gr.Textbox(label='Negative Prompt', value=DEFAULT_NEGATIVE_PROMPT, lines=3, placeholder='negative prompt', container=False)
with gr.Column(scale=1):
generate_button = gr.Button("Generate", variant='primary', min_width=96)
with gr.Row():
with gr.Column(scale=1):
with gr.Row():
control_image = gr.Image(
value=None,
label='Condition',
sources=['upload'],
type='pil',
height=512,
image_mode='RGB',
format='png',
show_download_button=True,
show_share_button=True,
)
with gr.Accordion(label='Preprocess', open=True):
with gr.Row():
threshold1 = gr.Slider(minimum=-1, maximum=255, step=1, value=-1, label='Threshold 1', info='-1 for auto')
threshold2 = gr.Slider(minimum=-1, maximum=255, step=1, value=-1, label='Threshold 2', info='-1 for auto')
process_button = gr.Button("Process", variant='primary', min_width=96, scale=0)
with gr.Row():
scheduler = gr.Dropdown(
label='Scheduler',
choices=schedulers,
value='Euler A',
multiselect=False,
allow_custom_value=False,
filterable=True,
)
num_inference_steps = gr.Slider(minimum=1, maximum=100, step=1, value=28, label='Steps')
with gr.Row():
cfg_scale = gr.Slider(minimum=1, maximum=30, step=1, value=7.5, label='CFG Scale')
controlnet_scale = gr.Slider(minimum=0, maximum=1, step=0.01, value=1, label='ControlNet Scale')
with gr.Row():
seed = gr.Number(label='Seed', step=1, precision=0, value=-1)
with gr.Column(scale=1):
with gr.Row():
output = gr.Gallery(
label='Output',
value=None,
object_fit='scale-down',
columns=4,
height=512,
show_download_button=True,
show_share_button=True,
)
with gr.Row():
examples = gr.Examples(
label='Examples',
examples=[
[
'best quality, 1girl, solo, open hand, outdoors, indoor, cute, young, cat, cat ear, glasses',
'examples/example_1.jpg',
],
[
'best quality, 1 komeiji koishi, solo, the pose, indoors, smile',
'examples/example_2.jpg',
]
],
inputs=[
prompt,
control_image,
],
cache_examples=False,
)
@spaces.GPU
def generate(
prompt,
control_image,
negative_prompt,
cfg_scale,
controlnet_scale,
num_inference_steps,
scheduler,
seed,
):
pipeline.scheduler = tools.get_scheduler(scheduler, pipeline.scheduler.config)
generator = torch.Generator(device=device).manual_seed(max(0, min(seed, np.iinfo(np.int32).max))) if seed != -1 else None
if control_image is None:
raise gr.Error('Please upload an image.')
width, height = utils.around_reso(control_image.width, control_image.height, reso=1024, max_width=2048, max_height=2048, divisible=32)
control_image = control_image.resize((width, height)).convert('RGB')
with torch.autocast(device):
output_images = pipeline.__call__(
prompt=prompt,
negative_prompt=negative_prompt,
controlnet_image=control_image,
controlnet_scale=controlnet_scale,
width=width,
height=height,
generator=generator,
guidance_scale=cfg_scale,
num_inference_steps=num_inference_steps,
).images
return output_images
def process(
image,
threshold1,
threshold2,
):
threshold1 = None if threshold1 == -1 else threshold1
threshold2 = None if threshold2 == -1 else threshold2
return preprocess.canny_extractor(image, threshold1, threshold2)
generate_button.click(
fn=generate,
inputs=[prompt, control_image, negative_prompt, cfg_scale, controlnet_scale, num_inference_steps, scheduler, seed],
outputs=[output],
)
process_button.click(
fn=process,
inputs=[control_image, threshold1, threshold2],
outputs=[control_image],
)
return demo
if __name__ == '__main__':
demo = ui()
demo.queue().launch()