openfree commited on
Commit
f635382
·
verified ·
1 Parent(s): 8d9a883

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -907
app.py DELETED
@@ -1,907 +0,0 @@
1
- import os
2
- import gradio as gr
3
- import json
4
- import logging
5
- import torch
6
- from PIL import Image
7
- import spaces
8
- from diffusers import DiffusionPipeline, AutoencoderTiny, AutoencoderKL, AutoPipelineForImage2Image
9
- from live_preview_helpers import calculate_shift, retrieve_timesteps, flux_pipe_call_that_returns_an_iterable_of_images
10
- from diffusers.utils import load_image
11
- from huggingface_hub import hf_hub_download, HfFileSystem, ModelCard, snapshot_download
12
- import copy
13
- import random
14
- import time
15
- import requests
16
- import pandas as pd
17
- from transformers import pipeline
18
- from gradio_imageslider import ImageSlider
19
- import numpy as np
20
- import warnings
21
-
22
-
23
- huggingface_token = os.getenv("HF_TOKEN")
24
-
25
-
26
- translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en", device="cpu")
27
-
28
-
29
-
30
- #Load prompts for randomization
31
- df = pd.read_csv('prompts.csv', header=None)
32
- prompt_values = df.values.flatten()
33
-
34
- # Load LoRAs from JSON file
35
- with open('loras.json', 'r') as f:
36
- loras = json.load(f)
37
-
38
- # Initialize the base model
39
- dtype = torch.bfloat16
40
-
41
- device = "cuda" if torch.cuda.is_available() else "cpu"
42
-
43
- # 공통 FLUX 모델 로드
44
- base_model = "black-forest-labs/FLUX.1-dev"
45
- pipe = DiffusionPipeline.from_pretrained(base_model, torch_dtype=dtype).to(device)
46
-
47
- # LoRA를 위한 설정
48
- taef1 = AutoencoderTiny.from_pretrained("madebyollin/taef1", torch_dtype=dtype).to(device)
49
- good_vae = AutoencoderKL.from_pretrained(base_model, subfolder="vae", torch_dtype=dtype).to(device)
50
-
51
- # Image-to-Image 파이프라인 설정
52
- pipe_i2i = AutoPipelineForImage2Image.from_pretrained(
53
- base_model,
54
- vae=good_vae,
55
- transformer=pipe.transformer,
56
- text_encoder=pipe.text_encoder,
57
- tokenizer=pipe.tokenizer,
58
- text_encoder_2=pipe.text_encoder_2,
59
- tokenizer_2=pipe.tokenizer_2,
60
- torch_dtype=dtype
61
- ).to(device)
62
-
63
- MAX_SEED = 2**32 - 1
64
- MAX_PIXEL_BUDGET = 1024 * 1024
65
-
66
- pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe)
67
-
68
- class calculateDuration:
69
- def __init__(self, activity_name=""):
70
- self.activity_name = activity_name
71
-
72
- def __enter__(self):
73
- self.start_time = time.time()
74
- return self
75
-
76
- def __exit__(self, exc_type, exc_value, traceback):
77
- self.end_time = time.time()
78
- self.elapsed_time = self.end_time - self.start_time
79
- if self.activity_name:
80
- print(f"Elapsed time for {self.activity_name}: {self.elapsed_time:.6f} seconds")
81
- else:
82
- print(f"Elapsed time: {self.elapsed_time:.6f} seconds")
83
-
84
- def download_file(url, directory=None):
85
- if directory is None:
86
- directory = os.getcwd() # Use current working directory if not specified
87
-
88
- # Get the filename from the URL
89
- filename = url.split('/')[-1]
90
-
91
- # Full path for the downloaded file
92
- filepath = os.path.join(directory, filename)
93
-
94
- # Download the file
95
- response = requests.get(url)
96
- response.raise_for_status() # Raise an exception for bad status codes
97
-
98
- # Write the content to the file
99
- with open(filepath, 'wb') as file:
100
- file.write(response.content)
101
-
102
- return filepath
103
-
104
- def update_selection(evt: gr.SelectData, selected_indices, loras_state, width, height):
105
- selected_index = evt.index
106
- selected_indices = selected_indices or []
107
- if selected_index in selected_indices:
108
- selected_indices.remove(selected_index)
109
- else:
110
- if len(selected_indices) < 3:
111
- selected_indices.append(selected_index)
112
- else:
113
- gr.Warning("You can select up to 3 LoRAs, remove one to select a new one.")
114
- return gr.update(), gr.update(), gr.update(), gr.update(), selected_indices, gr.update(), gr.update(), gr.update(), width, height, gr.update(), gr.update(), gr.update()
115
-
116
- selected_info_1 = "Select LoRA 1"
117
- selected_info_2 = "Select LoRA 2"
118
- selected_info_3 = "Select LoRA 3"
119
-
120
- lora_scale_1 = 1.15
121
- lora_scale_2 = 1.15
122
- lora_scale_3 = 1.15
123
- lora_image_1 = None
124
- lora_image_2 = None
125
- lora_image_3 = None
126
-
127
- if len(selected_indices) >= 1:
128
- lora1 = loras_state[selected_indices[0]]
129
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨"
130
- lora_image_1 = lora1['image']
131
- if len(selected_indices) >= 2:
132
- lora2 = loras_state[selected_indices[1]]
133
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨"
134
- lora_image_2 = lora2['image']
135
- if len(selected_indices) >= 3:
136
- lora3 = loras_state[selected_indices[2]]
137
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}](https://huggingface.co/{lora3['repo']}) ✨"
138
- lora_image_3 = lora3['image']
139
-
140
- if selected_indices:
141
- last_selected_lora = loras_state[selected_indices[-1]]
142
- new_placeholder = f"Type a prompt for {last_selected_lora['title']}"
143
- else:
144
- new_placeholder = "Type a prompt after selecting a LoRA"
145
-
146
- return gr.update(placeholder=new_placeholder), selected_info_1, selected_info_2, selected_info_3, selected_indices, lora_scale_1, lora_scale_2, lora_scale_3, width, height, lora_image_1, lora_image_2, lora_image_3
147
-
148
- def remove_lora(selected_indices, loras_state, index_to_remove):
149
- if len(selected_indices) > index_to_remove:
150
- selected_indices.pop(index_to_remove)
151
-
152
- selected_info_1 = "Select LoRA 1"
153
- selected_info_2 = "Select LoRA 2"
154
- selected_info_3 = "Select LoRA 3"
155
- lora_scale_1 = 1.15
156
- lora_scale_2 = 1.15
157
- lora_scale_3 = 1.15
158
- lora_image_1 = None
159
- lora_image_2 = None
160
- lora_image_3 = None
161
-
162
- for i, idx in enumerate(selected_indices):
163
- lora = loras_state[idx]
164
- if i == 0:
165
- selected_info_1 = f"### LoRA 1 Selected: [{lora['title']}]({lora['repo']}) ✨"
166
- lora_image_1 = lora['image']
167
- elif i == 1:
168
- selected_info_2 = f"### LoRA 2 Selected: [{lora['title']}]({lora['repo']}) ✨"
169
- lora_image_2 = lora['image']
170
- elif i == 2:
171
- selected_info_3 = f"### LoRA 3 Selected: [{lora['title']}]({lora['repo']}) ✨"
172
- lora_image_3 = lora['image']
173
-
174
- return selected_info_1, selected_info_2, selected_info_3, selected_indices, lora_scale_1, lora_scale_2, lora_scale_3, lora_image_1, lora_image_2, lora_image_3
175
-
176
- def remove_lora_1(selected_indices, loras_state):
177
- return remove_lora(selected_indices, loras_state, 0)
178
-
179
- def remove_lora_2(selected_indices, loras_state):
180
- return remove_lora(selected_indices, loras_state, 1)
181
-
182
- def remove_lora_3(selected_indices, loras_state):
183
- return remove_lora(selected_indices, loras_state, 2)
184
-
185
- def randomize_loras(selected_indices, loras_state):
186
- try:
187
- if len(loras_state) < 3:
188
- raise gr.Error("Not enough LoRAs to randomize.")
189
- selected_indices = random.sample(range(len(loras_state)), 3)
190
- lora1 = loras_state[selected_indices[0]]
191
- lora2 = loras_state[selected_indices[1]]
192
- lora3 = loras_state[selected_indices[2]]
193
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨"
194
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨"
195
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}](https://huggingface.co/{lora3['repo']}) ✨"
196
- lora_scale_1 = 1.15
197
- lora_scale_2 = 1.15
198
- lora_scale_3 = 1.15
199
- lora_image_1 = lora1.get('image', 'path/to/default/image.png')
200
- lora_image_2 = lora2.get('image', 'path/to/default/image.png')
201
- lora_image_3 = lora3.get('image', 'path/to/default/image.png')
202
- random_prompt = random.choice(prompt_values)
203
- return selected_info_1, selected_info_2, selected_info_3, selected_indices, lora_scale_1, lora_scale_2, lora_scale_3, lora_image_1, lora_image_2, lora_image_3, random_prompt
204
- except Exception as e:
205
- print(f"Error in randomize_loras: {str(e)}")
206
- return "Error", "Error", "Error", [], 1.15, 1.15, 1.15, 'path/to/default/image.png', 'path/to/default/image.png', 'path/to/default/image.png', ""
207
-
208
- def add_custom_lora(custom_lora, selected_indices, current_loras):
209
- if custom_lora:
210
- try:
211
- title, repo, path, trigger_word, image = check_custom_model(custom_lora)
212
- print(f"Loaded custom LoRA: {repo}")
213
- existing_item_index = next((index for (index, item) in enumerate(current_loras) if item['repo'] == repo), None)
214
- if existing_item_index is None:
215
- if repo.endswith(".safetensors") and repo.startswith("http"):
216
- repo = download_file(repo)
217
- new_item = {
218
- "image": image if image else "/home/user/app/custom.png",
219
- "title": title,
220
- "repo": repo,
221
- "weights": path,
222
- "trigger_word": trigger_word
223
- }
224
- print(f"New LoRA: {new_item}")
225
- existing_item_index = len(current_loras)
226
- current_loras.append(new_item)
227
-
228
- # Update gallery
229
- gallery_items = [(item["image"], item["title"]) for item in current_loras]
230
- # Update selected_indices if there's room
231
- if len(selected_indices) < 3:
232
- selected_indices.append(existing_item_index)
233
- else:
234
- gr.Warning("You can select up to 3 LoRAs, remove one to select a new one.")
235
-
236
- # Update selected_info and images
237
- selected_info_1 = "Select a LoRA 1"
238
- selected_info_2 = "Select a LoRA 2"
239
- selected_info_3 = "Select a LoRA 3"
240
- lora_scale_1 = 1.15
241
- lora_scale_2 = 1.15
242
- lora_scale_3 = 1.15
243
- lora_image_1 = None
244
- lora_image_2 = None
245
- lora_image_3 = None
246
- if len(selected_indices) >= 1:
247
- lora1 = current_loras[selected_indices[0]]
248
- selected_info_1 = f"### LoRA 1 Selected: {lora1['title']} ✨"
249
- lora_image_1 = lora1['image'] if lora1['image'] else None
250
- if len(selected_indices) >= 2:
251
- lora2 = current_loras[selected_indices[1]]
252
- selected_info_2 = f"### LoRA 2 Selected: {lora2['title']} ✨"
253
- lora_image_2 = lora2['image'] if lora2['image'] else None
254
- if len(selected_indices) >= 3:
255
- lora3 = current_loras[selected_indices[2]]
256
- selected_info_3 = f"### LoRA 3 Selected: {lora3['title']} ✨"
257
- lora_image_3 = lora3['image'] if lora3['image'] else None
258
- print("Finished adding custom LoRA")
259
- return (
260
- current_loras,
261
- gr.update(value=gallery_items),
262
- selected_info_1,
263
- selected_info_2,
264
- selected_info_3,
265
- selected_indices,
266
- lora_scale_1,
267
- lora_scale_2,
268
- lora_scale_3,
269
- lora_image_1,
270
- lora_image_2,
271
- lora_image_3
272
- )
273
- except Exception as e:
274
- print(e)
275
- gr.Warning(str(e))
276
- return current_loras, gr.update(), gr.update(), gr.update(), gr.update(), selected_indices, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
277
- else:
278
- return current_loras, gr.update(), gr.update(), gr.update(), gr.update(), selected_indices, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
279
-
280
- def remove_custom_lora(selected_indices, current_loras):
281
- if current_loras:
282
- custom_lora_repo = current_loras[-1]['repo']
283
- # Remove from loras list
284
- current_loras = current_loras[:-1]
285
- # Remove from selected_indices if selected
286
- custom_lora_index = len(current_loras)
287
- if custom_lora_index in selected_indices:
288
- selected_indices.remove(custom_lora_index)
289
- # Update gallery
290
- gallery_items = [(item["image"], item["title"]) for item in current_loras]
291
- # Update selected_info and images
292
- selected_info_1 = "Select a LoRA 1"
293
- selected_info_2 = "Select a LoRA 2"
294
- selected_info_3 = "Select a LoRA 3"
295
- lora_scale_1 = 1.15
296
- lora_scale_2 = 1.15
297
- lora_scale_3 = 1.15
298
- lora_image_1 = None
299
- lora_image_2 = None
300
- lora_image_3 = None
301
- if len(selected_indices) >= 1:
302
- lora1 = current_loras[selected_indices[0]]
303
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}]({lora1['repo']}) ✨"
304
- lora_image_1 = lora1['image']
305
- if len(selected_indices) >= 2:
306
- lora2 = current_loras[selected_indices[1]]
307
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}]({lora2['repo']}) ✨"
308
- lora_image_2 = lora2['image']
309
- if len(selected_indices) >= 3:
310
- lora3 = current_loras[selected_indices[2]]
311
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}]({lora3['repo']}) ✨"
312
- lora_image_3 = lora3['image']
313
- return (
314
- current_loras,
315
- gr.update(value=gallery_items),
316
- selected_info_1,
317
- selected_info_2,
318
- selected_info_3,
319
- selected_indices,
320
- lora_scale_1,
321
- lora_scale_2,
322
- lora_scale_3,
323
- lora_image_1,
324
- lora_image_2,
325
- lora_image_3
326
- )
327
-
328
- @spaces.GPU(duration=75)
329
- def generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress):
330
- print("Generating image...")
331
- pipe.to("cuda")
332
- generator = torch.Generator(device="cuda").manual_seed(seed)
333
- with calculateDuration("Generating image"):
334
- # Generate image
335
- for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
336
- prompt=prompt_mash,
337
- num_inference_steps=steps,
338
- guidance_scale=cfg_scale,
339
- width=width,
340
- height=height,
341
- generator=generator,
342
- joint_attention_kwargs={"scale": 1.0},
343
- output_type="pil",
344
- good_vae=good_vae,
345
- ):
346
- yield img
347
-
348
- @spaces.GPU(duration=75)
349
- def generate_image_to_image(prompt_mash, image_input_path, image_strength, steps, cfg_scale, width, height, seed):
350
- pipe_i2i.to("cuda")
351
- generator = torch.Generator(device="cuda").manual_seed(seed)
352
- image_input = load_image(image_input_path)
353
- final_image = pipe_i2i(
354
- prompt=prompt_mash,
355
- image=image_input,
356
- strength=image_strength,
357
- num_inference_steps=steps,
358
- guidance_scale=cfg_scale,
359
- width=width,
360
- height=height,
361
- generator=generator,
362
- joint_attention_kwargs={"scale": 1.0},
363
- output_type="pil",
364
- ).images[0]
365
- return final_image
366
-
367
- def run_lora(prompt, image_input, image_strength, cfg_scale, steps, selected_indices, lora_scale_1, lora_scale_2, lora_scale_3, randomize_seed, seed, width, height, loras_state, progress=gr.Progress(track_tqdm=True)):
368
- try:
369
- # 한글 감지 및 ���역 (이 부분은 그대로 유지)
370
- if any('\u3131' <= char <= '\u318E' or '\uAC00' <= char <= '\uD7A3' for char in prompt):
371
- translated = translator(prompt, max_length=512)[0]['translation_text']
372
- print(f"Original prompt: {prompt}")
373
- print(f"Translated prompt: {translated}")
374
- prompt = translated
375
-
376
- if not selected_indices:
377
- raise gr.Error("You must select at least one LoRA before proceeding.")
378
-
379
- selected_loras = [loras_state[idx] for idx in selected_indices]
380
-
381
- # Build the prompt with trigger words (이 부분은 그대로 유지)
382
- prepends = []
383
- appends = []
384
- for lora in selected_loras:
385
- trigger_word = lora.get('trigger_word', '')
386
- if trigger_word:
387
- if lora.get("trigger_position") == "prepend":
388
- prepends.append(trigger_word)
389
- else:
390
- appends.append(trigger_word)
391
- prompt_mash = " ".join(prepends + [prompt] + appends)
392
- print("Prompt Mash: ", prompt_mash)
393
-
394
- # Unload previous LoRA weights
395
- with calculateDuration("Unloading LoRA"):
396
- pipe.unload_lora_weights()
397
- pipe_i2i.unload_lora_weights()
398
-
399
- print(f"Active adapters before loading: {pipe.get_active_adapters()}")
400
-
401
- # Load LoRA weights with respective scales
402
- lora_names = []
403
- lora_weights = []
404
- with calculateDuration("Loading LoRA weights"):
405
- for idx, lora in enumerate(selected_loras):
406
- try:
407
- lora_name = f"lora_{idx}"
408
- lora_path = lora['repo']
409
- weight_name = lora.get("weights")
410
- print(f"Loading LoRA {lora_name} from {lora_path}")
411
- if image_input is not None:
412
- if weight_name:
413
- pipe_i2i.load_lora_weights(lora_path, weight_name=weight_name, adapter_name=lora_name)
414
- else:
415
- pipe_i2i.load_lora_weights(lora_path, adapter_name=lora_name)
416
- else:
417
- if weight_name:
418
- pipe.load_lora_weights(lora_path, weight_name=weight_name, adapter_name=lora_name)
419
- else:
420
- pipe.load_lora_weights(lora_path, adapter_name=lora_name)
421
- lora_names.append(lora_name)
422
- lora_weights.append(lora_scale_1 if idx == 0 else lora_scale_2 if idx == 1 else lora_scale_3)
423
- except Exception as e:
424
- print(f"Failed to load LoRA {lora_name}: {str(e)}")
425
-
426
- print("Loaded LoRAs:", lora_names)
427
- print("Adapter weights:", lora_weights)
428
-
429
- if lora_names:
430
- if image_input is not None:
431
- pipe_i2i.set_adapters(lora_names, adapter_weights=lora_weights)
432
- else:
433
- pipe.set_adapters(lora_names, adapter_weights=lora_weights)
434
- else:
435
- print("No LoRAs were successfully loaded.")
436
- return None, seed, gr.update(visible=False)
437
-
438
- print(f"Active adapters after loading: {pipe.get_active_adapters()}")
439
-
440
- # 여기서부터 이미지 생성 로직 (이 부분은 그대로 유지)
441
- with calculateDuration("Randomizing seed"):
442
- if randomize_seed:
443
- seed = random.randint(0, MAX_SEED)
444
-
445
- if image_input is not None:
446
- final_image = generate_image_to_image(prompt_mash, image_input, image_strength, steps, cfg_scale, width, height, seed)
447
- else:
448
- image_generator = generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress)
449
- final_image = None
450
- step_counter = 0
451
- for image in image_generator:
452
- step_counter += 1
453
- final_image = image
454
- progress_bar = f'<div class="progress-container"><div class="progress-bar" style="--current: {step_counter}; --total: {steps};"></div></div>'
455
- yield image, seed, gr.update(value=progress_bar, visible=True)
456
-
457
- if final_image is None:
458
- raise Exception("Failed to generate image")
459
-
460
- return final_image, seed, gr.update(visible=False)
461
-
462
- except Exception as e:
463
- print(f"Error in run_lora: {str(e)}")
464
- return None, seed, gr.update(visible=False)
465
-
466
- run_lora.zerogpu = True
467
-
468
- def get_huggingface_safetensors(link):
469
- split_link = link.split("/")
470
- if len(split_link) == 2:
471
- model_card = ModelCard.load(link)
472
- base_model = model_card.data.get("base_model")
473
- print(f"Base model: {base_model}")
474
- if base_model not in ["black-forest-labs/FLUX.1-dev", "black-forest-labs/FLUX.1-schnell"]:
475
- raise Exception("Not a FLUX LoRA!")
476
- image_path = model_card.data.get("widget", [{}])[0].get("output", {}).get("url", None)
477
- trigger_word = model_card.data.get("instance_prompt", "")
478
- image_url = f"https://huggingface.co/{link}/resolve/main/{image_path}" if image_path else None
479
- fs = HfFileSystem()
480
- safetensors_name = None
481
- try:
482
- list_of_files = fs.ls(link, detail=False)
483
- for file in list_of_files:
484
- if file.endswith(".safetensors"):
485
- safetensors_name = file.split("/")[-1]
486
- if not image_url and file.lower().endswith((".jpg", ".jpeg", ".png", ".webp")):
487
- image_elements = file.split("/")
488
- image_url = f"https://huggingface.co/{link}/resolve/main/{image_elements[-1]}"
489
- except Exception as e:
490
- print(e)
491
- raise gr.Error("Invalid Hugging Face repository with a *.safetensors LoRA")
492
- if not safetensors_name:
493
- raise gr.Error("No *.safetensors file found in the repository")
494
- return split_link[1], link, safetensors_name, trigger_word, image_url
495
- else:
496
- raise gr.Error("Invalid Hugging Face repository link")
497
-
498
- def check_custom_model(link):
499
- if link.endswith(".safetensors"):
500
- # Treat as direct link to the LoRA weights
501
- title = os.path.basename(link)
502
- repo = link
503
- path = None # No specific weight name
504
- trigger_word = ""
505
- image_url = None
506
- return title, repo, path, trigger_word, image_url
507
- elif link.startswith("https://"):
508
- if "huggingface.co" in link:
509
- link_split = link.split("huggingface.co/")
510
- return get_huggingface_safetensors(link_split[1])
511
- else:
512
- raise Exception("Unsupported URL")
513
- else:
514
- # Assume it's a Hugging Face model path
515
- return get_huggingface_safetensors(link)
516
-
517
- def update_history(new_image, history):
518
- """Updates the history gallery with the new image."""
519
- if history is None:
520
- history = []
521
- if new_image is not None:
522
- history.insert(0, new_image)
523
- return history
524
-
525
- custom_theme = gr.themes.Base(
526
- primary_hue="blue",
527
- secondary_hue="purple",
528
- neutral_hue="slate",
529
- ).set(
530
- button_primary_background_fill="*primary_500",
531
- button_primary_background_fill_dark="*primary_600",
532
- button_primary_background_fill_hover="*primary_400",
533
- button_primary_border_color="*primary_500",
534
- button_primary_border_color_dark="*primary_600",
535
- button_primary_text_color="white",
536
- button_primary_text_color_dark="white",
537
- button_secondary_background_fill="*neutral_100",
538
- button_secondary_background_fill_dark="*neutral_700",
539
- button_secondary_background_fill_hover="*neutral_50",
540
- button_secondary_text_color="*neutral_800",
541
- button_secondary_text_color_dark="white",
542
- background_fill_primary="*neutral_50",
543
- background_fill_primary_dark="*neutral_900",
544
- block_background_fill="white",
545
- block_background_fill_dark="*neutral_800",
546
- block_label_background_fill="*primary_500",
547
- block_label_background_fill_dark="*primary_600",
548
- block_label_text_color="white",
549
- block_label_text_color_dark="white",
550
- block_title_text_color="*neutral_800",
551
- block_title_text_color_dark="white",
552
- input_background_fill="white",
553
- input_background_fill_dark="*neutral_800",
554
- input_border_color="*neutral_200",
555
- input_border_color_dark="*neutral_700",
556
- input_placeholder_color="*neutral_400",
557
- input_placeholder_color_dark="*neutral_400",
558
- shadow_spread="8px",
559
- shadow_inset="0px 2px 4px 0px rgba(0,0,0,0.05)"
560
- )
561
-
562
- css = '''
563
- /* 기존 스타일 유지 */
564
- #gen_btn{height: 90%} /* 100% -> 90% */
565
- #title{text-align: center}
566
- #title h1{font-size: 2.7em; display:inline-flex; align-items:center} /* 3em -> 2.7em */
567
- #title img{width: 90px; margin-right: 0.225em} /* 100px -> 90px, 0.25em -> 0.225em */
568
- #lora_list{background: var(--block-background-fill);padding: 0 0.9em .27em; font-size: 81%} /* 90% 적용 */
569
- .custom_lora_card{margin-bottom: 0.9em}
570
- .card_internal{display: flex;height: 90px;margin-top: .45em} /* 100px -> 90px */
571
- .card_internal img{margin-right: 0.9em}
572
- .styler{--form-gap-width: 0px !important}
573
- #progress{height:27px} /* 30px -> 27px */
574
- #progress .generating{display:none}
575
- .progress-container {
576
- width: 90%; /* 100% -> 90% */
577
- height: 27px; /* 30px -> 27px */
578
- background-color: #f0f0f0;
579
- border-radius: 13.5px; /* 15px -> 13.5px */
580
- overflow: hidden;
581
- margin-bottom: 18px /* 20px -> 18px */
582
- }
583
-
584
- /* 갤러리 관련 스타일 */
585
- #lora_gallery {
586
- margin: 18px 0; /* 20px -> 18px */
587
- padding: 9px; /* 10px -> 9px */
588
- border: 1px solid #ddd;
589
- border-radius: 10.8px; /* 12px -> 10.8px */
590
- background: linear-gradient(to bottom right, #ffffff, #f8f9fa);
591
- width: 90% !important; /* 100% -> 90% */
592
- height: 720px !important; /* 800px -> 720px */
593
- box-shadow: 0 3.6px 5.4px -0.9px rgba(0, 0, 0, 0.1);
594
- }
595
-
596
- /* 컴포넌트 크기 조정을 위한 새로운 스타일 */
597
- .input-container {
598
- margin: 4.5px !important; /* 5px -> 4.5px */
599
- padding: 4.5px !important;
600
- }
601
-
602
- .button_total {
603
- padding: 7.2px 13.5px !important; /* 8px 15px -> 7.2px 13.5px */
604
- font-size: 0.81em !important; /* 0.9em -> 0.81em */
605
- }
606
-
607
- .slider-container {
608
- max-width: 85.5% !important; /* 95% -> 85.5% */
609
- }
610
-
611
- /* 탭 컨테이너 여백 조정 */
612
- .tab-content {
613
- padding: 0 18px !important; /* 20px -> 18px */
614
- max-width: 85.5% !important; /* 95% -> 85.5% */
615
- margin: 0 auto !important;
616
- }
617
-
618
- /* 컴포넌트들의 border-radius 조정 */
619
- .gradio-container .input,
620
- .gradio-container .button,
621
- .gradio-container .block,
622
- .gallery-item,
623
- #lora_gallery {
624
- border-radius: 10.8px; /* 12px -> 10.8px */
625
- }
626
-
627
- /* 입체감 있는 버튼 효과 조정 */
628
- .button_total {
629
- box-shadow: 0 3.6px 5.4px -0.9px rgba(0, 0, 0, 0.1), 0 1.8px 3.6px -0.9px rgba(0, 0, 0, 0.06);
630
- }
631
-
632
- .button_total:hover {
633
- transform: translateY(-1.8px); /* -2px -> -1.8px */
634
- box-shadow: 0 9px 13.5px -2.7px rgba(0, 0, 0, 0.1), 0 3.6px 5.4px -1.8px rgba(0, 0, 0, 0.05);
635
- }
636
-
637
- /* 스크롤바 크기 조정 */
638
- #gallery::-webkit-scrollbar {
639
- width: 7.2px; /* 8px -> 7.2px */
640
- }
641
-
642
- /* 입체감 있는 입력 필드 */
643
- input, textarea {
644
- box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
645
- transition: all 0.3s ease;
646
- }
647
-
648
- input:focus, textarea:focus {
649
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
650
- }
651
-
652
- /* 컴포넌트들의 border-radius 설정 */
653
- .gradio-container .input,
654
- .gradio-container .button,
655
- .gradio-container .block {
656
- border-radius: 12px;
657
- }
658
-
659
- /* 갤러리 스크롤바 스타일링 */
660
- #gallery::-webkit-scrollbar {
661
- width: 8px;
662
- }
663
-
664
- #gallery::-webkit-scrollbar-track {
665
- background: #f1f1f1;
666
- border-radius: 4px;
667
- }
668
-
669
- #gallery::-webkit-scrollbar-thumb {
670
- background: #888;
671
- border-radius: 4px;
672
- }
673
-
674
- #gallery::-webkit-scrollbar-thumb:hover {
675
- background: #555;
676
- }
677
-
678
- /* 갤러리 flex 컨테이너 */
679
- .flex {
680
- width: 100% !important;
681
- max-width: 100% !important;
682
- display: flex !important;
683
- }
684
-
685
- /* svelte 특정 클래스 */
686
- .svelte-1p9xokt {
687
- width: 100% !important;
688
- max-width: 100% !important;
689
- }
690
-
691
- #footer {visibility: hidden;}
692
-
693
- /* 갤러리 컨테이너 클래스 */
694
- .gallery-container {
695
- width: 100% !important;
696
- max-width: 100% !important;
697
- }
698
-
699
- /* 탭 컨테이너 여백 조정 */
700
- .tab-content {
701
- padding: 0 20px !important;
702
- max-width: 95% !important; /* 전체 너비를 95%로 제한 */
703
- margin: 0 auto !important;
704
- }
705
-
706
- /* 슬라이더 크기 조정 */
707
- .slider-container {
708
- max-width: 95% !important;
709
- }
710
-
711
- /* 버튼 크기 조정 */
712
- .button_total {
713
- padding: 8px 15px !important;
714
- font-size: 0.9em !important;
715
- }
716
-
717
- /* 입력 필드 여백 조정 */
718
- .input-container {
719
- margin: 5px !important;
720
- padding: 5px !important;
721
- }
722
- '''
723
-
724
-
725
- with gr.Blocks(theme=custom_theme, css=css, delete_cache=(60, 3600)) as app:
726
- loras_state = gr.State(loras)
727
- selected_indices = gr.State([])
728
-
729
- gr.Markdown(
730
- """
731
- # MixGen3: 멀티 Lora(이미지 학습) 통합 생성 모델
732
- ### 사용 안내:
733
- 갤러리에서 원하는 모델을 선택(최대 3개까지) < 프롬프트에 한글 또는 영문으로 원하는 내용을 입력 < Generate 버튼 실행
734
- """
735
- )
736
-
737
- with gr.Row(elem_id="lora_gallery", equal_height=True):
738
- gallery = gr.Gallery(
739
- value=[(item["image"], item["title"]) for item in loras],
740
- label="LoRA Explorer Gallery",
741
- columns=11, # 10개로 변경
742
- elem_id="gallery",
743
- height=800,
744
- object_fit="cover",
745
- show_label=True,
746
- allow_preview=False,
747
- show_share_button=False,
748
- container=True,
749
- preview=False
750
- )
751
-
752
- with gr.Tab(label="Generate"):
753
- # Prompt and Generate Button - 비율 조정
754
- with gr.Row():
755
- with gr.Column(scale=3.6):
756
- prompt = gr.Textbox(label="Prompt", lines=1, placeholder="Type a prompt after selecting a LoRA")
757
- with gr.Column(scale=0.9):
758
- generate_button = gr.Button("Generate", variant="primary", elem_classes=["button_total"])
759
-
760
- # LoRA Selection Area - 비율 조정
761
- with gr.Row(elem_id="loaded_loras"):
762
- with gr.Column(scale=0.9, min_width=18):
763
- randomize_button = gr.Button("🎲", variant="secondary", scale=1, elem_id="random_btn")
764
-
765
- # LoRA 1 - 비율 조정
766
- with gr.Column(scale=5.4):
767
- with gr.Row():
768
- with gr.Column(scale=0, min_width=36):
769
- lora_image_1 = gr.Image(label="LoRA 1 Image", interactive=False, min_width=40, width=40, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=40)
770
- with gr.Column(scale=2.7, min_width=72):
771
- selected_info_1 = gr.Markdown("Select a LoRA 1")
772
- with gr.Column(scale=3.6, min_width=36):
773
- lora_scale_1 = gr.Slider(label="LoRA 1 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
774
- with gr.Row():
775
- remove_button_1 = gr.Button("Remove", size="sm")
776
-
777
- # LoRA 2 - 비율 조정
778
- with gr.Column(scale=6):
779
- with gr.Row():
780
- with gr.Column(scale=0, min_width=36):
781
- lora_image_2 = gr.Image(label="LoRA 2 Image", interactive=False, min_width=40, width=40, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=40)
782
- with gr.Column(scale=2.7, min_width=72):
783
- selected_info_2 = gr.Markdown("Select a LoRA 2")
784
- with gr.Column(scale=3.6, min_width=36):
785
- lora_scale_2 = gr.Slider(label="LoRA 2 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
786
- with gr.Row():
787
- remove_button_2 = gr.Button("Remove", size="sm")
788
-
789
- # LoRA 3 - 비율 조정
790
- with gr.Column(scale=6):
791
- with gr.Row():
792
- with gr.Column(scale=0, min_width=36):
793
- lora_image_3 = gr.Image(label="LoRA 3 Image", interactive=False, min_width=40, width=40, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=40)
794
- with gr.Column(scale=2.7, min_width=72):
795
- selected_info_3 = gr.Markdown("Select a LoRA 3")
796
- with gr.Column(scale=3.6, min_width=36):
797
- lora_scale_3 = gr.Slider(label="LoRA 3 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
798
- with gr.Row():
799
- remove_button_3 = gr.Button("Remove", size="sm")
800
-
801
- # Result and Progress Area
802
- with gr.Column(scale=1):
803
- progress_bar = gr.Markdown(elem_id="progress", visible=False)
804
- result = gr.Image(label="Generated Image", interactive=False)
805
- with gr.Accordion("History", open=False):
806
- history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", interactive=False)
807
-
808
- # Advanced Settings
809
- with gr.Row():
810
- with gr.Accordion("Advanced Settings", open=False):
811
- with gr.Row():
812
- input_image = gr.Image(label="Input image", type="filepath")
813
- image_strength = gr.Slider(label="Denoise Strength", info="Lower means more image influence", minimum=0.1, maximum=1.0, step=0.01, value=0.75)
814
- with gr.Column():
815
- with gr.Row():
816
- cfg_scale = gr.Slider(label="CFG Scale", minimum=1, maximum=20, step=0.5, value=3.5)
817
- steps = gr.Slider(label="Steps", minimum=1, maximum=50, step=1, value=28)
818
- with gr.Row():
819
- width = gr.Slider(label="Width", minimum=256, maximum=1536, step=64, value=1024)
820
- height = gr.Slider(label="Height", minimum=256, maximum=1536, step=64, value=1024)
821
- with gr.Row():
822
- randomize_seed = gr.Checkbox(True, label="Randomize seed")
823
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, randomize=True)
824
-
825
- # Custom LoRA Section
826
- with gr.Column(scale=1):
827
- with gr.Group():
828
- with gr.Row(elem_id="custom_lora_structure"):
829
- custom_lora = gr.Textbox(label="Custom LoRA", info="LoRA Hugging Face path or *.safetensors public URL", placeholder="ginipick/flux-lora-eric-cat", scale=3, min_width=150)
830
- add_custom_lora_button = gr.Button("Add Custom LoRA", elem_id="custom_lora_btn", scale=2, min_width=150)
831
- remove_custom_lora_button = gr.Button("Remove Custom LoRA", visible=False)
832
- gr.Markdown("[Check the list of FLUX LoRAs](https://huggingface.co/models?other=base_model:adapter:black-forest-labs/FLUX.1-dev)", elem_id="lora_list")
833
-
834
-
835
- # Event Handlers (들여쓰기 수정)
836
- gallery.select(
837
- update_selection,
838
- inputs=[selected_indices, loras_state, width, height],
839
- outputs=[prompt, selected_info_1, selected_info_2, selected_info_3, selected_indices,
840
- lora_scale_1, lora_scale_2, lora_scale_3, width, height,
841
- lora_image_1, lora_image_2, lora_image_3]
842
- )
843
-
844
- remove_button_1.click(
845
- remove_lora_1,
846
- inputs=[selected_indices, loras_state],
847
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
848
- lora_scale_1, lora_scale_2, lora_scale_3,
849
- lora_image_1, lora_image_2, lora_image_3]
850
- )
851
-
852
- remove_button_2.click(
853
- remove_lora_2,
854
- inputs=[selected_indices, loras_state],
855
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
856
- lora_scale_1, lora_scale_2, lora_scale_3,
857
- lora_image_1, lora_image_2, lora_image_3]
858
- )
859
-
860
- remove_button_3.click(
861
- remove_lora_3,
862
- inputs=[selected_indices, loras_state],
863
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
864
- lora_scale_1, lora_scale_2, lora_scale_3,
865
- lora_image_1, lora_image_2, lora_image_3]
866
- )
867
-
868
- randomize_button.click(
869
- randomize_loras,
870
- inputs=[selected_indices, loras_state],
871
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
872
- lora_scale_1, lora_scale_2, lora_scale_3,
873
- lora_image_1, lora_image_2, lora_image_3, prompt]
874
- )
875
-
876
- add_custom_lora_button.click(
877
- add_custom_lora,
878
- inputs=[custom_lora, selected_indices, loras_state],
879
- outputs=[loras_state, gallery, selected_info_1, selected_info_2, selected_info_3,
880
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
881
- lora_image_1, lora_image_2, lora_image_3]
882
- )
883
-
884
- remove_custom_lora_button.click(
885
- remove_custom_lora,
886
- inputs=[selected_indices, loras_state],
887
- outputs=[loras_state, gallery, selected_info_1, selected_info_2, selected_info_3,
888
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
889
- lora_image_1, lora_image_2, lora_image_3]
890
- )
891
-
892
- gr.on(
893
- triggers=[generate_button.click, prompt.submit],
894
- fn=run_lora,
895
- inputs=[prompt, input_image, image_strength, cfg_scale, steps,
896
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
897
- randomize_seed, seed, width, height, loras_state],
898
- outputs=[result, seed, progress_bar]
899
- ).then(
900
- fn=lambda x, history: update_history(x, history) if x is not None else history,
901
- inputs=[result, history_gallery],
902
- outputs=history_gallery
903
- )
904
-
905
- if __name__ == "__main__":
906
- app.queue(max_size=20)
907
- app.launch(debug=True)