michaelj commited on
Commit
360d274
1 Parent(s): db5acaf

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. __init__.py +0 -0
  2. __pycache__/app_settings.cpython-310.pyc +0 -0
  3. __pycache__/constants.cpython-310.pyc +0 -0
  4. __pycache__/context.cpython-310.pyc +0 -0
  5. __pycache__/image_ops.cpython-310.pyc +0 -0
  6. __pycache__/paths.cpython-310.pyc +0 -0
  7. __pycache__/state.cpython-310.pyc +0 -0
  8. __pycache__/utils.cpython-310.pyc +0 -0
  9. app.py +161 -0
  10. app_settings.py +89 -0
  11. backend/__init__.py +0 -0
  12. backend/__pycache__/__init__.cpython-310.pyc +0 -0
  13. backend/__pycache__/device.cpython-310.pyc +0 -0
  14. backend/__pycache__/image_saver.cpython-310.pyc +0 -0
  15. backend/__pycache__/lcm_text_to_image.cpython-310.pyc +0 -0
  16. backend/__pycache__/tiny_decoder.cpython-310.pyc +0 -0
  17. backend/device.py +23 -0
  18. backend/image_saver.py +40 -0
  19. backend/lcm_text_to_image.py +352 -0
  20. backend/models/__pycache__/lcmdiffusion_setting.cpython-310.pyc +0 -0
  21. backend/models/lcmdiffusion_setting.py +39 -0
  22. backend/openvino/__pycache__/custom_ov_model_vae_decoder.cpython-310.pyc +0 -0
  23. backend/openvino/__pycache__/pipelines.cpython-310.pyc +0 -0
  24. backend/openvino/custom_ov_model_vae_decoder.py +21 -0
  25. backend/openvino/pipelines.py +75 -0
  26. backend/pipelines/__pycache__/lcm.cpython-310.pyc +0 -0
  27. backend/pipelines/__pycache__/lcm_lora.cpython-310.pyc +0 -0
  28. backend/pipelines/lcm.py +90 -0
  29. backend/pipelines/lcm_lora.py +25 -0
  30. backend/tiny_decoder.py +30 -0
  31. constants.py +18 -0
  32. context.py +46 -0
  33. frontend/__pycache__/utils.cpython-310.pyc +0 -0
  34. frontend/gui/app_window.py +604 -0
  35. frontend/gui/image_generator_worker.py +37 -0
  36. frontend/gui/ui.py +15 -0
  37. frontend/utils.py +54 -0
  38. frontend/webui/__pycache__/generation_settings_ui.cpython-310.pyc +0 -0
  39. frontend/webui/__pycache__/image_to_image_ui.cpython-310.pyc +0 -0
  40. frontend/webui/__pycache__/models_ui.cpython-310.pyc +0 -0
  41. frontend/webui/__pycache__/text_to_image_ui.cpython-310.pyc +0 -0
  42. frontend/webui/__pycache__/ui.cpython-310.pyc +0 -0
  43. frontend/webui/css/style.css +22 -0
  44. frontend/webui/generation_settings_ui.py +140 -0
  45. frontend/webui/image_to_image_ui.py +124 -0
  46. frontend/webui/models_ui.py +85 -0
  47. frontend/webui/realtime_ui.py +144 -0
  48. frontend/webui/text_to_image_ui.py +104 -0
  49. frontend/webui/ui.py +70 -0
  50. image_ops.py +15 -0
__init__.py ADDED
File without changes
__pycache__/app_settings.cpython-310.pyc CHANGED
Binary files a/__pycache__/app_settings.cpython-310.pyc and b/__pycache__/app_settings.cpython-310.pyc differ
 
__pycache__/constants.cpython-310.pyc CHANGED
Binary files a/__pycache__/constants.cpython-310.pyc and b/__pycache__/constants.cpython-310.pyc differ
 
__pycache__/context.cpython-310.pyc CHANGED
Binary files a/__pycache__/context.cpython-310.pyc and b/__pycache__/context.cpython-310.pyc differ
 
__pycache__/image_ops.cpython-310.pyc CHANGED
Binary files a/__pycache__/image_ops.cpython-310.pyc and b/__pycache__/image_ops.cpython-310.pyc differ
 
__pycache__/paths.cpython-310.pyc CHANGED
Binary files a/__pycache__/paths.cpython-310.pyc and b/__pycache__/paths.cpython-310.pyc differ
 
__pycache__/state.cpython-310.pyc CHANGED
Binary files a/__pycache__/state.cpython-310.pyc and b/__pycache__/state.cpython-310.pyc differ
 
__pycache__/utils.cpython-310.pyc CHANGED
Binary files a/__pycache__/utils.cpython-310.pyc and b/__pycache__/utils.cpython-310.pyc differ
 
app.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app_settings import AppSettings
2
+ from utils import show_system_info
3
+ import constants
4
+ from argparse import ArgumentParser
5
+ from context import Context
6
+ from constants import APP_VERSION, LCM_DEFAULT_MODEL_OPENVINO
7
+ from models.interface_types import InterfaceType
8
+ from constants import DEVICE
9
+
10
+ parser = ArgumentParser(description=f"FAST SD CPU {constants.APP_VERSION}")
11
+ parser.add_argument(
12
+ "-s",
13
+ "--share",
14
+ action="store_true",
15
+ help="Create sharable link(Web UI)",
16
+ required=False,
17
+ )
18
+ group = parser.add_mutually_exclusive_group(required=False)
19
+ group.add_argument(
20
+ "-g",
21
+ "--gui",
22
+ action="store_true",
23
+ help="Start desktop GUI",
24
+ )
25
+ group.add_argument(
26
+ "-w",
27
+ "--webui",
28
+ action="store_true",
29
+ help="Start Web UI",
30
+ )
31
+ group.add_argument(
32
+ "-r",
33
+ "--realtime",
34
+ action="store_true",
35
+ help="Start realtime inference UI(experimental)",
36
+ )
37
+ group.add_argument(
38
+ "-v",
39
+ "--version",
40
+ action="store_true",
41
+ help="Version",
42
+ )
43
+ parser.add_argument(
44
+ "--lcm_model_id",
45
+ type=str,
46
+ help="Model ID or path,Default SimianLuo/LCM_Dreamshaper_v7",
47
+ default="SimianLuo/LCM_Dreamshaper_v7",
48
+ )
49
+ parser.add_argument(
50
+ "--prompt",
51
+ type=str,
52
+ help="Describe the image you want to generate",
53
+ )
54
+ parser.add_argument(
55
+ "--image_height",
56
+ type=int,
57
+ help="Height of the image",
58
+ default=512,
59
+ )
60
+ parser.add_argument(
61
+ "--image_width",
62
+ type=int,
63
+ help="Width of the image",
64
+ default=512,
65
+ )
66
+ parser.add_argument(
67
+ "--inference_steps",
68
+ type=int,
69
+ help="Number of steps,default : 4",
70
+ default=4,
71
+ )
72
+ parser.add_argument(
73
+ "--guidance_scale",
74
+ type=int,
75
+ help="Guidance scale,default : 1.0",
76
+ default=1.0,
77
+ )
78
+
79
+ parser.add_argument(
80
+ "--number_of_images",
81
+ type=int,
82
+ help="Number of images to generate ,default : 1",
83
+ default=1,
84
+ )
85
+ parser.add_argument(
86
+ "--seed",
87
+ type=int,
88
+ help="Seed,default : -1 (disabled) ",
89
+ default=-1,
90
+ )
91
+ parser.add_argument(
92
+ "--use_openvino",
93
+ action="store_true",
94
+ help="Use OpenVINO model",
95
+ )
96
+
97
+ parser.add_argument(
98
+ "--use_offline_model",
99
+ action="store_true",
100
+ help="Use offline model",
101
+ )
102
+ parser.add_argument(
103
+ "--use_safety_checker",
104
+ action="store_false",
105
+ help="Use safety checker",
106
+ )
107
+ parser.add_argument(
108
+ "--use_lcm_lora",
109
+ action="store_true",
110
+ help="Use LCM-LoRA",
111
+ )
112
+ parser.add_argument(
113
+ "--base_model_id",
114
+ type=str,
115
+ help="LCM LoRA base model ID,Default Lykon/dreamshaper-8",
116
+ default="Lykon/dreamshaper-8",
117
+ )
118
+ parser.add_argument(
119
+ "--lcm_lora_id",
120
+ type=str,
121
+ help="LCM LoRA model ID,Default latent-consistency/lcm-lora-sdv1-5",
122
+ default="latent-consistency/lcm-lora-sdv1-5",
123
+ )
124
+ parser.add_argument(
125
+ "-i",
126
+ "--interactive",
127
+ action="store_true",
128
+ help="Interactive CLI mode",
129
+ )
130
+ parser.add_argument(
131
+ "--use_tiny_auto_encoder",
132
+ action="store_true",
133
+ help="Use tiny auto encoder for SD (TAESD)",
134
+ )
135
+ args = parser.parse_args()
136
+
137
+ if args.version:
138
+ print(APP_VERSION)
139
+ exit()
140
+
141
+ # parser.print_help()
142
+ show_system_info()
143
+ print(f"Using device : {constants.DEVICE}")
144
+ app_settings = AppSettings()
145
+ app_settings.load()
146
+ print(
147
+ f"Found {len(app_settings.stable_diffsuion_models)} stable diffusion models in config/stable-diffusion-models.txt"
148
+ )
149
+ print(
150
+ f"Found {len(app_settings.lcm_lora_models)} LCM-LoRA models in config/lcm-lora-models.txt"
151
+ )
152
+ print(
153
+ f"Found {len(app_settings.openvino_lcm_models)} OpenVINO LCM models in config/openvino-lcm-models.txt"
154
+ )
155
+
156
+ from frontend.webui.ui import start_webui
157
+
158
+ print("Starting web UI mode")
159
+ start_webui(
160
+ args.share,
161
+ )
app_settings.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yaml
2
+ from os import path, makedirs
3
+ from models.settings import Settings
4
+ from paths import FastStableDiffusionPaths
5
+ from utils import get_models_from_text_file
6
+ from constants import (
7
+ OPENVINO_LCM_MODELS_FILE,
8
+ LCM_LORA_MODELS_FILE,
9
+ SD_MODELS_FILE,
10
+ LCM_MODELS_FILE,
11
+ )
12
+ from copy import deepcopy
13
+
14
+
15
+ class AppSettings:
16
+ def __init__(self):
17
+ self.config_path = FastStableDiffusionPaths().get_app_settings_path()
18
+ self._stable_diffsuion_models = get_models_from_text_file(
19
+ FastStableDiffusionPaths().get_models_config_path(SD_MODELS_FILE)
20
+ )
21
+ self._lcm_lora_models = get_models_from_text_file(
22
+ FastStableDiffusionPaths().get_models_config_path(LCM_LORA_MODELS_FILE)
23
+ )
24
+ self._openvino_lcm_models = get_models_from_text_file(
25
+ FastStableDiffusionPaths().get_models_config_path(OPENVINO_LCM_MODELS_FILE)
26
+ )
27
+ self._lcm_models = get_models_from_text_file(
28
+ FastStableDiffusionPaths().get_models_config_path(LCM_MODELS_FILE)
29
+ )
30
+
31
+ @property
32
+ def settings(self):
33
+ return self._config
34
+
35
+ @property
36
+ def stable_diffsuion_models(self):
37
+ return self._stable_diffsuion_models
38
+
39
+ @property
40
+ def openvino_lcm_models(self):
41
+ return self._openvino_lcm_models
42
+
43
+ @property
44
+ def lcm_models(self):
45
+ return self._lcm_models
46
+
47
+ @property
48
+ def lcm_lora_models(self):
49
+ return self._lcm_lora_models
50
+
51
+ def load(self, skip_file=False):
52
+ if skip_file:
53
+ print("Skipping config file")
54
+ settings_dict = self._load_default()
55
+ self._config = Settings.parse_obj(settings_dict)
56
+ else:
57
+ if not path.exists(self.config_path):
58
+ base_dir = path.dirname(self.config_path)
59
+ if not path.exists(base_dir):
60
+ makedirs(base_dir)
61
+ try:
62
+ print("Settings not found creating default settings")
63
+ with open(self.config_path, "w") as file:
64
+ yaml.dump(
65
+ self._load_default(),
66
+ file,
67
+ )
68
+ except Exception as ex:
69
+ print(f"Error in creating settings : {ex}")
70
+ exit()
71
+ try:
72
+ with open(self.config_path) as file:
73
+ settings_dict = yaml.safe_load(file)
74
+ self._config = Settings.parse_obj(settings_dict)
75
+ except Exception as ex:
76
+ print(f"Error in loading settings : {ex}")
77
+
78
+ def save(self):
79
+ try:
80
+ with open(self.config_path, "w") as file:
81
+ tmp_cfg = deepcopy(self._config)
82
+ tmp_cfg.lcm_diffusion_setting.init_image = None
83
+ yaml.dump(tmp_cfg.dict(), file)
84
+ except Exception as ex:
85
+ print(f"Error in saving settings : {ex}")
86
+
87
+ def _load_default(self) -> dict:
88
+ defult_config = Settings()
89
+ return defult_config.dict()
backend/__init__.py ADDED
File without changes
backend/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (138 Bytes). View file
 
