Superigni commited on
Commit
632f5c5
·
verified ·
1 Parent(s): 59ec49b

flux pipeline restored

Browse files
Files changed (1) hide show
  1. app.py +65 -153
app.py CHANGED
@@ -1,221 +1,133 @@
1
  # app.py
2
  import gradio as gr
3
  import torch
4
- import requests
5
- from PIL import Image
6
  import numpy as np
7
- import os
8
- from tqdm import tqdm # Добавляем импорт tqdm
 
9
 
10
- # Импорты из diffusers
11
- from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler, StableDiffusionPipeline
12
  # from diffusers.utils import load_image # Не нужен для этого кода
13
- # from huggingface_hub import hf_hub_download # Не нужен для этого кода
14
-
15
- # --- Вспомогательная функция для скачивания файлов (например, с Civitai) ---
16
- # Эта функция будет скачивать модель SafeTensor внутри Space при первом запуске
17
- def download_file(url, local_filename):
18
- """Скачивает файл по URL с индикатором прогресса."""
19
- print(f"Скачиваю {url} в {local_filename}...")
20
- # Проверяем, существует ли файл, чтобы не скачивать его каждый раз
21
- if os.path.exists(local_filename):
22
- print(f"Файл уже существует: {local_filename}. Пропускаю скачивание.")
23
- return local_filename
24
-
25
- try:
26
- response = requests.get(url, stream=True)
27
- response.raise_for_status() # Проверка на ошибки HTTP
28
-
29
- total_size_in_bytes = int(response.headers.get('content-length', 0))
30
- block_size = 8192 # 8 Kibibytes
31
-
32
- # Используем tqdm для индикатора прогресса, только если размер известен
33
- if total_size_in_bytes > 0:
34
- progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True, desc=f"Скачивание {local_filename}")
35
- else:
36
- print("Размер файла неизвестен, скачивание без индикатора прогресса.")
37
- progress_bar = None
38
-
39
-
40
- with open(local_filename, 'wb') as f:
41
- for chunk in response.iter_content(chunk_size=block_size):
42
- if progress_bar:
43
- progress_bar.update(len(chunk))
44
- f.write(chunk)
45
-
46
- if progress_bar:
47
- progress_bar.close()
48
-
49
- print(f"Скачивание завершено: {local_filename}")
50
- return local_filename
51
- except requests.exceptions.RequestException as e:
52
- print(f"Ошибка скачивания {url}: {e}")
53
- return None
54
- except Exception as e:
55
- print(f"Произошла другая ошибка при скачивании: {e}")
56
- return None
57
 
 
 
 
 
 
58
 
59
- # --- Определение путей/ID моделей ---
60
- # URL вашей SafeTensor модели с Civitai
61
- CIVITAI_SAFETENSOR_URL = "https://civitai.com/api/download/models/1413133?type=Model&format=SafeTensor&size=full&fp=fp8"
62
- # Локальное имя файла для сохранения SafeTensor модели внутри Space
63
- LOCAL_SAFETENSOR_FILENAME = "ultrareal_fine_tune_fp8_full.safetensors"
64
-
65
- # ControlNet модель с Hugging Face
66
- CONTROLNET_MODEL_ID = "ABDALLALSWAITI/FLUX.1-dev-ControlNet-Union-Pro-2.0-fp8"
67
 
68
  # Переменная для хранения пайплайна (будет загружен при запуске скрипта)
69
  pipeline = None
70
- downloaded_base_model_path = None # Переменная для пути к скачанному файлу
71
-
72
- # --- Скачиваем SafeTensor модель (выполнится при запуске скрипта в Space) ---
73
- print("Начинаю скачивание базовой модели...")
74
- downloaded_base_model_path = download_file(CIVITAI_SAFETENSOR_URL, LOCAL_SAFETENSOR_FILENAME)
75
 
76
- # --- Загрузка моделей и создание пайплайна ---
77
  # Эта функция вызывается один раз при запуске скрипта
