trashchenkov commited on
Commit
ba1587e
·
verified ·
1 Parent(s): 5406720

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +376 -188
app.py CHANGED
@@ -1,107 +1,289 @@
1
  import gradio as gr
2
  import numpy as np
3
  import torch
4
- from diffusers import DiffusionPipeline
5
- from peft import PeftModel
6
  import re
7
 
8
- # Устройство и тип данных
9
- device = "cuda" if torch.cuda.is_available() else "cpu"
10
- torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
11
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  # Регулярное выражение для проверки корректности модели
 
13
  VALID_REPO_ID_REGEX = re.compile(r"^[a-zA-Z0-9._\-]+/[a-zA-Z0-9._\-]+$")
14
  def is_valid_repo_id(repo_id):
15
  return bool(VALID_REPO_ID_REGEX.match(repo_id)) and not repo_id.endswith(('-', '.'))
16
 
17
- # Базовые константы
 
 
 
 
 
 
 
 
18
  MAX_SEED = np.iinfo(np.int32).max
19
  MAX_IMAGE_SIZE = 1024
20
 
21
- # Изначально загружаем модель по умолчанию
 
 
22
  model_repo_id = "CompVis/stable-diffusion-v1-4"
23
- pipe = DiffusionPipeline.from_pretrained(model_repo_id, torch_dtype=torch_dtype, safety_checker=None).to(device)
24
 
25
- # Попробуем подгрузить LoRA-модификации (unet + text_encoder)
 
 
 
 
 
 
 
 
26
  try:
27
  pipe.unet = PeftModel.from_pretrained(pipe.unet, "./unet")
28
  pipe.text_encoder = PeftModel.from_pretrained(pipe.text_encoder, "./text_encoder")
29
  except Exception as e:
30
  print(f"Не удалось подгрузить LoRA по умолчанию: {e}")
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  def infer(
33
- model,
34
- prompt,
35
- negative_prompt,
36
- seed,
37
- width,
38
- height,
39
- guidance_scale,
40
- num_inference_steps,
41
- use_controlnet,
42
- control_strength,
43
- controlnet_mode,
44
- controlnet_image,
45
- use_ip_adapter,
46
- ip_adapter_scale,
47
- ip_adapter_image,
48
  progress=gr.Progress(track_tqdm=True),
49
  ):
50
- """
51
- Функция генерации изображения.
52
- В реальном проекте здесь нужно добавить интеграцию с ControlNet и IP-adapter.
53
- Сейчас они служат лишь демонстрацией UI (заглушка).
54
- """
55
- global model_repo_id, pipe
56
-
57
- # Если пользователь ввёл другую модель, пробуем её загрузить с нуля
58
  if model != model_repo_id:
59
  if not is_valid_repo_id(model):
60
  raise gr.Error(f"Некорректный идентификатор модели: '{model}'. Проверьте название.")
61
 
62
  try:
63
- new_pipe = DiffusionPipeline.from_pretrained(model, torch_dtype=torch_dtype).to(device)
64
- # Повторно подгружаем LoRA для нового пайплайна
 
 
 
 
 
65
  try:
66
  new_pipe.unet = PeftModel.from_pretrained(new_pipe.unet, "./unet")
67
  new_pipe.text_encoder = PeftModel.from_pretrained(new_pipe.text_encoder, "./text_encoder")
68
  except Exception as e:
69
- raise gr.Error(f"Не удалось подгрузить LoRA: {e}")
70
 
71
- # Обновляем глобальные переменные
72
  pipe = new_pipe
73
  model_repo_id = model
74
 
75
  except Exception as e:
76
  raise gr.Error(f"Не удалось загрузить модель '{model}'.\nОшибка: {e}")
77
 
78
- # Создаём генератор случайных чисел для детерминированности
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  generator = torch.Generator(device=device).manual_seed(seed)
80
 
81
- # Заглушка: пока что просто вызываем pipe без учёта ControlNet/IP-adapter
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  try:
83
- image = pipe(
84
  prompt=prompt,
85
  negative_prompt=negative_prompt,
86
- guidance_scale=guidance_scale,
87
  num_inference_steps=num_inference_steps,
 
88
  width=width,
89
  height=height,
90
  generator=generator,
91
- ).images[0]
 
 
 
