openfree commited on
Commit
54aeac4
1 Parent(s): 82ae436

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -1221
app.py CHANGED
@@ -1,1222 +1,2 @@
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
- # 상단에 허깅페이스 USERNAME (해당 계정) 반드시 개별 지정할것
23
- USERNAME = "openfree"
24
-
25
- huggingface_token = os.getenv("HF_TOKEN")
26
-
27
-
28
- translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en", device="cpu")
29
-
30
-
31
-
32
- #Load prompts for randomization
33
- df = pd.read_csv('prompts.csv', header=None)
34
- prompt_values = df.values.flatten()
35
-
36
- # Load LoRAs from JSON file
37
- with open('loras.json', 'r') as f:
38
- loras = json.load(f)
39
-
40
- # Initialize the base model
41
- dtype = torch.bfloat16
42
-
43
- device = "cuda" if torch.cuda.is_available() else "cpu"
44
-
45
- # 공통 FLUX 모델 로드
46
- base_model = "black-forest-labs/FLUX.1-dev"
47
- pipe = DiffusionPipeline.from_pretrained(base_model, torch_dtype=dtype).to(device)
48
-
49
- # LoRA를 위한 설정
50
- taef1 = AutoencoderTiny.from_pretrained("madebyollin/taef1", torch_dtype=dtype).to(device)
51
- good_vae = AutoencoderKL.from_pretrained(base_model, subfolder="vae", torch_dtype=dtype).to(device)
52
-
53
- # Image-to-Image 파이프라인 설정
54
- pipe_i2i = AutoPipelineForImage2Image.from_pretrained(
55
- base_model,
56
- vae=good_vae,
57
- transformer=pipe.transformer,
58
- text_encoder=pipe.text_encoder,
59
- tokenizer=pipe.tokenizer,
60
- text_encoder_2=pipe.text_encoder_2,
61
- tokenizer_2=pipe.tokenizer_2,
62
- torch_dtype=dtype
63
- ).to(device)
64
-
65
- MAX_SEED = 2**32 - 1
66
- MAX_PIXEL_BUDGET = 1024 * 1024
67
-
68
- pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe)
69
-
70
- class calculateDuration:
71
- def __init__(self, activity_name=""):
72
- self.activity_name = activity_name
73
-
74
- def __enter__(self):
75
- self.start_time = time.time()
76
- return self
77
-
78
- def __exit__(self, exc_type, exc_value, traceback):
79
- self.end_time = time.time()
80
- self.elapsed_time = self.end_time - self.start_time
81
- if self.activity_name:
82
- print(f"Elapsed time for {self.activity_name}: {self.elapsed_time:.6f} seconds")
83
- else:
84
- print(f"Elapsed time: {self.elapsed_time:.6f} seconds")
85
-
86
- def download_file(url, directory=None):
87
- if directory is None:
88
- directory = os.getcwd() # Use current working directory if not specified
89
-
90
- # Get the filename from the URL
91
- filename = url.split('/')[-1]
92
-
93
- # Full path for the downloaded file
94
- filepath = os.path.join(directory, filename)
95
-
96
- # Download the file
97
- response = requests.get(url)
98
- response.raise_for_status() # Raise an exception for bad status codes
99
-
100
- # Write the content to the file
101
- with open(filepath, 'wb') as file:
102
- file.write(response.content)
103
-
104
- return filepath
105
-
106
- def update_selection(evt: gr.SelectData, selected_indices, loras_state, width, height):
107
- selected_index = evt.index
108
- selected_indices = selected_indices or []
109
- if selected_index in selected_indices:
110
- selected_indices.remove(selected_index)
111
- else:
112
- if len(selected_indices) < 3:
113
- selected_indices.append(selected_index)
114
- else:
115
- gr.Warning("You can select up to 3 LoRAs, remove one to select a new one.")
116
- 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()
117
-
118
- selected_info_1 = "Select LoRA 1"
119
- selected_info_2 = "Select LoRA 2"
120
- selected_info_3 = "Select LoRA 3"
121
-
122
- lora_scale_1 = 1.15
123
- lora_scale_2 = 1.15
124
- lora_scale_3 = 1.15
125
- lora_image_1 = None
126
- lora_image_2 = None
127
- lora_image_3 = None
128
-
129
- if len(selected_indices) >= 1:
130
- lora1 = loras_state[selected_indices[0]]
131
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨"
132
- lora_image_1 = lora1['image']
133
- if len(selected_indices) >= 2:
134
- lora2 = loras_state[selected_indices[1]]
135
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨"
136
- lora_image_2 = lora2['image']
137
- if len(selected_indices) >= 3:
138
- lora3 = loras_state[selected_indices[2]]
139
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}](https://huggingface.co/{lora3['repo']}) ✨"
140
- lora_image_3 = lora3['image']
141
-
142
- if selected_indices:
143
- last_selected_lora = loras_state[selected_indices[-1]]
144
- new_placeholder = f"Type a prompt for {last_selected_lora['title']}"
145
- else:
146
- new_placeholder = "Type a prompt after selecting a LoRA"
147
-
148
- 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
149
-
150
- def remove_lora(selected_indices, loras_state, index_to_remove):
151
- if len(selected_indices) > index_to_remove:
152
- selected_indices.pop(index_to_remove)
153
-
154
- selected_info_1 = "Select LoRA 1"
155
- selected_info_2 = "Select LoRA 2"
156
- selected_info_3 = "Select LoRA 3"
157
- lora_scale_1 = 1.15
158
- lora_scale_2 = 1.15
159
- lora_scale_3 = 1.15
160
- lora_image_1 = None
161
- lora_image_2 = None
162
- lora_image_3 = None
163
-
164
- for i, idx in enumerate(selected_indices):
165
- lora = loras_state[idx]
166
- if i == 0:
167
- selected_info_1 = f"### LoRA 1 Selected: [{lora['title']}]({lora['repo']}) ✨"
168
- lora_image_1 = lora['image']
169
- elif i == 1:
170
- selected_info_2 = f"### LoRA 2 Selected: [{lora['title']}]({lora['repo']}) ✨"
171
- lora_image_2 = lora['image']
172
- elif i == 2:
173
- selected_info_3 = f"### LoRA 3 Selected: [{lora['title']}]({lora['repo']}) ✨"
174
- lora_image_3 = lora['image']
175
-
176
- 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
177
-
178
- def remove_lora_1(selected_indices, loras_state):
179
- return remove_lora(selected_indices, loras_state, 0)
180
-
181
- def remove_lora_2(selected_indices, loras_state):
182
- return remove_lora(selected_indices, loras_state, 1)
183
-
184
- def remove_lora_3(selected_indices, loras_state):
185
- return remove_lora(selected_indices, loras_state, 2)
186
-
187
- def randomize_loras(selected_indices, loras_state):
188
- try:
189
- if len(loras_state) < 3:
190
- raise gr.Error("Not enough LoRAs to randomize.")
191
- selected_indices = random.sample(range(len(loras_state)), 3)
192
- lora1 = loras_state[selected_indices[0]]
193
- lora2 = loras_state[selected_indices[1]]
194
- lora3 = loras_state[selected_indices[2]]
195
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨"
196
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨"
197
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}](https://huggingface.co/{lora3['repo']}) ✨"
198
- lora_scale_1 = 1.15
199
- lora_scale_2 = 1.15
200
- lora_scale_3 = 1.15
201
- lora_image_1 = lora1.get('image', 'path/to/default/image.png')
202
- lora_image_2 = lora2.get('image', 'path/to/default/image.png')
203
- lora_image_3 = lora3.get('image', 'path/to/default/image.png')
204
- random_prompt = random.choice(prompt_values)
205
- 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
206
- except Exception as e:
207
- print(f"Error in randomize_loras: {str(e)}")
208
- 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', ""
209
-
210
- def add_custom_lora(custom_lora, selected_indices, current_loras):
211
- if custom_lora:
212
- try:
213
- title, repo, path, trigger_word, image = check_custom_model(custom_lora)
214
- print(f"Loaded custom LoRA: {repo}")
215
- existing_item_index = next((index for (index, item) in enumerate(current_loras) if item['repo'] == repo), None)
216
- if existing_item_index is None:
217
- if repo.endswith(".safetensors") and repo.startswith("http"):
218
- repo = download_file(repo)
219
- new_item = {
220
- "image": image if image else "/home/user/app/custom.png",
221
- "title": title,
222
- "repo": repo,
223
- "weights": path,
224
- "trigger_word": trigger_word
225
- }
226
- print(f"New LoRA: {new_item}")
227
- existing_item_index = len(current_loras)
228
- current_loras.append(new_item)
229
-
230
- # Update gallery
231
- gallery_items = [(item["image"], item["title"]) for item in current_loras]
232
- # Update selected_indices if there's room
233
- if len(selected_indices) < 3:
234
- selected_indices.append(existing_item_index)
235
- else:
236
- gr.Warning("You can select up to 3 LoRAs, remove one to select a new one.")
237
-
238
- # Update selected_info and images
239
- selected_info_1 = "Select a LoRA 1"
240
- selected_info_2 = "Select a LoRA 2"
241
- selected_info_3 = "Select a LoRA 3"
242
- lora_scale_1 = 1.15
243
- lora_scale_2 = 1.15
244
- lora_scale_3 = 1.15
245
- lora_image_1 = None
246
- lora_image_2 = None
247
- lora_image_3 = None
248
- if len(selected_indices) >= 1:
249
- lora1 = current_loras[selected_indices[0]]
250
- selected_info_1 = f"### LoRA 1 Selected: {lora1['title']} ✨"
251
- lora_image_1 = lora1['image'] if lora1['image'] else None
252
- if len(selected_indices) >= 2:
253
- lora2 = current_loras[selected_indices[1]]
254
- selected_info_2 = f"### LoRA 2 Selected: {lora2['title']} ✨"
255
- lora_image_2 = lora2['image'] if lora2['image'] else None
256
- if len(selected_indices) >= 3:
257
- lora3 = current_loras[selected_indices[2]]
258
- selected_info_3 = f"### LoRA 3 Selected: {lora3['title']} ✨"
259
- lora_image_3 = lora3['image'] if lora3['image'] else None
260
- print("Finished adding custom LoRA")
261
- return (
262
- current_loras,
263
- gr.update(value=gallery_items),
264
- selected_info_1,
265
- selected_info_2,
266
- selected_info_3,
267
- selected_indices,
268
- lora_scale_1,
269
- lora_scale_2,
270
- lora_scale_3,
271
- lora_image_1,
272
- lora_image_2,
273
- lora_image_3
274
- )
275
- except Exception as e:
276
- print(e)
277
- gr.Warning(str(e))
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
- else:
280
- 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()
281
-
282
- def remove_custom_lora(selected_indices, current_loras):
283
- if current_loras:
284
- custom_lora_repo = current_loras[-1]['repo']
285
- # Remove from loras list
286
- current_loras = current_loras[:-1]
287
- # Remove from selected_indices if selected
288
- custom_lora_index = len(current_loras)
289
- if custom_lora_index in selected_indices:
290
- selected_indices.remove(custom_lora_index)
291
- # Update gallery
292
- gallery_items = [(item["image"], item["title"]) for item in current_loras]
293
- # Update selected_info and images
294
- selected_info_1 = "Select a LoRA 1"
295
- selected_info_2 = "Select a LoRA 2"
296
- selected_info_3 = "Select a LoRA 3"
297
- lora_scale_1 = 1.15
298
- lora_scale_2 = 1.15
299
- lora_scale_3 = 1.15
300
- lora_image_1 = None
301
- lora_image_2 = None
302
- lora_image_3 = None
303
- if len(selected_indices) >= 1:
304
- lora1 = current_loras[selected_indices[0]]
305
- selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}]({lora1['repo']}) ✨"
306
- lora_image_1 = lora1['image']
307
- if len(selected_indices) >= 2:
308
- lora2 = current_loras[selected_indices[1]]
309
- selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}]({lora2['repo']}) ✨"
310
- lora_image_2 = lora2['image']
311
- if len(selected_indices) >= 3:
312
- lora3 = current_loras[selected_indices[2]]
313
- selected_info_3 = f"### LoRA 3 Selected: [{lora3['title']}]({lora3['repo']}) ✨"
314
- lora_image_3 = lora3['image']
315
- return (
316
- current_loras,
317
- gr.update(value=gallery_items),
318
- selected_info_1,
319
- selected_info_2,
320
- selected_info_3,
321
- selected_indices,
322
- lora_scale_1,
323
- lora_scale_2,
324
- lora_scale_3,
325
- lora_image_1,
326
- lora_image_2,
327
- lora_image_3
328
- )
329
-
330
-
331
- def generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress):
332
- print("Generating image...")
333
- pipe.to("cuda")
334
- generator = torch.Generator(device="cuda").manual_seed(seed)
335
- with calculateDuration("Generating image"):
336
- # Generate image
337
- for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
338
- prompt=prompt_mash,
339
- num_inference_steps=steps,
340
- guidance_scale=cfg_scale,
341
- width=width,
342
- height=height,
343
- generator=generator,
344
- joint_attention_kwargs={"scale": 1.0},
345
- output_type="pil",
346
- good_vae=good_vae,
347
- ):
348
- yield img
349
-
350
-
351
- def generate_image_to_image(prompt_mash, image_input_path, image_strength, steps, cfg_scale, width, height, seed):
352
- pipe_i2i.to("cuda")
353
- generator = torch.Generator(device="cuda").manual_seed(seed)
354
- image_input = load_image(image_input_path)
355
- final_image = pipe_i2i(
356
- prompt=prompt_mash,
357
- image=image_input,
358
- strength=image_strength,
359
- num_inference_steps=steps,
360
- guidance_scale=cfg_scale,
361
- width=width,
362
- height=height,
363
- generator=generator,
364
- joint_attention_kwargs={"scale": 1.0},
365
- output_type="pil",
366
- ).images[0]
367
- return final_image
368
-
369
- def run_lora(prompt, image_input, image_strength, cfg_scale, steps, selected_indices,
370
- lora_scale_1, lora_scale_2, lora_scale_3, randomize_seed, seed,
371
- width, height, loras_state, progress=gr.Progress(track_tqdm=True)):
372
- try:
373
- # 한글 감지 및 번역
374
- if any('\u3131' <= char <= '\u318E' or '\uAC00' <= char <= '\uD7A3' for char in prompt):
375
- translated = translator(prompt, max_length=512)[0]['translation_text']
376
- print(f"Original prompt: {prompt}")
377
- print(f"Translated prompt: {translated}")
378
- prompt = translated
379
-
380
- if not selected_indices:
381
- raise gr.Error("You must select at least one LoRA before proceeding.")
382
-
383
- selected_loras = [loras_state[idx] for idx in selected_indices]
384
-
385
- # Build the prompt with trigger words
386
- prepends = []
387
- appends = []
388
- for lora in selected_loras:
389
- trigger_word = lora.get('trigger_word', '')
390
- if trigger_word:
391
- if lora.get("trigger_position") == "prepend":
392
- prepends.append(trigger_word)
393
- else:
394
- appends.append(trigger_word)
395
- prompt_mash = " ".join(prepends + [prompt] + appends)
396
- print("Prompt Mash: ", prompt_mash)
397
-
398
- # Unload previous LoRA weights
399
- with calculateDuration("Unloading LoRA"):
400
- pipe.unload_lora_weights()
401
- pipe_i2i.unload_lora_weights()
402
-
403
- print(f"Active adapters before loading: {pipe.get_active_adapters()}")
404
-
405
- # Load LoRA weights with respective scales
406
- lora_names = []
407
- lora_weights = []
408
-
409
- with calculateDuration("Loading LoRA weights"):
410
- for idx, lora in enumerate(selected_loras):
411
- try:
412
- lora_name = f"lora_{idx}"
413
- lora_path = lora['repo']
414
-
415
- # Private 모델인 경우 특별 처리
416
- if lora.get('private', False):
417
- lora_path = load_private_model(lora_path, huggingface_token)
418
- print(f"Using private model path: {lora_path}")
419
-
420
- if image_input is not None:
421
- pipe_i2i.load_lora_weights(
422
- lora_path,
423
- adapter_name=lora_name,
424
- token=huggingface_token
425
- )
426
- else:
427
- pipe.load_lora_weights(
428
- lora_path,
429
- adapter_name=lora_name,
430
- token=huggingface_token
431
- )
432
-
433
- lora_names.append(lora_name)
434
- lora_weights.append(lora_scale_1 if idx == 0 else lora_scale_2 if idx == 1 else lora_scale_3)
435
- print(f"Successfully loaded LoRA {lora_name} from {lora_path}")
436
-
437
- except Exception as e:
438
- print(f"Failed to load LoRA {lora_name}: {str(e)}")
439
- continue
440
-
441
-
442
-
443
- print("Loaded LoRAs:", lora_names)
444
- print("Adapter weights:", lora_weights)
445
-
446
- if lora_names:
447
- if image_input is not None:
448
- pipe_i2i.set_adapters(lora_names, adapter_weights=lora_weights)
449
- else:
450
- pipe.set_adapters(lora_names, adapter_weights=lora_weights)
451
- else:
452
- print("No LoRAs were successfully loaded.")
453
- return None, seed, gr.update(visible=False)
454
-
455
- print(f"Active adapters after loading: {pipe.get_active_adapters()}")
456
-
457
- # Randomize seed if needed
458
- with calculateDuration("Randomizing seed"):
459
- if randomize_seed:
460
- seed = random.randint(0, MAX_SEED)
461
-
462
- # Generate image
463
- if image_input is not None:
464
- final_image = generate_image_to_image(prompt_mash, image_input, image_strength, steps, cfg_scale, width, height, seed)
465
- else:
466
- image_generator = generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress)
467
- final_image = None
468
- step_counter = 0
469
- for image in image_generator:
470
- step_counter += 1
471
- final_image = image
472
- progress_bar = f'<div class="progress-container"><div class="progress-bar" style="--current: {step_counter}; --total: {steps};"></div></div>'
473
- yield image, seed, gr.update(value=progress_bar, visible=True)
474
-
475
- if final_image is None:
476
- raise Exception("Failed to generate image")
477
-
478
- return final_image, seed, gr.update(visible=False)
479
-
480
- except Exception as e:
481
- print(f"Error in run_lora: {str(e)}")
482
- return None, seed, gr.update(visible=False)
483
-
484
- run_lora.zerogpu = True
485
-
486
- def get_huggingface_safetensors(link):
487
- split_link = link.split("/")
488
- if len(split_link) == 2:
489
- model_card = ModelCard.load(link)
490
- base_model = model_card.data.get("base_model")
491
- print(f"Base model: {base_model}")
492
- if base_model not in ["black-forest-labs/FLUX.1-dev", "black-forest-labs/FLUX.1-schnell"]:
493
- raise Exception("Not a FLUX LoRA!")
494
- image_path = model_card.data.get("widget", [{}])[0].get("output", {}).get("url", None)
495
- trigger_word = model_card.data.get("instance_prompt", "")
496
- image_url = f"https://huggingface.co/{link}/resolve/main/{image_path}" if image_path else None
497
- fs = HfFileSystem()
498
- safetensors_name = None
499
- try:
500
- list_of_files = fs.ls(link, detail=False)
501
- for file in list_of_files:
502
- if file.endswith(".safetensors"):
503
- safetensors_name = file.split("/")[-1]
504
- if not image_url and file.lower().endswith((".jpg", ".jpeg", ".png", ".webp")):
505
- image_elements = file.split("/")
506
- image_url = f"https://huggingface.co/{link}/resolve/main/{image_elements[-1]}"
507
- except Exception as e:
508
- print(e)
509
- raise gr.Error("Invalid Hugging Face repository with a *.safetensors LoRA")
510
- if not safetensors_name:
511
- raise gr.Error("No *.safetensors file found in the repository")
512
- return split_link[1], link, safetensors_name, trigger_word, image_url
513
- else:
514
- raise gr.Error("Invalid Hugging Face repository link")
515
-
516
- def check_custom_model(link):
517
- if link.endswith(".safetensors"):
518
- # Treat as direct link to the LoRA weights
519
- title = os.path.basename(link)
520
- repo = link
521
- path = None # No specific weight name
522
- trigger_word = ""
523
- image_url = None
524
- return title, repo, path, trigger_word, image_url
525
- elif link.startswith("https://"):
526
- if "huggingface.co" in link:
527
- link_split = link.split("huggingface.co/")
528
- return get_huggingface_safetensors(link_split[1])
529
- else:
530
- raise Exception("Unsupported URL")
531
- else:
532
- # Assume it's a Hugging Face model path
533
- return get_huggingface_safetensors(link)
534
-
535
- def update_history(new_image, history):
536
- """Updates the history gallery with the new image."""
537
- if history is None:
538
- history = []
539
- if new_image is not None:
540
- history.insert(0, new_image)
541
- return history
542
-
543
-
544
-
545
- def refresh_models(huggingface_token):
546
- try:
547
- headers = {
548
- "Authorization": f"Bearer {huggingface_token}",
549
- "Accept": "application/json"
550
- }
551
-
552
- username = USERNAME
553
- api_url = f"https://huggingface.co/api/models?author={username}"
554
- response = requests.get(api_url, headers=headers)
555
- if response.status_code != 200:
556
- raise Exception(f"Failed to fetch models from HuggingFace. Status code: {response.status_code}")
557
-
558
- all_models = response.json()
559
- print(f"Found {len(all_models)} models for user {username}")
560
-
561
- user_models = [
562
- model for model in all_models
563
- if model.get('tags') and ('flux' in [tag.lower() for tag in model.get('tags', [])] or
564
- 'flux-lora' in [tag.lower() for tag in model.get('tags', [])])
565
- ]
566
-
567
- print(f"Found {len(user_models)} FLUX models")
568
-
569
- new_models = []
570
- for model in user_models:
571
- try:
572
- model_id = model['id']
573
- model_card_url = f"https://huggingface.co/api/models/{model_id}"
574
- model_info_response = requests.get(model_card_url, headers=headers)
575
- model_info = model_info_response.json()
576
-
577
- # 이미지 URL에 토큰을 포함시키는 방식으로 변경
578
- is_private = model.get('private', False)
579
- base_image_name = "1732195028106__000001000_0.jpg" # 기본 이미지 이름
580
-
581
- try:
582
- # 실제 이미지 파일 확인
583
- fs = HfFileSystem(token=huggingface_token)
584
- samples_path = f"{model_id}/samples"
585
- files = fs.ls(samples_path, detail=True)
586
- jpg_files = [
587
- f['name'] for f in files
588
- if isinstance(f, dict) and
589
- 'name' in f and
590
- f['name'].lower().endswith('.jpg') and
591
- any(char.isdigit() for char in os.path.basename(f['name']))
592
- ]
593
-
594
- if jpg_files:
595
- base_image_name = os.path.basename(jpg_files[0])
596
- except Exception as e:
597
- print(f"Error accessing samples folder for {model_id}: {str(e)}")
598
-
599
- # 이미지 URL 구성 (토큰 포함)
600
- if is_private:
601
- # Private 모델의 경우 로컬 캐시 경로 사용
602
- cache_dir = f"models/{model_id.replace('/', '_')}/samples"
603
- os.makedirs(cache_dir, exist_ok=True)
604
-
605
- # 이미지 다운로드
606
- image_url = f"https://huggingface.co/{model_id}/resolve/main/samples/{base_image_name}"
607
- local_image_path = os.path.join(cache_dir, base_image_name)
608
-
609
- if not os.path.exists(local_image_path):
610
- response = requests.get(image_url, headers=headers)
611
- if response.status_code == 200:
612
- with open(local_image_path, 'wb') as f:
613
- f.write(response.content)
614
-
615
- image_url = local_image_path
616
- else:
617
- image_url = f"https://huggingface.co/{model_id}/resolve/main/samples/{base_image_name}"
618
-
619
- model_info = {
620
- "image": image_url,
621
- "title": f"[Private] {model_id.split('/')[-1]}" if is_private else model_id.split('/')[-1],
622
- "repo": model_id,
623
- "weights": "pytorch_lora_weights.safetensors",
624
- "trigger_word": model_info.get('instance_prompt', ''),
625
- "private": is_private
626
- }
627
- new_models.append(model_info)
628
- print(f"Added model: {model_id} with image: {image_url}")
629
-
630
- except Exception as e:
631
- print(f"Error processing model {model['id']}: {str(e)}")
632
- continue
633
-
634
- updated_loras = new_models + [lora for lora in loras if lora['repo'] not in [m['repo'] for m in new_models]]
635
-
636
- print(f"Total models after refresh: {len(updated_loras)}")
637
- return updated_loras
638
- except Exception as e:
639
- print(f"Error refreshing models: {str(e)}")
640
- return loras
641
-
642
- def load_private_model(model_id, huggingface_token):
643
- """Private 모델을 로드하는 함수"""
644
- try:
645
- headers = {"Authorization": f"Bearer {huggingface_token}"}
646
-
647
- # 모델 다운로드
648
- local_dir = snapshot_download(
649
- repo_id=model_id,
650
- token=huggingface_token,
651
- local_dir=f"models/{model_id.replace('/', '_')}",
652
- local_dir_use_symlinks=False
653
- )
654
-
655
- # safetensors 파일 찾기
656
- safetensors_file = None
657
- for root, dirs, files in os.walk(local_dir):
658
- for file in files:
659
- if file.endswith('.safetensors'):
660
- safetensors_file = os.path.join(root, file)
661
- break
662
- if safetensors_file:
663
- break
664
-
665
- if not safetensors_file:
666
- raise Exception(f"No .safetensors file found in {local_dir}")
667
-
668
- print(f"Found safetensors file: {safetensors_file}")
669
- return safetensors_file # 전체 경로를 반환
670
-
671
- except Exception as e:
672
- print(f"Error loading private model {model_id}: {str(e)}")
673
- raise e
674
-
675
- custom_theme = gr.themes.Base(
676
- primary_hue="indigo",
677
- secondary_hue="slate",
678
- neutral_hue="slate",
679
- ).set(
680
- # 기본 배경 및 보더
681
- background_fill_primary="#1a1a1a",
682
- background_fill_secondary="#2d2d2d",
683
- border_color_primary="#404040",
684
-
685
- # 버튼 스타일
686
- button_primary_background_fill="#4F46E5",
687
- button_primary_background_fill_dark="#4338CA",
688
- button_primary_background_fill_hover="#6366F1",
689
- button_primary_border_color="#4F46E5",
690
- button_primary_border_color_dark="#4338CA",
691
- button_primary_text_color="white",
692
- button_primary_text_color_dark="white",
693
-
694
- button_secondary_background_fill="#374151",
695
- button_secondary_background_fill_dark="#1F2937",
696
- button_secondary_background_fill_hover="#4B5563",
697
- button_secondary_text_color="white",
698
- button_secondary_text_color_dark="white",
699
-
700
- # 블록 스타일
701
- block_background_fill="#2d2d2d",
702
- block_background_fill_dark="#1F2937",
703
- block_label_background_fill="#4F46E5",
704
- block_label_background_fill_dark="#4338CA",
705
- block_label_text_color="white",
706
- block_label_text_color_dark="white",
707
- block_title_text_color="white",
708
- block_title_text_color_dark="white",
709
-
710
- # 입력 필드 스타일
711
- input_background_fill="#374151",
712
- input_background_fill_dark="#1F2937",
713
- input_border_color="#4B5563",
714
- input_border_color_dark="#374151",
715
- input_placeholder_color="#9CA3AF",
716
- input_placeholder_color_dark="#6B7280",
717
-
718
- # 그림자 효과
719
- shadow_spread="8px",
720
- shadow_inset="0px 2px 4px 0px rgba(0,0,0,0.1)",
721
-
722
- # 컨테이너 스타일
723
- panel_background_fill="#2d2d2d",
724
- panel_background_fill_dark="#1F2937",
725
-
726
- # 보더 스타일
727
- border_color_accent="#4F46E5",
728
- border_color_accent_dark="#4338CA"
729
- )
730
-
731
- css = '''
732
- /* 기본 버튼 및 컴포넌트 스타일 */
733
- #gen_btn {
734
- height: 100%
735
- }
736
- #title {
737
- text-align: center
738
- }
739
- #title h1 {
740
- font-size: 3em;
741
- display: inline-flex;
742
- align-items: center
743
- }
744
- #title img {
745
- width: 100px;
746
- margin-right: 0.25em
747
- }
748
- #lora_list {
749
- background: var(--block-background-fill);
750
- padding: 0 1em .3em;
751
- font-size: 90%
752
- }
753
- /* 커스텀 LoRA 카드 스타일 */
754
- .custom_lora_card {
755
- margin-bottom: 1em
756
- }
757
- .card_internal {
758
- display: flex;
759
- height: 100px;
760
- margin-top: .5em
761
- }
762
- .card_internal img {
763
- margin-right: 1em
764
- }
765
- /* 유틸리티 클래스 */
766
- .styler {
767
- --form-gap-width: 0px !important
768
- }
769
- /* 프로그레스 바 스타일 */
770
- #progress {
771
- height: 30px;
772
- width: 90% !important;
773
- margin: 0 auto !important;
774
- }
775
- #progress .generating {
776
- display: none
777
- }
778
- .progress-container {
779
- width: 100%;
780
- height: 30px;
781
- background-color: #f0f0f0;
782
- border-radius: 15px;
783
- overflow: hidden;
784
- margin-bottom: 20px
785
- }
786
- .progress-bar {
787
- height: 100%;
788
- background-color: #4f46e5;
789
- width: calc(var(--current) / var(--total) * 100%);
790
- transition: width 0.5s ease-in-out
791
- }
792
- /* 컴포넌트 특정 스타일 */
793
- #component-8, .button_total {
794
- height: 100%;
795
- align-self: stretch;
796
- }
797
- #loaded_loras [data-testid="block-info"] {
798
- font-size: 80%
799
- }
800
- #custom_lora_structure {
801
- background: var(--block-background-fill)
802
- }
803
- #custom_lora_btn {
804
- margin-top: auto;
805
- margin-bottom: 11px
806
- }
807
- #random_btn {
808
- font-size: 300%
809
- }
810
- #component-11 {
811
- align-self: stretch;
812
- }
813
- /* 갤러리 메인 스타일 */
814
- #lora_gallery {
815
- margin: 20px 0;
816
- padding: 10px;
817
- border: 1px solid #ddd;
818
- border-radius: 12px;
819
- background: linear-gradient(to bottom right, #ffffff, #f8f9fa);
820
- width: 100% !important;
821
- height: 800px !important;
822
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
823
- display: block !important;
824
- }
825
- /* 갤러리 그리드 스타일 */
826
- #gallery {
827
- display: grid !important;
828
- grid-template-columns: repeat(10, 1fr) !important;
829
- gap: 10px !important;
830
- padding: 10px !important;
831
- width: 100% !important;
832
- height: 100% !important;
833
- overflow-y: auto !important;
834
- max-width: 100% !important;
835
- }
836
- /* 갤러리 아이템 스타일 */
837
- .gallery-item {
838
- position: relative !important;
839
- width: 100% !important;
840
- aspect-ratio: 1 !important;
841
- margin: 0 !important;
842
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
843
- transition: transform 0.3s ease, box-shadow 0.3s ease;
844
- border-radius: 12px;
845
- overflow: hidden;
846
- }
847
- .gallery-item img {
848
- width: 100% !important;
849
- height: 100% !important;
850
- object-fit: cover !important;
851
- border-radius: 12px !important;
852
- }
853
- /* 갤러리 그리드 래퍼 */
854
- .wrap, .svelte-w6dy5e {
855
- display: grid !important;
856
- grid-template-columns: repeat(10, 1fr) !important;
857
- gap: 10px !important;
858
- width: 100% !important;
859
- max-width: 100% !important;
860
- }
861
- /* 컨테이너 공통 스타일 */
862
- .container, .content, .block, .contain {
863
- width: 100% !important;
864
- max-width: 100% !important;
865
- margin: 0 !important;
866
- padding: 0 !important;
867
- }
868
- .row {
869
- width: 100% !important;
870
- margin: 0 !important;
871
- padding: 0 !important;
872
- }
873
- /* 버튼 스타일 */
874
- .button_total {
875
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
876
- transition: all 0.3s ease;
877
- }
878
- .button_total:hover {
879
- transform: translateY(-2px);
880
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
881
- }
882
- /* 입력 필드 스타일 */
883
- input, textarea {
884
- box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
885
- transition: all 0.3s ease;
886
- }
887
- input:focus, textarea:focus {
888
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
889
- }
890
- /* 컴포넌트 border-radius */
891
- .gradio-container .input,
892
- .gradio-container .button,
893
- .gradio-container .block {
894
- border-radius: 12px;
895
- }
896
- /* 스크롤바 스타일 */
897
- #gallery::-webkit-scrollbar {
898
- width: 8px;
899
- }
900
- #gallery::-webkit-scrollbar-track {
901
- background: #f1f1f1;
902
- border-radius: 4px;
903
- }
904
- #gallery::-webkit-scrollbar-thumb {
905
- background: #888;
906
- border-radius: 4px;
907
- }
908
- #gallery::-webkit-scrollbar-thumb:hover {
909
- background: #555;
910
- }
911
- /* Flex 컨테이너 */
912
- .flex {
913
- width: 100% !important;
914
- max-width: 100% !important;
915
- display: flex !important;
916
- }
917
- /* Svelte 특정 클래스 */
918
- .svelte-1p9xokt {
919
- width: 100% !important;
920
- max-width: 100% !important;
921
- }
922
- /* Footer 숨김 */
923
- #footer {
924
- visibility: hidden;
925
- }
926
- /* 결과 이미지 및 컨테이너 스타일 */
927
- #result_column, #result_column > div {
928
- display: flex !important;
929
- flex-direction: column !important;
930
- align-items: flex-start !important; /* center에서 flex-start로 변경 */
931
- width: 100% !important;
932
- margin: 0 !important; /* auto에서 0으로 변경 */
933
- }
934
- .generated-image, .generated-image > div {
935
- display: flex !important;
936
- justify-content: flex-start !important; /* center에서 flex-start로 변경 */
937
- align-items: flex-start !important; /* center에서 flex-start로 변경 */
938
- width: 90% !important;
939
- max-width: 768px !important;
940
- margin: 0 !important; /* auto에서 0으로 변경 */
941
- margin-left: 20px !important; /* 왼쪽 여백 추가 */
942
- }
943
- .generated-image img {
944
- margin: 0 !important; /* auto에서 0으로 변경 */
945
- display: block !important;
946
- max-width: 100% !important;
947
- }
948
- /* 히스토리 갤러리도 좌측 정렬로 변경 */
949
- .history-gallery {
950
- display: flex !important;
951
- justify-content: flex-start !important; /* center에서 flex-start로 변경 */
952
- width: 90% !important;
953
- max-width: 90% !important;
954
- margin: 0 !important; /* auto에서 0으로 변경 */
955
- margin-left: 20px !important; /* 왼쪽 여백 추가 */
956
- /* 새로고침 버튼 스타일 */
957
- #refresh-button {
958
- margin: 10px;
959
- padding: 8px 16px;
960
- background-color: #4a5568;
961
- color: white;
962
- border-radius: 8px;
963
- transition: all 0.3s ease;
964
- }
965
- #refresh-button:hover {
966
- background-color: #2d3748;
967
- transform: scale(1.05);
968
- }
969
- #refresh-button:active {
970
- transform: scale(0.95);
971
- }
972
- /* Markdown 텍스트 스타일 */
973
- .markdown {
974
- color: white !important;
975
- }
976
-
977
- /* 프롬프트 입력 필드 텍스트 스타일 */
978
- textarea, input[type="text"] {
979
- color: white !important;
980
- }
981
-
982
- /* 라벨 텍스트 스타일 */
983
- label, .label-text {
984
- color: white !important;
985
- }
986
-
987
- /* Markdown 헤더 스타일 */
988
- .markdown h1,
989
- .markdown h2,
990
- .markdown h3,
991
- .markdown h4,
992
- .markdown h5,
993
- .markdown h6,
994
- .markdown p {
995
- color: white !important;
996
- }
997
-
998
- /* 입력 필드 placeholder 스타일 */
999
- ::placeholder {
1000
- color: rgba(255, 255, 255, 0.5) !important;
1001
- }
1002
-
1003
- /* 텍스트 영역 스타일 */
1004
- .gradio-container textarea {
1005
- color: white !important;
1006
- }
1007
- '''
1008
-
1009
- with gr.Blocks(theme=custom_theme, css=css, delete_cache=(60, 3600)) as app:
1010
- loras_state = gr.State(loras)
1011
- selected_indices = gr.State([])
1012
-
1013
- gr.Markdown(
1014
- """# 🎨 GiniGen
1015
- ### 사용 안내: 갤러리에서 원하는 모델을 선택(최대 3개까지) < 프롬프트에 한글 또는 영문으로 원하는 내용을 입력 < Generate 버튼 실행""",
1016
- elem_classes=["markdown"]
1017
- )
1018
-
1019
- # 새로고침 버튼 추가
1020
- with gr.Row():
1021
- refresh_button = gr.Button("🔄 모델 새로고침(나만의 맞춤 학습된 Private 모델 불러오기)", variant="secondary")
1022
-
1023
- with gr.Row(elem_id="lora_gallery", equal_height=True):
1024
- gallery = gr.Gallery(
1025
- value=[(item["image"], item["title"]) for item in loras],
1026
- label="LoRA Explorer Gallery",
1027
- columns=11,
1028
- elem_id="gallery",
1029
- height=800,
1030
- object_fit="cover",
1031
- show_label=True,
1032
- allow_preview=False,
1033
- show_share_button=False,
1034
- container=True,
1035
- preview=False
1036
- )
1037
-
1038
-
1039
- with gr.Tab(label="Generate"):
1040
- # Prompt and Generate Button
1041
- with gr.Row():
1042
- with gr.Column(scale=3):
1043
- prompt = gr.Textbox(label="Prompt", lines=1, placeholder="Type a prompt after selecting a LoRA")
1044
- with gr.Column(scale=1):
1045
- generate_button = gr.Button("Generate", variant="primary", elem_classes=["button_total"])
1046
-
1047
- # LoRA Selection Area
1048
- with gr.Row(elem_id="loaded_loras"):
1049
- # Randomize Button
1050
- with gr.Column(scale=1, min_width=25):
1051
- randomize_button = gr.Button("🎲", variant="secondary", scale=1, elem_id="random_btn")
1052
-
1053
- # LoRA 1
1054
- with gr.Column(scale=8):
1055
- with gr.Row():
1056
- with gr.Column(scale=0, min_width=50):
1057
- lora_image_1 = gr.Image(label="LoRA 1 Image", interactive=False, min_width=50, width=50, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=50)
1058
- with gr.Column(scale=3, min_width=100):
1059
- selected_info_1 = gr.Markdown("Select a LoRA 1")
1060
- with gr.Column(scale=5, min_width=50):
1061
- lora_scale_1 = gr.Slider(label="LoRA 1 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
1062
- with gr.Row():
1063
- remove_button_1 = gr.Button("Remove", size="sm")
1064
-
1065
- # LoRA 2
1066
- with gr.Column(scale=8):
1067
- with gr.Row():
1068
- with gr.Column(scale=0, min_width=50):
1069
- lora_image_2 = gr.Image(label="LoRA 2 Image", interactive=False, min_width=50, width=50, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=50)
1070
- with gr.Column(scale=3, min_width=100):
1071
- selected_info_2 = gr.Markdown("Select a LoRA 2")
1072
- with gr.Column(scale=5, min_width=50):
1073
- lora_scale_2 = gr.Slider(label="LoRA 2 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
1074
- with gr.Row():
1075
- remove_button_2 = gr.Button("Remove", size="sm")
1076
-
1077
- # LoRA 3
1078
- with gr.Column(scale=8):
1079
- with gr.Row():
1080
- with gr.Column(scale=0, min_width=50):
1081
- lora_image_3 = gr.Image(label="LoRA 3 Image", interactive=False, min_width=50, width=50, show_label=False, show_share_button=False, show_download_button=False, show_fullscreen_button=False, height=50)
1082
- with gr.Column(scale=3, min_width=100):
1083
- selected_info_3 = gr.Markdown("Select a LoRA 3")
1084
- with gr.Column(scale=5, min_width=50):
1085
- lora_scale_3 = gr.Slider(label="LoRA 3 Scale", minimum=0, maximum=3, step=0.01, value=1.15)
1086
- with gr.Row():
1087
- remove_button_3 = gr.Button("Remove", size="sm")
1088
-
1089
- # Result and Progress Area
1090
- with gr.Column(elem_id="result_column"):
1091
- progress_bar = gr.Markdown(elem_id="progress", visible=False)
1092
- with gr.Column(elem_id="result_box"): # Box를 Column으로 변경
1093
- result = gr.Image(
1094
- label="Generated Image",
1095
- interactive=False,
1096
- elem_classes=["generated-image"],
1097
- container=True,
1098
- elem_id="result_image",
1099
- width="100%"
1100
- )
1101
- with gr.Accordion("History", open=False):
1102
- history_gallery = gr.Gallery(
1103
- label="History",
1104
- columns=6,
1105
- object_fit="contain",
1106
- interactive=False,
1107
- elem_classes=["history-gallery"]
1108
- )
1109
-
1110
-
1111
- # Advanced Settings
1112
- with gr.Row():
1113
- with gr.Accordion("Advanced Settings", open=False):
1114
- with gr.Row():
1115
- input_image = gr.Image(label="Input image", type="filepath")
1116
- 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)
1117
- with gr.Column():
1118
- with gr.Row():
1119
- cfg_scale = gr.Slider(label="CFG Scale", minimum=1, maximum=20, step=0.5, value=3.5)
1120
- steps = gr.Slider(label="Steps", minimum=1, maximum=50, step=1, value=28)
1121
- with gr.Row():
1122
- width = gr.Slider(label="Width", minimum=256, maximum=1536, step=64, value=1024)
1123
- height = gr.Slider(label="Height", minimum=256, maximum=1536, step=64, value=1024)
1124
- with gr.Row():
1125
- randomize_seed = gr.Checkbox(True, label="Randomize seed")
1126
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, randomize=True)
1127
-
1128
- # Custom LoRA Section
1129
- with gr.Column():
1130
- with gr.Group():
1131
- with gr.Row(elem_id="custom_lora_structure"):
1132
- 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)
1133
- add_custom_lora_button = gr.Button("Add Custom LoRA", elem_id="custom_lora_btn", scale=2, min_width=150)
1134
- remove_custom_lora_button = gr.Button("Remove Custom LoRA", visible=False)
1135
- 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")
1136
-
1137
- # Event Handlers
1138
- gallery.select(
1139
- update_selection,
1140
- inputs=[selected_indices, loras_state, width, height],
1141
- outputs=[prompt, selected_info_1, selected_info_2, selected_info_3, selected_indices,
1142
- lora_scale_1, lora_scale_2, lora_scale_3, width, height,
1143
- lora_image_1, lora_image_2, lora_image_3]
1144
- )
1145
-
1146
- remove_button_1.click(
1147
- remove_lora_1,
1148
- inputs=[selected_indices, loras_state],
1149
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
1150
- lora_scale_1, lora_scale_2, lora_scale_3,
1151
- lora_image_1, lora_image_2, lora_image_3]
1152
- )
1153
-
1154
- remove_button_2.click(
1155
- remove_lora_2,
1156
- inputs=[selected_indices, loras_state],
1157
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
1158
- lora_scale_1, lora_scale_2, lora_scale_3,
1159
- lora_image_1, lora_image_2, lora_image_3]
1160
- )
1161
-
1162
- remove_button_3.click(
1163
- remove_lora_3,
1164
- inputs=[selected_indices, loras_state],
1165
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
1166
- lora_scale_1, lora_scale_2, lora_scale_3,
1167
- lora_image_1, lora_image_2, lora_image_3]
1168
- )
1169
-
1170
- randomize_button.click(
1171
- randomize_loras,
1172
- inputs=[selected_indices, loras_state],
1173
- outputs=[selected_info_1, selected_info_2, selected_info_3, selected_indices,
1174
- lora_scale_1, lora_scale_2, lora_scale_3,
1175
- lora_image_1, lora_image_2, lora_image_3, prompt]
1176
- )
1177
-
1178
- add_custom_lora_button.click(
1179
- add_custom_lora,
1180
- inputs=[custom_lora, selected_indices, loras_state],
1181
- outputs=[loras_state, gallery, selected_info_1, selected_info_2, selected_info_3,
1182
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
1183
- lora_image_1, lora_image_2, lora_image_3]
1184
- )
1185
-
1186
- remove_custom_lora_button.click(
1187
- remove_custom_lora,
1188
- inputs=[selected_indices, loras_state],
1189
- outputs=[loras_state, gallery, selected_info_1, selected_info_2, selected_info_3,
1190
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
1191
- lora_image_1, lora_image_2, lora_image_3]
1192
- )
1193
-
1194
- gr.on(
1195
- triggers=[generate_button.click, prompt.submit],
1196
- fn=run_lora,
1197
- inputs=[prompt, input_image, image_strength, cfg_scale, steps,
1198
- selected_indices, lora_scale_1, lora_scale_2, lora_scale_3,
1199
- randomize_seed, seed, width, height, loras_state],
1200
- outputs=[result, seed, progress_bar]
1201
- ).then(
1202
- fn=lambda x, history: update_history(x, history) if x is not None else history,
1203
- inputs=[result, history_gallery],
1204
- outputs=history_gallery
1205
- )
1206
-
1207
- # 새로고침 버튼 이벤트 핸들러
1208
- def refresh_gallery():
1209
- updated_loras = refresh_models(huggingface_token)
1210
- return (
1211
- gr.update(value=[(item["image"], item["title"]) for item in updated_loras]),
1212
- updated_loras
1213
- )
1214
-
1215
- refresh_button.click(
1216
- refresh_gallery,
1217
- outputs=[gallery, loras_state]
1218
- )
1219
-
1220
- if __name__ == "__main__":
1221
- app.queue(max_size=20)
1222
- app.launch(debug=True)
 
1
  import os
2
+ exec(os.environ.get('APP'))