2023-01-28 23:09:19 +00:00
|
|
|
from . import logging
|
2023-01-05 05:39:50 +00:00
|
|
|
from diffusers import (
|
|
|
|
DDIMScheduler,
|
2023-01-05 23:23:37 +00:00
|
|
|
DDPMScheduler,
|
|
|
|
DPMSolverMultistepScheduler,
|
2023-01-08 14:19:24 +00:00
|
|
|
DPMSolverSinglestepScheduler,
|
2023-01-05 05:39:50 +00:00
|
|
|
EulerDiscreteScheduler,
|
|
|
|
EulerAncestralDiscreteScheduler,
|
2023-01-08 14:19:24 +00:00
|
|
|
HeunDiscreteScheduler,
|
|
|
|
KDPM2AncestralDiscreteScheduler,
|
|
|
|
KDPM2DiscreteScheduler,
|
|
|
|
KarrasVeScheduler,
|
2023-01-05 23:23:37 +00:00
|
|
|
LMSDiscreteScheduler,
|
|
|
|
PNDMScheduler,
|
2023-01-05 05:39:50 +00:00
|
|
|
)
|
2023-01-23 04:38:03 +00:00
|
|
|
from flask import Flask, jsonify, make_response, request, send_from_directory, url_for
|
2023-01-14 16:18:53 +00:00
|
|
|
from flask_cors import CORS
|
2023-01-13 01:19:01 +00:00
|
|
|
from flask_executor import Executor
|
2023-01-17 02:10:52 +00:00
|
|
|
from glob import glob
|
2023-01-07 21:05:29 +00:00
|
|
|
from io import BytesIO
|
2023-01-29 04:31:34 +00:00
|
|
|
from jsonschema import validate
|
2023-01-28 23:09:19 +00:00
|
|
|
from logging import getLogger
|
2023-01-14 21:19:41 +00:00
|
|
|
from PIL import Image
|
2023-01-22 01:40:10 +00:00
|
|
|
from onnxruntime import get_available_providers
|
2023-01-28 23:09:19 +00:00
|
|
|
from os import path
|
2023-01-16 01:47:57 +00:00
|
|
|
from typing import Tuple
|
2023-01-10 04:58:37 +00:00
|
|
|
|
2023-01-28 23:09:19 +00:00
|
|
|
|
2023-01-28 14:19:40 +00:00
|
|
|
from .chain import (
|
2023-01-29 04:31:34 +00:00
|
|
|
blend_img2img,
|
|
|
|
blend_inpaint,
|
2023-01-28 14:19:40 +00:00
|
|
|
correct_gfpgan,
|
2023-01-28 15:08:59 +00:00
|
|
|
persist_disk,
|
2023-01-28 18:42:02 +00:00
|
|
|
persist_s3,
|
2023-01-29 21:23:01 +00:00
|
|
|
reduce_thumbnail,
|
|
|
|
reduce_crop,
|
|
|
|
source_noise,
|
2023-01-29 04:31:34 +00:00
|
|
|
source_txt2img,
|
2023-01-28 14:19:40 +00:00
|
|
|
upscale_outpaint,
|
|
|
|
upscale_resrgan,
|
|
|
|
upscale_stable_diffusion,
|
2023-01-28 14:37:17 +00:00
|
|
|
ChainPipeline,
|
2023-01-28 14:19:40 +00:00
|
|
|
)
|
2023-01-29 02:15:39 +00:00
|
|
|
from .diffusion.run import (
|
2023-01-26 02:31:39 +00:00
|
|
|
run_img2img_pipeline,
|
|
|
|
run_inpaint_pipeline,
|
|
|
|
run_txt2img_pipeline,
|
|
|
|
run_upscale_pipeline,
|
|
|
|
)
|
2023-01-15 17:09:47 +00:00
|
|
|
from .image import (
|
|
|
|
# mask filters
|
2023-01-15 20:04:54 +00:00
|
|
|
mask_filter_gaussian_multiply,
|
|
|
|
mask_filter_gaussian_screen,
|
2023-01-15 17:09:47 +00:00
|
|
|
mask_filter_none,
|
|
|
|
# noise sources
|
2023-01-15 20:26:04 +00:00
|
|
|
noise_source_fill_edge,
|
|
|
|
noise_source_fill_mask,
|
2023-01-15 17:09:47 +00:00
|
|
|
noise_source_gaussian,
|
|
|
|
noise_source_histogram,
|
|
|
|
noise_source_normal,
|
|
|
|
noise_source_uniform,
|
|
|
|
)
|
2023-01-28 04:48:06 +00:00
|
|
|
from .params import (
|
|
|
|
Border,
|
|
|
|
ImageParams,
|
|
|
|
Size,
|
2023-01-28 14:37:17 +00:00
|
|
|
StageParams,
|
2023-01-28 05:28:14 +00:00
|
|
|
UpscaleParams,
|
2023-01-28 04:48:06 +00:00
|
|
|
)
|
2023-01-16 00:54:20 +00:00
|
|
|
from .utils import (
|
2023-01-20 01:46:36 +00:00
|
|
|
is_debug,
|
2023-01-16 00:54:20 +00:00
|
|
|
get_and_clamp_float,
|
|
|
|
get_and_clamp_int,
|
2023-01-17 02:10:52 +00:00
|
|
|
get_from_list,
|
2023-01-16 00:54:20 +00:00
|
|
|
get_from_map,
|
2023-01-22 19:48:14 +00:00
|
|
|
get_not_empty,
|
2023-01-29 05:06:25 +00:00
|
|
|
get_size,
|
2023-01-16 13:42:10 +00:00
|
|
|
make_output_name,
|
2023-01-27 23:08:36 +00:00
|
|
|
base_join,
|
2023-01-16 13:31:42 +00:00
|
|
|
ServerContext,
|
2023-01-16 00:04:10 +00:00
|
|
|
)
|
|
|
|
|
2023-01-20 01:46:36 +00:00
|
|
|
import gc
|
2023-01-05 06:44:28 +00:00
|
|
|
import numpy as np
|
2023-01-28 23:09:19 +00:00
|
|
|
import yaml
|
|
|
|
|
|
|
|
logger = getLogger(__name__)
|
2023-01-05 00:25:00 +00:00
|
|
|
|
2023-01-28 23:09:19 +00:00
|
|
|
# config caching
|
2023-01-10 04:58:37 +00:00
|
|
|
config_params = {}
|
2023-01-06 04:50:30 +00:00
|
|
|
|
|
|
|
# pipeline params
|
2023-01-05 23:24:14 +00:00
|
|
|
platform_providers = {
|
|
|
|
'amd': 'DmlExecutionProvider',
|
|
|
|
'cpu': 'CPUExecutionProvider',
|
2023-01-19 23:37:26 +00:00
|
|
|
'cuda': 'CUDAExecutionProvider',
|
|
|
|
'directml': 'DmlExecutionProvider',
|
2023-01-07 14:56:21 +00:00
|
|
|
'nvidia': 'CUDAExecutionProvider',
|
2023-01-22 01:40:10 +00:00
|
|
|
'rocm': 'ROCMExecutionProvider',
|
2023-01-05 23:24:14 +00:00
|
|
|
}
|
2023-01-05 23:23:37 +00:00
|
|
|
pipeline_schedulers = {
|
2023-01-06 04:50:30 +00:00
|
|
|
'ddim': DDIMScheduler,
|
|
|
|
'ddpm': DDPMScheduler,
|
|
|
|
'dpm-multi': DPMSolverMultistepScheduler,
|
2023-01-08 14:19:24 +00:00
|
|
|
'dpm-single': DPMSolverSinglestepScheduler,
|
2023-01-06 04:50:30 +00:00
|
|
|
'euler': EulerDiscreteScheduler,
|
|
|
|
'euler-a': EulerAncestralDiscreteScheduler,
|
2023-01-08 14:19:24 +00:00
|
|
|
'heun': HeunDiscreteScheduler,
|
|
|
|
'k-dpm-2-a': KDPM2AncestralDiscreteScheduler,
|
|
|
|
'k-dpm-2': KDPM2DiscreteScheduler,
|
|
|
|
'karras-ve': KarrasVeScheduler,
|
2023-01-06 04:50:30 +00:00
|
|
|
'lms-discrete': LMSDiscreteScheduler,
|
|
|
|
'pndm': PNDMScheduler,
|
2023-01-05 05:39:50 +00:00
|
|
|
}
|
2023-01-15 15:21:09 +00:00
|
|
|
noise_sources = {
|
2023-01-15 20:26:04 +00:00
|
|
|
'fill-edge': noise_source_fill_edge,
|
|
|
|
'fill-mask': noise_source_fill_mask,
|
2023-01-15 15:21:09 +00:00
|
|
|
'gaussian': noise_source_gaussian,
|
|
|
|
'histogram': noise_source_histogram,
|
|
|
|
'normal': noise_source_normal,
|
|
|
|
'uniform': noise_source_uniform,
|
|
|
|
}
|
2023-01-15 17:09:47 +00:00
|
|
|
mask_filters = {
|
|
|
|
'none': mask_filter_none,
|
2023-01-15 20:04:54 +00:00
|
|
|
'gaussian-multiply': mask_filter_gaussian_multiply,
|
|
|
|
'gaussian-screen': mask_filter_gaussian_screen,
|
2023-01-15 15:21:09 +00:00
|
|
|
}
|
2023-01-28 04:48:06 +00:00
|
|
|
chain_stages = {
|
2023-01-29 04:31:34 +00:00
|
|
|
'blend-img2img': blend_img2img,
|
|
|
|
'blend-inpaint': blend_inpaint,
|
|
|
|
'correct-gfpgan': correct_gfpgan,
|
|
|
|
'persist-disk': persist_disk,
|
|
|
|
'persist-s3': persist_s3,
|
2023-01-29 21:23:01 +00:00
|
|
|
'reduce-crop': reduce_crop,
|
|
|
|
'reduce-thumbnail': reduce_thumbnail,
|
|
|
|
'source-noise': source_noise,
|
2023-01-29 04:31:34 +00:00
|
|
|
'source-txt2img': source_txt2img,
|
|
|
|
'upscale-outpaint': upscale_outpaint,
|
|
|
|
'upscale-resrgan': upscale_resrgan,
|
|
|
|
'upscale-stable-diffusion': upscale_stable_diffusion,
|
2023-01-28 04:48:06 +00:00
|
|
|
}
|
2023-01-05 05:39:50 +00:00
|
|
|
|
2023-01-22 01:40:10 +00:00
|
|
|
# Available ORT providers
|
|
|
|
available_platforms = []
|
|
|
|
|
2023-01-17 02:10:52 +00:00
|
|
|
# loaded from model_path
|
|
|
|
diffusion_models = []
|
|
|
|
correction_models = []
|
|
|
|
upscaling_models = []
|
2023-01-16 20:52:56 +00:00
|
|
|
|
2023-01-05 17:19:42 +00:00
|
|
|
|
2023-01-22 19:48:14 +00:00
|
|
|
def get_config_value(key: str, subkey: str = 'default'):
|
|
|
|
return config_params.get(key).get(subkey)
|
|
|
|
|
|
|
|
|
2023-01-16 01:33:40 +00:00
|
|
|
def url_from_rule(rule) -> str:
|
2023-01-06 03:13:45 +00:00
|
|
|
options = {}
|
|
|
|
for arg in rule.arguments:
|
|
|
|
options[arg] = ":%s" % (arg)
|
|
|
|
|
|
|
|
return url_for(rule.endpoint, **options)
|
|
|
|
|
2023-01-11 05:00:18 +00:00
|
|
|
|
2023-01-27 23:08:36 +00:00
|
|
|
def pipeline_from_request() -> Tuple[ImageParams, Size]:
|
2023-01-11 05:00:18 +00:00
|
|
|
user = request.remote_addr
|
|
|
|
|
|
|
|
# pipeline stuff
|
2023-01-22 19:48:14 +00:00
|
|
|
model = get_not_empty(request.args, 'model', get_config_value('model'))
|
|
|
|
model_path = get_model_path(model)
|
2023-01-11 05:00:18 +00:00
|
|
|
provider = get_from_map(request.args, 'platform',
|
2023-01-22 19:48:14 +00:00
|
|
|
platform_providers, get_config_value('platform'))
|
2023-01-11 05:00:18 +00:00
|
|
|
scheduler = get_from_map(request.args, 'scheduler',
|
2023-01-22 19:48:14 +00:00
|
|
|
pipeline_schedulers, get_config_value('scheduler'))
|
2023-01-11 05:00:18 +00:00
|
|
|
|
|
|
|
# image params
|
2023-01-22 19:48:14 +00:00
|
|
|
prompt = get_not_empty(request.args,
|
|
|
|
'prompt', get_config_value('prompt'))
|
2023-01-12 03:50:19 +00:00
|
|
|
negative_prompt = request.args.get('negativePrompt', None)
|
2023-01-11 05:00:18 +00:00
|
|
|
|
2023-01-12 03:50:19 +00:00
|
|
|
if negative_prompt is not None and negative_prompt.strip() == '':
|
2023-01-11 05:00:18 +00:00
|
|
|
negative_prompt = None
|
|
|
|
|
2023-01-13 01:19:01 +00:00
|
|
|
cfg = get_and_clamp_float(
|
2023-01-14 18:45:18 +00:00
|
|
|
request.args, 'cfg',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('cfg'),
|
|
|
|
get_config_value('cfg', 'max'),
|
|
|
|
get_config_value('cfg', 'min'))
|
2023-01-13 01:19:01 +00:00
|
|
|
steps = get_and_clamp_int(
|
2023-01-14 18:45:18 +00:00
|
|
|
request.args, 'steps',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('steps'),
|
|
|
|
get_config_value('steps', 'max'),
|
|
|
|
get_config_value('steps', 'min'))
|
2023-01-11 05:00:18 +00:00
|
|
|
height = get_and_clamp_int(
|
2023-01-14 18:45:18 +00:00
|
|
|
request.args, 'height',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('height'),
|
|
|
|
get_config_value('height', 'max'),
|
|
|
|
get_config_value('height', 'min'))
|
2023-01-13 01:19:01 +00:00
|
|
|
width = get_and_clamp_int(
|
2023-01-14 18:45:18 +00:00
|
|
|
request.args, 'width',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('width'),
|
|
|
|
get_config_value('width', 'max'),
|
|
|
|
get_config_value('width', 'min'))
|
2023-01-11 05:00:18 +00:00
|
|
|
|
|
|
|
seed = int(request.args.get('seed', -1))
|
|
|
|
if seed == -1:
|
|
|
|
seed = np.random.randint(np.iinfo(np.int32).max)
|
|
|
|
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info("request from %s: %s rounds of %s using %s on %s, %sx%s, %s, %s - %s",
|
|
|
|
user, steps, scheduler.__name__, model_path, provider, width, height, cfg, seed, prompt)
|
2023-01-11 05:00:18 +00:00
|
|
|
|
2023-01-27 23:08:36 +00:00
|
|
|
params = ImageParams(model_path, provider, scheduler, prompt,
|
2023-01-28 04:48:06 +00:00
|
|
|
negative_prompt, cfg, steps, seed)
|
2023-01-16 01:14:58 +00:00
|
|
|
size = Size(width, height)
|
|
|
|
return (params, size)
|
2023-01-13 01:19:01 +00:00
|
|
|
|
|
|
|
|
2023-01-16 13:45:50 +00:00
|
|
|
def border_from_request() -> Border:
|
2023-01-23 04:25:00 +00:00
|
|
|
left = get_and_clamp_int(request.args, 'left', 0,
|
|
|
|
get_config_value('width', 'max'), 0)
|
|
|
|
right = get_and_clamp_int(request.args, 'right',
|
|
|
|
0, get_config_value('width', 'max'), 0)
|
|
|
|
top = get_and_clamp_int(request.args, 'top', 0,
|
|
|
|
get_config_value('height', 'max'), 0)
|
|
|
|
bottom = get_and_clamp_int(
|
|
|
|
request.args, 'bottom', 0, get_config_value('height', 'max'), 0)
|
2023-01-16 13:45:50 +00:00
|
|
|
|
|
|
|
return Border(left, right, top, bottom)
|
|
|
|
|
|
|
|
|
2023-01-22 22:35:53 +00:00
|
|
|
def upscale_from_request(provider: str) -> UpscaleParams:
|
2023-01-16 19:12:08 +00:00
|
|
|
denoise = get_and_clamp_float(request.args, 'denoise', 0.5, 1.0, 0.0)
|
|
|
|
scale = get_and_clamp_int(request.args, 'scale', 1, 4, 1)
|
2023-01-16 20:52:56 +00:00
|
|
|
outscale = get_and_clamp_int(request.args, 'outscale', 1, 4, 1)
|
2023-01-17 02:10:52 +00:00
|
|
|
upscaling = get_from_list(request.args, 'upscaling', upscaling_models)
|
|
|
|
correction = get_from_list(request.args, 'correction', correction_models)
|
2023-01-22 19:48:14 +00:00
|
|
|
faces = get_not_empty(request.args, 'faces', 'false') == 'true'
|
2023-01-17 05:45:54 +00:00
|
|
|
face_strength = get_and_clamp_float(
|
|
|
|
request.args, 'faceStrength', 0.5, 1.0, 0.0)
|
2023-01-17 02:10:52 +00:00
|
|
|
|
2023-01-16 20:52:56 +00:00
|
|
|
return UpscaleParams(
|
2023-01-17 02:10:52 +00:00
|
|
|
upscaling,
|
2023-01-22 22:35:53 +00:00
|
|
|
provider,
|
2023-01-17 02:10:52 +00:00
|
|
|
correction_model=correction,
|
2023-01-16 20:52:56 +00:00
|
|
|
denoise=denoise,
|
2023-01-22 22:35:53 +00:00
|
|
|
faces=faces,
|
2023-01-17 04:54:01 +00:00
|
|
|
face_strength=face_strength,
|
2023-01-22 22:35:53 +00:00
|
|
|
format='onnx',
|
|
|
|
outscale=outscale,
|
|
|
|
scale=scale,
|
2023-01-16 20:52:56 +00:00
|
|
|
)
|
2023-01-16 19:12:08 +00:00
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
|
|
|
|
def check_paths(context: ServerContext):
|
|
|
|
if not path.exists(context.model_path):
|
2023-01-06 04:50:30 +00:00
|
|
|
raise RuntimeError('model path must exist')
|
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
if not path.exists(context.output_path):
|
|
|
|
makedirs(context.output_path)
|
2023-01-06 04:50:30 +00:00
|
|
|
|
|
|
|
|
2023-01-17 02:25:09 +00:00
|
|
|
def get_model_name(model: str) -> str:
|
|
|
|
base = path.basename(model)
|
|
|
|
(file, _ext) = path.splitext(base)
|
|
|
|
return file
|
|
|
|
|
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
def load_models(context: ServerContext):
|
2023-01-17 02:10:52 +00:00
|
|
|
global diffusion_models
|
|
|
|
global correction_models
|
|
|
|
global upscaling_models
|
|
|
|
|
2023-01-17 02:25:09 +00:00
|
|
|
diffusion_models = [get_model_name(f) for f in glob(
|
|
|
|
path.join(context.model_path, 'diffusion-*'))]
|
|
|
|
diffusion_models.extend([
|
|
|
|
get_model_name(f) for f in glob(path.join(context.model_path, 'stable-diffusion-*'))])
|
2023-01-17 02:58:08 +00:00
|
|
|
diffusion_models = list(set(diffusion_models))
|
|
|
|
diffusion_models.sort()
|
2023-01-17 02:10:52 +00:00
|
|
|
|
2023-01-17 02:25:09 +00:00
|
|
|
correction_models = [
|
|
|
|
get_model_name(f) for f in glob(path.join(context.model_path, 'correction-*'))]
|
2023-01-17 02:58:08 +00:00
|
|
|
correction_models = list(set(correction_models))
|
|
|
|
correction_models.sort()
|
2023-01-17 02:28:29 +00:00
|
|
|
|
2023-01-17 02:25:09 +00:00
|
|
|
upscaling_models = [
|
|
|
|
get_model_name(f) for f in glob(path.join(context.model_path, 'upscaling-*'))]
|
2023-01-17 02:58:08 +00:00
|
|
|
upscaling_models = list(set(upscaling_models))
|
|
|
|
upscaling_models.sort()
|
2023-01-06 04:50:30 +00:00
|
|
|
|
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
def load_params(context: ServerContext):
|
2023-01-10 04:58:37 +00:00
|
|
|
global config_params
|
2023-01-16 22:39:30 +00:00
|
|
|
params_file = path.join(context.params_path, 'params.json')
|
2023-01-28 23:09:19 +00:00
|
|
|
with open(params_file, 'r') as f:
|
|
|
|
config_params = yaml.safe_load(f)
|
2023-01-10 04:58:37 +00:00
|
|
|
|
2023-01-31 14:45:06 +00:00
|
|
|
if 'platform' in config_params and context.default_platform is not None:
|
|
|
|
logger.info('overriding default platform to %s', context.default_platform)
|
|
|
|
config_platform = config_params.get('platform')
|
|
|
|
config_platform['default'] = context.default_platform
|
|
|
|
|
2023-01-10 04:58:37 +00:00
|
|
|
|
2023-01-22 01:40:10 +00:00
|
|
|
def load_platforms():
|
|
|
|
global available_platforms
|
|
|
|
|
|
|
|
providers = get_available_providers()
|
2023-01-22 01:44:54 +00:00
|
|
|
available_platforms = [p for p in platform_providers if (
|
2023-01-25 05:19:57 +00:00
|
|
|
platform_providers[p] in providers and p not in context.block_platforms)]
|
2023-01-22 01:40:10 +00:00
|
|
|
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info('available acceleration platforms: %s', available_platforms)
|
2023-01-22 01:40:10 +00:00
|
|
|
|
|
|
|
|
2023-01-16 22:40:32 +00:00
|
|
|
context = ServerContext.from_environ()
|
2023-01-16 22:39:30 +00:00
|
|
|
check_paths(context)
|
|
|
|
load_models(context)
|
|
|
|
load_params(context)
|
2023-01-22 01:40:10 +00:00
|
|
|
load_platforms()
|
2023-01-13 16:32:03 +00:00
|
|
|
|
2023-01-05 01:42:37 +00:00
|
|
|
app = Flask(__name__)
|
2023-01-16 22:39:30 +00:00
|
|
|
app.config['EXECUTOR_MAX_WORKERS'] = context.num_workers
|
2023-01-14 20:20:42 +00:00
|
|
|
app.config['EXECUTOR_PROPAGATE_EXCEPTIONS'] = True
|
2023-01-13 16:32:03 +00:00
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
CORS(app, origins=context.cors_origin)
|
2023-01-13 01:19:01 +00:00
|
|
|
executor = Executor(app)
|
2023-01-05 00:25:00 +00:00
|
|
|
|
2023-01-20 01:46:36 +00:00
|
|
|
if is_debug():
|
|
|
|
gc.set_debug(gc.DEBUG_STATS)
|
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
|
|
|
|
# TODO: these two use context
|
|
|
|
|
|
|
|
def get_model_path(model: str):
|
2023-01-27 23:08:36 +00:00
|
|
|
return base_join(context.model_path, model)
|
2023-01-16 22:39:30 +00:00
|
|
|
|
|
|
|
|
2023-01-23 04:38:03 +00:00
|
|
|
def ready_reply(ready: bool):
|
|
|
|
return jsonify({
|
|
|
|
'ready': ready,
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
def error_reply(err: str):
|
|
|
|
response = make_response(jsonify({
|
|
|
|
'error': err,
|
|
|
|
}))
|
|
|
|
response.status_code = 400
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2023-01-16 22:39:30 +00:00
|
|
|
def serve_bundle_file(filename='index.html'):
|
|
|
|
return send_from_directory(path.join('..', context.bundle_path), filename)
|
|
|
|
|
2023-01-16 13:31:42 +00:00
|
|
|
|
2023-01-05 01:42:37 +00:00
|
|
|
# routes
|
2023-01-05 17:19:42 +00:00
|
|
|
|
|
|
|
|
2023-01-05 00:25:00 +00:00
|
|
|
@app.route('/')
|
2023-01-06 03:54:40 +00:00
|
|
|
def index():
|
2023-01-13 04:54:32 +00:00
|
|
|
return serve_bundle_file()
|
2023-01-13 04:10:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.route('/<path:filename>')
|
|
|
|
def index_path(filename):
|
2023-01-13 04:54:32 +00:00
|
|
|
return serve_bundle_file(filename)
|
2023-01-13 04:10:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api')
|
|
|
|
def introspect():
|
2023-01-06 03:13:45 +00:00
|
|
|
return {
|
|
|
|
'name': 'onnx-web',
|
|
|
|
'routes': [{
|
|
|
|
'path': url_from_rule(rule),
|
2023-01-06 17:00:20 +00:00
|
|
|
'methods': list(rule.methods).sort()
|
2023-01-06 03:13:45 +00:00
|
|
|
} for rule in app.url_map.iter_rules()]
|
|
|
|
}
|
2023-01-05 00:25:00 +00:00
|
|
|
|
2023-01-05 17:19:42 +00:00
|
|
|
|
2023-01-15 17:09:47 +00:00
|
|
|
@app.route('/api/settings/masks')
|
|
|
|
def list_mask_filters():
|
|
|
|
return jsonify(list(mask_filters.keys()))
|
2023-01-15 15:32:30 +00:00
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/settings/models')
|
2023-01-06 04:01:58 +00:00
|
|
|
def list_models():
|
2023-01-17 02:10:52 +00:00
|
|
|
return jsonify({
|
|
|
|
'diffusion': diffusion_models,
|
|
|
|
'correction': correction_models,
|
|
|
|
'upscaling': upscaling_models,
|
|
|
|
})
|
2023-01-06 04:01:58 +00:00
|
|
|
|
|
|
|
|
2023-01-15 15:32:30 +00:00
|
|
|
@app.route('/api/settings/noises')
|
|
|
|
def list_noise_sources():
|
|
|
|
return jsonify(list(noise_sources.keys()))
|
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/settings/params')
|
2023-01-10 04:58:37 +00:00
|
|
|
def list_params():
|
2023-01-14 16:18:53 +00:00
|
|
|
return jsonify(config_params)
|
2023-01-10 04:58:37 +00:00
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/settings/platforms')
|
2023-01-06 03:54:40 +00:00
|
|
|
def list_platforms():
|
2023-01-22 01:41:43 +00:00
|
|
|
return jsonify(list(available_platforms))
|
2023-01-06 03:54:40 +00:00
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/settings/schedulers')
|
2023-01-06 03:54:40 +00:00
|
|
|
def list_schedulers():
|
2023-01-14 16:18:53 +00:00
|
|
|
return jsonify(list(pipeline_schedulers.keys()))
|
2023-01-06 03:54:40 +00:00
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/img2img', methods=['POST'])
|
2023-01-07 21:05:29 +00:00
|
|
|
def img2img():
|
2023-01-23 04:38:03 +00:00
|
|
|
if 'source' not in request.files:
|
|
|
|
return error_reply('source image is required')
|
|
|
|
|
2023-01-16 13:31:42 +00:00
|
|
|
source_file = request.files.get('source')
|
|
|
|
source_image = Image.open(BytesIO(source_file.read())).convert('RGB')
|
2023-01-07 21:05:29 +00:00
|
|
|
|
2023-01-16 13:45:50 +00:00
|
|
|
params, size = pipeline_from_request()
|
2023-01-22 22:35:53 +00:00
|
|
|
upscale = upscale_from_request(params.provider)
|
2023-01-16 13:45:50 +00:00
|
|
|
|
2023-01-16 02:00:26 +00:00
|
|
|
strength = get_and_clamp_float(
|
|
|
|
request.args,
|
|
|
|
'strength',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('strength'),
|
|
|
|
get_config_value('strength', 'max'),
|
|
|
|
get_config_value('strength', 'min'))
|
2023-01-07 21:19:24 +00:00
|
|
|
|
2023-01-16 13:42:10 +00:00
|
|
|
output = make_output_name(
|
2023-01-15 17:28:12 +00:00
|
|
|
'img2img',
|
2023-01-16 01:14:58 +00:00
|
|
|
params,
|
|
|
|
size,
|
2023-01-17 23:50:36 +00:00
|
|
|
extras=(strength,))
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info("img2img output saved: %s", output)
|
2023-01-16 01:14:58 +00:00
|
|
|
|
2023-01-16 13:31:42 +00:00
|
|
|
source_image.thumbnail((size.width, size.height))
|
2023-01-16 13:42:10 +00:00
|
|
|
executor.submit_stored(output, run_img2img_pipeline,
|
2023-01-16 19:12:08 +00:00
|
|
|
context, params, output, upscale, source_image, strength)
|
2023-01-07 21:05:29 +00:00
|
|
|
|
2023-01-14 16:18:53 +00:00
|
|
|
return jsonify({
|
2023-01-16 13:42:10 +00:00
|
|
|
'output': output,
|
2023-01-16 01:33:40 +00:00
|
|
|
'params': params.tojson(),
|
2023-01-16 21:11:40 +00:00
|
|
|
'size': upscale.resize(size).tojson(),
|
2023-01-07 21:05:29 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/txt2img', methods=['POST'])
|
2023-01-07 21:05:29 +00:00
|
|
|
def txt2img():
|
2023-01-16 01:33:40 +00:00
|
|
|
params, size = pipeline_from_request()
|
2023-01-22 22:35:53 +00:00
|
|
|
upscale = upscale_from_request(params.provider)
|
2023-01-05 17:19:42 +00:00
|
|
|
|
2023-01-16 13:42:10 +00:00
|
|
|
output = make_output_name(
|
2023-01-15 17:28:12 +00:00
|
|
|
'txt2img',
|
2023-01-16 01:33:40 +00:00
|
|
|
params,
|
|
|
|
size)
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info("txt2img output saved: %s", output)
|
2023-01-16 01:33:40 +00:00
|
|
|
|
|
|
|
executor.submit_stored(
|
2023-01-16 19:12:08 +00:00
|
|
|
output, run_txt2img_pipeline, context, params, size, output, upscale)
|
2023-01-06 02:32:46 +00:00
|
|
|
|
2023-01-14 16:18:53 +00:00
|
|
|
return jsonify({
|
2023-01-16 13:42:10 +00:00
|
|
|
'output': output,
|
2023-01-16 01:33:40 +00:00
|
|
|
'params': params.tojson(),
|
2023-01-16 21:11:40 +00:00
|
|
|
'size': upscale.resize(size).tojson(),
|
2023-01-06 02:32:46 +00:00
|
|
|
})
|
2023-01-05 23:24:33 +00:00
|
|
|
|
2023-01-06 02:32:46 +00:00
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/inpaint', methods=['POST'])
|
2023-01-09 00:11:34 +00:00
|
|
|
def inpaint():
|
2023-01-23 04:38:03 +00:00
|
|
|
if 'source' not in request.files:
|
|
|
|
return error_reply('source image is required')
|
|
|
|
|
|
|
|
if 'mask' not in request.files:
|
|
|
|
return error_reply('mask image is required')
|
|
|
|
|
2023-01-09 00:11:34 +00:00
|
|
|
source_file = request.files.get('source')
|
|
|
|
source_image = Image.open(BytesIO(source_file.read())).convert('RGB')
|
|
|
|
|
|
|
|
mask_file = request.files.get('mask')
|
|
|
|
mask_image = Image.open(BytesIO(mask_file.read())).convert('RGB')
|
|
|
|
|
2023-01-16 01:33:40 +00:00
|
|
|
params, size = pipeline_from_request()
|
2023-01-16 13:45:50 +00:00
|
|
|
expand = border_from_request()
|
2023-01-22 22:35:53 +00:00
|
|
|
upscale = upscale_from_request(params.provider)
|
2023-01-15 15:21:09 +00:00
|
|
|
|
2023-01-22 19:48:14 +00:00
|
|
|
fill_color = get_not_empty(request.args, 'fillColor', 'white')
|
2023-01-15 17:28:12 +00:00
|
|
|
mask_filter = get_from_map(request.args, 'filter', mask_filters, 'none')
|
2023-01-15 15:21:09 +00:00
|
|
|
noise_source = get_from_map(
|
|
|
|
request.args, 'noise', noise_sources, 'histogram')
|
2023-01-17 23:50:36 +00:00
|
|
|
strength = get_and_clamp_float(
|
|
|
|
request.args,
|
|
|
|
'strength',
|
2023-01-22 19:48:14 +00:00
|
|
|
get_config_value('strength'),
|
|
|
|
get_config_value('strength', 'max'),
|
|
|
|
get_config_value('strength', 'min'))
|
2023-01-14 22:59:38 +00:00
|
|
|
|
2023-01-16 13:42:10 +00:00
|
|
|
output = make_output_name(
|
2023-01-16 01:33:40 +00:00
|
|
|
'inpaint',
|
|
|
|
params,
|
|
|
|
size,
|
|
|
|
extras=(
|
2023-01-16 13:45:50 +00:00
|
|
|
expand.left,
|
|
|
|
expand.right,
|
|
|
|
expand.top,
|
|
|
|
expand.bottom,
|
2023-01-15 17:28:12 +00:00
|
|
|
mask_filter.__name__,
|
|
|
|
noise_source.__name__,
|
2023-01-17 23:50:36 +00:00
|
|
|
strength,
|
2023-01-18 14:41:02 +00:00
|
|
|
fill_color,
|
2023-01-16 01:33:40 +00:00
|
|
|
)
|
|
|
|
)
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info("inpaint output saved: %s", output)
|
2023-01-13 01:36:43 +00:00
|
|
|
|
2023-01-16 01:33:40 +00:00
|
|
|
source_image.thumbnail((size.width, size.height))
|
|
|
|
mask_image.thumbnail((size.width, size.height))
|
2023-01-15 15:21:09 +00:00
|
|
|
executor.submit_stored(
|
2023-01-16 13:42:10 +00:00
|
|
|
output,
|
2023-01-15 15:21:09 +00:00
|
|
|
run_inpaint_pipeline,
|
2023-01-16 13:31:42 +00:00
|
|
|
context,
|
2023-01-16 01:33:40 +00:00
|
|
|
params,
|
|
|
|
size,
|
|
|
|
output,
|
2023-01-16 19:12:08 +00:00
|
|
|
upscale,
|
2023-01-15 15:21:09 +00:00
|
|
|
source_image,
|
|
|
|
mask_image,
|
2023-01-16 01:33:40 +00:00
|
|
|
expand,
|
2023-01-15 15:21:09 +00:00
|
|
|
noise_source,
|
2023-01-17 23:50:36 +00:00
|
|
|
mask_filter,
|
2023-01-18 14:41:02 +00:00
|
|
|
strength,
|
|
|
|
fill_color)
|
2023-01-09 00:11:34 +00:00
|
|
|
|
2023-01-14 16:18:53 +00:00
|
|
|
return jsonify({
|
2023-01-16 13:42:10 +00:00
|
|
|
'output': output,
|
2023-01-16 01:33:40 +00:00
|
|
|
'params': params.tojson(),
|
2023-01-17 02:10:52 +00:00
|
|
|
'size': upscale.resize(size.add_border(expand)).tojson(),
|
2023-01-09 00:11:34 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
2023-01-17 05:45:54 +00:00
|
|
|
@app.route('/api/upscale', methods=['POST'])
|
|
|
|
def upscale():
|
2023-01-23 04:38:03 +00:00
|
|
|
if 'source' not in request.files:
|
|
|
|
return error_reply('source image is required')
|
|
|
|
|
2023-01-17 05:45:54 +00:00
|
|
|
source_file = request.files.get('source')
|
|
|
|
source_image = Image.open(BytesIO(source_file.read())).convert('RGB')
|
|
|
|
|
|
|
|
params, size = pipeline_from_request()
|
2023-01-22 22:35:53 +00:00
|
|
|
upscale = upscale_from_request(params.provider)
|
2023-01-17 05:45:54 +00:00
|
|
|
|
|
|
|
output = make_output_name(
|
2023-01-17 23:50:36 +00:00
|
|
|
'upscale',
|
2023-01-17 05:45:54 +00:00
|
|
|
params,
|
2023-01-17 23:50:36 +00:00
|
|
|
size)
|
2023-01-28 23:09:19 +00:00
|
|
|
logger.info("upscale output: %s", output)
|
2023-01-17 05:45:54 +00:00
|
|
|
|
|
|
|
source_image.thumbnail((size.width, size.height))
|
|
|
|
executor.submit_stored(output, run_upscale_pipeline,
|
2023-01-18 03:53:44 +00:00
|
|
|
context, params, size, output, upscale, source_image)
|
2023-01-17 05:45:54 +00:00
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
'output': output,
|
|
|
|
'params': params.tojson(),
|
|
|
|
'size': upscale.resize(size).tojson(),
|
|
|
|
})
|
|
|
|
|
|
|
|
|
2023-01-27 23:08:36 +00:00
|
|
|
@app.route('/api/chain', methods=['POST'])
|
|
|
|
def chain():
|
2023-01-29 04:31:34 +00:00
|
|
|
data = request.json
|
|
|
|
|
|
|
|
with open('./schema.yaml', 'r') as f:
|
|
|
|
schema = yaml.safe_load(f.read())
|
|
|
|
|
|
|
|
logger.info('validating chain request: %s against %s', data, schema)
|
|
|
|
validate(data, schema)
|
|
|
|
|
|
|
|
# get defaults from the regular parameters
|
2023-01-28 14:37:17 +00:00
|
|
|
params, size = pipeline_from_request()
|
2023-01-28 15:08:59 +00:00
|
|
|
output = make_output_name('chain', params, size)
|
2023-01-28 14:37:17 +00:00
|
|
|
|
2023-01-29 04:31:34 +00:00
|
|
|
pipeline = ChainPipeline()
|
|
|
|
for stage_data in data.get('stages', []):
|
|
|
|
callback = chain_stages[stage_data.get('type')]
|
|
|
|
kwargs = stage_data.get('params', {})
|
2023-01-30 00:42:05 +00:00
|
|
|
logger.info('request stage: %s, %s', callback.__name__, kwargs)
|
2023-01-29 04:31:34 +00:00
|
|
|
|
|
|
|
stage = StageParams(
|
|
|
|
stage_data.get('name', callback.__name__),
|
2023-01-29 05:06:25 +00:00
|
|
|
tile_size=get_size(kwargs.get('tile_size')),
|
|
|
|
outscale=get_and_clamp_int(kwargs,'outscale', 1, 4),
|
2023-01-29 04:31:34 +00:00
|
|
|
)
|
2023-01-29 04:48:53 +00:00
|
|
|
|
|
|
|
if 'border' in kwargs:
|
|
|
|
border = Border.even(int(kwargs.get('border')))
|
|
|
|
kwargs['border'] = border
|
|
|
|
|
|
|
|
if 'upscale' in kwargs:
|
2023-01-29 04:52:39 +00:00
|
|
|
upscale = UpscaleParams(kwargs.get('upscale'), params.provider)
|
2023-01-29 04:48:53 +00:00
|
|
|
kwargs['upscale'] = upscale
|
|
|
|
|
2023-01-29 04:31:34 +00:00
|
|
|
pipeline.append((callback, stage, kwargs))
|
2023-01-28 14:37:17 +00:00
|
|
|
|
2023-01-29 05:50:41 +00:00
|
|
|
logger.info('running chain pipeline with %s stages', len(pipeline.stages))
|
|
|
|
|
2023-01-28 15:08:59 +00:00
|
|
|
# build and run chain pipeline
|
2023-01-29 04:31:34 +00:00
|
|
|
fake_source = Image.new('RGB', (1, 1))
|
|
|
|
executor.submit_stored(output, pipeline, context,
|
|
|
|
params, fake_source, output=output, size=size)
|
2023-01-28 14:37:17 +00:00
|
|
|
|
2023-01-28 15:08:59 +00:00
|
|
|
return jsonify({
|
|
|
|
'output': output,
|
|
|
|
'params': params.tojson(),
|
2023-01-28 15:15:02 +00:00
|
|
|
'size': size.tojson(),
|
2023-01-28 15:08:59 +00:00
|
|
|
})
|
2023-01-27 23:08:36 +00:00
|
|
|
|
|
|
|
|
2023-01-13 04:10:46 +00:00
|
|
|
@app.route('/api/ready')
|
2023-01-13 01:56:41 +00:00
|
|
|
def ready():
|
|
|
|
output_file = request.args.get('output', None)
|
2023-01-23 04:25:00 +00:00
|
|
|
|
2023-01-15 17:43:47 +00:00
|
|
|
done = executor.futures.done(output_file)
|
|
|
|
|
2023-01-23 04:25:00 +00:00
|
|
|
if done is None:
|
2023-01-27 23:08:36 +00:00
|
|
|
file = base_join(context.output_path, output_file)
|
2023-01-23 04:25:00 +00:00
|
|
|
if path.exists(file):
|
2023-01-23 04:38:03 +00:00
|
|
|
return ready_reply(True)
|
|
|
|
|
2023-01-23 04:25:00 +00:00
|
|
|
elif done == True:
|
2023-01-15 17:43:47 +00:00
|
|
|
executor.futures.pop(output_file)
|
2023-01-13 01:56:41 +00:00
|
|
|
|
2023-01-23 04:38:03 +00:00
|
|
|
return ready_reply(done)
|
2023-01-13 01:36:43 +00:00
|
|
|
|
|
|
|
|
2023-01-22 01:44:54 +00:00
|
|
|
@app.route('/output/<path:filename>')
|
2023-01-10 05:26:47 +00:00
|
|
|
def output(filename: str):
|
2023-01-16 22:39:30 +00:00
|
|
|
return send_from_directory(path.join('..', context.output_path), filename, as_attachment=False)
|