92
  except Exception as e:
93
  raise gr.Error(f"Ошибка при генерации изображения: {e}")
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  return image, seed
96
 
 
97
  # Примеры для удобного тестирования
 
98
  examples = [
99
  "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
100
  "An astronaut riding a green horse",
101
  "A delicious ceviche cheesecake slice",
102
  ]
103
 
104
- # Дополнительный CSS для оформления
 
 
105
  css = """
106
  #col-container {
107
  margin: 0 auto;
@@ -109,161 +291,167 @@ css = """
109
  }
110
  """
111
 
 
112
  # Создаём Gradio-приложение
113
- with gr.Blocks(css=css) as demo:
114
- with gr.Column(elem_id="col-container"):
115
- gr.Markdown("# Text-to-Image App")
116
-
117
- # Поле для ввода/смены модели
118
- model = gr.Textbox(
119
- label="Model",
120
- value="CompVis/stable-diffusion-v1-4", # Значение по умолчанию
121
- interactive=True
122
- )
123
-
124
- # Основные поля для Prompt и Negative Prompt
125
- prompt = gr.Text(
126
- label="Prompt",
127
- show_label=False,
128
- max_lines=1,
129
- placeholder="Enter your prompt",
130
- container=False,
131
- )
132
- negative_prompt = gr.Text(
133
- label="Negative prompt",
134
- max_lines=1,
135
- placeholder="Enter a negative prompt",
136
- visible=True,
137
- )
138
-
139
- # Слайдер для выбора seed
140
- seed = gr.Slider(
141
- label="Seed",
142
- minimum=0,
143
- maximum=MAX_SEED,
144
- step=1,
145
- value=42,
146
- )
147
-
148
- # Слайдеры для guidance_scale и num_inference_steps
149
- guidance_scale = gr.Slider(
150
- label="Guidance scale",
151
- minimum=0.0,
152
- maximum=10.0,
153
- step=0.1,
154
- value=7.0,
155
- )
156
- num_inference_steps = gr.Slider(
157
- label="Number of inference steps",
158
- minimum=1,
159
- maximum=50,
160
- step=1,
161
- value=20,
162
- )
163
-
164
- # Кнопка запуска
165
- run_button = gr.Button("Run", variant="primary")
166
-
167
- # Поле для отображения результата
168
- result = gr.Image(label="Result", show_label=False)
169
-
170
- # Продвинутые настройки (Accordion)
171
- with gr.Accordion("Advanced Settings", open=False):
172
- with gr.Row():
173
- width = gr.Slider(
174
- label="Width",
175
- minimum=256,
176
- maximum=MAX_IMAGE_SIZE,
177
- step=32,
178
- value=512,
179
- )
180
- height = gr.Slider(
181
- label="Height",
182
- minimum=256,
183
- maximum=MAX_IMAGE_SIZE,
184
- step=32,
185
- value=512,
186
- )
187
 
188
- # Блоки ControlNet
189
- use_controlnet = gr.Checkbox(label="Use ControlNet", value=False)
190
- with gr.Group(visible=False) as controlnet_group:
191
- control_strength = gr.Slider(
192
- label="ControlNet Strength",
193
- minimum=0.0,
194
- maximum=2.0,
195
- step=0.1,
196
- value=1.0,
197
- )
198
- controlnet_mode = gr.Dropdown(
199
- label="ControlNet Mode",
200
- choices=["edge_detection", "pose_estimation", "depth_estimation"],
201
- value="edge_detection",
202
- )
203
- controlnet_image = gr.Image(
204
- label="ControlNet Image",
205
- type="pil"
206
- )
207
 
208
- def update_controlnet_group(use_controlnet):
209
- return {"visible": use_controlnet}
 
 
 
 
 
 
210
 
211
- use_controlnet.change(
212
- update_controlnet_group,
213
- inputs=[use_controlnet],
214
- outputs=[controlnet_group]
 
 
 
 
 
 
 
 
 
 
215
  )
216
 
217
- # Блоки IP-adapter
218
- use_ip_adapter = gr.Checkbox(label="Use IP-adapter", value=False)
219
- with gr.Group(visible=False) as ip_adapter_group:
220
- ip_adapter_scale = gr.Slider(
221
- label="IP-adapter Scale",
222
- minimum=0.0,
223
- maximum=2.0,
224
- step=0.1,
225
- value=1.0,
226
- )
227
- ip_adapter_image = gr.Image(
228
- label="IP-adapter Image",
229
- type="pil"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  )
231
 
232
- def update_ip_adapter_group(use_ip_adapter):
233
- return {"visible": use_ip_adapter}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
 
235
- use_ip_adapter.change(
236
- update_ip_adapter_group,
237
- inputs=[use_ip_adapter],
238
- outputs=[ip_adapter_group]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  )
240
 
241
- # Примеры
242
- gr.Examples(examples=examples, inputs=[prompt])
243
-
244
- # Связка кнопки "Run" с функцией "infer"
245
- run_button.click(
246
- infer,
247
- inputs=[
248
- model,
249
- prompt,
250
- negative_prompt,
251
- seed,
252
- width,
253
- height,
254
- guidance_scale,
255
- num_inference_steps,
256
- use_controlnet,
257
- control_strength,
258
- controlnet_mode,
259
- controlnet_image,
260
- use_ip_adapter,
261
- ip_adapter_scale,
262
- ip_adapter_image
263
- ],
264
- outputs=[result, seed],
265
- )
266
 
267
- # Запуск
268
  if __name__ == "__main__":
269
- demo.launch()
 
1
  import gradio as gr
2
  import numpy as np
3
  import torch
 
 
4
  import re
5
 
6
+ from diffusers import (
7
+ StableDiffusionPipeline,
8
+ ControlNetModel,
9
+ StableDiffusionControlNetPipeline,
10
+ DDIMScheduler,
11
+ )
12
+ from peft import PeftModel
13
+ from PIL import Image
14
+
15
+ # ------------------------------------------------------------------
16
+ # Пример «заготовки» для IP-Adapter:
17
+ # Предполагается, что у вас есть некий класс, умеющий:
18
+ # 1) Загружать веса IP-Adapter
19
+ # 2) Преобразовывать дополнительное «референс-изображение» в эмбеддинг
20
+ # 3) Подмешивать этот эмбеддинг в процесс диффузии или текстовые эмбеддинги
21
+ # ------------------------------------------------------------------
22
+ class IPAdapterModel:
23
+ def __init__(self, path_to_weights: str, device="cpu"):
24
+ """
25
+ Инициализация и загрузка весов IP-Adapter.
26
+ path_to_weights - путь к файлам модели
27
+ """
28
+ # Здесь должен быть код инициализации вашей модели.
29
+ # Например, что-то вроде:
30
+ # self.model = torch.load(path_to_weights, map_location=device)
31
+ # self.model.eval()
32
+ # ...
33
+ self.device = device
34
+ self.dummy_weights_loaded = True # признак, что "что-то" загрузили
35
+
36
+ def encode_reference_image(self, image: Image.Image):
37
+ """
38
+ Преобразовать референс-изображение в некий вектор (embedding),
39
+ который затем можно использовать для модификации генерации.
40
+ """
41
+ # В реальном коде будет извлечение фич.
42
+ # Для примера вернём фиктивный тензор.
43
+ dummy_embedding = torch.zeros((1, 768)).to(self.device)
44
+ return dummy_embedding
45
+
46
+ def blend_latents_with_adapter(self, latents: torch.Tensor, adapter_embedding: torch.Tensor, scale: float):
47
+ """
48
+ Примерная функция, которая «подмешивает» признаки из адаптера
49
+ в латенты перед декодированием.
50
+ latents: (batch, channels, height, width)
51
+ adapter_embedding: (1, embedding_dim)
52
+ scale: сила влияния адаптера
53
+ """
54
+ # Для демонстрации просто прибавим (scale * mean(adapter_embedding))
55
+ # В реальном IP-Adapter это гораздо сложнее.
56
+ if adapter_embedding is not None:
57
+ # Возьмём скаляр (к примеру)
58
+ mean_val = adapter_embedding.mean()
59
+ latents = latents + scale * mean_val
60
+ return latents
61
+
62
+
63
+ # ------------------------------------------------------------------
64
  # Регулярное выражение для проверки корректности модели
65
+ # ------------------------------------------------------------------
66
  VALID_REPO_ID_REGEX = re.compile(r"^[a-zA-Z0-9._\-]+/[a-zA-Z0-9._\-]+$")
67
  def is_valid_repo_id(repo_id):
68
  return bool(VALID_REPO_ID_REGEX.match(repo_id)) and not repo_id.endswith(('-', '.'))
69
 
70
+ # ------------------------------------------------------------------
71
+ # Аппаратные настройки
72
+ # ------------------------------------------------------------------
73
+ device = "cuda" if torch.cuda.is_available() else "cpu"
74
+ torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
75
+
76
+ # ------------------------------------------------------------------
77
+ # Константы
78
+ # ------------------------------------------------------------------
79
  MAX_SEED = np.iinfo(np.int32).max
80
  MAX_IMAGE_SIZE = 1024
81
 
82
+ # ------------------------------------------------------------------
83
+ # Базовая модель (Stable Diffusion) по умолчанию
84
+ # ------------------------------------------------------------------
85
  model_repo_id = "CompVis/stable-diffusion-v1-4"
 
86
 
87
+ # Загрузка базового пайплайна (без ControlNet)
88
+ pipe = StableDiffusionPipeline.from_pretrained(
89
+ model_repo_id, torch_dtype=torch_dtype, safety_checker=None
90
+ ).to(device)
91
+
92
+ # Применим DDIM-схему как пример
93
+ pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
94
+
95
+ # Пробуем подгрузить LoRA (unet + text_encoder)
96
  try:
97
  pipe.unet = PeftModel.from_pretrained(pipe.unet, "./unet")
98
  pipe.text_encoder = PeftModel.from_pretrained(pipe.text_encoder, "./text_encoder")
99
  except Exception as e:
100
  print(f"Не удалось подгрузить LoRA по умолчанию: {e}")
101
 
102
+ # ------------------------------------------------------------------
103
+ # Инициализация «IP-Adapter» (для примера укажем вымышленный путь).
104
+ # Предположим, что IP-Adapter мы храним в ./ip_adapter_weights
105
+ # ------------------------------------------------------------------
106
+ ip_adapter_model = None
107
+ try:
108
+ ip_adapter_model = IPAdapterModel("./ip_adapter_weights", device=device)
109
+ except Exception as e:
110
+ print(f"Не удалось загрузить IP-Adapter: {e}")
111
+
112
+ # ------------------------------------------------------------------
113
+ # Функция генерации
114
+ # ------------------------------------------------------------------
115
  def infer(
116
+ model, # Текстовое поле: модель (repo) напр. "CompVis/stable-diffusion-v1-4"
117
+ prompt, # Текст: позитивный промпт
118
+ negative_prompt, # Текст: негативный промпт
119
+ seed, # Сид генератора
120
+ width, # Ширина
121
+ height, # Высота
122
+ guidance_scale, # guidance scale
123
+ num_inference_steps, # Количество шагов диффузии
124
+ use_controlnet, # Чекбокс: включать ли ControlNet
125
+ control_strength, # Слайдер: сила влияния ControlNet
126
+ controlnet_mode, # Выпадающий список: edge_detection, pose_estimation, depth_estimation
127
+ controlnet_image, # Изображение для ControlNet
128
+ use_ip_adapter, # Чекбокс: включать ли IP-adapter
129
+ ip_adapter_scale, # Слайдер: сила влияния IP-adapter
130
+ ip_adapter_image, # Изображение для IP-adapter
131
  progress=gr.Progress(track_tqdm=True),
132
  ):
133
+ global model_repo_id, pipe, ip_adapter_model
134
+
135
+ # ---------------------------
136
+ # 1) Проверяем, не сменил ли пользователь модель
137
+ # ---------------------------
 
 
 
138
  if model != model_repo_id:
139
  if not is_valid_repo_id(model):
140
  raise gr.Error(f"Некорректный идентификатор модели: '{model}'. Проверьте название.")
141
 
142
  try:
143
+ # Подгружаем модель (без ControlNet)
144
+ new_pipe = StableDiffusionPipeline.from_pretrained(
145
+ model, torch_dtype=torch_dtype, safety_checker=None
146
+ ).to(device)
147
+ new_pipe.scheduler = DDIMScheduler.from_config(new_pipe.scheduler.config)
148
+
149
+ # Повторно загружаем LoRA
150
  try:
151
  new_pipe.unet = PeftModel.from_pretrained(new_pipe.unet, "./unet")
152
  new_pipe.text_encoder = PeftModel.from_pretrained(new_pipe.text_encoder, "./text_encoder")
153
  except Exception as e:
154
+ print(f"Не удалось подгрузить LoRA для новой модели: {e}")
155
 
 
156
  pipe = new_pipe
157
  model_repo_id = model
158
 
159
  except Exception as e:
160
  raise gr.Error(f"Не удалось загрузить модель '{model}'.\nОшибка: {e}")
161
 
162
+ # ---------------------------
163
+ # 2) Если включён ControlNet — создаём ControlNetPipeline
164
+ # ---------------------------
165
+ local_pipe = pipe # по умолчанию используем базовый pipe
166
+
167
+ if use_controlnet:
168
+ # Выбираем репозиторий ControlNet в зависимости от режима
169
+ if controlnet_mode == "edge_detection":
170
+ controlnet_repo = "lllyasviel/sd-controlnet-canny"
171
+ elif controlnet_mode == "pose_estimation":
172
+ controlnet_repo = "lllyasviel/sd-controlnet-openpose"
173
+ elif controlnet_mode == "depth_estimation":
174
+ controlnet_repo = "lllyasviel/sd-controlnet-depth"
175
+ else:
176
+ raise gr.Error(f"Неизвестный режим ControlNet: {controlnet_mode}")
177
+
178
+ try:
179
+ controlnet_model = ControlNetModel.from_pretrained(
180
+ controlnet_repo,
181
+ torch_dtype=torch_dtype
182
+ ).to(device)
183
+
184
+ # Создаём новый pipeline, указывая ControlNet
185
+ local_pipe = StableDiffusionControlNetPipeline(
186
+ vae=pipe.vae,
187
+ text_encoder=pipe.text_encoder,
188
+ tokenizer=pipe.tokenizer,
189
+ unet=pipe.unet,
190
+ controlnet=controlnet_model,
191
+ scheduler=pipe.scheduler,
192
+ safety_checker=None,
193
+ feature_extractor=pipe.feature_extractor,
194
+ requires_safety_checker=False,
195
+ ).to(device)
196
+
197
+ except Exception as e:
198
+ raise gr.Error(f"Ошибка загрузки ControlNet ({controlnet_mode}): {e}")
199
+
200
+ # ---------------------------
201
+ # 3) Генератор случайных чисел для детерминированности
202
+ # ---------------------------
203
  generator = torch.Generator(device=device).manual_seed(seed)
204
 
205
+ # ---------------------------
206
+ # 4) Если есть IP-Adapter, подгружаем фичи из референс-изображения
207
+ # ---------------------------
208
+ ip_adapter_embedding = None
209
+ if use_ip_adapter and ip_adapter_model is not None and ip_adapter_model.dummy_weights_loaded:
210
+ if ip_adapter_image is not None:
211
+ ip_adapter_embedding = ip_adapter_model.encode_reference_image(ip_adapter_image)
212
+ else:
213
+ print("IP-Adapter включён, но не загружено референс-изображение.")
214
+ elif use_ip_adapter:
215
+ print("IP-Adapter включён, но модель не загружена или не инициализирована.")
216
+
217
+ # ---------------------------
218
+ # 5) Выполняем диффузию
219
+ # (с учётом ControlNet, если включён)
220
+ # ---------------------------
221
+
222
+ # Параметры для ControlNetPipeline
223
+ # - Для edge/pose/depth обычно передают control_image через параметр "image"
224
+ # - Дополнительно можно задать "controlnet_conditioning_scale" (aka strength)
225
+ # чтобы указать вес ControlNet.
226
+ # - Документация: https://huggingface.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/controlnet
227
+ extra_kwargs = {}
228
+ if use_controlnet and controlnet_image is not None:
229
+ extra_kwargs["image"] = controlnet_image
230
+ extra_kwargs["controlnet_conditioning_scale"] = control_strength
231
+ elif use_controlnet:
232
+ print("ControlNet включён, но не загружено изображение для ControlNet.")
233
+
234
+ # Запуск генерации
235
  try:
236
+ output = local_pipe(
237
  prompt=prompt,
238
  negative_prompt=negative_prompt,
 
239
  num_inference_steps=num_inference_steps,
240
+ guidance_scale=guidance_scale,
241
  width=width,
242
  height=height,
243
  generator=generator,
244
+ **extra_kwargs
245
+ )
246
+ image = output.images[0]
247
+ latents = getattr(output, "latents", None) # не во всех версиях diffusers есть latents
248
  except Exception as e:
249
  raise gr.Error(f"Ошибка при генерации изображения: {e}")
250
 
251
+ # ---------------------------
252
+ # 6) Применяем IP-Adapter к результату (если нужно).
253
+ # В реальных библиотеках IP-Adapter может вмешиваться раньше (до/во время диффузии).
254
+ # Для примера демонстрируем "пост-обработку latents" (если latents сохранились).
255
+ # ---------------------------
256
+ if use_ip_adapter and ip_adapter_embedding is not None and latents is not None:
257
+ try:
258
+ # Простейший «пример» подмешивания в латенты
259
+ new_latents = ip_adapter_model.blend_latents_with_adapter(latents, ip_adapter_embedding, ip_adapter_scale)
260
+
261
+ # Теперь нужно декодировать latents в картинку заново
262
+ # (подразумеваем, что local_pipe поддерживает .vae.decode())
263
+ new_latents = new_latents.to(dtype=pipe.vae.dtype)
264
+ image = pipe.vae.decode(new_latents / 0.18215)
265
+ image = (image / 2 + 0.5).clamp(0, 1)
266
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()[0]
267
+ image = (image * 255).astype(np.uint8)
268
+ image = Image.fromarray(image)
269
+
270
+ except Exception as e:
271
+ raise gr.Error(f"Ошибка при применении IP-Adapter: {e}")
272
+
273
  return image, seed
274
 
275
+ # ------------------------------------------------------------------
276
  # Примеры для удобного тестирования
277
+ # ------------------------------------------------------------------
278
  examples = [
279
  "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
280
  "An astronaut riding a green horse",
281
  "A delicious ceviche cheesecake slice",
282
  ]
283
 
284
+ # ------------------------------------------------------------------
285
+ # CSS (дополнительно, опционально)
286
+ # ------------------------------------------------------------------
287
  css = """