backend/__pycache__/device.cpython-310.pyc ADDED
Binary file (817 Bytes). View file
 
backend/__pycache__/image_saver.cpython-310.pyc ADDED
Binary file (1.27 kB). View file
 
backend/__pycache__/lcm_text_to_image.cpython-310.pyc ADDED
Binary file (6.4 kB). View file
 
backend/__pycache__/tiny_decoder.cpython-310.pyc ADDED
Binary file (878 Bytes). View file
 
backend/device.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import platform
2
+ from constants import DEVICE
3
+ import torch
4
+ import openvino as ov
5
+
6
+ core = ov.Core()
7
+
8
+
9
+ def is_openvino_device() -> bool:
10
+ if DEVICE.lower() == "cpu" or DEVICE.lower()[0] == "g":
11
+ return True
12
+ else:
13
+ return False
14
+
15
+
16
+ def get_device_name() -> str:
17
+ if DEVICE == "cuda" or DEVICE == "mps":
18
+ default_gpu_index = torch.cuda.current_device()
19
+ return torch.cuda.get_device_name(default_gpu_index)
20
+ elif platform.system().lower() == "darwin":
21
+ return platform.processor()
22
+ elif is_openvino_device():
23
+ return core.get_property(DEVICE.upper(), "FULL_DEVICE_NAME")
backend/image_saver.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from os import path, mkdir
2
+ from typing import Any
3
+ from uuid import uuid4
4
+ from backend.models.lcmdiffusion_setting import LCMDiffusionSetting
5
+ import json
6
+
7
+
8
+ class ImageSaver:
9
+ @staticmethod
10
+ def save_images(
11
+ output_path: str,
12
+ images: Any,
13
+ folder_name: str = "",
14
+ format: str = ".png",
15
+ lcm_diffusion_setting: LCMDiffusionSetting = None,
16
+ ) -> None:
17
+ gen_id = uuid4()
18
+
19
+ for index, image in enumerate(images):
20
+ if not path.exists(output_path):
21
+ mkdir(output_path)
22
+
23
+ if folder_name:
24
+ out_path = path.join(
25
+ output_path,
26
+ folder_name,
27
+ )
28
+ else:
29
+ out_path = output_path
30
+
31
+ if not path.exists(out_path):
32
+ mkdir(out_path)
33
+ image.save(path.join(out_path, f"{gen_id}-{index+1}{format}"))
34
+ if lcm_diffusion_setting:
35
+ with open(path.join(out_path, f"{gen_id}.json"), "w") as json_file:
36
+ json.dump(
37
+ lcm_diffusion_setting.model_dump(exclude="init_image"),
38
+ json_file,
39
+ indent=4,
40
+ )
backend/lcm_text_to_image.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ from diffusers import LCMScheduler
3
+ import torch
4
+ from backend.models.lcmdiffusion_setting import LCMDiffusionSetting
5
+ import numpy as np
6
+ from constants import DEVICE
7
+ from backend.models.lcmdiffusion_setting import LCMLora
8
+ from backend.device import is_openvino_device
9
+ from backend.openvino.pipelines import (
10
+ get_ov_text_to_image_pipeline,
11
+ ov_load_taesd,
12
+ get_ov_image_to_image_pipeline,
13
+ )
14
+ from backend.pipelines.lcm import (
15
+ get_lcm_model_pipeline,
16
+ load_taesd,
17
+ get_image_to_image_pipeline,
18
+ )
19
+ from backend.pipelines.lcm_lora import get_lcm_lora_pipeline
20
+ from backend.models.lcmdiffusion_setting import DiffusionTask
21
+ from image_ops import resize_pil_image
22
+ from math import ceil
23
+
24
+
25
+ class LCMTextToImage:
26
+ def __init__(
27
+ self,
28
+ device: str = "cpu",
29
+ ) -> None:
30
+ self.pipeline = None
31
+ self.use_openvino = False
32
+ self.device = ""
33
+ self.previous_model_id = None
34
+ self.previous_use_tae_sd = False
35
+ self.previous_use_lcm_lora = False
36
+ self.previous_ov_model_id = ""
37
+ self.previous_safety_checker = False
38
+ self.previous_use_openvino = False
39
+ self.img_to_img_pipeline = None
40
+ self.is_openvino_init = False
41
+ self.torch_data_type = (
42
+ torch.float32 if is_openvino_device() or DEVICE == "mps" else torch.float16
43
+ )
44
+ print(f"Torch datatype : {self.torch_data_type}")
45
+
46
+ def _pipeline_to_device(self):
47
+ print(f"Pipeline device : {DEVICE}")
48
+ print(f"Pipeline dtype : {self.torch_data_type}")
49
+ self.pipeline.to(
50
+ torch_device=DEVICE,
51
+ torch_dtype=self.torch_data_type,
52
+ )
53
+
54
+ def _add_freeu(self):
55
+ pipeline_class = self.pipeline.__class__.__name__
56
+ if isinstance(self.pipeline.scheduler, LCMScheduler):
57
+ if pipeline_class == "StableDiffusionPipeline":
58
+ print("Add FreeU - SD")
59
+ self.pipeline.enable_freeu(
60
+ s1=0.9,
61
+ s2=0.2,
62
+ b1=1.2,
63
+ b2=1.4,
64
+ )
65
+ elif pipeline_class == "StableDiffusionXLPipeline":
66
+ print("Add FreeU - SDXL")
67
+ self.pipeline.enable_freeu(
68
+ s1=0.6,
69
+ s2=0.4,
70
+ b1=1.1,
71
+ b2=1.2,
72
+ )
73
+
74
+ def _update_lcm_scheduler_params(self):
75
+ if isinstance(self.pipeline.scheduler, LCMScheduler):
76
+ self.pipeline.scheduler = LCMScheduler.from_config(
77
+ self.pipeline.scheduler.config,
78
+ beta_start=0.001,
79
+ beta_end=0.01,
80
+ )
81
+
82
+ def init(
83
+ self,
84
+ device: str = "cpu",
85
+ lcm_diffusion_setting: LCMDiffusionSetting = LCMDiffusionSetting(),
86
+ ) -> None:
87
+ self.device = device
88
+ self.use_openvino = lcm_diffusion_setting.use_openvino
89
+ model_id = lcm_diffusion_setting.lcm_model_id
90
+ use_local_model = lcm_diffusion_setting.use_offline_model
91
+ use_tiny_auto_encoder = lcm_diffusion_setting.use_tiny_auto_encoder
92
+ use_lora = lcm_diffusion_setting.use_lcm_lora
93
+ lcm_lora: LCMLora = lcm_diffusion_setting.lcm_lora
94
+ ov_model_id = lcm_diffusion_setting.openvino_lcm_model_id
95
+
96
+ if lcm_diffusion_setting.diffusion_task == DiffusionTask.image_to_image.value:
97
+ lcm_diffusion_setting.init_image = resize_pil_image(
98
+ lcm_diffusion_setting.init_image,
99
+ lcm_diffusion_setting.image_width,
100
+ lcm_diffusion_setting.image_height,
101
+ )
102
+
103
+ if (
104
+ self.pipeline is None
105
+ or self.previous_model_id != model_id
106
+ or self.previous_use_tae_sd != use_tiny_auto_encoder
107
+ or self.previous_lcm_lora_base_id != lcm_lora.base_model_id
108
+ or self.previous_lcm_lora_id != lcm_lora.lcm_lora_id
109
+ or self.previous_use_lcm_lora != use_lora
110
+ or self.previous_ov_model_id != ov_model_id
111
+ or self.previous_safety_checker != lcm_diffusion_setting.use_safety_checker
112
+ or self.previous_use_openvino != lcm_diffusion_setting.use_openvino
113
+ ):
114
+ if self.use_openvino and is_openvino_device():
115
+ if self.pipeline:
116
+ del self.pipeline
117
+ self.pipeline = None
118
+ self.is_openvino_init = True
119
+ if (
120
+ lcm_diffusion_setting.diffusion_task
121
+ == DiffusionTask.text_to_image.value
122
+ ):
123
+ print(f"***** Init Text to image (OpenVINO) - {ov_model_id} *****")
124
+ self.pipeline = get_ov_text_to_image_pipeline(
125
+ ov_model_id,
126
+ use_local_model,
127
+ )
128
+ elif (
129
+ lcm_diffusion_setting.diffusion_task
130
+ == DiffusionTask.image_to_image.value
131
+ ):
132
+ print(f"***** Image to image (OpenVINO) - {ov_model_id} *****")
133
+ self.pipeline = get_ov_image_to_image_pipeline(
134
+ ov_model_id,
135
+ use_local_model,
136
+ )
137
+ else:
138
+ if self.pipeline:
139
+ del self.pipeline
140
+ self.pipeline = None
141
+ if self.img_to_img_pipeline:
142
+ del self.img_to_img_pipeline
143
+ self.img_to_img_pipeline = None
144
+
145
+ if use_lora:
146
+ print(
147
+ f"***** Init LCM-LoRA pipeline - {lcm_lora.base_model_id} *****"
148
+ )
149
+ self.pipeline = get_lcm_lora_pipeline(
150
+ lcm_lora.base_model_id,
151
+ lcm_lora.lcm_lora_id,
152
+ use_local_model,
153
+ torch_data_type=self.torch_data_type,
154
+ )
155
+ else:
156
+ print(f"***** Init LCM Model pipeline - {model_id} *****")
157
+ self.pipeline = get_lcm_model_pipeline(
158
+ model_id,
159
+ use_local_model,
160
+ )
161
+
162
+ if (
163
+ lcm_diffusion_setting.diffusion_task
164
+ == DiffusionTask.image_to_image.value
165
+ ):
166
+ self.img_to_img_pipeline = get_image_to_image_pipeline(
167
+ self.pipeline
168
+ )
169
+ self._pipeline_to_device()
170
+
171
+ if use_tiny_auto_encoder:
172
+ if self.use_openvino and is_openvino_device():
173
+ print("Using Tiny Auto Encoder (OpenVINO)")
174
+ ov_load_taesd(
175
+ self.pipeline,
176
+ use_local_model,
177
+ )
178
+ else:
179
+ print("Using Tiny Auto Encoder")
180
+ if (
181
+ lcm_diffusion_setting.diffusion_task
182
+ == DiffusionTask.text_to_image.value
183
+ ):
184
+ load_taesd(
185
+ self.pipeline,
186
+ use_local_model,
187
+ self.torch_data_type,
188
+ )
189
+ elif (
190
+ lcm_diffusion_setting.diffusion_task
191
+ == DiffusionTask.image_to_image.value
192
+ ):
193
+ load_taesd(
194
+ self.img_to_img_pipeline,
195
+ use_local_model,
196
+ self.torch_data_type,
197
+ )
198
+
199
+ if (
200
+ lcm_diffusion_setting.diffusion_task
201
+ == DiffusionTask.image_to_image.value
202
+ and lcm_diffusion_setting.use_openvino
203
+ ):
204
+ self.pipeline.scheduler = LCMScheduler.from_config(
205
+ self.pipeline.scheduler.config,
206
+ )
207
+ else:
208
+ self._update_lcm_scheduler_params()
209
+
210
+ if use_lora:
211
+ self._add_freeu()
212
+
213
+ self.previous_model_id = model_id
214
+ self.previous_ov_model_id = ov_model_id
215
+ self.previous_use_tae_sd = use_tiny_auto_encoder
216
+ self.previous_lcm_lora_base_id = lcm_lora.base_model_id
217
+ self.previous_lcm_lora_id = lcm_lora.lcm_lora_id
218
+ self.previous_use_lcm_lora = use_lora
219
+ self.previous_safety_checker = lcm_diffusion_setting.use_safety_checker
220
+ self.previous_use_openvino = lcm_diffusion_setting.use_openvino
221
+ if (
222
+ lcm_diffusion_setting.diffusion_task
223
+ == DiffusionTask.text_to_image.value
224
+ ):
225
+ print(f"Pipeline : {self.pipeline}")
226
+ elif (
227
+ lcm_diffusion_setting.diffusion_task
228
+ == DiffusionTask.image_to_image.value
229
+ ):
230
+ if self.use_openvino and is_openvino_device():
231
+ print(f"Pipeline : {self.pipeline}")
232
+ else:
233
+ print(f"Pipeline : {self.img_to_img_pipeline}")
234
+
235
+ def generate(
236
+ self,
237
+ lcm_diffusion_setting: LCMDiffusionSetting,
238
+ reshape: bool = False,
239
+ ) -> Any:
240
+ guidance_scale = lcm_diffusion_setting.guidance_scale
241
+ img_to_img_inference_steps = lcm_diffusion_setting.inference_steps
242
+ check_step_value = int(
243
+ lcm_diffusion_setting.inference_steps * lcm_diffusion_setting.strength
244
+ )
245
+ if (
246
+ lcm_diffusion_setting.diffusion_task == DiffusionTask.image_to_image.value
247
+ and check_step_value < 1
248
+ ):
249
+ img_to_img_inference_steps = ceil(1 / lcm_diffusion_setting.strength)
250
+ print(
251
+ f"Strength: {lcm_diffusion_setting.strength},{img_to_img_inference_steps}"
252
+ )
253
+
254
+ if lcm_diffusion_setting.use_seed:
255
+ cur_seed = lcm_diffusion_setting.seed
256
+ if self.use_openvino:
257
+ np.random.seed(cur_seed)
258
+ else:
259
+ torch.manual_seed(cur_seed)
260
+
261
+ is_openvino_pipe = lcm_diffusion_setting.use_openvino and is_openvino_device()
262
+ if is_openvino_pipe:
263
+ print("Using OpenVINO")
264
+ if reshape and not self.is_openvino_init:
265
+ print("Reshape and compile")
266
+ self.pipeline.reshape(
267
+ batch_size=-1,
268
+ height=lcm_diffusion_setting.image_height,
269
+ width=lcm_diffusion_setting.image_width,
270
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
271
+ )
272
+ self.pipeline.compile()
273
+
274
+ if self.is_openvino_init:
275
+ self.is_openvino_init = False
276
+
277
+ if not lcm_diffusion_setting.use_safety_checker:
278
+ self.pipeline.safety_checker = None
279
+ if (
280
+ lcm_diffusion_setting.diffusion_task
281
+ == DiffusionTask.image_to_image.value
282
+ and not is_openvino_pipe
283
+ ):
284
+ self.img_to_img_pipeline.safety_checker = None
285
+
286
+ if (
287
+ not lcm_diffusion_setting.use_lcm_lora
288
+ and not lcm_diffusion_setting.use_openvino
289
+ and lcm_diffusion_setting.guidance_scale != 1.0
290
+ ):
291
+ print("Not using LCM-LoRA so setting guidance_scale 1.0")
292
+ guidance_scale = 1.0
293
+
294
+ if lcm_diffusion_setting.use_openvino:
295
+ if (
296
+ lcm_diffusion_setting.diffusion_task
297
+ == DiffusionTask.text_to_image.value
298
+ ):
299
+ result_images = self.pipeline(
300
+ prompt=lcm_diffusion_setting.prompt,
301
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
302
+ num_inference_steps=lcm_diffusion_setting.inference_steps,
303
+ guidance_scale=guidance_scale,
304
+ width=lcm_diffusion_setting.image_width,
305
+ height=lcm_diffusion_setting.image_height,
306
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
307
+ ).images
308
+ elif (
309
+ lcm_diffusion_setting.diffusion_task
310
+ == DiffusionTask.image_to_image.value
311
+ ):
312
+ result_images = self.pipeline(
313
+ image=lcm_diffusion_setting.init_image,
314
+ strength=lcm_diffusion_setting.strength,
315
+ prompt=lcm_diffusion_setting.prompt,
316
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
317
+ num_inference_steps=img_to_img_inference_steps * 3,
318
+ guidance_scale=guidance_scale,
319
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
320
+ ).images
321
+
322
+ else:
323
+ if (
324
+ lcm_diffusion_setting.diffusion_task
325
+ == DiffusionTask.text_to_image.value
326
+ ):
327
+ result_images = self.pipeline(
328
+ prompt=lcm_diffusion_setting.prompt,
329
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
330
+ num_inference_steps=lcm_diffusion_setting.inference_steps,
331
+ guidance_scale=guidance_scale,
332
+ width=lcm_diffusion_setting.image_width,
333
+ height=lcm_diffusion_setting.image_height,
334
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
335
+ ).images
336
+ elif (
337
+ lcm_diffusion_setting.diffusion_task
338
+ == DiffusionTask.image_to_image.value
339
+ ):
340
+ result_images = self.img_to_img_pipeline(
341
+ image=lcm_diffusion_setting.init_image,
342
+ strength=lcm_diffusion_setting.strength,
343
+ prompt=lcm_diffusion_setting.prompt,
344
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
345
+ num_inference_steps=img_to_img_inference_steps,
346
+ guidance_scale=guidance_scale,
347
+ width=lcm_diffusion_setting.image_width,
348
+ height=lcm_diffusion_setting.image_height,
349
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
350
+ ).images
351
+
352
+ return result_images
backend/models/__pycache__/lcmdiffusion_setting.cpython-310.pyc ADDED
Binary file (1.87 kB). View file
 