78
- def load_pipeline_components(base_model_path, controlnet_model_id):
79
- """Загружает базовую модель из локального файла, ControlNet и собирает пайплайн."""
80
- if not base_model_path or not os.path.exists(base_model_path):
81
- print(f"Ошибка загрузки: Файл базовой модели не найден по пути: {base_model_path}")
82
- return None # Не можем загрузить пайплайн без файла модели
83
-
84
- print(f"Загрузка ControlNet модели: {controlnet_model_id}")
85
- # Загрузка ControlNet с Hugging Face Hub - кешируется автоматически Space
86
- try:
87
- controlnet = ControlNetModel.from_pretrained(controlnet_model_id, torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32)
88
- except Exception as e:
89
- print(f"Ошибка загрузки ControlNet модели с HF Hub: {controlnet_model_id}. Проверьте ID или соединение.")
90
- print(f"Ошибка: {e}")
91
- return None # Не можем загрузить пайплайн без ControlNet
92
 
93
- print(f"Загрузка базовой модели из локального файла: {base_model_path} с использованием from_single_file")
94
- # Используем from_single_file для загрузки пайплайна из одного SafeTensor файла
95
  try:
96
- pipe = StableDiffusionPipeline.from_single_file(
97
- base_model_path, # Указываем путь к локальному файлу .safetensors
 
 
 
 
98
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
99
- # from_single_file пытается найти конфигурацию VAE, tokenizer и scheduler.
100
- # Если ваша модель требует специфической конфигурации, возможно,
101
- # потребуется указать путь к папке с конфигом или загрузить их отдельно.
102
- # Для большинства Safetensor SD 1.5/2.x from_single_file работает из коробки.
103
- )
104
- # Отключение safety checker после загрузки, если он был загружен
105
- if hasattr(pipe, 'safety_checker') and pipe.safety_checker is not None:
106
- print("Отключаю safety checker...")
107
- pipe.safety_checker = None
108
- print("Safety checker отключен.")
109
-
110
- except Exception as e:
111
- print(f"Ошибка при загрузке базовой модели из файла {base_model_path}: {e}")
112
- print("Убедитесь, что файл не поврежден, соответствует формату StableDiffusion и from_single_file может его обработать.")
113
- return None # Возвращаем None, если загрузка базовой модели не удалась
114
-
115
- # --- Создание пайплайна StableDiffusionControlNetPipeline из компонентов ---
116
- # Этот блок выполняется ТОЛЬКО если базовая модель и ControlNet успешно загружены
117
- print("Создание финального пайплайна StableDiffusionControlNetPipeline...")
118
- try:
119
- controlnet_pipe = StableDiffusionControlNetPipeline(
120
- vae=pipe.vae,
121
- text_encoder=pipe.text_encoder,
122
- tokenizer=pipe.tokenizer,
123
- unet=pipe.unet,
124
- controlnet=controlnet, # Передаем загруженный ControlNet
125
- scheduler=pipe.scheduler, # Используем планировщик из базового пайплайна
126
- safety_checker=None, # Убираем safety_checker здесь при создании нового пайплайна
127
- feature_extractor=pipe.feature_extractor
128
  )
129
 
130
- # Рекомендуется использовать планировщик UniPC для ControlNet (или обновить существующий)
131
- # Обновляем планировщик в новом ControlNet пайплайне
132
- controlnet_pipe.scheduler = UniPCMultistepScheduler.from_config(controlnet_pipe.scheduler.config)
133
-
134
- # Удаляем старый объект пайплайна для освобождения памяти GPU
135
- del pipe
136
- if torch.cuda.is_available():
137
- torch.cuda.empty_cache()
138
- print("Память GPU очищена после создания ControlNet пайплайна.")
139
-
140
 
141
- # Перемещаем ControlNet пайплайн на GPU, если доступно
142
  if torch.cuda.is_available():
143
- controlnet_pipe = controlnet_pipe.to("cuda")
144
- print("Финальный пайплайн перемещен на GPU.")
145
  else:
146
- print("GPU не найдено. Пайплайн будет работать на CPU (крайне медленно).") # В Space на CPU работать не будет эффективно
147
 
148
- return controlnet_pipe # Возвращаем готовый пайплайн
 
149
 
150
  except Exception as e:
151
- print(f"Ошибка при создании финального StableDiffusionControlNetPipeline: {e}")
152
- print("Проверьте совместимость компонентов (базовая модель и ControlNet).")
153
- return None # Возвращаем None, если собрать финальный пайплайн не удалось
 
 
 
 
 
 
154
 
155
 
