michaelj commited on
Commit
e23d4ed
1 Parent(s): 45144b6

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -25,6 +25,7 @@
25
  *.safetensors filter=lfs diff=lfs merge=lfs -text
26
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
  *.tar.* filter=lfs diff=lfs merge=lfs -text
 
28
  *.tflite filter=lfs diff=lfs merge=lfs -text
29
  *.tgz filter=lfs diff=lfs merge=lfs -text
30
  *.wasm filter=lfs diff=lfs merge=lfs -text
 
25
  *.safetensors filter=lfs diff=lfs merge=lfs -text
26
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
  *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
  *.tflite filter=lfs diff=lfs merge=lfs -text
30
  *.tgz filter=lfs diff=lfs merge=lfs -text
31
  *.wasm filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,4 +1,3 @@
1
-
2
  FROM python:3.9
3
 
4
  WORKDIR /code
 
 
1
  FROM python:3.9
2
 
3
  WORKDIR /code
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: FastAPI In Docker
3
- emoji: 🐢
4
- colorFrom: yellow
5
- colorTo: red
6
- sdk: docker
 
 
7
  pinned: false
 
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Fastlcm
3
+ emoji: 🏆
4
+ colorFrom: gray
5
+ colorTo: yellow
6
+ sdk: gradio
7
+ sdk_version: 4.8.0
8
+ app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
__init__.py ADDED
File without changes
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/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,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.task_type = DiffusionTask.text_to_image
42
+ self.torch_data_type = (
43
+ torch.float32 if is_openvino_device() or DEVICE == "mps" else torch.float16
44
+ )
45
+ print(f"Torch datatype : {self.torch_data_type}")
46
+
47
+ def _pipeline_to_device(self):
48
+ print(f"Pipeline device : {DEVICE}")
49
+ print(f"Pipeline dtype : {self.torch_data_type}")
50
+ self.pipeline.to(
51
+ torch_device=DEVICE,
52
+ torch_dtype=self.torch_data_type,
53
+ )
54
+
55
+ def _add_freeu(self):
56
+ pipeline_class = self.pipeline.__class__.__name__
57
+ if isinstance(self.pipeline.scheduler, LCMScheduler):
58
+ if pipeline_class == "StableDiffusionPipeline":
59
+ print("Add FreeU - SD")
60
+ self.pipeline.enable_freeu(
61
+ s1=0.9,
62
+ s2=0.2,
63
+ b1=1.2,
64
+ b2=1.4,
65
+ )
66
+ elif pipeline_class == "StableDiffusionXLPipeline":
67
+ print("Add FreeU - SDXL")
68
+ self.pipeline.enable_freeu(
69
+ s1=0.6,
70
+ s2=0.4,
71
+ b1=1.1,
72
+ b2=1.2,
73
+ )
74
+
75
+ def _update_lcm_scheduler_params(self):
76
+ if isinstance(self.pipeline.scheduler, LCMScheduler):
77
+ self.pipeline.scheduler = LCMScheduler.from_config(
78
+ self.pipeline.scheduler.config,
79
+ beta_start=0.001,
80
+ beta_end=0.01,
81
+ )
82
+
83
+ def init(
84
+ self,
85
+ device: str = "cpu",
86
+ lcm_diffusion_setting: LCMDiffusionSetting = LCMDiffusionSetting(),
87
+ ) -> None:
88
+ self.device = device
89
+ self.use_openvino = lcm_diffusion_setting.use_openvino
90
+ model_id = lcm_diffusion_setting.lcm_model_id
91
+ use_local_model = lcm_diffusion_setting.use_offline_model
92
+ use_tiny_auto_encoder = lcm_diffusion_setting.use_tiny_auto_encoder
93
+ use_lora = lcm_diffusion_setting.use_lcm_lora
94
+ lcm_lora: LCMLora = lcm_diffusion_setting.lcm_lora
95
+ ov_model_id = lcm_diffusion_setting.openvino_lcm_model_id
96
+
97
+ if lcm_diffusion_setting.diffusion_task == DiffusionTask.image_to_image.value:
98
+ w, h = lcm_diffusion_setting.init_image.size
99
+ newW = lcm_diffusion_setting.image_width
100
+ newH = int(h * newW / w)
101
+ img = lcm_diffusion_setting.init_image.resize((newW, newH))
102
+ print("新图",newH,newW, lcm_diffusion_setting.image_height)
103
+ lcm_diffusion_setting.init_image = resize_pil_image(
104
+ img,
105
+ lcm_diffusion_setting.image_width,
106
+ lcm_diffusion_setting.image_height,
107
+ )
108
+ print("图片大小",lcm_diffusion_setting.init_image)
109
+
110
+ if (
111
+ self.pipeline is None
112
+ or self.previous_model_id != model_id
113
+ or self.previous_use_tae_sd != use_tiny_auto_encoder
114
+ or self.previous_lcm_lora_base_id != lcm_lora.base_model_id
115
+ or self.previous_lcm_lora_id != lcm_lora.lcm_lora_id
116
+ or self.previous_use_lcm_lora != use_lora
117
+ or self.previous_ov_model_id != ov_model_id
118
+ or self.previous_safety_checker != lcm_diffusion_setting.use_safety_checker
119
+ or self.previous_use_openvino != lcm_diffusion_setting.use_openvino
120
+ or self.previous_task_type != lcm_diffusion_setting.diffusion_task
121
+ ):
122
+ if self.use_openvino and is_openvino_device():
123
+ if self.pipeline:
124
+ del self.pipeline
125
+ self.pipeline = None
126
+ self.is_openvino_init = True
127
+ if (
128
+ lcm_diffusion_setting.diffusion_task
129
+ == DiffusionTask.text_to_image.value
130
+ ):
131
+ print(f"***** Init Text to image (OpenVINO) - {ov_model_id} *****")
132
+ self.pipeline = get_ov_text_to_image_pipeline(
133
+ ov_model_id,
134
+ use_local_model,
135
+ )
136
+ elif (
137
+ lcm_diffusion_setting.diffusion_task
138
+ == DiffusionTask.image_to_image.value
139
+ ):
140
+ print(f"***** Image to image (OpenVINO) - {ov_model_id} *****")
141
+ self.pipeline = get_ov_image_to_image_pipeline(
142
+ ov_model_id,
143
+ use_local_model,
144
+ )
145
+ else:
146
+ if self.pipeline:
147
+ del self.pipeline
148
+ self.pipeline = None
149
+ if self.img_to_img_pipeline:
150
+ del self.img_to_img_pipeline
151
+ self.img_to_img_pipeline = None
152
+
153
+ if use_lora:
154
+ print(
155
+ f"***** Init LCM-LoRA pipeline - {lcm_lora.base_model_id} *****"
156
+ )
157
+ self.pipeline = get_lcm_lora_pipeline(
158
+ lcm_lora.base_model_id,
159
+ lcm_lora.lcm_lora_id,
160
+ use_local_model,
161
+ torch_data_type=self.torch_data_type,
162
+ )
163
+ else:
164
+ print(f"***** Init LCM Model pipeline - {model_id} *****")
165
+ self.pipeline = get_lcm_model_pipeline(
166
+ model_id,
167
+ use_local_model,
168
+ )
169
+
170
+ if (
171
+ lcm_diffusion_setting.diffusion_task
172
+ == DiffusionTask.image_to_image.value
173
+ ):
174
+ self.img_to_img_pipeline = get_image_to_image_pipeline(
175
+ self.pipeline
176
+ )
177
+ self._pipeline_to_device()
178
+
179
+ if use_tiny_auto_encoder:
180
+ if self.use_openvino and is_openvino_device():
181
+ print("Using Tiny Auto Encoder (OpenVINO)")
182
+ ov_load_taesd(
183
+ self.pipeline,
184
+ use_local_model,
185
+ )
186
+ else:
187
+ print("Using Tiny Auto Encoder")
188
+ if (
189
+ lcm_diffusion_setting.diffusion_task
190
+ == DiffusionTask.text_to_image.value
191
+ ):
192
+ load_taesd(
193
+ self.pipeline,
194
+ use_local_model,
195
+ self.torch_data_type,
196
+ )
197
+ elif (
198
+ lcm_diffusion_setting.diffusion_task
199
+ == DiffusionTask.image_to_image.value
200
+ ):
201
+ load_taesd(
202
+ self.img_to_img_pipeline,
203
+ use_local_model,
204
+ self.torch_data_type,
205
+ )
206
+
207
+ if (
208
+ lcm_diffusion_setting.diffusion_task
209
+ == DiffusionTask.image_to_image.value
210
+ and lcm_diffusion_setting.use_openvino
211
+ ):
212
+ self.pipeline.scheduler = LCMScheduler.from_config(
213
+ self.pipeline.scheduler.config,
214
+ )
215
+ else:
216
+ self._update_lcm_scheduler_params()
217
+
218
+ if use_lora:
219
+ self._add_freeu()
220
+
221
+ self.previous_model_id = model_id
222
+ self.previous_ov_model_id = ov_model_id
223
+ self.previous_use_tae_sd = use_tiny_auto_encoder
224
+ self.previous_lcm_lora_base_id = lcm_lora.base_model_id
225
+ self.previous_lcm_lora_id = lcm_lora.lcm_lora_id
226
+ self.previous_use_lcm_lora = use_lora
227
+ self.previous_safety_checker = lcm_diffusion_setting.use_safety_checker
228
+ self.previous_use_openvino = lcm_diffusion_setting.use_openvino
229
+ self.previous_task_type = lcm_diffusion_setting.diffusion_task
230
+ if (
231
+ lcm_diffusion_setting.diffusion_task
232
+ == DiffusionTask.text_to_image.value
233
+ ):
234
+ print(f"Pipeline : {self.pipeline}")
235
+ elif (
236
+ lcm_diffusion_setting.diffusion_task
237
+ == DiffusionTask.image_to_image.value
238
+ ):
239
+ if self.use_openvino and is_openvino_device():
240
+ print(f"Pipeline : {self.pipeline}")
241
+ else:
242
+ print(f"Pipeline : {self.img_to_img_pipeline}")
243
+
244
+ def generate(
245
+ self,
246
+ lcm_diffusion_setting: LCMDiffusionSetting,
247
+ reshape: bool = False,
248
+ ) -> Any:
249
+ guidance_scale = lcm_diffusion_setting.guidance_scale
250
+ img_to_img_inference_steps = lcm_diffusion_setting.inference_steps
251
+ check_step_value = int(
252
+ lcm_diffusion_setting.inference_steps * lcm_diffusion_setting.strength
253
+ )
254
+ if (
255
+ lcm_diffusion_setting.diffusion_task == DiffusionTask.image_to_image.value
256
+ and check_step_value < 1
257
+ ):
258
+ img_to_img_inference_steps = ceil(1 / lcm_diffusion_setting.strength)
259
+ print(
260
+ f"Strength: {lcm_diffusion_setting.strength},{img_to_img_inference_steps}"
261
+ )
262
+
263
+ if lcm_diffusion_setting.use_seed:
264
+ cur_seed = lcm_diffusion_setting.seed
265
+ if self.use_openvino:
266
+ np.random.seed(cur_seed)
267
+ else:
268
+ torch.manual_seed(cur_seed)
269
+
270
+ is_openvino_pipe = lcm_diffusion_setting.use_openvino and is_openvino_device()
271
+ if is_openvino_pipe:
272
+ print("Using OpenVINO")
273
+ if reshape and not self.is_openvino_init:
274
+ print("Reshape and compile")
275
+ self.pipeline.reshape(
276
+ batch_size=-1,
277
+ height=lcm_diffusion_setting.image_height,
278
+ width=lcm_diffusion_setting.image_width,
279
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
280
+ )
281
+ self.pipeline.compile()
282
+
283
+ if self.is_openvino_init:
284
+ self.is_openvino_init = False
285
+
286
+ if not lcm_diffusion_setting.use_safety_checker:
287
+ self.pipeline.safety_checker = None
288
+ if (
289
+ lcm_diffusion_setting.diffusion_task
290
+ == DiffusionTask.image_to_image.value
291
+ and not is_openvino_pipe
292
+ ):
293
+ self.img_to_img_pipeline.safety_checker = None
294
+
295
+ if (
296
+ not lcm_diffusion_setting.use_lcm_lora
297
+ and not lcm_diffusion_setting.use_openvino
298
+ and lcm_diffusion_setting.guidance_scale != 1.0
299
+ ):
300
+ print("Not using LCM-LoRA so setting guidance_scale 1.0")
301
+ guidance_scale = 1.0
302
+
303
+ if lcm_diffusion_setting.use_openvino:
304
+ if (
305
+ lcm_diffusion_setting.diffusion_task
306
+ == DiffusionTask.text_to_image.value
307
+ ):
308
+ result_images = self.pipeline(
309
+ prompt=lcm_diffusion_setting.prompt,
310
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
311
+ num_inference_steps=lcm_diffusion_setting.inference_steps,
312
+ guidance_scale=guidance_scale,
313
+ width=lcm_diffusion_setting.image_width,
314
+ height=lcm_diffusion_setting.image_height,
315
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
316
+ ).images
317
+ elif (
318
+ lcm_diffusion_setting.diffusion_task
319
+ == DiffusionTask.image_to_image.value
320
+ ):
321
+ result_images = self.pipeline(
322
+ image=lcm_diffusion_setting.init_image,
323
+ strength=lcm_diffusion_setting.strength,
324
+ prompt=lcm_diffusion_setting.prompt,
325
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
326
+ num_inference_steps=img_to_img_inference_steps * 3,
327
+ guidance_scale=guidance_scale,
328
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
329
+ ).images
330
+
331
+ else:
332
+ if (
333
+ lcm_diffusion_setting.diffusion_task
334
+ == DiffusionTask.text_to_image.value
335
+ ):
336
+ result_images = self.pipeline(
337
+ prompt=lcm_diffusion_setting.prompt,
338
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
339
+ num_inference_steps=lcm_diffusion_setting.inference_steps,
340
+ guidance_scale=guidance_scale,
341
+ width=lcm_diffusion_setting.image_width,
342
+ height=lcm_diffusion_setting.image_height,
343
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
344
+ ).images
345
+ elif (
346
+ lcm_diffusion_setting.diffusion_task
347
+ == DiffusionTask.image_to_image.value
348
+ ):
349
+ result_images = self.img_to_img_pipeline(
350
+ image=lcm_diffusion_setting.init_image,
351
+ strength=lcm_diffusion_setting.strength,
352
+ prompt=lcm_diffusion_setting.prompt,
353
+ negative_prompt=lcm_diffusion_setting.negative_prompt,
354
+ num_inference_steps=img_to_img_inference_steps,
355
+ guidance_scale=guidance_scale,
356
+ width=lcm_diffusion_setting.image_width,
357
+ height=lcm_diffusion_setting.image_height,
358
+ num_images_per_prompt=lcm_diffusion_setting.number_of_images,
359
+ ).images
360
+
361
+ return result_images
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/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/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!")
configs/lcm-lora-models.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ latent-consistency/lcm-lora-sdv1-5
2
+ latent-consistency/lcm-lora-sdxl
3
+ latent-consistency/lcm-lora-ssd-1b
configs/lcm-models.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ SimianLuo/LCM_Dreamshaper_v7
2
+ stabilityai/sd-turbo
3
+ stabilityai/sdxl-turbo
4
+ latent-consistency/lcm-sdxl
5
+ latent-consistency/lcm-ssd-1b
configs/openvino-lcm-models.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ rupeshs/LCM-dreamshaper-v7-openvino
2
+ rupeshs/sd-turbo-openvino
3
+ rupeshs/sdxl-turbo-openvino-int8
4
+ Disty0/LCM_SoteMix
configs/stable-diffusion-models.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Lykon/dreamshaper-8
2
+ Fictiverse/Stable_Diffusion_PaperCut_Model
3
+ stabilityai/stable-diffusion-xl-base-1.0
4
+ runwayml/stable-diffusion-v1-5
5
+ segmind/SSD-1B
6
+ stablediffusionapi/anything-v5
7
+ prompthero/openjourney-v4
constants.py CHANGED
@@ -1,211 +1,18 @@
1
- DESCRIPTION = """
2
- # Real Time Latent Consistency Model
3
 
4
- This space is using a **CPU runtime**, and it takes about 30 seconds to generate an image.
5
- For a faster experience, you can duplicate it and use with a **GPU runtime**.
6
-
7
- At the meantime you can use **[dynamic 🔥](https://www.fal.ai/dynamic)** by [fal](fal.ai), or **[a hosted space 🤗](https://huggingface.co/spaces/fal-ai/realtime-stable-diffusion)**
8
- to generate images in real time.
9
- """
10
-
11
-
12
- LOGO = """
13
- <svg
14
- width="100%"
15
- height="100%"
16
- viewBox="0 0 89 32"
17
- fill="none"
18
- xmlns="http://www.w3.org/2000/svg"
19
- >
20
- <path
21
- d="M52.308 3.07812H57.8465V4.92428H56.0003V6.77043H54.1541V10.4627H57.8465V12.3089H54.1541V25.232H52.308V27.0781H46.7695V25.232H48.6157V12.3089H46.7695V10.4627H48.6157V6.77043H50.4618V4.92428H52.308V3.07812Z"
22
- fill="currentColor"
23
- ></path>
24
- <path
25
- d="M79.3849 23.3858H81.2311V25.232H83.0772V27.0781H88.6157V25.232H86.7695V23.3858H84.9234V4.92428H79.3849V23.3858Z"
26
- fill="currentColor"
27
- ></path>
28
- <path
29
- d="M57.8465 14.155H59.6926V12.3089H61.5388V10.4627H70.7695V12.3089H74.4618V23.3858H76.308V25.232H78.1541V27.0781H72.6157V25.232H70.7695V23.3858H68.9234V14.155H67.0772V12.3089H65.2311V14.155H63.3849V23.3858H65.2311V25.232H67.0772V27.0781H61.5388V25.232H59.6926V23.3858H57.8465V14.155Z"
30
- fill="currentColor"
31
- ></path>
32
- <path
33
- d="M67.0772 25.232V23.3858H68.9234V25.232H67.0772Z"
34
- fill="currentColor"
35
- ></path>
36
- <rect
37
- opacity="0.22"
38
- x="7.38477"
39
- y="29.5391"
40
- width="2.46154"
41
- height="2.46154"
42
- fill="#5F4CD9"
43
- ></rect>
44
- <rect
45
- opacity="0.85"
46
- x="2.46094"
47
- y="19.6914"
48
- width="12.3077"
49
- height="2.46154"
50
- fill="#5F4CD9"
51
- ></rect>
52
- <rect
53
- x="4.92383"
54
- y="17.2305"
55
- width="9.84615"
56
- height="2.46154"
57
- fill="#5F4CD9"
58
- ></rect>
59
- <rect
60
- opacity="0.4"
61
- x="7.38477"
62
- y="27.0781"
63
- width="4.92308"
64
- height="2.46154"
65
- fill="#5F4CD9"
66
- ></rect>
67
- <rect
68
- opacity="0.7"
69
- y="22.1562"
70
- width="14.7692"
71
- height="2.46154"
72
- fill="#5F4CD9"
73
- ></rect>
74
- <rect
75
- opacity="0.5"
76
- x="7.38477"
77
- y="24.6133"
78
- width="7.38462"
79
- height="2.46154"
80
- fill="#5F4CD9"
81
- ></rect>
82
- <rect
83
- opacity="0.22"
84
- x="7.38477"
85
- y="12.3086"
86
- width="2.46154"
87
- height="2.46154"
88
- fill="#5F4CD9"
89
- ></rect>
90
- <rect
91
- opacity="0.85"
92
- x="2.46094"
93
- y="2.46094"
94
- width="12.3077"
95
- height="2.46154"
96
- fill="#5F4CD9"
97
- ></rect>
98
- <rect x="4.92383" width="9.84615" height="2.46154" fill="#5F4CD9"></rect>
99
- <rect
100
- opacity="0.4"
101
- x="7.38477"
102
- y="9.84375"
103
- width="4.92308"
104
- height="2.46154"
105
- fill="#5F4CD9"
106
- ></rect>
107
- <rect
108
- opacity="0.7"
109
- y="4.92188"
110
- width="14.7692"
111
- height="2.46154"
112
- fill="#5F4CD9"
113
- ></rect>
114
- <rect
115
- opacity="0.5"
116
- x="7.38477"
117
- y="7.38281"
118
- width="7.38462"
119
- height="2.46154"
120
- fill="#5F4CD9"
121
- ></rect>
122
- <rect
123
- opacity="0.22"
124
- x="24.6152"
125
- y="29.5391"
126
- width="2.46154"
127
- height="2.46154"
128
- fill="#5F4CD9"
129
- ></rect>
130
- <rect
131
- opacity="0.85"
132
- x="19.6914"
133
- y="19.6914"
134
- width="12.3077"
135
- height="2.46154"
136
- fill="#5F4CD9"
137
- ></rect>
138
- <rect
139
- x="22.1543"
140
- y="17.2305"
141
- width="9.84615"
142
- height="2.46154"
143
- fill="#5F4CD9"
144
- ></rect>
145
- <rect
146
- opacity="0.4"
147
- x="24.6152"
148
- y="27.0781"
149
- width="4.92308"
150
- height="2.46154"
151
- fill="#5F4CD9"
152
- ></rect>
153
- <rect
154
- opacity="0.7"
155
- x="17.2305"
156
- y="22.1562"
157
- width="14.7692"
158
- height="2.46154"
159
- fill="#5F4CD9"
160
- ></rect>
161
- <rect
162
- opacity="0.5"
163
- x="24.6152"
164
- y="24.6133"
165
- width="7.38462"
166
- height="2.46154"
167
- fill="#5F4CD9"
168
- ></rect>
169
- <rect
170
- opacity="0.22"
171
- x="24.6152"
172
- y="12.3086"
173
- width="2.46154"
174
- height="2.46154"
175
- fill="#5F4CD9"
176
- ></rect>
177
- <rect
178
- opacity="0.85"
179
- x="19.6914"
180
- y="2.46094"
181
- width="12.3077"
182
- height="2.46154"
183
- fill="#5F4CD9"
184
- ></rect>
185
- <rect x="22.1543" width="9.84615" height="2.46154" fill="#5F4CD9"></rect>
186
- <rect
187
- opacity="0.4"
188
- x="24.6152"
189
- y="9.84375"
190
- width="4.92308"
191
- height="2.46154"
192
- fill="#5F4CD9"
193
- ></rect>
194
- <rect
195
- opacity="0.7"
196
- x="17.2305"
197
- y="4.92188"
198
- width="14.7692"
199
- height="2.46154"
200
- fill="#5F4CD9"
201
- ></rect>
202
- <rect
203
- opacity="0.5"
204
- x="24.6152"
205
- y="7.38281"
206
- width="7.38462"
207
- height="2.46154"
208
- fill="#5F4CD9"
209
- ></rect>
210
- </svg>
211
- """
 