backend/models/lcmdiffusion_setting.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional, Any
2
+ from enum import Enum
3
+ from pydantic import BaseModel
4
+ from constants import LCM_DEFAULT_MODEL, LCM_DEFAULT_MODEL_OPENVINO
5
+
6
+
7
+ class LCMLora(BaseModel):
8
+ base_model_id: str = "Lykon/dreamshaper-8"
9
+ lcm_lora_id: str = "latent-consistency/lcm-lora-sdv1-5"
10
+
11
+
12
+ class DiffusionTask(str, Enum):
13
+ """Diffusion task types"""
14
+
15
+ text_to_image = "text_to_image"
16
+ image_to_image = "image_to_image"
17
+
18
+
19
+ class LCMDiffusionSetting(BaseModel):
20
+ lcm_model_id: str = LCM_DEFAULT_MODEL
21
+ openvino_lcm_model_id: str = LCM_DEFAULT_MODEL_OPENVINO
22
+ use_offline_model: bool = False
23
+ use_lcm_lora: bool = False
24
+ lcm_lora: Optional[LCMLora] = LCMLora()
25
+ use_tiny_auto_encoder: bool = False
26
+ use_openvino: bool = False
27
+ prompt: str = ""
28
+ negative_prompt: str = ""
29
+ init_image: Any = None
30
+ strength: Optional[float] = 0.6
31
+ image_height: Optional[int] = 512
32
+ image_width: Optional[int] = 512
33
+ inference_steps: Optional[int] = 1
34
+ guidance_scale: Optional[float] = 1
35
+ number_of_images: Optional[int] = 1
36
+ seed: Optional[int] = 123123
37
+ use_seed: bool = False
38
+ use_safety_checker: bool = False
39
+ diffusion_task: str = DiffusionTask.text_to_image.value
backend/openvino/__pycache__/custom_ov_model_vae_decoder.cpython-310.pyc ADDED
Binary file (772 Bytes). View file
 
backend/openvino/__pycache__/pipelines.cpython-310.pyc ADDED
Binary file (1.86 kB). View file
 
backend/openvino/custom_ov_model_vae_decoder.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from backend.device import is_openvino_device
2
+
3
+ if is_openvino_device():
4
+ from optimum.intel.openvino.modeling_diffusion import OVModelVaeDecoder
5
+
6
+
7
+ class CustomOVModelVaeDecoder(OVModelVaeDecoder):
8
+ def __init__(
9
+ self,
10
+ model,
11
+ parent_model,
12
+ ov_config=None,
13
+ model_dir=None,
14
+ ):
15
+ super(OVModelVaeDecoder, self).__init__(
16
+ model,
17
+ parent_model,
18
+ ov_config,
19
+ "vae_decoder",
20
+ model_dir,
21
+ )
backend/openvino/pipelines.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from constants import DEVICE, LCM_DEFAULT_MODEL_OPENVINO
2
+ from backend.tiny_decoder import get_tiny_decoder_vae_model
3
+ from typing import Any
4
+ from backend.device import is_openvino_device
5
+ from paths import get_base_folder_name
6
+
7
+ if is_openvino_device():
8
+ from huggingface_hub import snapshot_download
9
+ from optimum.intel.openvino.modeling_diffusion import OVBaseModel
10
+
11
+ from optimum.intel.openvino.modeling_diffusion import (
12
+ OVStableDiffusionPipeline,
13
+ OVStableDiffusionImg2ImgPipeline,
14
+ OVStableDiffusionXLPipeline,
15
+ OVStableDiffusionXLImg2ImgPipeline,
16
+ )
17
+ from backend.openvino.custom_ov_model_vae_decoder import CustomOVModelVaeDecoder
18
+
19
+
20
+ def ov_load_taesd(
21
+ pipeline: Any,
22
+ use_local_model: bool = False,
23
+ ):
24
+ taesd_dir = snapshot_download(
25
+ repo_id=get_tiny_decoder_vae_model(pipeline.__class__.__name__),
26
+ local_files_only=use_local_model,
27
+ )
28
+ pipeline.vae_decoder = CustomOVModelVaeDecoder(
29
+ model=OVBaseModel.load_model(f"{taesd_dir}/vae_decoder/openvino_model.xml"),
30
+ parent_model=pipeline,
31
+ model_dir=taesd_dir,
32
+ )
33
+
34
+
35
+ def get_ov_text_to_image_pipeline(
36
+ model_id: str = LCM_DEFAULT_MODEL_OPENVINO,
37
+ use_local_model: bool = False,
38
+ ) -> Any:
39
+ if "xl" in get_base_folder_name(model_id).lower():
40
+ pipeline = OVStableDiffusionXLPipeline.from_pretrained(
41
+ model_id,
42
+ local_files_only=use_local_model,
43
+ ov_config={"CACHE_DIR": ""},
44
+ device=DEVICE.upper(),
45
+ )
46
+ else:
47
+ pipeline = OVStableDiffusionPipeline.from_pretrained(
48
+ model_id,
49
+ local_files_only=use_local_model,
50
+ ov_config={"CACHE_DIR": ""},
51
+ device=DEVICE.upper(),
52
+ )
53
+
54
+ return pipeline
55
+
56
+
57
+ def get_ov_image_to_image_pipeline(
58
+ model_id: str = LCM_DEFAULT_MODEL_OPENVINO,
59
+ use_local_model: bool = False,
60
+ ) -> Any:
61
+ if "xl" in get_base_folder_name(model_id).lower():
62
+ pipeline = OVStableDiffusionXLImg2ImgPipeline.from_pretrained(
63
+ model_id,
64
+ local_files_only=use_local_model,
65
+ ov_config={"CACHE_DIR": ""},
66
+ device=DEVICE.upper(),
67
+ )
68
+ else:
69
+ pipeline = OVStableDiffusionImg2ImgPipeline.from_pretrained(
70
+ model_id,
71
+ local_files_only=use_local_model,
72
+ ov_config={"CACHE_DIR": ""},
73
+ device=DEVICE.upper(),
74
+ )
75
+ return pipeline
backend/pipelines/__pycache__/lcm.cpython-310.pyc ADDED
Binary file (2.1 kB). View file
 
backend/pipelines/__pycache__/lcm_lora.cpython-310.pyc ADDED
Binary file (867 Bytes). View file
 