288
  #col-container {
289
  margin: 0 auto;
 
291
  }
292
  """
293
 
294
+ # ------------------------------------------------------------------
295
  # Создаём Gradio-приложение
296
+ # ------------------------------------------------------------------
297
+ import sys
298
+
299
+ def run_app():
300
+ with gr.Blocks(css=css) as demo:
301
+ with gr.Column(elem_id="col-container"):
302
+ gr.Markdown("# Text-to-Image App (ControlNet + IP-Adapter)")
303
+
304
+ # Поле для ввода/смены модели
305
+ model = gr.Textbox(
306
+ label="Model (HuggingFace repo)",
307
+ value="CompVis/stable-diffusion-v1-4",
308
+ interactive=True
309
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
+ # Основные поля для Prompt и Negative Prompt
312
+ prompt = gr.Text(
313
+ label="Prompt",
314
+ show_label=False,
315
+ max_lines=1,
316
+ placeholder="Enter your prompt",
317
+ container=False,
318
+ )
319
+ negative_prompt = gr.Text(
320
+ label="Negative prompt",
321
+ max_lines=1,
322
+ placeholder="Enter a negative prompt",
323
+ visible=True,
324
+ )
 
 
 
 
 
325
 
326
+ # Слайдер для выбора seed
327
+ seed = gr.Slider(
328
+ label="Seed",
329
+ minimum=0,
330
+ maximum=MAX_SEED,
331
+ step=1,
332
+ value=42,
333
+ )
334
 
335
+ # Слайдеры
336
+ guidance_scale = gr.Slider(
337
+ label="Guidance scale",
338
+ minimum=0.0,
339
+ maximum=15.0,
340
+ step=0.1,
341
+ value=7.0,
342
+ )
343
+ num_inference_steps = gr.Slider(
344
+ label="Number of inference steps",
345
+ minimum=1,
346
+ maximum=100,
347
+ step=1,
348
+ value=20,
349
  )
350
 
351
+ # Кнопка запуска
352
+ run_button = gr.Button("Run", variant="primary")
353
+
354
+ # Поле для отображения результата
355
+ result = gr.Image(label="Result", show_label=False)
356
+
357
+ # Продвинутые настройки
358
+ with gr.Accordion("Advanced Settings", open=False):
359
+ with gr.Row():
360
+ width = gr.Slider(
361
+ label="Width",
362
+ minimum=256,
363
+ maximum=MAX_IMAGE_SIZE,
364
+ step=64,
365
+ value=512,
366
+ )
367
+ height = gr.Slider(
368
+ label="Height",
369
+ minimum=256,
370
+ maximum=MAX_IMAGE_SIZE,
371
+ step=64,
372
+ value=512,
373
+ )
374
+
375
+ # Блоки ControlNet
376
+ use_controlnet = gr.Checkbox(label="Use ControlNet", value=False)
377
+ with gr.Group(visible=False) as controlnet_group:
378
+ control_strength = gr.Slider(
379
+ label="ControlNet Strength (Conditioning Scale)",
380
+ minimum=0.0,
381
+ maximum=2.0,
382
+ step=0.1,
383
+ value=1.0,
384
+ )
385
+ controlnet_mode = gr.Dropdown(
386
+ label="ControlNet Mode",
387
+ choices=["edge_detection", "pose_estimation", "depth_estimation"],
388
+ value="edge_detection",
389
+ )
390
+ controlnet_image = gr.Image(
391
+ label="ControlNet Image (map / pose / edges)",
392
+ type="pil"
393
+ )
394
+
395
+ def update_controlnet_group(use_controlnet):
396
+ return {"visible": use_controlnet}
397
+
398
+ use_controlnet.change(
399
+ update_controlnet_group,
400
+ inputs=[use_controlnet],
401
+ outputs=[controlnet_group]
402
  )
403
 
404
+ # Блоки IP-adapter
405
+ use_ip_adapter = gr.Checkbox(label="Use IP-adapter", value=False)
406
+ with gr.Group(visible=False) as ip_adapter_group:
407
+ ip_adapter_scale = gr.Slider(
408
+ label="IP-adapter Scale",
409
+ minimum=0.0,
410
+ maximum=2.0,
411
+ step=0.1,
412
+ value=1.0,
413
+ )
414
+ ip_adapter_image = gr.Image(
415
+ label="IP-adapter Image (reference)",
416
+ type="pil"
417
+ )
418
+
419
+ def update_ip_adapter_group(use_ip_adapter):
420
+ return {"visible": use_ip_adapter}
421
+
422
+ use_ip_adapter.change(
423
+ update_ip_adapter_group,
424
+ inputs=[use_ip_adapter],
425
+ outputs=[ip_adapter_group]
426
+ )
427
 
428
+ # Примеры
429
+ gr.Examples(examples=examples, inputs=[prompt])
430
+
431
+ # Связка кнопки "Run" с функцией "infer"
432
+ run_button.click(
433
+ infer,
434
+ inputs=[
435
+ model,
436
+ prompt,
437
+ negative_prompt,
438
+ seed,
439
+ width,
440
+ height,
441
+ guidance_scale,
442
+ num_inference_steps,
443
+ use_controlnet,
444
+ control_strength,
445
+ controlnet_mode,
446
+ controlnet_image,
447
+ use_ip_adapter,
448
+ ip_adapter_scale,
449
+ ip_adapter_image
450
+ ],
451
+ outputs=[result, seed],
452
  )
453
 
454
+ demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
 
 
456
  if __name__ == "__main__":
457
+ run_app()