1
+ from os import environ
 
2
 
3
+ APP_VERSION = "v1.0.0 beta 23"
4
+ LCM_DEFAULT_MODEL = "SimianLuo/LCM_Dreamshaper_v7"
5
+ LCM_DEFAULT_MODEL_OPENVINO = "rupeshs/LCM-dreamshaper-v7-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,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+
10
+ class Context:
11
+ def __init__(
12
+ self,
13
+ interface_type: InterfaceType,
14
+ device="cpu",
15
+ ):
16
+ self.interface_type = interface_type
17
+ self.lcm_text_to_image = LCMTextToImage(device)
18
+
19
+ def generate_text_to_image(
20
+ self,
21
+ settings: Settings,
22
+ reshape: bool = False,
23
+ device: str = "cpu",
24
+ ) -> Any:
25
+ tick = perf_counter()
26
+ from state import get_settings
27
+
28
+ get_settings().save()
29
+ pprint(settings.lcm_diffusion_setting.model_dump())
30
+ if not settings.lcm_diffusion_setting.lcm_lora:
31
+ return None
32
+ self.lcm_text_to_image.init(
33
+ device,
34
+ settings.lcm_diffusion_setting,
35
+ )
36
+ images = self.lcm_text_to_image.generate(
37
+ settings.lcm_diffusion_setting,
38
+ reshape,
39
+ )
40
+ elapsed = perf_counter() - tick
41
+ ImageSaver.save_images(
42
+ settings.results_path,
43
+ images=images,
44
+ lcm_diffusion_setting=settings.lcm_diffusion_setting,
45
+ )
46
+ print(f"Latency : {elapsed:.2f} seconds")
47
+ return images
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/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_offline_checkbox, offline_checkbox)
frontend/webui/image_to_image_ui.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ import gradio as gr
3
+ from backend.models.lcmdiffusion_setting import DiffusionTask
4
+ from models.interface_types import InterfaceType
5
+ from frontend.utils import is_reshape_required
6
+ from constants import DEVICE
7
+ from state import get_settings, get_context
8
+ from concurrent.futures import ThreadPoolExecutor
9
+
10
+ app_settings = get_settings()
11
+
12
+ context = get_context(InterfaceType.WEBUI)
13
+ previous_width = 0
14
+ previous_height = 0
15
+ previous_model_id = ""
16
+ previous_num_of_images = 0
17
+
18
+
19
+ def generate_image_to_image(
20
+ prompt,
21
+ negative_prompt,
22
+ init_image,
23
+ strength,
24
+ ) -> Any:
25
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
26
+
27
+ app_settings.settings.lcm_diffusion_setting.prompt = prompt
28
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = negative_prompt
29
+ app_settings.settings.lcm_diffusion_setting.init_image = init_image
30
+ app_settings.settings.lcm_diffusion_setting.strength = strength
31
+
32
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
33
+ DiffusionTask.image_to_image.value
34
+ )
35
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
36
+ reshape = False
37
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
38
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
39
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
40
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
41
+ reshape = is_reshape_required(
42
+ previous_width,
43
+ image_width,
44
+ previous_height,
45
+ image_height,
46
+ previous_model_id,
47
+ model_id,
48
+ previous_num_of_images,
49
+ num_images,
50
+ )
51
+
52
+ with ThreadPoolExecutor(max_workers=1) as executor:
53
+ future = executor.submit(
54
+ context.generate_text_to_image,
55
+ app_settings.settings,
56
+ reshape,
57
+ DEVICE,
58
+ )
59
+ images = future.result()
60
+ # images = context.generate_text_to_image(
61
+ # app_settings.settings,
62
+ # reshape,
63
+ # DEVICE,
64
+ # )
65
+ previous_width = image_width
66
+ previous_height = image_height
67
+ previous_model_id = model_id
68
+ previous_num_of_images = num_images
69
+ return images
70
+
71
+
72
+ def get_image_to_image_ui() -> None:
73
+ with gr.Blocks():
74
+ with gr.Row():
75
+ with gr.Column():
76
+ input_image = gr.Image(label="Init image", type="pil")
77
+ with gr.Row():
78
+ prompt = gr.Textbox(
79
+ show_label=False,
80
+ lines=3,
81
+ placeholder="A fantasy landscape",
82
+ container=False,
83
+ )
84
+
85
+ generate_btn = gr.Button(
86
+ "Generate",
87
+ elem_id="generate_button",
88
+ scale=0,
89
+ )
90
+ negative_prompt = gr.Textbox(
91
+ label="Negative prompt (Works in LCM-LoRA mode, set guidance > 1.0):",
92
+ lines=1,
93
+ placeholder="",
94
+ )
95
+ strength = gr.Slider(
96
+ 0.1,
97
+ 1,
98
+ value=app_settings.settings.lcm_diffusion_setting.strength,
99
+ step=0.01,
100
+ label="Strength",
101
+ )
102
+
103
+ input_params = [
104
+ prompt,
105
+ negative_prompt,
106
+ input_image,
107
+ strength,
108
+ ]
109
+
110
+ with gr.Column():
111
+ output = gr.Gallery(
112
+ label="Generated images",
113
+ show_label=True,
114
+ elem_id="gallery",
115
+ columns=2,
116
+ height=512,
117
+ )
118
+
119
+ generate_btn.click(
120
+ fn=generate_image_to_image,
121
+ inputs=input_params,
122
+ outputs=output,
123
+ )
frontend/webui/image_variations_ui.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, get_context
9
+ from concurrent.futures import ThreadPoolExecutor
10
+
11
+ app_settings = get_settings()
12
+
13
+ context = get_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_variations(
21
+ init_image,
22
+ variation_strength,
23
+ ) -> Any:
24
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
25
+
26
+ app_settings.settings.lcm_diffusion_setting.init_image = init_image
27
+ app_settings.settings.lcm_diffusion_setting.strength = variation_strength
28
+ app_settings.settings.lcm_diffusion_setting.prompt = ""
29
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = ""
30
+
31
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
32
+ DiffusionTask.image_to_image.value
33
+ )
34
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
35
+ reshape = False
36
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
37
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
38
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
39
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
40
+ reshape = is_reshape_required(
41
+ previous_width,
42
+ image_width,
43
+ previous_height,
44
+ image_height,
45
+ previous_model_id,
46
+ model_id,
47
+ previous_num_of_images,
48
+ num_images,
49
+ )
50
+
51
+ with ThreadPoolExecutor(max_workers=1) as executor:
52
+ future = executor.submit(
53
+ context.generate_text_to_image,
54
+ app_settings.settings,
55
+ reshape,
56
+ DEVICE,
57
+ )
58
+ images = future.result()
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_image_variations_ui() -> None:
68
+ with gr.Blocks():
69
+ with gr.Row():
70
+ with gr.Column():
71
+ input_image = gr.Image(label="Init image", type="pil")
72
+ with gr.Row():
73
+ generate_btn = gr.Button(
74
+ "Generate",
75
+ elem_id="generate_button",
76
+ scale=0,
77
+ )
78
+
79
+ variation_strength = gr.Slider(
80
+ 0.1,
81
+ 1,
82
+ value=0.4,
83
+ step=0.01,
84
+ label="Variations Strength",
85
+ )
86
+
87
+ input_params = [
88
+ input_image,
89
+ variation_strength,
90
+ ]
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
+
101
+ generate_btn.click(
102
+ fn=generate_image_variations,
103
+ inputs=input_params,
104
+ outputs=output,
105
+ )
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,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from typing import Any
3
+ from backend.models.lcmdiffusion_setting import DiffusionTask
4
+ from models.interface_types import InterfaceType
5
+ from constants import DEVICE
6
+ from state import get_settings, get_context
7
+ from frontend.utils import is_reshape_required
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ from pprint import pprint
10
+
11
+ app_settings = get_settings()
12
+ context = get_context(InterfaceType.WEBUI)
13
+ previous_width = 0
14
+ previous_height = 0
15
+ previous_model_id = ""
16
+ previous_num_of_images = 0
17
+
18
+
19
+ def generate_text_to_image(
20
+ prompt,
21
+ neg_prompt,
22
+ ) -> Any:
23
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
24
+ app_settings.settings.lcm_diffusion_setting.prompt = prompt
25
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = neg_prompt
26
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
27
+ DiffusionTask.text_to_image.value
28
+ )
29
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
30
+ reshape = False
31
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
32
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
33
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
34
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
35
+ reshape = is_reshape_required(
36
+ previous_width,
37
+ image_width,
38
+ previous_height,
39
+ image_height,
40
+ previous_model_id,
41
+ model_id,
42
+ previous_num_of_images,
43
+ num_images,
44
+ )
45
+
46
+ with ThreadPoolExecutor(max_workers=1) as executor:
47
+ future = executor.submit(
48
+ context.generate_text_to_image,
49
+ app_settings.settings,
50
+ reshape,
51
+ DEVICE,
52
+ )
53
+ images = future.result()
54
+ # images = context.generate_text_to_image(
55
+ # app_settings.settings,
56
+ # reshape,
57
+ # DEVICE,
58
+ # )
59
+ previous_width = image_width
60
+ previous_height = image_height
61
+ previous_model_id = model_id
62
+ previous_num_of_images = num_images
63
+ return images
64
+
65
+
66
+ def get_text_to_image_ui() -> None:
67
+ with gr.Blocks():
68
+ with gr.Row():
69
+ with gr.Column():
70
+ with gr.Row():
71
+ prompt = gr.Textbox(
72
+ show_label=False,
73
+ lines=3,
74
+ placeholder="A fantasy landscape",
75
+ container=False,
76
+ )
77
+
78
+ generate_btn = gr.Button(
79
+ "Generate",
80
+ elem_id="generate_button",
81
+ scale=0,
82
+ )
83
+ negative_prompt = gr.Textbox(
84
+ label="Negative prompt (Works in LCM-LoRA mode, set guidance > 1.0) :",
85
+ lines=1,
86
+ placeholder="",
87
+ )
88
+
89
+ input_params = [prompt, negative_prompt]
90
+
91
+ with gr.Column():
92
+ output = gr.Gallery(
93
+ label="Generated images",
94
+ show_label=True,
95
+ elem_id="gallery",
96
+ columns=2,
97
+ height=512,
98
+ )
99
+ generate_btn.click(
100
+ fn=generate_text_to_image,
101
+ inputs=input_params,
102
+ outputs=output,
103
+ )
frontend/webui/ui.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 frontend.webui.image_variations_ui import get_image_variations_ui
8
+ from paths import FastStableDiffusionPaths
9
+ from state import get_settings
10
+
11
+ app_settings = get_settings()
12
+
13
+
14
+ def _get_footer_message() -> str:
15
+ version = f"<center><p> {APP_VERSION} "
16
+ footer_msg = version + (
17
+ ' © 2023 <a href="https://github.com/rupeshs">'
18
+ " Rupesh Sreeraman</a></p></center>"
19
+ )
20
+ return footer_msg
21
+
22
+
23
+ def get_web_ui() -> gr.Blocks:
24
+ def change_mode(mode):
25
+ global app_settings
26
+ app_settings.settings.lcm_diffusion_setting.use_lcm_lora = False
27
+ app_settings.settings.lcm_diffusion_setting.use_openvino = False
28
+ if mode == "LCM-LoRA":
29
+ app_settings.settings.lcm_diffusion_setting.use_lcm_lora = True
30
+ elif mode == "LCM-OpenVINO":
31
+ app_settings.settings.lcm_diffusion_setting.use_openvino = True
32
+
33
+ with gr.Blocks(
34
+ css=FastStableDiffusionPaths.get_css_path(),
35
+ title="FastSD CPU",
36
+ ) as fastsd_web_ui:
37
+ gr.HTML("<center><H1>FastSD CPU</H1></center>")
38
+ current_mode = "LCM"
39
+ if app_settings.settings.lcm_diffusion_setting.use_openvino:
40
+ current_mode = "LCM-OpenVINO"
41
+ elif app_settings.settings.lcm_diffusion_setting.use_lcm_lora:
42
+ current_mode = "LCM-LoRA"
43
+
44
+ mode = gr.Radio(
45
+ ["LCM", "LCM-LoRA", "LCM-OpenVINO"],
46
+ label="Mode",
47
+ info="Current working mode",
48
+ value=current_mode,
49
+ )
50
+ mode.change(change_mode, inputs=mode)
51
+
52
+ with gr.Tabs():
53
+ with gr.TabItem("Text to Image"):
54
+ get_text_to_image_ui()
55
+ with gr.TabItem("Image to Image"):
56
+ get_image_to_image_ui()
57
+ with gr.TabItem("Image Variations"):
58
+ get_image_variations_ui()
59
+ with gr.TabItem("Generation Settings"):
60
+ get_generation_settings_ui()
61
+ with gr.TabItem("Models"):
62
+ get_models_ui()
63
+
64
+ gr.HTML(_get_footer_message())
65
+
66
+ return fastsd_web_ui
67
+
68
+
69
+ def start_webui(
70
+ share: bool = False,
71
+ ):
72
+ webui = get_web_ui()
73
+ 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
+ )
main.py CHANGED
@@ -1,3 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
1
 