backend/pipelines/lcm.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from constants import LCM_DEFAULT_MODEL
2
+ from diffusers import (
3
+ DiffusionPipeline,
4
+ AutoencoderTiny,
5
+ UNet2DConditionModel,
6
+ LCMScheduler,
7
+ )
8
+ import torch
9
+ from backend.tiny_decoder import get_tiny_decoder_vae_model
10
+ from typing import Any
11
+ from diffusers import (
12
+ LCMScheduler,
13
+ StableDiffusionImg2ImgPipeline,
14
+ StableDiffusionXLImg2ImgPipeline,
15
+ )
16
+
17
+
18
+ def _get_lcm_pipeline_from_base_model(
19
+ lcm_model_id: str,
20
+ base_model_id: str,
21
+ use_local_model: bool,
22
+ ):
23
+ pipeline = None
24
+ unet = UNet2DConditionModel.from_pretrained(
25
+ lcm_model_id,
26
+ torch_dtype=torch.float32,
27
+ local_files_only=use_local_model,
28
+ )
29
+ pipeline = DiffusionPipeline.from_pretrained(
30
+ base_model_id,
31
+ unet=unet,
32
+ torch_dtype=torch.float32,
33
+ local_files_only=use_local_model,
34
+ )
35
+ pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
36
+ return pipeline
37
+
38
+
39
+ def load_taesd(
40
+ pipeline: Any,
41
+ use_local_model: bool = False,
42
+ torch_data_type: torch.dtype = torch.float32,
43
+ ):
44
+ vae_model = get_tiny_decoder_vae_model(pipeline.__class__.__name__)
45
+ pipeline.vae = AutoencoderTiny.from_pretrained(
46
+ vae_model,
47
+ torch_dtype=torch_data_type,
48
+ local_files_only=use_local_model,
49
+ )
50
+
51
+
52
+ def get_lcm_model_pipeline(
53
+ model_id: str = LCM_DEFAULT_MODEL,
54
+ use_local_model: bool = False,
55
+ ):
56
+ pipeline = None
57
+ if model_id == "latent-consistency/lcm-sdxl":
58
+ pipeline = _get_lcm_pipeline_from_base_model(
59
+ model_id,
60
+ "stabilityai/stable-diffusion-xl-base-1.0",
61
+ use_local_model,
62
+ )
63
+
64
+ elif model_id == "latent-consistency/lcm-ssd-1b":
65
+ pipeline = _get_lcm_pipeline_from_base_model(
66
+ model_id,
67
+ "segmind/SSD-1B",
68
+ use_local_model,
69
+ )
70
+ else:
71
+ pipeline = DiffusionPipeline.from_pretrained(
72
+ model_id,
73
+ local_files_only=use_local_model,
74
+ )
75
+
76
+ return pipeline
77
+
78
+
79
+ def get_image_to_image_pipeline(pipeline: Any) -> Any:
80
+ components = pipeline.components
81
+ pipeline_class = pipeline.__class__.__name__
82
+ if (
83
+ pipeline_class == "LatentConsistencyModelPipeline"
84
+ or pipeline_class == "StableDiffusionPipeline"
85
+ ):
86
+ return StableDiffusionImg2ImgPipeline(**components)
87
+ elif pipeline_class == "StableDiffusionXLPipeline":
88
+ return StableDiffusionXLImg2ImgPipeline(**components)
89
+ else:
90
+ raise Exception(f"Unknown pipeline {pipeline_class}")
backend/pipelines/lcm_lora.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from diffusers import DiffusionPipeline, LCMScheduler
2
+ import torch
3
+
4
+
5
+ def get_lcm_lora_pipeline(
6
+ base_model_id: str,
7
+ lcm_lora_id: str,
8
+ use_local_model: bool,
9
+ torch_data_type: torch.dtype,
10
+ ):
11
+ pipeline = DiffusionPipeline.from_pretrained(
12
+ base_model_id,
13
+ torch_dtype=torch_data_type,
14
+ local_files_only=use_local_model,
15
+ )
16
+ pipeline.load_lora_weights(
17
+ lcm_lora_id,
18
+ local_files_only=use_local_model,
19
+ )
20
+ if "lcm" in lcm_lora_id.lower():
21
+ print("LCM LoRA model detected so using recommended LCMScheduler")
22
+ pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
23
+ pipeline.fuse_lora()
24
+ pipeline.unet.to(memory_format=torch.channels_last)
25
+ return pipeline
backend/tiny_decoder.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from constants import (
2
+ TAESD_MODEL,
3
+ TAESDXL_MODEL,
4
+ TAESD_MODEL_OPENVINO,
5
+ TAESDXL_MODEL_OPENVINO,
6
+ )
7
+
8
+
9
+ def get_tiny_decoder_vae_model(pipeline_class) -> str:
10
+ print(f"Pipeline class : {pipeline_class}")
11
+ if (
12
+ pipeline_class == "LatentConsistencyModelPipeline"
13
+ or pipeline_class == "StableDiffusionPipeline"
14
+ or pipeline_class == "StableDiffusionImg2ImgPipeline"
15
+ ):
16
+ return TAESD_MODEL
17
+ elif (
18
+ pipeline_class == "StableDiffusionXLPipeline"
19
+ or pipeline_class == "StableDiffusionXLImg2ImgPipeline"
20
+ ):
21
+ return TAESDXL_MODEL
22
+ elif (
23
+ pipeline_class == "OVStableDiffusionPipeline"
24
+ or pipeline_class == "OVStableDiffusionImg2ImgPipeline"
25
+ ):
26
+ return TAESD_MODEL_OPENVINO
27
+ elif pipeline_class == "OVStableDiffusionXLPipeline":
28
+ return TAESDXL_MODEL_OPENVINO
29
+ else:
30
+ raise Exception("No valid pipeline class found!")
constants.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from os import environ
2
+
3
+ APP_VERSION = "v1.0.0 beta 22"
4
+ LCM_DEFAULT_MODEL = "stabilityai/sd-turbo"
5
+ LCM_DEFAULT_MODEL_OPENVINO = "rupeshs/sd-turbo-openvino"
6
+ APP_NAME = "FastSD CPU"
7
+ APP_SETTINGS_FILE = "settings.yaml"
8
+ RESULTS_DIRECTORY = "results"
9
+ CONFIG_DIRECTORY = "configs"
10
+ DEVICE = environ.get("DEVICE", "cpu")
11
+ SD_MODELS_FILE = "stable-diffusion-models.txt"
12
+ LCM_LORA_MODELS_FILE = "lcm-lora-models.txt"
13
+ OPENVINO_LCM_MODELS_FILE = "openvino-lcm-models.txt"
14
+ TAESD_MODEL = "madebyollin/taesd"
15
+ TAESDXL_MODEL = "madebyollin/taesdxl"
16
+ TAESD_MODEL_OPENVINO = "deinferno/taesd-openvino"
17
+ LCM_MODELS_FILE = "lcm-models.txt"
18
+ TAESDXL_MODEL_OPENVINO = "rupeshs/taesdxl-openvino"
context.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ from app_settings import Settings
3
+ from models.interface_types import InterfaceType
4
+ from backend.lcm_text_to_image import LCMTextToImage
5
+ from time import perf_counter
6
+ from backend.image_saver import ImageSaver
7
+ from pprint import pprint
8
+ from state import get_settings
9
+
10
+
11
+ class Context:
12
+ def __init__(
13
+ self,
14
+ interface_type: InterfaceType,
15
+ device="cpu",
16
+ ):
17
+ self.interface_type = interface_type
18
+ self.lcm_text_to_image = LCMTextToImage(device)
19
+
20
+ def generate_text_to_image(
21
+ self,
22
+ settings: Settings,
23
+ reshape: bool = False,
24
+ device: str = "cpu",
25
+ ) -> Any:
26
+ get_settings().save()
27
+ tick = perf_counter()
28
+ pprint(settings.lcm_diffusion_setting.model_dump())
29
+ if not settings.lcm_diffusion_setting.lcm_lora:
30
+ return None
31
+ self.lcm_text_to_image.init(
32
+ device,
33
+ settings.lcm_diffusion_setting,
34
+ )
35
+ images = self.lcm_text_to_image.generate(
36
+ settings.lcm_diffusion_setting,
37
+ reshape,
38
+ )
39
+ elapsed = perf_counter() - tick
40
+ ImageSaver.save_images(
41
+ settings.results_path,
42
+ images=images,
43
+ lcm_diffusion_setting=settings.lcm_diffusion_setting,
44
+ )
45
+ print(f"Latency : {elapsed:.2f} seconds")
46
+ return images
frontend/__pycache__/utils.cpython-310.pyc ADDED
Binary file (1.4 kB). View file
 