156
- # --- Загружаем пайплайн при запуске скрипта, только если файл модели успешно скачан ---
157
- # Этот код выполняется после скачивания файла
158
- if downloaded_base_model_path and os.path.exists(downloaded_base_model_path):
159
- pipeline = load_pipeline_components(downloaded_base_model_path, CONTROLNET_MODEL_ID)
160
- else:
161
- print("Пропуск загрузки пайплайна из-за ошибки скачивания или отсутствия файла.")
162
- pipeline = None # Убеждаемся, что pipeline равен None при ошибке
163
 
164
 
165
  # --- Функция рендеринга для Gradio ---
166
  # Эта функция будет вызываться интерфейсом Gradio в Space
167
- def generate_image_gradio(controlnet_image: np.ndarray, prompt: str, negative_prompt: str = "", guidance_scale: float = 7.5, num_inference_steps: int = 30, controlnet_conditioning_scale: float = 1.0):
168
  """
169
- Генерирует изображение с использованием Stable Diffusion ControlNet.
170
  Принимает изображение NumPy, текст промта и другие параметры.
171
  Возвращает сгенерированное изображение в формате PIL Image.
172
  """
173
  # Проверяем, успешно ли загрузился пайплайн
174
  if pipeline is None:
175
  print("Попытка генерации, но пайплайн модели не загружен.")
176
- return None, "Ошибка: Пайплайн модели не загружен. Проверьте логи Space."
177
 
178
  if controlnet_image is None:
179
  return None, "Ошибка: необходимо загрузить изображение для ControlNet."
180
 
181
- print(f"Генерация изображения с промтом: '{prompt}'")
182
- print(f"Размер входного изображения: {controlnet_image.shape}")
183
 
184
  # Gradio возвращает изображение как numpy array. Преобразуем в PIL Image для пайплайна.
185
- # diffusers ControlNet ожидают изображение в формате PIL Image или PyTorch Tensor в RGB
186
  input_image_pil = Image.fromarray(controlnet_image).convert("RGB")
187
 
188
- # Выполняем рендеринг с помощью пайплайна
 
 
 
189
  try:
190
- # Здесь вы можете добавить generator=... (для сидов), width=..., height=..., etc.
191
- # Передаем все параметры в вызов пайплайна
192
  output = pipeline(
193
  prompt=prompt,
194
  image=input_image_pil, # Входное изображение для ControlNet
195
  negative_prompt=negative_prompt,
196
  guidance_scale=guidance_scale,
197
  num_inference_steps=num_inference_steps,
198
- controlnet_conditioning_scale=controlnet_conditioning_scale
 
 
199
  )
200
 
201
  # Результат находится в output.images[0]
202
  generated_image_pil = output.images[0]
203
 
204
- print("Генерация завершена.")
205
  return generated_image_pil, "Успех!"
206
  except Exception as e:
207
- print(f"Ошибка при генерации: {e}")
208
  # Возвращаем None и сообщение об ошибке в интерфейс Gradio
209
- return None, f"Ошибка при генерации: {e}"
210
 
211
 
212
  # --- Настройка интерфейса Gradio ---
213
  # Определяем входные и выходные элементы
 
214
  input_image_comp = gr.Image(type="numpy", label="Изображение для ControlNet (набросок, карта глубины и т.д.)")
215
  prompt_comp = gr.Textbox(label="Промт (Prompt)")
216
  negative_prompt_comp = gr.Textbox(label="Негативный промт (Negative Prompt)")
217
- guidance_scale_comp = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.1, label="Степень соответствия промту (Guidance Scale)")
218
- num_inference_steps_comp = gr.Slider(minimum=10, maximum=150, value=30, step=1, label="Количество шагов (Inference Steps)")
219
  controlnet_conditioning_scale_comp = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.05, label="Вес ControlNet (ControlNet Scale)")
220
 
221
  output_image_comp = gr.Image(type="pil", label="Сгенерированное изображение")
@@ -236,8 +148,8 @@ interface = gr.Interface(
236
  controlnet_conditioning_scale_comp
237
  ],
238
  outputs=[output_image_comp, status_text_comp],
239
- title="Stable Diffusion ControlNet Interface (SafeTensor Base Model on HF Space)",
240
- description="Загрузите изображение для ControlNet, введите промт и нажмите 'Generate'. Используется локальная SafeTensor модель и ControlNet с Hugging Face."
241
  )
242
 
243
  # Нет необходимости вызывать interface.launch() в блоке if __name__ == "__main__":
 
1
  # app.py
2
  import gradio as gr
3
  import torch
 
 
4
  import numpy as np