2
  from fastapi import FastAPI,Body
3
 
@@ -6,26 +17,187 @@ import json
6
  import logging
7
  from PIL import Image
8
  import time
9
- from constants import DESCRIPTION, LOGO
10
- from model import get_pipeline
11
- from utils import replace_background
12
  from diffusers.utils import load_image
13
  import base64
14
  import io
15
  from datetime import datetime
16
 
17
- app = FastAPI(name="mutilParam")
18
- pipeline = get_pipeline()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- #Endpoints
21
- #Root endpoints
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  @app.get("/")
23
  def root():
24
- return {"API": "Sum of 2 Squares"}
25
-
26
  @app.post("/img2img")
27
- async def predict(prompt=Body(...),imgbase64data=Body(...),userId=Body(None)):
28
- pipeline = get_pipeline()
29
  MAX_QUEUE_SIZE = 4
30
  start = time.time()
31
  print("参数",imgbase64data,prompt)
@@ -40,17 +212,47 @@ async def predict(prompt=Body(...),imgbase64data=Body(...),userId=Body(None)):
40
  print(now)
41
  print("图像:", img.size)
42
  print("加载管道:", end1 - start)
43
- result = pipeline(
44
- prompt=prompt,
45
- image=image1,
46
- strength=0.6,
47
- seed=10,
48
- width=256,
49
- height=256,
50
- guidance_scale=1,
51
- num_inference_steps=4,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  )
53
- output_image = result.images[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  end2 = time.time()
55
  print("测试",output_image)
56
  print("s生成完成:", end2 - end1)
@@ -64,12 +266,9 @@ async def predict(prompt=Body(...),imgbase64data=Body(...),userId=Body(None)):
64
  image_data_bytes = image_data.getvalue()
65
  output_image_base64 = base64.b64encode(image_data_bytes).decode('utf-8')
66
  print("完成的图片:", output_image_base64)
67
- logger = logging.getLogger('')
68
- logger.info(output_image_base64)
69
  return output_image_base64
70
 
71
 
72
  @app.post("/predict")
73
  async def predict(prompt=Body(...)):
74
  return f"您好,{prompt}"
75
-
 
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
+ from state import get_settings
10
+ import traceback
11
+
12
 
13
  from fastapi import FastAPI,Body
14
 
 
17
  import logging
18
  from PIL import Image
19
  import time
20
+
 
 
21
  from diffusers.utils import load_image
22
  import base64
23
  import io
24
  from datetime import datetime
25
 
26
+ from typing import Any
27
+ from backend.models.lcmdiffusion_setting import DiffusionTask
28
+
29
+ from frontend.utils import is_reshape_required
30
+ from concurrent.futures import ThreadPoolExecutor
31
+
32
+
33
+ context = Context(InterfaceType.WEBUI)
34
+ previous_width = 0
35
+ previous_height = 0
36
+ previous_model_id = ""
37
+ previous_num_of_images = 0
38
+
39
+ parser = ArgumentParser(description=f"FAST SD CPU {constants.APP_VERSION}")
40
+ parser.add_argument(
41
+ "-s",
42
+ "--share",
43
+ action="store_true",
44
+ help="Create sharable link(Web UI)",
45
+ required=False,
46
+ )
47
+ group = parser.add_mutually_exclusive_group(required=False)
48
+ group.add_argument(
49
+ "-g",
50
+ "--gui",
51
+ action="store_true",
52
+ help="Start desktop GUI",
53
+ )
54
+ group.add_argument(
55
+ "-w",
56
+ "--webui",
57
+ action="store_true",
58
+ help="Start Web UI",
59
+ )
60
+ group.add_argument(
61
+ "-r",
62
+ "--realtime",
63
+ action="store_true",
64
+ help="Start realtime inference UI(experimental)",
65
+ )
66
+ group.add_argument(
67
+ "-v",
68
+ "--version",
69
+ action="store_true",
70
+ help="Version",
71
+ )
72
+ parser.add_argument(
73
+ "--lcm_model_id",
74
+ type=str,
75
+ help="Model ID or path,Default SimianLuo/LCM_Dreamshaper_v7",
76
+ default="SimianLuo/LCM_Dreamshaper_v7",
77
+ )
78
+ parser.add_argument(
79
+ "--prompt",
80
+ type=str,
81
+ help="Describe the image you want to generate",
82
+ )
83
+ parser.add_argument(
84
+ "--image_height",
85
+ type=int,
86
+ help="Height of the image",
87
+ default=512,
88
+ )
89
+ parser.add_argument(
90
+ "--image_width",
91
+ type=int,
92
+ help="Width of the image",
93
+ default=512,
94
+ )
95
+ parser.add_argument(
96
+ "--inference_steps",
97
+ type=int,
98
+ help="Number of steps,default : 4",
99
+ default=4,
100
+ )
101
+ parser.add_argument(
102
+ "--guidance_scale",
103
+ type=int,
104
+ help="Guidance scale,default : 1.0",
105
+ default=1.0,
106
+ )
107
+
108
+ parser.add_argument(
109
+ "--number_of_images",
110
+ type=int,
111
+ help="Number of images to generate ,default : 1",
112
+ default=1,
113
+ )
114
+ parser.add_argument(
115
+ "--seed",
116
+ type=int,
117
+ help="Seed,default : -1 (disabled) ",
118
+ default=-1,
119
+ )
120
+ parser.add_argument(
121
+ "--use_openvino",
122
+ action="store_true",
123
+ help="Use OpenVINO model",
124
+ )
125
+
126
+ parser.add_argument(
127
+ "--use_offline_model",
128
+ action="store_true",
129
+ help="Use offline model",
130
+ )
131
+ parser.add_argument(
132
+ "--use_safety_checker",
133
+ action="store_false",
134
+ help="Use safety checker",
135
+ )
136
+ parser.add_argument(
137
+ "--use_lcm_lora",
138
+ action="store_true",
139
+ help="Use LCM-LoRA",
140
+ )
141
+ parser.add_argument(
142
+ "--base_model_id",
143
+ type=str,
144
+ help="LCM LoRA base model ID,Default Lykon/dreamshaper-8",
145
+ default="Lykon/dreamshaper-8",
146
+ )
147
+ parser.add_argument(
148
+ "--lcm_lora_id",
149
+ type=str,
150
+ help="LCM LoRA model ID,Default latent-consistency/lcm-lora-sdv1-5",
151
+ default="latent-consistency/lcm-lora-sdv1-5",
152
+ )
153
+ parser.add_argument(
154
+ "-i",
155
+ "--interactive",
156
+ action="store_true",
157
+ help="Interactive CLI mode",
158
+ )
159
+ parser.add_argument(
160
+ "--use_tiny_auto_encoder",
161
+ action="store_true",
162
+ help="Use tiny auto encoder for SD (TAESD)",
163
+ )
164
+ args = parser.parse_args()
165
+
166
+ if args.version:
167
+ print(APP_VERSION)
168
+ exit()
169
+
170
+ # parser.print_help()
171
+ show_system_info()
172
+ print(f"Using device : {constants.DEVICE}")
173
+ app_settings = get_settings()
174
 
175
+ print(f"Found {len(app_settings.lcm_models)} LCM models in config/lcm-models.txt")
176
+ print(
177
+ f"Found {len(app_settings.stable_diffsuion_models)} stable diffusion models in config/stable-diffusion-models.txt"
178
+ )
179
+ print(
180
+ f"Found {len(app_settings.lcm_lora_models)} LCM-LoRA models in config/lcm-lora-models.txt"
181
+ )
182
+ print(
183
+ f"Found {len(app_settings.openvino_lcm_models)} OpenVINO LCM models in config/openvino-lcm-models.txt"
184
+ )
185
+ app_settings.settings.lcm_diffusion_setting.use_openvino = True
186
+ # from frontend.webui.ui import start_webui
187
+
188
+ # print("Starting web UI mode")
189
+ # start_webui(
190
+ # args.share,
191
+ # )
192
+
193
+ app = FastAPI(name="mutilParam")
194
+ print("我执行了")
195
  @app.get("/")
196
  def root():
197
+ return {"API": "hello"}
198
+
199
  @app.post("/img2img")
200
+ async def predict(prompt=Body(...),imgbase64data=Body(...),negative_prompt=Body(None),userId=Body(None)):
 
201
  MAX_QUEUE_SIZE = 4
202
  start = time.time()
203
  print("参数",imgbase64data,prompt)
 
212
  print(now)
213
  print("图像:", img.size)
214
  print("加载管道:", end1 - start)
215
+ global previous_height, previous_width, previous_model_id, previous_num_of_images, app_settings
216
+
217
+ app_settings.settings.lcm_diffusion_setting.prompt = prompt
218
+ app_settings.settings.lcm_diffusion_setting.negative_prompt = negative_prompt
219
+ app_settings.settings.lcm_diffusion_setting.init_image = img
220
+ app_settings.settings.lcm_diffusion_setting.strength = 0.6
221
+
222
+ app_settings.settings.lcm_diffusion_setting.diffusion_task = (
223
+ DiffusionTask.image_to_image.value
224
+ )
225
+ model_id = app_settings.settings.lcm_diffusion_setting.openvino_lcm_model_id
226
+ reshape = False
227
+ app_settings.settings.lcm_diffusion_setting.image_height=newH
228
+ image_width = app_settings.settings.lcm_diffusion_setting.image_width
229
+ image_height = app_settings.settings.lcm_diffusion_setting.image_height
230
+ num_images = app_settings.settings.lcm_diffusion_setting.number_of_images
231
+ reshape = is_reshape_required(
232
+ previous_width,
233
+ image_width,
234
+ previous_height,
235
+ image_height,
236
+ previous_model_id,
237
+ model_id,
238
+ previous_num_of_images,
239
+ num_images,
240
  )
241
+
242
+
243
+ with ThreadPoolExecutor(max_workers=1) as executor:
244
+ future = executor.submit(
245
+ context.generate_text_to_image,
246
+ app_settings.settings,
247
+ reshape,
248
+ DEVICE,
249
+ )
250
+ images = future.result()
251
+ previous_width = image_width
252
+ previous_height = image_height
253
+ previous_model_id = model_id
254
+ previous_num_of_images = num_images
255
+ output_image = images[0]
256
  end2 = time.time()
257
  print("测试",output_image)
258
  print("s生成完成:", end2 - end1)
 
266
  image_data_bytes = image_data.getvalue()
267
  output_image_base64 = base64.b64encode(image_data_bytes).decode('utf-8')
268
  print("完成的图片:", output_image_base64)
 
 
269
  return output_image_base64
270
 
271
 
272
  @app.post("/predict")
273
  async def predict(prompt=Body(...)):
274
  return f"您好,{prompt}"
 
models/interface_types.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+
4
+ class InterfaceType(Enum):
5
+ WEBUI = "Web User Interface"
6
+ GUI = "Graphical User Interface"
7
+ CLI = "Command Line Interface"
models/settings.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from backend.models.lcmdiffusion_setting import LCMDiffusionSetting, LCMLora
3
+ from paths import FastStableDiffusionPaths
4
+
5
+
6
+ class Settings(BaseModel):
7
+ results_path: str = FastStableDiffusionPaths().get_results_path()
8
+ lcm_diffusion_setting: LCMDiffusionSetting = LCMDiffusionSetting(lcm_lora=LCMLora())
paths.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import constants
3
+
4
+
5
+ def join_paths(
6
+ first_path: str,
7
+ second_path: str,
8
+ ) -> str:
9
+ return os.path.join(first_path, second_path)
10
+
11
+
12
+ def get_app_path() -> str:
13
+ app_dir = os.path.dirname(__file__)
14
+ work_dir = os.path.dirname(app_dir)+'/app/'
15
+ return work_dir
16
+
17
+
18
+ def get_configs_path() -> str:
19
+ config_path = join_paths(get_app_path(), constants.CONFIG_DIRECTORY)
20
+ return config_path
21
+
22
+
23
+ class FastStableDiffusionPaths:
24
+ @staticmethod
25
+ def get_app_settings_path() -> str:
26
+ configs_path = get_configs_path()
27
+ settings_path = join_paths(
28
+ configs_path,
29
+ constants.APP_SETTINGS_FILE,
30
+ )
31
+ return settings_path
32
+
33
+ @staticmethod
34
+ def get_results_path() -> str:
35
+ results_path = join_paths(get_app_path(), constants.RESULTS_DIRECTORY)
36
+ return results_path
37
+
38
+ @staticmethod
39
+ def get_css_path() -> str:
40
+ app_dir = os.path.dirname(__file__)
41
+ css_path = os.path.join(
42
+ app_dir,
43
+ "frontend",
44
+ "webui",
45
+ "css",
46
+ "style.css",
47
+ )
48
+ return css_path
49
+
50
+ @staticmethod
51
+ def get_models_config_path(model_config_file: str) -> str:
52
+ configs_path = get_configs_path()
53
+ models_path = join_paths(
54
+ configs_path,
55
+ model_config_file,
56
+ )
57
+ return models_path
58
+
59
+
60
+ def get_base_folder_name(path: str) -> str:
61
+ return os.path.basename(path)
requirements.txt CHANGED
@@ -1,6 +1,18 @@
1
  fastapi[all]
2
  uvicorn[standard]
3
- accelerate
4
- diffusers[torch]
5
- transformers
6
- xformers
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  fastapi[all]
2
  uvicorn[standard]
3
+ accelerate==0.23.0
4
+ diffusers==0.23.0
5
+ transformers==4.35.0
6
+ PyQt5
7
+ Pillow==9.4.0
8
+ openvino==2023.2.0
9
+ optimum==1.14.0
10
+ optimum-intel==1.12.1
11
+ onnx==1.15.0
12
+ onnxruntime==1.16.1
13
+ pydantic==2.4.2
14
+ typing-extensions==4.8.0
15
+ pyyaml==6.0.1
16
+ gradio==3.39.0
17
+ peft==0.6.1
18
+ opencv-python==4.8.1.78
state.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app_settings import AppSettings
2
+ from typing import Optional
3
+
4
+ from context import Context
5
+ from models.interface_types import InterfaceType
6
+
7
+
8
+ class _AppState:
9
+ _instance: Optional["_AppState"] = None
10
+ settings: Optional[AppSettings] = None
11
+ context: Optional[Context] = None
12
+
13
+
14
+ def get_state() -> _AppState:
15
+ if _AppState._instance is None:
16
+ _AppState._instance = _AppState()
17
+ return _AppState._instance
18
+
19
+
20
+ def get_settings(skip_file: bool = False) -> AppSettings:
21
+ state = get_state()
22
+ if state.settings is None:
23
+ state.settings = AppSettings()
24
+ state.settings.load(skip_file)
25
+ return state.settings
26
+
27
+
28
+ def get_context(interface_type: InterfaceType) -> Context:
29
+ state = get_state()
30
+ if state.context is None:
31
+ state.context = Context(interface_type)
32
+ return state.context
utils.py CHANGED
@@ -1,15 +1,21 @@
1
- from PIL import Image
2
- import numpy as np
3
 
4
 
5
- def replace_background(image: Image.Image, new_background_color=(0, 255, 255)):
6
- image_np = np.array(image)
 
 
 
 
 
7
 
8
- white_threshold = 255 * 3
9
- white_pixels = np.sum(image_np, axis=-1) == white_threshold
10
 
11
- image_np[white_pixels] = new_background_color
12
-
13
- result = Image.fromarray(image_np)
14
-
15
- return result
 
 
 
 
1
+ import platform
2
+ from typing import List
3
 
4
 
5
+ def show_system_info():
6
+ try:
7
+ print(f"Running on {platform.system()} platform")
8
+ print(f"OS: {platform.platform()}")
9
+ print(f"Processor: {platform.processor()}")
10
+ except Exception as ex:
11
+ print(f"Error ocurred while getting system information {ex}")
12
 
 
 
13
 
14
+ def get_models_from_text_file(file_path: str) -> List:
15
+ models = []
16
+ with open(file_path, "r") as file:
17
+ lines = file.readlines()
18
+ for repo_id in lines:
19
+ if repo_id.strip() != "":
20
+ models.append(repo_id.strip())
21
+ return models