frontend/gui/app_window.py ADDED
@@ -0,0 +1,604 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PyQt5.QtWidgets import (
2
+ QWidget,
3
+ QPushButton,
4
+ QHBoxLayout,
5
+ QVBoxLayout,
6
+ QLabel,
7
+ QLineEdit,
8
+ QMainWindow,
9
+ QSlider,
10
+ QTabWidget,
11
+ QSpacerItem,
12
+ QSizePolicy,
13
+ QComboBox,
14
+ QCheckBox,
15
+ QTextEdit,
16
+ QToolButton,
17
+ QFileDialog,
18
+ )
19
+ from PyQt5 import QtWidgets, QtCore
20
+ from PyQt5.QtGui import QPixmap, QDesktopServices
21
+ from PyQt5.QtCore import QSize, QThreadPool, Qt, QUrl
22
+
23
+ from PIL.ImageQt import ImageQt
24
+ from constants import (
25
+ LCM_DEFAULT_MODEL,
26
+ LCM_DEFAULT_MODEL_OPENVINO,
27
+ APP_NAME,
28
+ APP_VERSION,
29
+ )
30
+ from frontend.gui.image_generator_worker import ImageGeneratorWorker
31
+ from app_settings import AppSettings
32
+ from paths import FastStableDiffusionPaths
33
+ from frontend.utils import is_reshape_required
34
+ from context import Context
35
+ from models.interface_types import InterfaceType
36
+ from constants import DEVICE
37
+ from frontend.utils import enable_openvino_controls, get_valid_model_id
38
+ from backend.models.lcmdiffusion_setting import DiffusionTask
39
+
40
+ # DPI scale fix
41
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
42
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
43
+
44
+
45
+ class MainWindow(QMainWindow):
46
+ def __init__(self, config: AppSettings):
47
+ super().__init__()
48
+ self.config = config
49
+ self.setWindowTitle(APP_NAME)
50
+ self.setFixedSize(QSize(600, 670))
51
+ self.init_ui()
52
+ self.pipeline = None
53
+ self.threadpool = QThreadPool()
54
+ self.device = "cpu"
55
+ self.previous_width = 0
56
+ self.previous_height = 0
57
+ self.previous_model = ""
58
+ self.previous_num_of_images = 0
59
+ self.context = Context(InterfaceType.GUI)
60
+ self.init_ui_values()
61
+ self.gen_images = []
62
+ self.image_index = 0
63
+ print(f"Output path : { self.config.settings.results_path}")
64
+
65
+ def init_ui_values(self):
66
+ self.lcm_model.setEnabled(
67
+ not self.config.settings.lcm_diffusion_setting.use_openvino
68
+ )
69
+ self.guidance.setValue(
70
+ int(self.config.settings.lcm_diffusion_setting.guidance_scale * 10)
71
+ )
72
+ self.seed_value.setEnabled(self.config.settings.lcm_diffusion_setting.use_seed)
73
+ self.safety_checker.setChecked(
74
+ self.config.settings.lcm_diffusion_setting.use_safety_checker
75
+ )
76
+ self.use_openvino_check.setChecked(
77
+ self.config.settings.lcm_diffusion_setting.use_openvino
78
+ )
79
+ self.width.setCurrentText(
80
+ str(self.config.settings.lcm_diffusion_setting.image_width)
81
+ )
82
+ self.height.setCurrentText(
83
+ str(self.config.settings.lcm_diffusion_setting.image_height)
84
+ )
85
+ self.inference_steps.setValue(
86
+ int(self.config.settings.lcm_diffusion_setting.inference_steps)
87
+ )
88
+ self.seed_check.setChecked(self.config.settings.lcm_diffusion_setting.use_seed)
89
+ self.seed_value.setText(str(self.config.settings.lcm_diffusion_setting.seed))
90
+ self.use_local_model_folder.setChecked(
91
+ self.config.settings.lcm_diffusion_setting.use_offline_model
92
+ )
93
+ self.results_path.setText(self.config.settings.results_path)
94
+ self.num_images.setValue(
95
+ self.config.settings.lcm_diffusion_setting.number_of_images
96
+ )
97
+ self.use_tae_sd.setChecked(
98
+ self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder
99
+ )
100
+ self.use_lcm_lora.setChecked(
101
+ self.config.settings.lcm_diffusion_setting.use_lcm_lora
102
+ )
103
+ self.lcm_model.setCurrentText(
104
+ get_valid_model_id(
105
+ self.config.lcm_models,
106
+ self.config.settings.lcm_diffusion_setting.lcm_model_id,
107
+ LCM_DEFAULT_MODEL,
108
+ )
109
+ )
110
+ self.base_model_id.setCurrentText(
111
+ get_valid_model_id(
112
+ self.config.stable_diffsuion_models,
113
+ self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id,
114
+ )
115
+ )
116
+ self.lcm_lora_id.setCurrentText(
117
+ get_valid_model_id(
118
+ self.config.lcm_lora_models,
119
+ self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id,
120
+ )
121
+ )
122
+ self.openvino_lcm_model_id.setCurrentText(
123
+ get_valid_model_id(
124
+ self.config.openvino_lcm_models,
125
+ self.config.settings.lcm_diffusion_setting.openvino_lcm_model_id,
126
+ LCM_DEFAULT_MODEL_OPENVINO,
127
+ )
128
+ )
129
+ self.neg_prompt.setEnabled(
130
+ self.config.settings.lcm_diffusion_setting.use_lcm_lora
131
+ or self.config.settings.lcm_diffusion_setting.use_openvino
132
+ )
133
+ self.openvino_lcm_model_id.setEnabled(
134
+ self.config.settings.lcm_diffusion_setting.use_openvino
135
+ )
136
+
137
+ def init_ui(self):
138
+ self.create_main_tab()
139
+ self.create_settings_tab()
140
+ self.create_about_tab()
141
+ self.show()
142
+
143
+ def create_main_tab(self):
144
+ self.img = QLabel("<<Image>>")
145
+ self.img.setAlignment(Qt.AlignCenter)
146
+ self.img.setFixedSize(QSize(512, 512))
147
+ self.vspacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
148
+
149
+ self.prompt = QTextEdit()
150
+ self.prompt.setPlaceholderText("A fantasy landscape")
151
+ self.prompt.setAcceptRichText(False)
152
+ self.neg_prompt = QTextEdit()
153
+ self.neg_prompt.setPlaceholderText("")
154
+ self.neg_prompt.setAcceptRichText(False)
155
+ self.neg_prompt_label = QLabel("Negative prompt (Set guidance scale > 1.0):")
156
+ self.generate = QPushButton("Generate")
157
+ self.generate.clicked.connect(self.text_to_image)
158
+ self.prompt.setFixedHeight(40)
159
+ self.neg_prompt.setFixedHeight(35)
160
+ self.browse_results = QPushButton("...")
161
+ self.browse_results.setFixedWidth(30)
162
+ self.browse_results.clicked.connect(self.on_open_results_folder)
163
+ self.browse_results.setToolTip("Open output folder")
164
+
165
+ hlayout = QHBoxLayout()
166
+ hlayout.addWidget(self.neg_prompt)
167
+ hlayout.addWidget(self.generate)
168
+ hlayout.addWidget(self.browse_results)
169
+
170
+ self.previous_img_btn = QToolButton()
171
+ self.previous_img_btn.setText("<")
172
+ self.previous_img_btn.clicked.connect(self.on_show_previous_image)
173
+ self.next_img_btn = QToolButton()
174
+ self.next_img_btn.setText(">")
175
+ self.next_img_btn.clicked.connect(self.on_show_next_image)
176
+ hlayout_nav = QHBoxLayout()
177
+ hlayout_nav.addWidget(self.previous_img_btn)
178
+ hlayout_nav.addWidget(self.img)
179
+ hlayout_nav.addWidget(self.next_img_btn)
180
+
181
+ vlayout = QVBoxLayout()
182
+ vlayout.addLayout(hlayout_nav)
183
+ vlayout.addItem(self.vspacer)
184
+ vlayout.addWidget(self.prompt)
185
+ vlayout.addWidget(self.neg_prompt_label)
186
+ vlayout.addLayout(hlayout)
187
+
188
+ self.tab_widget = QTabWidget(self)
189
+ self.tab_main = QWidget()
190
+ self.tab_settings = QWidget()
191
+ self.tab_about = QWidget()
192
+ self.tab_main.setLayout(vlayout)
193
+
194
+ self.tab_widget.addTab(self.tab_main, "Text to Image")
195
+ self.tab_widget.addTab(self.tab_settings, "Settings")
196
+ self.tab_widget.addTab(self.tab_about, "About")
197
+
198
+ self.setCentralWidget(self.tab_widget)
199
+ self.use_seed = False
200
+
201
+ def create_settings_tab(self):
202
+ self.lcm_model_label = QLabel("Latent Consistency Model:")
203
+ # self.lcm_model = QLineEdit(LCM_DEFAULT_MODEL)
204
+ self.lcm_model = QComboBox(self)
205
+ self.lcm_model.addItems(self.config.lcm_models)
206
+ self.lcm_model.currentIndexChanged.connect(self.on_lcm_model_changed)
207
+
208
+ self.use_lcm_lora = QCheckBox("Use LCM LoRA")
209
+ self.use_lcm_lora.setChecked(False)
210
+ self.use_lcm_lora.stateChanged.connect(self.use_lcm_lora_changed)
211
+
212
+ self.lora_base_model_id_label = QLabel("Lora base model ID :")
213
+ self.base_model_id = QComboBox(self)
214
+ self.base_model_id.addItems(self.config.stable_diffsuion_models)
215
+ self.base_model_id.currentIndexChanged.connect(self.on_base_model_id_changed)
216
+
217
+ self.lcm_lora_model_id_label = QLabel("LCM LoRA model ID :")
218
+ self.lcm_lora_id = QComboBox(self)
219
+ self.lcm_lora_id.addItems(self.config.lcm_lora_models)
220
+ self.lcm_lora_id.currentIndexChanged.connect(self.on_lcm_lora_id_changed)
221
+
222
+ self.inference_steps_value = QLabel("Number of inference steps: 4")
223
+ self.inference_steps = QSlider(orientation=Qt.Orientation.Horizontal)
224
+ self.inference_steps.setMaximum(25)
225
+ self.inference_steps.setMinimum(1)
226
+ self.inference_steps.setValue(4)
227
+ self.inference_steps.valueChanged.connect(self.update_steps_label)
228
+
229
+ self.num_images_value = QLabel("Number of images: 1")
230
+ self.num_images = QSlider(orientation=Qt.Orientation.Horizontal)
231
+ self.num_images.setMaximum(100)
232
+ self.num_images.setMinimum(1)
233
+ self.num_images.setValue(1)
234
+ self.num_images.valueChanged.connect(self.update_num_images_label)
235
+
236
+ self.guidance_value = QLabel("Guidance scale: 1")
237
+ self.guidance = QSlider(orientation=Qt.Orientation.Horizontal)
238
+ self.guidance.setMaximum(20)
239
+ self.guidance.setMinimum(10)
240
+ self.guidance.setValue(10)
241
+ self.guidance.valueChanged.connect(self.update_guidance_label)
242
+
243
+ self.width_value = QLabel("Width :")
244
+ self.width = QComboBox(self)
245
+ self.width.addItem("256")
246
+ self.width.addItem("512")
247
+ self.width.addItem("768")
248
+ self.width.addItem("1024")
249
+ self.width.setCurrentText("512")
250
+ self.width.currentIndexChanged.connect(self.on_width_changed)
251
+
252
+ self.height_value = QLabel("Height :")
253
+ self.height = QComboBox(self)
254
+ self.height.addItem("256")
255
+ self.height.addItem("512")
256
+ self.height.addItem("768")
257
+ self.height.addItem("1024")
258
+ self.height.setCurrentText("512")
259
+ self.height.currentIndexChanged.connect(self.on_height_changed)
260
+
261
+ self.seed_check = QCheckBox("Use seed")
262
+ self.seed_value = QLineEdit()
263
+ self.seed_value.setInputMask("9999999999")
264
+ self.seed_value.setText("123123")
265
+ self.seed_check.stateChanged.connect(self.seed_changed)
266
+
267
+ self.safety_checker = QCheckBox("Use safety checker")
268
+ self.safety_checker.setChecked(True)
269
+ self.safety_checker.stateChanged.connect(self.use_safety_checker_changed)
270
+
271
+ self.use_openvino_check = QCheckBox("Use OpenVINO")
272
+ self.use_openvino_check.setChecked(False)
273
+ self.openvino_model_label = QLabel("OpenVINO LCM model:")
274
+ self.use_local_model_folder = QCheckBox(
275
+ "Use locally cached model or downloaded model folder(offline)"
276
+ )
277
+ self.openvino_lcm_model_id = QComboBox(self)
278
+ self.openvino_lcm_model_id.addItems(self.config.openvino_lcm_models)
279
+ self.openvino_lcm_model_id.currentIndexChanged.connect(
280
+ self.on_openvino_lcm_model_id_changed
281
+ )
282
+
283
+ self.use_openvino_check.setEnabled(enable_openvino_controls())
284
+ self.use_local_model_folder.setChecked(False)
285
+ self.use_local_model_folder.stateChanged.connect(self.use_offline_model_changed)
286
+ self.use_openvino_check.stateChanged.connect(self.use_openvino_changed)
287
+
288
+ self.use_tae_sd = QCheckBox(
289
+ "Use Tiny Auto Encoder - TAESD (Fast, moderate quality)"
290
+ )
291
+ self.use_tae_sd.setChecked(False)
292
+ self.use_tae_sd.stateChanged.connect(self.use_tae_sd_changed)
293
+
294
+ hlayout = QHBoxLayout()
295
+ hlayout.addWidget(self.seed_check)
296
+ hlayout.addWidget(self.seed_value)
297
+ hspacer = QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)
298
+ slider_hspacer = QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)
299
+
300
+ self.results_path_label = QLabel("Output path:")
301
+ self.results_path = QLineEdit()
302
+ self.results_path.textChanged.connect(self.on_path_changed)
303
+ self.browse_folder_btn = QToolButton()
304
+ self.browse_folder_btn.setText("...")
305
+ self.browse_folder_btn.clicked.connect(self.on_browse_folder)
306
+
307
+ self.reset = QPushButton("Reset All")
308
+ self.reset.clicked.connect(self.reset_all_settings)
309
+
310
+ vlayout = QVBoxLayout()
311
+ vspacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)
312
+ vlayout.addItem(hspacer)
313
+ vlayout.setSpacing(3)
314
+ vlayout.addWidget(self.lcm_model_label)
315
+ vlayout.addWidget(self.lcm_model)
316
+ vlayout.addWidget(self.use_local_model_folder)
317
+ vlayout.addWidget(self.use_lcm_lora)
318
+ vlayout.addWidget(self.lora_base_model_id_label)
319
+ vlayout.addWidget(self.base_model_id)
320
+ vlayout.addWidget(self.lcm_lora_model_id_label)
321
+ vlayout.addWidget(self.lcm_lora_id)
322
+ vlayout.addWidget(self.use_openvino_check)
323
+ vlayout.addWidget(self.openvino_model_label)
324
+ vlayout.addWidget(self.openvino_lcm_model_id)
325
+ vlayout.addWidget(self.use_tae_sd)
326
+ vlayout.addItem(slider_hspacer)
327
+ vlayout.addWidget(self.inference_steps_value)
328
+ vlayout.addWidget(self.inference_steps)
329
+ vlayout.addWidget(self.num_images_value)
330
+ vlayout.addWidget(self.num_images)
331
+ vlayout.addWidget(self.width_value)
332
+ vlayout.addWidget(self.width)
333
+ vlayout.addWidget(self.height_value)
334
+ vlayout.addWidget(self.height)
335
+ vlayout.addWidget(self.guidance_value)
336
+ vlayout.addWidget(self.guidance)
337
+ vlayout.addLayout(hlayout)
338
+ vlayout.addWidget(self.safety_checker)
339
+
340
+ vlayout.addWidget(self.results_path_label)
341
+ hlayout_path = QHBoxLayout()
342
+ hlayout_path.addWidget(self.results_path)
343
+ hlayout_path.addWidget(self.browse_folder_btn)
344
+ vlayout.addLayout(hlayout_path)
345
+ self.tab_settings.setLayout(vlayout)
346
+ hlayout_reset = QHBoxLayout()
347
+ hspacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
348
+ hlayout_reset.addItem(hspacer)
349
+ hlayout_reset.addWidget(self.reset)
350
+ vlayout.addLayout(hlayout_reset)
351
+ vlayout.addItem(vspacer)
352
+
353
+ def create_about_tab(self):
354
+ self.label = QLabel()
355
+ self.label.setAlignment(Qt.AlignCenter)
356
+ self.label.setText(
357
+ f"""<h1>FastSD CPU {APP_VERSION}</h1>
358
+ <h3>(c)2023 - Rupesh Sreeraman</h3>
359
+ <h3>Faster stable diffusion on CPU</h3>
360
+ <h3>Based on Latent Consistency Models</h3>
361
+ <h3>GitHub : https://github.com/rupeshs/fastsdcpu/</h3>"""
362
+ )
363
+
364
+ vlayout = QVBoxLayout()
365
+ vlayout.addWidget(self.label)
366
+ self.tab_about.setLayout(vlayout)
367
+
368
+ def show_image(self, pixmap):
369
+ image_width = self.config.settings.lcm_diffusion_setting.image_width
370
+ image_height = self.config.settings.lcm_diffusion_setting.image_height
371
+ if image_width > 512 or image_height > 512:
372
+ new_width = 512 if image_width > 512 else image_width
373
+ new_height = 512 if image_height > 512 else image_height
374
+ self.img.setPixmap(
375
+ pixmap.scaled(
376
+ new_width,
377
+ new_height,
378
+ Qt.KeepAspectRatio,
379
+ )
380
+ )
381
+ else:
382
+ self.img.setPixmap(pixmap)
383
+
384
+ def on_show_next_image(self):
385
+ if self.image_index != len(self.gen_images) - 1 and len(self.gen_images) > 0:
386
+ self.previous_img_btn.setEnabled(True)
387
+ self.image_index += 1
388
+ self.show_image(self.gen_images[self.image_index])
389
+ if self.image_index == len(self.gen_images) - 1:
390
+ self.next_img_btn.setEnabled(False)
391
+
392
+ def on_open_results_folder(self):
393
+ QDesktopServices.openUrl(QUrl.fromLocalFile(self.config.settings.results_path))
394
+
395
+ def on_show_previous_image(self):
396
+ if self.image_index != 0:
397
+ self.next_img_btn.setEnabled(True)
398
+ self.image_index -= 1
399
+ self.show_image(self.gen_images[self.image_index])
400
+ if self.image_index == 0:
401
+ self.previous_img_btn.setEnabled(False)
402
+
403
+ def on_path_changed(self, text):
404
+ self.config.settings.results_path = text
405
+
406
+ def on_browse_folder(self):
407
+ options = QFileDialog.Options()
408
+ options |= QFileDialog.ShowDirsOnly
409
+
410
+ folder_path = QFileDialog.getExistingDirectory(
411
+ self, "Select a Folder", "", options=options
412
+ )
413
+
414
+ if folder_path:
415
+ self.config.settings.results_path = folder_path
416
+ self.results_path.setText(folder_path)
417
+
418
+ def on_width_changed(self, index):
419
+ width_txt = self.width.itemText(index)
420
+ self.config.settings.lcm_diffusion_setting.image_width = int(width_txt)
421
+
422
+ def on_height_changed(self, index):
423
+ height_txt = self.height.itemText(index)
424
+ self.config.settings.lcm_diffusion_setting.image_height = int(height_txt)
425
+
426
+ def on_lcm_model_changed(self, index):
427
+ model_id = self.lcm_model.itemText(index)
428
+ self.config.settings.lcm_diffusion_setting.lcm_model_id = model_id
429
+
430
+ def on_base_model_id_changed(self, index):
431
+ model_id = self.base_model_id.itemText(index)
432
+ self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id = model_id
433
+
434
+ def on_lcm_lora_id_changed(self, index):
435
+ model_id = self.lcm_lora_id.itemText(index)
436
+ self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id = model_id
437
+
438
+ def on_openvino_lcm_model_id_changed(self, index):
439
+ model_id = self.openvino_lcm_model_id.itemText(index)
440
+ self.config.settings.lcm_diffusion_setting.openvino_lcm_model_id = model_id
441
+
442
+ def use_openvino_changed(self, state):
443
+ if state == 2:
444
+ self.lcm_model.setEnabled(False)
445
+ self.use_lcm_lora.setEnabled(False)
446
+ self.lcm_lora_id.setEnabled(False)
447
+ self.base_model_id.setEnabled(False)
448
+ self.neg_prompt.setEnabled(True)
449
+ self.openvino_lcm_model_id.setEnabled(True)
450
+ self.config.settings.lcm_diffusion_setting.use_openvino = True
451
+ else:
452
+ self.lcm_model.setEnabled(True)
453
+ self.use_lcm_lora.setEnabled(True)
454
+ self.lcm_lora_id.setEnabled(True)
455
+ self.base_model_id.setEnabled(True)
456
+ self.neg_prompt.setEnabled(False)
457
+ self.openvino_lcm_model_id.setEnabled(False)
458
+ self.config.settings.lcm_diffusion_setting.use_openvino = False
459
+
460
+ def use_tae_sd_changed(self, state):
461
+ if state == 2:
462
+ self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder = True
463
+ else:
464
+ self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder = False
465
+
466
+ def use_offline_model_changed(self, state):
467
+ if state == 2:
468
+ self.config.settings.lcm_diffusion_setting.use_offline_model = True
469
+ else:
470
+ self.config.settings.lcm_diffusion_setting.use_offline_model = False
471
+
472
+ def use_lcm_lora_changed(self, state):
473
+ if state == 2:
474
+ self.lcm_model.setEnabled(False)
475
+ self.lcm_lora_id.setEnabled(True)
476
+ self.base_model_id.setEnabled(True)
477
+ self.neg_prompt.setEnabled(True)
478
+ self.config.settings.lcm_diffusion_setting.use_lcm_lora = True
479
+ else:
480
+ self.lcm_model.setEnabled(True)
481
+ self.lcm_lora_id.setEnabled(False)
482
+ self.base_model_id.setEnabled(False)
483
+ self.neg_prompt.setEnabled(False)
484
+ self.config.settings.lcm_diffusion_setting.use_lcm_lora = False
485
+
486
+ def use_safety_checker_changed(self, state):
487
+ if state == 2:
488
+ self.config.settings.lcm_diffusion_setting.use_safety_checker = True
489
+ else:
490
+ self.config.settings.lcm_diffusion_setting.use_safety_checker = False
491
+
492
+ def update_steps_label(self, value):
493
+ self.inference_steps_value.setText(f"Number of inference steps: {value}")
494
+ self.config.settings.lcm_diffusion_setting.inference_steps = value
495
+
496
+ def update_num_images_label(self, value):
497
+ self.num_images_value.setText(f"Number of images: {value}")
498
+ self.config.settings.lcm_diffusion_setting.number_of_images = value
499
+
500
+ def update_guidance_label(self, value):
501
+ val = round(int(value) / 10, 1)
502
+ self.guidance_value.setText(f"Guidance scale: {val}")
503
+ self.config.settings.lcm_diffusion_setting.guidance_scale = val
504
+
505
+ def seed_changed(self, state):
506
+ if state == 2:
507
+ self.seed_value.setEnabled(True)
508
+ self.config.settings.lcm_diffusion_setting.use_seed = True
509
+ else:
510
+ self.seed_value.setEnabled(False)
511
+ self.config.settings.lcm_diffusion_setting.use_seed = False
512
+
513
+ def get_seed_value(self) -> int:
514
+ use_seed = self.config.settings.lcm_diffusion_setting.use_seed
515
+ seed_value = int(self.seed_value.text()) if use_seed else -1
516
+ return seed_value
517
+
518
+ def generate_image(self):
519
+ self.config.settings.lcm_diffusion_setting.seed = self.get_seed_value()
520
+ self.config.settings.lcm_diffusion_setting.prompt = self.prompt.toPlainText()
521
+ self.config.settings.lcm_diffusion_setting.negative_prompt = (
522
+ self.neg_prompt.toPlainText()
523
+ )
524
+ self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id = (
525
+ self.lcm_lora_id.currentText()
526
+ )
527
+ self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id = (
528
+ self.base_model_id.currentText()
529
+ )
530
+
531
+ if self.config.settings.lcm_diffusion_setting.use_openvino:
532
+ model_id = self.openvino_lcm_model_id.currentText()
533
+ else:
534
+ model_id = self.lcm_model.currentText()
535
+
536
+ self.config.settings.lcm_diffusion_setting.lcm_model_id = model_id
537
+
538
+ reshape_required = False
539
+ if self.config.settings.lcm_diffusion_setting.use_openvino:
540
+ # Detect dimension change
541
+ reshape_required = is_reshape_required(
542
+ self.previous_width,
543
+ self.config.settings.lcm_diffusion_setting.image_width,
544
+ self.previous_height,
545
+ self.config.settings.lcm_diffusion_setting.image_height,
546
+ self.previous_model,
547
+ model_id,
548
+ self.previous_num_of_images,
549
+ self.config.settings.lcm_diffusion_setting.number_of_images,
550
+ )
551
+ self.config.settings.lcm_diffusion_setting.diffusion_task = (
552
+ DiffusionTask.text_to_image.value
553
+ )
554
+ images = self.context.generate_text_to_image(
555
+ self.config.settings,
556
+ reshape_required,
557
+ DEVICE,
558
+ )
559
+ self.image_index = 0
560
+ self.gen_images = []
561
+ for img in images:
562
+ im = ImageQt(img).copy()
563
+ pixmap = QPixmap.fromImage(im)
564
+ self.gen_images.append(pixmap)
565
+
566
+ if len(self.gen_images) > 1:
567
+ self.next_img_btn.setEnabled(True)
568
+ self.previous_img_btn.setEnabled(False)
569
+ else:
570
+ self.next_img_btn.setEnabled(False)
571
+ self.previous_img_btn.setEnabled(False)
572
+
573
+ self.show_image(self.gen_images[0])
574
+
575
+ self.previous_width = self.config.settings.lcm_diffusion_setting.image_width
576
+ self.previous_height = self.config.settings.lcm_diffusion_setting.image_height
577
+ self.previous_model = model_id
578
+ self.previous_num_of_images = (
579
+ self.config.settings.lcm_diffusion_setting.number_of_images
580
+ )
581
+
582
+ def text_to_image(self):
583
+ self.img.setText("Please wait...")
584
+ worker = ImageGeneratorWorker(self.generate_image)
585
+ self.threadpool.start(worker)
586
+
587
+ def closeEvent(self, event):
588
+ self.config.settings.lcm_diffusion_setting.seed = self.get_seed_value()
589
+ print(self.config.settings.lcm_diffusion_setting)
590
+ print("Saving settings")
591
+ self.config.save()
592
+
593
+ def reset_all_settings(self):
594
+ self.use_local_model_folder.setChecked(False)
595
+ self.width.setCurrentText("512")
596
+ self.height.setCurrentText("512")
597
+ self.inference_steps.setValue(4)
598
+ self.guidance.setValue(10)
599
+ self.use_openvino_check.setChecked(False)
600
+ self.seed_check.setChecked(False)
601
+ self.safety_checker.setChecked(False)
602
+ self.results_path.setText(FastStableDiffusionPaths().get_results_path())
603
+ self.use_tae_sd.setChecked(False)
604
+ self.use_lcm_lora.setChecked(False)
frontend/gui/image_generator_worker.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PyQt5.QtCore import (
2
+ pyqtSlot,
3
+ QRunnable,
4
+ pyqtSignal,
5
+ pyqtSlot,
6
+ )
7
+ from PyQt5.QtCore import QObject
8
+ import traceback
9
+ import sys
10
+
11
+
12
+ class WorkerSignals(QObject):
13
+ finished = pyqtSignal()
14
+ error = pyqtSignal(tuple)
15
+ result = pyqtSignal(object)
16
+
17
+
18
+ class ImageGeneratorWorker(QRunnable):
19
+ def __init__(self, fn, *args, **kwargs):
20
+ super(ImageGeneratorWorker, self).__init__()
21
+ self.fn = fn
22
+ self.args = args
23
+ self.kwargs = kwargs
24
+ self.signals = WorkerSignals()
25
+
26
+ @pyqtSlot()
27
+ def run(self):
28
+ try:
29
+ result = self.fn(*self.args, **self.kwargs)
30
+ except:
31
+ traceback.print_exc()
32
+ exctype, value = sys.exc_info()[:2]
33
+ self.signals.error.emit((exctype, value, traceback.format_exc()))
34
+ else:
35
+ self.signals.result.emit(result)
36
+ finally:
37
+ self.signals.finished.emit()
frontend/gui/ui.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+ from frontend.gui.app_window import MainWindow
3
+ from PyQt5.QtWidgets import QApplication
4
+ import sys
5
+ from app_settings import AppSettings
6
+
7
+
8
+ def start_gui(
9
+ argv: List[str],
10
+ app_settings: AppSettings,
11
+ ):
12
+ app = QApplication(sys.argv)
13
+ window = MainWindow(app_settings)
14
+ window.show()
15
+ app.exec()
frontend/utils.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from constants import DEVICE
2
+ from typing import List
3
+ import platform
4
+ from backend.device import is_openvino_device
5
+
6
+
7
+ def is_reshape_required(
8
+ prev_width: int,
9
+ cur_width: int,
10
+ prev_height: int,
11
+ cur_height: int,
12
+ prev_model: int,
13
+ cur_model: int,
14
+ prev_num_of_images: int,
15
+ cur_num_of_images: int,
16
+ ) -> bool:
17
+ reshape_required = False
18
+ if (
19
+ prev_width != cur_width
20
+ or prev_height != cur_height
21
+ or prev_model != cur_model
22
+ or prev_num_of_images != cur_num_of_images
23
+ ):
24
+ print("Reshape and compile")
25
+ reshape_required = True
26
+
27
+ return reshape_required
28
+
29
+
30
+ def enable_openvino_controls() -> bool:
31
+ return is_openvino_device() and platform.system().lower() != "darwin"
32
+
33
+
34
+ def get_valid_model_id(
35
+ models: List,
36
+ model_id: str,
37
+ default_model: str = "",
38
+ ) -> str:
39
+ if len(models) == 0:
40
+ print("Error: model configuration file is empty,please add some models.")
41
+ return ""
42
+ if model_id == "":
43
+ if default_model:
44
+ return default_model
45
+ else:
46
+ return models[0]
47
+
48
+ if model_id in models:
49
+ return model_id
50
+ else:
51
+ print(
52
+ f"Error:{model_id} Model not found in configuration file,so using first model : {models[0]}"
53
+ )
54
+ return models[0]
frontend/webui/__pycache__/generation_settings_ui.cpython-310.pyc ADDED
Binary file (3.23 kB). View file
 