5
+ from PIL import Image
6
+ import os # Хотя скачивание не используется, оставим на всякий случай
7
+ # from tqdm import tqdm # Не используется в этом скрипте
8
 
9
+ # Импорты для FLUX ControlNet пайплайна
10
+ from diffusers import FluxControlNetPipeline, ControlNetModel, FluxPipeline
11
  # from diffusers.utils import load_image # Не нужен для этого кода
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # --- Определение ID моделей FLUX на Hugging Face Hub ---
14
+ # Базовая модель FLUX (ОГРАНИЧЕННЫЙ ДОСТУП - требуется токен HF и доступ к репо)
15
+ BASE_FLUX_MODEL_ID = "black-forest-labs/FLUX.1-dev"
16
+ # ControlNet модель для FLUX (также на HF Hub)
17
+ CONTROLNET_FLUX_MODEL_ID = "ABDALLALSWAITI/FLUX.1-dev-ControlNet-Union-Pro-2.0-fp8"
18
 
 
 
 
 
 
 
 
 
19
 
20
  # Переменная для хранения пайплайна (будет загружен при запуске скрипта)
21
  pipeline = None
 
 
 
 
 
22
 
23
+ # --- Загрузка пайплайна FLUX ControlNet ---
24
  # Эта функция вызывается один раз при запуске скрипта
25
+ def load_flux_pipeline(base_model_id, controlnet_model_id):
26
+ """Загружает пайплайн FLUX ControlNet с Hugging Face Hub."""
27
+ print(f"Начинаю загрузку пайплайна FLUX ControlNet...")
28
+ print(f"Базовая модель FLUX: {base_model_id}")
29
+ print(f"ControlNet модель FLUX: {controlnet_model_id}")
 
 
 
 
 
 
 
 
 
30
 
 
 
31
  try:
32
+ # Пайплайн FluxControlNetPipeline загружает и объединяет обе модели из репозиториев HF
33
+ # from_pretrained автоматически использует HF_TOKEN, если он установлен как секрет в Space
34
+ # Убедитесь, что версия diffusers поддерживает этот пайплайн и модели FLUX
35
+ pipe = FluxControlNetPipeline.from_pretrained(
36
+ base_model_id,
37
+ controlnet=controlnet_model_id, # Передаем ID ControlNet модели
38
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
39
+ # safety_checker=None # Обычно from_pretrained для FLUX пайплайна не принимает этот аргумент напрямую
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  )
41
 
42
+ # Для FLUX планировщик специфичный, from_pretrained должен загрузить правильный.
43
+ print(f"Планировщик загружен: {type(pipe.scheduler).__name__}")
 
 
 
 
 
 
 
 
44
 
45
+ # Перемещаем пайплайн на GPU, если доступно
46
  if torch.cuda.is_available():
47
+ pipe = pipe.to("cuda")
48
+ print("Пайплайн FLUX ControlNet перемещен на GPU.")
49
  else:
50
+ print("GPU не найдено. Пайплайн будет работать на CPU (не рекомендуется для FLUX).")
51
 
52
+ print("Загрузка пайплайна FLUX ControlNet завершена успешно.")
53
+ return pipe # Возвращаем готовый пайплайн
54
 
55
  except Exception as e:
56
+ print(f"Ошибка при загрузке пайплайна FLUX ControlNet с Hugging Face Hub: {e}")
57
+ print(f"Частые причины:")
58
+ print(f"- Ваш аккаунт не имеет доступа к '{base_model_id}' (нужно зайти на страницу модели на hf.co и принять условия).")
59
+ print(f"- Секрет HF_TOKEN неправильно установлен в настройках Space или не имеет достаточных прав.")
60
+ print(f"- Указан неверный ID модели.")
61
+ print(f"- Проблемы с интернет-соединением Space.")
62
+ print(f"- Версия библиотеки diffusers слишком старая для моделей FLUX.")
63
+ print(f"Подробности ошибки: {e}")
64
+ return None # Возвращаем None, если загрузка не удалась
65
 
66
 
67
+ # --- Загружаем пайплайн при запуске скрипта ---
68
+ # Этот код выполняется один раз при старте Space
69
+ pipeline = load_flux_pipeline(BASE_FLUX_MODEL_ID, CONTROLNET_FLUX_MODEL_ID)
 
 
 
 
70
 
71
 
72
  # --- Функция рендеринга для Gradio ---