frontend/webui/__pycache__/image_to_image_ui.cpython-310.pyc ADDED
Binary file (2.65 kB). View file
 
frontend/webui/__pycache__/models_ui.cpython-310.pyc ADDED
Binary file (2.22 kB). View file
 
frontend/webui/__pycache__/text_to_image_ui.cpython-310.pyc ADDED
Binary file (2.41 kB). View file
 
frontend/webui/__pycache__/ui.cpython-310.pyc ADDED
Binary file (2.33 kB). View file
 
frontend/webui/css/style.css ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ footer {
2
+ visibility: hidden
3
+ }
4
+
5
+ #generate_button {
6
+ color: white;
7
+ border-color: #007bff;
8
+ background: #2563eb;
9
+
10
+ }
11
+
12
+ #save_button {
13
+ color: white;
14
+ border-color: #028b40;
15
+ background: #01b97c;
16
+ width: 200px;
17
+ }
18
+
19
+ #settings_header {
20
+ background: rgb(245, 105, 105);
21
+
22
+ }
frontend/webui/generation_settings_ui.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from state import get_settings
3
+
4
+ app_settings = get_settings()
5
+
6
+
7
+ def on_change_inference_steps(steps):
8
+ app_settings.settings.lcm_diffusion_setting.inference_steps = steps
9
+
10
+
11
+ def on_change_image_width(img_width):
12
+ app_settings.settings.lcm_diffusion_setting.image_width = img_width
13
+
14
+
15
+ def on_change_image_height(img_height):
16
+ app_settings.settings.lcm_diffusion_setting.image_height = img_height
17
+
18
+
19
+ def on_change_num_images(num_images):
20
+ app_settings.settings.lcm_diffusion_setting.number_of_images = num_images
21
+
22
+
23
+ def on_change_guidance_scale(guidance_scale):
24
+ app_settings.settings.lcm_diffusion_setting.guidance_scale = guidance_scale
25
+
26
+
27
+ def on_change_seed_value(seed):
28
+ app_settings.settings.lcm_diffusion_setting.seed = seed
29
+
30
+
31
+ def on_change_seed_checkbox(seed_checkbox):
32
+ app_settings.settings.lcm_diffusion_setting.use_seed = seed_checkbox
33
+
34
+
35
+ def on_change_safety_checker_checkbox(safety_checker_checkbox):
36
+ app_settings.settings.lcm_diffusion_setting.use_safety_checker = (
37
+ safety_checker_checkbox
38
+ )
39
+
40
+
41
+ def on_change_tiny_auto_encoder_checkbox(tiny_auto_encoder_checkbox):
42
+ app_settings.settings.lcm_diffusion_setting.use_tiny_auto_encoder = (
43
+ tiny_auto_encoder_checkbox
44
+ )
45
+
46
+
47
+ def on_offline_checkbox(offline_checkbox):
48
+ app_settings.settings.lcm_diffusion_setting.use_offline_model = offline_checkbox
49
+
50
+
51
+ def get_generation_settings_ui() -> None:
52
+ with gr.Blocks():
53
+ with gr.Row():
54
+ with gr.Column():
55
+ num_inference_steps = gr.Slider(
56
+ 1,
57
+ 25,
58
+ value=app_settings.settings.lcm_diffusion_setting.inference_steps,
59
+ step=1,
60
+ label="Inference Steps",
61
+ interactive=True,
62
+ )
63
+
64
+ image_height = gr.Slider(
65
+ 256,
66
+ 1024,
67
+ value=app_settings.settings.lcm_diffusion_setting.image_height,
68
+ step=256,
69
+ label="Image Height",
70
+ interactive=True,
71
+ )
72
+ image_width = gr.Slider(
73
+ 256,
74
+ 1024,
75
+ value=app_settings.settings.lcm_diffusion_setting.image_width,
76
+ step=256,
77
+ label="Image Width",
78
+ interactive=True,
79
+ )
80
+ num_images = gr.Slider(
81
+ 1,
82
+ 50,
83
+ value=app_settings.settings.lcm_diffusion_setting.number_of_images,
84
+ step=1,
85
+ label="Number of images to generate",
86
+ interactive=True,
87
+ )
88
+ guidance_scale = gr.Slider(
89
+ 1.0,
90
+ 2.0,
91
+ value=app_settings.settings.lcm_diffusion_setting.guidance_scale,
92
+ step=0.1,
93
+ label="Guidance Scale",
94
+ interactive=True,
95
+ )
96
+
97
+ seed = gr.Slider(
98
+ value=app_settings.settings.lcm_diffusion_setting.seed,
99
+ minimum=0,
100
+ maximum=999999999,
101
+ label="Seed",
102
+ step=1,
103
+ interactive=True,
104
+ )
105
+ seed_checkbox = gr.Checkbox(
106
+ label="Use seed",
107
+ value=app_settings.settings.lcm_diffusion_setting.use_seed,
108
+ interactive=True,
109
+ )
110
+
111
+ safety_checker_checkbox = gr.Checkbox(
112
+ label="Use Safety Checker",
113
+ value=app_settings.settings.lcm_diffusion_setting.use_safety_checker,
114
+ interactive=True,
115
+ )
116
+ tiny_auto_encoder_checkbox = gr.Checkbox(
117
+ label="Use tiny auto encoder for SD",
118
+ value=app_settings.settings.lcm_diffusion_setting.use_tiny_auto_encoder,
119
+ interactive=True,
120
+ )
121
+ offline_checkbox = gr.Checkbox(
122
+ label="Use locally cached model or downloaded model folder(offline)",
123
+ value=app_settings.settings.lcm_diffusion_setting.use_offline_model,
124
+ interactive=True,
125
+ )
126
+
127
+ num_inference_steps.change(on_change_inference_steps, num_inference_steps)
128
+ image_height.change(on_change_image_height, image_height)
129
+ image_width.change(on_change_image_width, image_width)
130
+ num_images.change(on_change_num_images, num_images)
131
+ guidance_scale.change(on_change_guidance_scale, guidance_scale)
132
+ seed.change(on_change_seed_value, seed)
133
+ seed_checkbox.change(on_change_seed_checkbox, seed_checkbox)
134
+ safety_checker_checkbox.change(
135
+ on_change_safety_checker_checkbox, safety_checker_checkbox
136
+ )
137
+ tiny_auto_encoder_checkbox.change(
138
+ on_change_tiny_auto_encoder_checkbox, tiny_auto_encoder_checkbox
139
+ )
140
+ offline_checkbox.change(on_change_tiny_auto_encoder_checkbox, offline_checkbox)
frontend/webui/image_to_image_ui.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ import gradio as gr
3
+ from backend.models.lcmdiffusion_setting import DiffusionTask
4
+ from context import Context
5
+ from models.interface_types import InterfaceType
6
+ from frontend.utils import is_reshape_required
7
+ from constants import DEVICE
8
+ from state import get_settings
9
+ from concurrent.futures import ThreadPoolExecutor
10
+
11
+ app_settings = get_settings()
12
+
13
+ context = Context(InterfaceType.WEBUI)
14
+ previous_width = 0
15
+ previous_height = 0
16
+ previous_model_id = ""
17
+ previous_num_of_images = 0
18
+
19
+
20
+ def generate_image_to_image(
21
+ prompt,
22
+ negative_prompt,
23
+ init_image,
24
+ strength,
25
+ ) -> Any:
26
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
27
+
28
+ app_settings.settings.lcm_diffusion_setting.prompt = prompt
29
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = negative_prompt
30
+ app_settings.settings.lcm_diffusion_setting.init_image = init_image
31
+ app_settings.settings.lcm_diffusion_setting.strength = strength
32
+
33
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
34
+ DiffusionTask.image_to_image.value
35
+ )
36
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
37
+ reshape = False
38
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
39
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
40
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
41
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
42
+ reshape = is_reshape_required(
43
+ previous_width,
44
+ image_width,
45
+ previous_height,
46
+ image_height,
47
+ previous_model_id,
48
+ model_id,
49
+ previous_num_of_images,
50
+ num_images,
51
+ )
52
+
53
+ with ThreadPoolExecutor(max_workers=1) as executor:
54
+ future = executor.submit(
55
+ context.generate_text_to_image,
56
+ app_settings.settings,
57
+ reshape,
58
+ DEVICE,
59
+ )
60
+ images = future.result()
61
+ # images = context.generate_text_to_image(
62
+ # app_settings.settings,
63
+ # reshape,
64
+ # DEVICE,
65
+ # )
66
+ previous_width = image_width
67
+ previous_height = image_height
68
+ previous_model_id = model_id
69
+ previous_num_of_images = num_images
70
+ return images
71
+
72
+
73
+ def get_image_to_image_ui() -> None:
74
+ with gr.Blocks():
75
+ with gr.Row():
76
+ with gr.Column():
77
+ input_image = gr.Image(label="Init image", type="pil")
78
+ with gr.Row():
79
+ prompt = gr.Textbox(
80
+ show_label=False,
81
+ lines=3,
82
+ placeholder="A fantasy landscape",
83
+ container=False,
84
+ )
85
+
86
+ generate_btn = gr.Button(
87
+ "Generate",
88
+ elem_id="generate_button",
89
+ scale=0,
90
+ )
91
+ negative_prompt = gr.Textbox(
92
+ label="Negative prompt (Works in LCM-LoRA mode, set guidance > 1.0):",
93
+ lines=1,
94
+ placeholder="",
95
+ )
96
+ strength = gr.Slider(
97
+ 0.1,
98
+ 1,
99
+ value=app_settings.settings.lcm_diffusion_setting.strength,
100
+ step=0.01,
101
+ label="Strength",
102
+ )
103
+
104
+ input_params = [
105
+ prompt,
106
+ negative_prompt,
107
+ input_image,
108
+ strength,
109
+ ]
110
+
111
+ with gr.Column():
112
+ output = gr.Gallery(
113
+ label="Generated images",
114
+ show_label=True,
115
+ elem_id="gallery",
116
+ columns=2,
117
+ height=512,
118
+ )
119
+
120
+ generate_btn.click(
121
+ fn=generate_image_to_image,
122
+ inputs=input_params,
123
+ outputs=output,
124
+ )
frontend/webui/models_ui.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app_settings import AppSettings
2
+ from typing import Any
3
+ import gradio as gr
4
+ from constants import LCM_DEFAULT_MODEL, LCM_DEFAULT_MODEL_OPENVINO
5
+ from state import get_settings
6
+ from frontend.utils import get_valid_model_id
7
+
8
+ app_settings = get_settings()
9
+ app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id = get_valid_model_id(
10
+ app_settings.openvino_lcm_models,
11
+ app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id,
12
+ )
13
+
14
+
15
+ def change_lcm_model_id(model_id):
16
+ app_settings.settings.lcm_diffusion_setting.lcm_model_id = model_id
17
+
18
+
19
+ def change_lcm_lora_model_id(model_id):
20
+ app_settings.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id = model_id
21
+
22
+
23
+ def change_lcm_lora_base_model_id(model_id):
24
+ app_settings.settings.lcm_diffusion_setting.lcm_lora.base_model_id = model_id
25
+
26
+
27
+ def change_openvino_lcm_model_id(model_id):
28
+ app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id = model_id
29
+
30
+
31
+ def get_models_ui() -> None:
32
+ with gr.Blocks():
33
+ with gr.Row():
34
+ lcm_model_id = gr.Dropdown(
35
+ app_settings.lcm_models,
36
+ label="LCM model",
37
+ info="Diffusers LCM model ID",
38
+ value=get_valid_model_id(
39
+ app_settings.lcm_models,
40
+ app_settings.settings.lcm_diffusion_setting.lcm_model_id,
41
+ LCM_DEFAULT_MODEL,
42
+ ),
43
+ interactive=True,
44
+ )
45
+ with gr.Row():
46
+ lcm_lora_model_id = gr.Dropdown(
47
+ app_settings.lcm_lora_models,
48
+ label="LCM LoRA model",
49
+ info="Diffusers LCM LoRA model ID",
50
+ value=get_valid_model_id(
51
+ app_settings.lcm_lora_models,
52
+ app_settings.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id,
53
+ ),
54
+ interactive=True,
55
+ )
56
+ lcm_lora_base_model_id = gr.Dropdown(
57
+ app_settings.stable_diffsuion_models,
58
+ label="LCM LoRA base model",
59
+ info="Diffusers LCM LoRA base model ID",
60
+ value=get_valid_model_id(
61
+ app_settings.stable_diffsuion_models,
62
+ app_settings.settings.lcm_diffusion_setting.lcm_lora.base_model_id,
63
+ ),
64
+ interactive=True,
65
+ )
66
+ with gr.Row():
67
+ lcm_openvino_model_id = gr.Dropdown(
68
+ app_settings.openvino_lcm_models,
69
+ label="LCM OpenVINO model",
70
+ info="OpenVINO LCM-LoRA fused model ID",
71
+ value=get_valid_model_id(
72
+ app_settings.openvino_lcm_models,
73
+ app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id,
74
+ ),
75
+ interactive=True,
76
+ )
77
+
78
+ lcm_model_id.change(change_lcm_model_id, lcm_model_id)
79
+ lcm_lora_model_id.change(change_lcm_lora_model_id, lcm_lora_model_id)
80
+ lcm_lora_base_model_id.change(
81
+ change_lcm_lora_base_model_id, lcm_lora_base_model_id
82
+ )
83
+ lcm_openvino_model_id.change(
84
+ change_openvino_lcm_model_id, lcm_openvino_model_id
85
+ )
frontend/webui/realtime_ui.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from backend.lcm_text_to_image import LCMTextToImage
3
+ from backend.models.lcmdiffusion_setting import LCMLora, LCMDiffusionSetting
4
+ from constants import DEVICE, LCM_DEFAULT_MODEL_OPENVINO
5
+ from time import perf_counter
6
+ import numpy as np
7
+ from cv2 import imencode
8
+ import base64
9
+ from backend.device import get_device_name
10
+ from constants import APP_VERSION
11
+ from backend.device import is_openvino_device
12
+
13
+ lcm_text_to_image = LCMTextToImage()
14
+ lcm_lora = LCMLora(
15
+ base_model_id="Lykon/dreamshaper-8",
16
+ lcm_lora_id="latent-consistency/lcm-lora-sdv1-5",
17
+ )
18
+
19
+
20
+ # https://github.com/gradio-app/gradio/issues/2635#issuecomment-1423531319
21
+ def encode_pil_to_base64_new(pil_image):
22
+ image_arr = np.asarray(pil_image)[:, :, ::-1]
23
+ _, byte_data = imencode(".png", image_arr)
24
+ base64_data = base64.b64encode(byte_data)
25
+ base64_string_opencv = base64_data.decode("utf-8")
26
+ return "data:image/png;base64," + base64_string_opencv
27
+
28
+
29
+ # monkey patching encode pil
30
+ gr.processing_utils.encode_pil_to_base64 = encode_pil_to_base64_new
31
+
32
+
33
+ def predict(
34
+ prompt,
35
+ steps,
36
+ seed,
37
+ ):
38
+ lcm_diffusion_setting = LCMDiffusionSetting()
39
+ lcm_diffusion_setting.openvino_lcm_model_id = "rupeshs/LCM-dreamshaper-v7-openvino"
40
+ lcm_diffusion_setting.prompt = prompt
41
+ lcm_diffusion_setting.guidance_scale = 1.0
42
+ lcm_diffusion_setting.inference_steps = steps
43
+ lcm_diffusion_setting.seed = seed
44
+ lcm_diffusion_setting.use_seed = True
45
+ lcm_diffusion_setting.image_width = 256 if is_openvino_device() else 512
46
+ lcm_diffusion_setting.image_height = 256 if is_openvino_device() else 512
47
+ lcm_diffusion_setting.use_openvino = True if is_openvino_device() else False
48
+ lcm_text_to_image.init(
49
+ DEVICE,
50
+ lcm_diffusion_setting,
51
+ )
52
+ start = perf_counter()
53
+
54
+ images = lcm_text_to_image.generate(lcm_diffusion_setting)
55
+ latency = perf_counter() - start
56
+ print(f"Latency: {latency:.2f} seconds")
57
+ return images[0]
58
+
59
+
60
+ css = """
61
+ #container{
62
+ margin: 0 auto;
63
+ max-width: 40rem;
64
+ }
65
+ #intro{
66
+ max-width: 100%;
67
+ text-align: center;
68
+ margin: 0 auto;
69
+ }
70
+ #generate_button {
71
+ color: white;
72
+ border-color: #007bff;
73
+ background: #007bff;
74
+ width: 200px;
75
+ height: 50px;
76
+ }
77
+ footer {
78
+ visibility: hidden
79
+ }
80
+ """
81
+
82
+
83
+ def _get_footer_message() -> str:
84
+ version = f"<center><p> {APP_VERSION} "
85
+ footer_msg = version + (
86
+ ' © 2023 <a href="https://github.com/rupeshs">'
87
+ " Rupesh Sreeraman</a></p></center>"
88
+ )
89
+ return footer_msg
90
+
91
+
92
+ with gr.Blocks(css=css) as demo:
93
+ with gr.Column(elem_id="container"):
94
+ use_openvino = "- OpenVINO" if is_openvino_device() else ""
95
+ gr.Markdown(
96
+ f"""# Realtime FastSD CPU {use_openvino}
97
+ **Device : {DEVICE} , {get_device_name()}**
98
+ """,
99
+ elem_id="intro",
100
+ )
101
+
102
+ with gr.Row():
103
+ with gr.Row():
104
+ prompt = gr.Textbox(
105
+ placeholder="Describe the image you'd like to see",
106
+ scale=5,
107
+ container=False,
108
+ )
109
+ generate_btn = gr.Button(
110
+ "Generate",
111
+ scale=1,
112
+ elem_id="generate_button",
113
+ )
114
+
115
+ image = gr.Image(type="filepath")
116
+ with gr.Accordion("Advanced options", open=False):
117
+ steps = gr.Slider(
118
+ label="Steps",
119
+ value=4 if is_openvino_device() else 3,
120
+ minimum=1,
121
+ maximum=6,
122
+ step=1,
123
+ )
124
+ seed = gr.Slider(
125
+ randomize=True,
126
+ minimum=0,
127
+ maximum=999999999,
128
+ label="Seed",
129
+ step=1,
130
+ )
131
+ gr.HTML(_get_footer_message())
132
+
133
+ inputs = [prompt, steps, seed]
134
+ prompt.input(fn=predict, inputs=inputs, outputs=image, show_progress=False)
135
+ generate_btn.click(
136
+ fn=predict, inputs=inputs, outputs=image, show_progress=False
137
+ )
138
+ steps.change(fn=predict, inputs=inputs, outputs=image, show_progress=False)
139
+ seed.change(fn=predict, inputs=inputs, outputs=image, show_progress=False)
140
+
141
+
142
+ def start_realtime_text_to_image(share=False):
143
+ demo.queue()
144
+ demo.launch(share=share)
frontend/webui/text_to_image_ui.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from typing import Any
3
+ from backend.models.lcmdiffusion_setting import DiffusionTask
4
+ from context import Context
5
+ from models.interface_types import InterfaceType
6
+ from constants import DEVICE
7
+ from state import get_settings
8
+ from frontend.utils import is_reshape_required
9
+ from concurrent.futures import ThreadPoolExecutor
10
+ from pprint import pprint
11
+
12
+ app_settings = get_settings()
13
+ context = Context(InterfaceType.WEBUI)
14
+ previous_width = 0
15
+ previous_height = 0
16
+ previous_model_id = ""
17
+ previous_num_of_images = 0
18
+
19
+
20
+ def generate_text_to_image(
21
+ prompt,
22
+ neg_prompt,
23
+ ) -> Any:
24
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
25
+ app_settings.settings.lcm_diffusion_setting.prompt = prompt
26
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = neg_prompt
27
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
28
+ DiffusionTask.text_to_image.value
29
+ )
30
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
31
+ reshape = False
32
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
33
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
34
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
35
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
36
+ reshape = is_reshape_required(
37
+ previous_width,
38
+ image_width,
39
+ previous_height,
40
+ image_height,
41
+ previous_model_id,
42
+ model_id,
43
+ previous_num_of_images,
44
+ num_images,
45
+ )
46
+
47
+ with ThreadPoolExecutor(max_workers=1) as executor:
48
+ future = executor.submit(
49
+ context.generate_text_to_image,
50
+ app_settings.settings,
51
+ reshape,
52
+ DEVICE,
53
+ )
54
+ images = future.result()
55
+ # images = context.generate_text_to_image(
56
+ # app_settings.settings,
57
+ # reshape,
58
+ # DEVICE,
59
+ # )
60
+ previous_width = image_width
61
+ previous_height = image_height
62
+ previous_model_id = model_id
63
+ previous_num_of_images = num_images
64
+ return images
65
+
66
+
67
+ def get_text_to_image_ui() -> None:
68
+ with gr.Blocks():
69
+ with gr.Row():
70
+ with gr.Column():
71
+ with gr.Row():
72
+ prompt = gr.Textbox(
73
+ show_label=False,
74
+ lines=3,
75
+ placeholder="A fantasy landscape",
76
+ container=False,
77
+ )
78
+
79
+ generate_btn = gr.Button(
80
+ "Generate",
81
+ elem_id="generate_button",
82
+ scale=0,
83
+ )
84
+ negative_prompt = gr.Textbox(
85
+ label="Negative prompt (Works in LCM-LoRA mode, set guidance > 1.0) :",
86
+ lines=1,
87
+ placeholder="",
88
+ )
89
+
90
+ input_params = [prompt, negative_prompt]
91
+
92
+ with gr.Column():
93
+ output = gr.Gallery(
94
+ label="Generated images",
95
+ show_label=True,
96
+ elem_id="gallery",
97
+ columns=2,
98
+ height=512,
99
+ )
100
+ generate_btn.click(
101
+ fn=generate_text_to_image,
102
+ inputs=input_params,
103
+ outputs=output,
104
+ )
frontend/webui/ui.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from constants import APP_VERSION
3
+ from frontend.webui.text_to_image_ui import get_text_to_image_ui
4
+ from frontend.webui.image_to_image_ui import get_image_to_image_ui
5
+ from frontend.webui.generation_settings_ui import get_generation_settings_ui
6
+ from frontend.webui.models_ui import get_models_ui
7
+ from paths import FastStableDiffusionPaths
8
+ from state import get_settings
9
+
10
+ app_settings = get_settings()
11
+
12
+
13
+ def _get_footer_message() -> str:
14
+ version = f"<center><p> {APP_VERSION} "
15
+ footer_msg = version + (
16
+ ' © 2023 <a href="https://github.com/rupeshs">'
17
+ " Rupesh Sreeraman</a></p></center>"
18
+ )
19
+ return footer_msg
20
+
21
+
22
+ def get_web_ui() -> gr.Blocks:
23
+ def change_mode(mode):
24
+ global app_settings
25
+ app_settings.settings.lcm_diffusion_setting.use_lcm_lora = False
26
+ app_settings.settings.lcm_diffusion_setting.use_openvino = False
27
+ if mode == "LCM-LoRA":
28
+ app_settings.settings.lcm_diffusion_setting.use_lcm_lora = True
29
+ elif mode == "LCM-OpenVINO":
30
+ app_settings.settings.lcm_diffusion_setting.use_openvino = True
31
+
32
+ with gr.Blocks(
33
+ css=FastStableDiffusionPaths.get_css_path(),
34
+ title="FastSD CPU",
35
+ ) as fastsd_web_ui:
36
+ gr.HTML("<center><H1>FastSD CPU</H1></center>")
37
+ current_mode = "LCM"
38
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
39
+ current_mode = "LCM-OpenVINO"
40
+ elif app_settings.settings.lcm_diffusion_setting.use_lcm_lora:
41
+ current_mode = "LCM-LoRA"
42
+
43
+ mode = gr.Radio(
44
+ ["LCM", "LCM-LoRA", "LCM-OpenVINO"],
45
+ label="Mode",
46
+ info="Current working mode",
47
+ value=current_mode,
48
+ )
49
+ mode.change(change_mode, inputs=mode)
50
+
51
+ with gr.Tabs():
52
+ with gr.TabItem("Text to Image"):
53
+ get_text_to_image_ui()
54
+ with gr.TabItem("Image to Image"):
55
+ get_image_to_image_ui()
56
+ with gr.TabItem("Generation Settings"):
57
+ get_generation_settings_ui()
58
+ with gr.TabItem("Models"):
59
+ get_models_ui()
60
+
61
+ gr.HTML(_get_footer_message())
62
+
63
+ return fastsd_web_ui
64
+
65
+
66
+ def start_webui(
67
+ share: bool = False,
68
+ ):
69
+ webui = get_web_ui()
70
+ webui.launch(share=share)
image_ops.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+
3
+
4
+ def resize_pil_image(
5
+ pil_image: Image,
6
+ image_width,
7
+ image_height,
8
+ ):
9
+ return pil_image.convert("RGB").resize(
10
+ (
11
+ image_width,
12
+ image_height,
13
+ ),
14
+ Image.Resampling.LANCZOS,
15
+ )