73
  # Эта функция будет вызываться интерфейсом Gradio в Space
74
+ def generate_image_gradio(controlnet_image: np.ndarray, prompt: str, negative_prompt: str = "", guidance_scale: float = 7.0, num_inference_steps: int = 50, controlnet_conditioning_scale: float = 1.0):
75
  """
76
+ Генерирует изображение с использованием FLUX ControlNet.
77
  Принимает изображение NumPy, текст промта и другие параметры.
78
  Возвращает сгенерированное изображение в формате PIL Image.
79
  """
80
  # Проверяем, успешно ли загрузился пайплайн
81
  if pipeline is None:
82
  print("Попытка генерации, но пайплайн модели не загружен.")
83
+ return None, "Ошибка: Пайплайн модели FLUX не загружен. Проверьте логи Space и доступ к моделям."
84
 
85
  if controlnet_image is None:
86
  return None, "Ошибка: необходимо загрузить изображение для ControlNet."
87
 
88
+ print(f"Генерация изображения FLUX с промтом: '{prompt}'")
89
+ print(f"Размер входного изображения для ControlNet: {controlnet_image.shape}")
90
 
91
  # Gradio возвращает изображение как numpy array. Преобразуем в PIL Image для пайплайна.
92
+ # Пайплайны ControlNet обычно ожидают PIL Image в RGB.
93
  input_image_pil = Image.fromarray(controlnet_image).convert("RGB")
94
 
95
+ # Выполняем рендеринг с помощью пайплайна FLUX ControlNet
96
+ # Параметры для FLUX могут немного отличаться от SD, проверьте документацию diffusers для FluxControlNetPipeline
97
+ # guidance_scale и num_inference_steps - стандартные параметры
98
+ # controlnet_conditioning_scale - стандартный параметр ControlNet
99
  try:
100
+ # Вызов пайплайна FLUX ControlNet
 
101
  output = pipeline(
102
  prompt=prompt,
103
  image=input_image_pil, # Входное изображение для ControlNet
104
  negative_prompt=negative_prompt,
105
  guidance_scale=guidance_scale,
106
  num_inference_steps=num_inference_steps,
107
+ controlnet_conditioning_scale=controlnet_conditioning_scale,
108
+ # Другие параметры, специфичные для FLUX, могут быть доступны здесь.
109
+ # Проверьте сигнатуру вызова пайплайна FLUX в diffusers.
110
  )
111
 
112
  # Результат находится в output.images[0]
113
  generated_image_pil = output.images[0]
114
 
115
+ print("Генерация FLUX завершена.")
116
  return generated_image_pil, "Успех!"
117
  except Exception as e:
118
+ print(f"Ошибка при генерации FLUX: {e}")
119
  # Возвращаем None и сообщение об ошибке в интерфейс Gradio
120
+ return None, f"Ошибка при генерации FLUX: {e}"
121
 
122
 
123
  # --- Настройка интерфейса Gradio ---
124
  # Определяем входные и выходные элементы
125
+ # Элементы интерфейса могут остаться теми же, так как они универсальны
126
  input_image_comp = gr.Image(type="numpy", label="Изображение для ControlNet (набросок, карта глубины и т.д.)")
127
  prompt_comp = gr.Textbox(label="Промт (Prompt)")
128
  negative_prompt_comp = gr.Textbox(label="Негативный промт (Negative Prompt)")
129
+ guidance_scale_comp = gr.Slider(minimum=1.0, maximum=20.0, value=7.0, step=0.1, label="Степень соответствия промту (Guidance Scale)")
130
+ num_inference_steps_comp = gr.Slider(minimum=10, maximum=150, value=50, step=1, label="Количество шагов (Inference Steps)") # Шаги для FLUX могут отличаться
131
  controlnet_conditioning_scale_comp = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.05, label="Вес ControlNet (ControlNet Scale)")
132
 
133
  output_image_comp = gr.Image(type="pil", label="Сгенерированное изображение")
 
148
  controlnet_conditioning_scale_comp
149
  ],
150
  outputs=[output_image_comp, status_text_comp],
151
+ title="FLUX ControlNet Interface on HF Space",
152
+ description="Загрузите изображение для ControlNet, введите промт и нажмите 'Generate'. Используются модели FLUX и FLUX ControlNet с Hugging Face Hub."
153
  )
154
 
155
  # Нет необходимости вызывать interface.launch() в блоке if __name__ == "__main__":