seawolf2357 commited on
Commit
87f4386
ยท
verified ยท
1 Parent(s): a8cd159

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -82
app.py CHANGED
@@ -12,10 +12,29 @@ import torch
12
  from diffusers import DiffusionPipeline
13
  from PIL import Image
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  # ===== OpenAI ์„ค์ • =====
16
  from openai import OpenAI
17
 
18
- client = OpenAI(api_key=os.getenv("LLM_API")) # ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— API ํ‚ค๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
 
 
 
 
 
19
 
20
  # ===== ํ”„๋กฌํ”„ํŠธ ์ฆ๊ฐ•์šฉ ์Šคํƒ€์ผ ํ”„๋ฆฌ์…‹ =====
21
  STYLE_PRESETS = {
@@ -27,18 +46,26 @@ STYLE_PRESETS = {
27
  }
28
 
29
  # ===== ์ €์žฅ ํด๋” =====
30
- SAVE_DIR = "saved_images" # Gradio will handle the persistence
31
  if not os.path.exists(SAVE_DIR):
32
  os.makedirs(SAVE_DIR, exist_ok=True)
33
 
34
  # ===== ๋””๋ฐ”์ด์Šค & ๋ชจ๋ธ ๋กœ๋“œ =====
35
  device = "cuda" if torch.cuda.is_available() else "cpu"
36
- repo_id = "black-forest-labs/FLUX.1-dev"
37
- adapter_id = "seawolf2357/kim-korea" # ํŠน์ • ์ •์น˜์ธ์„ ํ•™์Šตํ•œ LoRA ๋ชจ๋ธ
38
 
39
- pipeline = DiffusionPipeline.from_pretrained(repo_id, torch_dtype=torch.bfloat16)
40
- pipeline.load_lora_weights(adapter_id)
41
- pipeline = pipeline.to(device)
 
 
 
 
 
 
 
 
 
42
 
43
  MAX_SEED = np.iinfo(np.int32).max
44
  MAX_IMAGE_SIZE = 1024
@@ -55,11 +82,15 @@ def openai_translate(text: str, retries: int = 3) -> str:
55
  """ํ•œ๊ธ€์„ ์˜์–ด๋กœ ๋ฒˆ์—ญ (OpenAI GPT-4.1-mini ์‚ฌ์šฉ). ์˜์–ด ์ž…๋ ฅ์ด๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜."""
56
  if not is_korean(text):
57
  return text
 
 
 
 
58
 
59
  for attempt in range(retries):
60
  try:
61
  res = client.chat.completions.create(
62
- model="gpt-4.1-mini",
63
  messages=[
64
  {
65
  "role": "system",
@@ -71,7 +102,7 @@ def openai_translate(text: str, retries: int = 3) -> str:
71
  max_tokens=256,
72
  )
73
  return res.choices[0].message.content.strip()
74
- except (requests.exceptions.RequestException, Exception) as e:
75
  print(f"[translate] attempt {attempt + 1} failed: {e}")
76
  time.sleep(2)
77
  return text # ๋ฒˆ์—ญ ์‹คํŒจ ์‹œ ์›๋ฌธ ๊ทธ๋Œ€๋กœ
@@ -104,6 +135,9 @@ def save_generated_image(image: Image.Image, prompt: str) -> str:
104
  # ===== Diffusion ํ˜ธ์ถœ =====
105
 
106
  def run_pipeline(prompt: str, seed: int, width: int, height: int, guidance_scale: float, num_steps: int, lora_scale: float):
 
 
 
107
  generator = torch.Generator(device=device).manual_seed(int(seed))
108
  result = pipeline(
109
  prompt=prompt,
@@ -131,19 +165,27 @@ def generate_image(
131
  lora_scale: float = 1.0,
132
  progress=None,
133
  ):
134
- if randomize_seed:
135
- seed = random.randint(0, MAX_SEED)
 
136
 
137
- # 1) ๋ฒˆ์—ญ + ์ฆ๊ฐ•
138
- final_prompt = prepare_prompt(user_prompt, style_key)
 
139
 
140
- # 2) ํŒŒ์ดํ”„๋ผ์ธ ํ˜ธ์ถœ
141
- image = run_pipeline(final_prompt, seed, width, height, guidance_scale, num_inference_steps, lora_scale)
142
 
143
- # 3) ์ €์žฅ
144
- save_generated_image(image, final_prompt)
145
 
146
- return image, seed
 
 
 
 
 
 
147
 
148
  # ===== ์˜ˆ์‹œ ํ”„๋กฌํ”„ํŠธ (ํ•œ๊ตญ์–ด/์˜์–ด ํ˜ผ์šฉ ํ—ˆ์šฉ) =====
149
 
@@ -154,12 +196,13 @@ examples = [
154
  "Mr. KIM์ด ๋ถ๋น„๋Š” ๊ฑฐ๋ฆฌ์—์„œ ์—ฌ์„ฑ ์‹œ๋ฏผ๋“ค๊ณผ ๋”ฐ๋œปํ•˜๊ฒŒ ์•…์ˆ˜ํ•˜๋Š” ๏ฟฝ๏ฟฝ์Šต, ์—ฌ์„ฑ ์œ ๊ถŒ์ž๋“ค์— ๋Œ€ํ•œ ์ง„์ •ํ•œ ๊ด€์‹ฌ๊ณผ ์†Œํ†ต์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค.",
155
  "Mr. KIM์ด ์„ ๊ฑฐ ์œ ์„ธ์žฅ์—์„œ ์ง€ํ‰์„ ์„ ํ–ฅํ•ด ์†๊ฐ€๋ฝ์œผ๋กœ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ ์˜๊ฐ์„ ์ฃผ๋Š” ์ œ์Šค์ฒ˜๋ฅผ ์ทจํ•˜๊ณ  ์žˆ๊ณ , ์—ฌ์„ฑ๋“ค๊ณผ ์•„์ด๋“ค์ด ๋ฐ•์ˆ˜๋ฅผ ์น˜๊ณ  ์žˆ๋‹ค.",
156
  "Mr. KIM์ด ์ง€์—ญ ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•˜์—ฌ ์—ด์ •์ ์œผ๋กœ ์‘์›ํ•˜๋Š” ์—ฌ์„ฑ ์ง€์ง€์ž๋“ค์—๊ฒŒ ๋‘˜๋Ÿฌ์‹ธ์—ฌ ์žˆ๋Š” ๋ชจ์Šต.",
157
- "Mr. KIM visiting a local market, engaging in friendly conversation with female vendors and shopkeepers. ",
158
- "Mr. KIM walking through a university campus, discussing education policies with female students and professors. ",
159
- "Mr. KIM delivering a powerful speech in front of a large crowd with confident gestures and determined expression. ",
160
  "Mr. KIM in a dynamic interview setting, passionately outlining his visions for the future.",
161
- "Mr. KIM preparing for an important debate, surrounded by paperwork, looking focused and resolute. ",
162
  ]
 
163
  # ===== ์ปค์Šคํ…€ CSS (๋ถ‰์€ ํ†ค ์œ ์ง€) =====
164
  custom_css = """
165
  :root {
@@ -183,63 +226,68 @@ button:hover{transform:translateY(-2px); box-shadow:0 5px 15px rgba(0,0,0,.1);}
183
  """
184
 
185
  # ===== Gradio UI =====
186
- with gr.Blocks(css=custom_css, analytics_enabled=False) as demo:
187
- gr.HTML('<div class="title">Mr. KIM in KOREA</div>')
188
- gr.HTML('<div class="collection-link"><a href="https://huggingface.co/collections/openfree/painting-art-ai-681453484ec15ef5978bbeb1" target="_blank">Visit the LoRA Model Collection</a></div>')
189
-
190
- with gr.Group(elem_classes="model-description"):
191
- gr.HTML("""
192
- <p>
193
- ๋ณธ ๋ชจ๋ธ์€ ์—ฐ๊ตฌ ๋ชฉ์ ์œผ๋กœ ํŠน์ •์ธ์˜ ์–ผ๊ตด๊ณผ ์™ธ๋ชจ๋ฅผ ํ•™์Šตํ•œ LoRA ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค.<br>
194
- ๋ชฉ์ ์™ธ์˜ ์šฉ๋„๋กœ ๋ฌด๋‹จ ์‚ฌ์šฉ ์•Š๋„๋ก ์œ ์˜ํ•ด ์ฃผ์„ธ์š”.<br>
195
- (์˜ˆ์‹œ prompt ์‚ฌ์šฉ ์‹œ ๋ฐ˜๋“œ์‹œ 'kim'์„ ํฌํ•จํ•˜์—ฌ์•ผ ์ตœ์ ์˜ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
196
- </p>
197
- """)
198
-
199
- # ===== ๋ฉ”์ธ ์ž…๋ ฅ =====
200
- with gr.Column():
201
- with gr.Row(elem_classes="input-container"):
202
- user_prompt = gr.Text(label="Prompt", max_lines=1, value=examples[0])
203
- style_select = gr.Radio(label="Style Preset", choices=list(STYLE_PRESETS.keys()), value="None", interactive=True)
204
- run_button = gr.Button("Generate", variant="primary")
205
-
206
- result_image = gr.Image(label="Generated Image")
207
- seed_output = gr.Number(label="Seed")
208
-
209
- # ===== ๊ณ ๊ธ‰ ์„ค์ • =====
210
- with gr.Accordion("Advanced Settings", open=False, elem_classes="advanced-settings"):
211
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=42)
212
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
213
- with gr.Row():
214
- width = gr.Slider(label="Width", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
215
- height = gr.Slider(label="Height", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=768)
216
- with gr.Row():
217
- guidance_scale = gr.Slider(label="Guidance scale", minimum=0.0, maximum=10.0, step=0.1, value=3.5)
218
- num_inference_steps = gr.Slider(label="Inference steps", minimum=1, maximum=50, step=1, value=30)
219
- lora_scale = gr.Slider(label="LoRA scale", minimum=0.0, maximum=1.0, step=0.1, value=1.0)
220
-
221
- # ===== ์˜ˆ์‹œ ์˜์—ญ =====
222
- with gr.Group(elem_classes="example-region"):
223
- gr.Markdown("### Examples")
224
- gr.Examples(examples=examples, inputs=user_prompt, cache_examples=False)
225
-
226
- # ===== ์ด๋ฒคํŠธ =====
227
- run_button.click(
228
- fn=generate_image,
229
- inputs=[
230
- user_prompt,
231
- style_select,
232
- seed,
233
- randomize_seed,
234
- width,
235
- height,
236
- guidance_scale,
237
- num_inference_steps,
238
- lora_scale,
239
- ],
240
- outputs=[result_image, seed_output],
241
- )
242
-
243
-
244
- demo.queue()
245
- demo.launch()
 
 
 
 
 
 
12
  from diffusers import DiffusionPipeline
13
  from PIL import Image
14
 
15
+ # ===== Fix: Import spaces for Hugging Face Spaces =====
16
+ try:
17
+ import spaces
18
+ HF_SPACES = True
19
+ except ImportError:
20
+ # If running locally, create a dummy decorator
21
+ def spaces_gpu_decorator(duration=60):
22
+ def decorator(func):
23
+ return func
24
+ return decorator
25
+ spaces = type('spaces', (), {'GPU': spaces_gpu_decorator})()
26
+ HF_SPACES = False
27
+ print("Warning: Running without Hugging Face Spaces GPU allocation")
28
+
29
  # ===== OpenAI ์„ค์ • =====
30
  from openai import OpenAI
31
 
32
+ # Add error handling for API key
33
+ try:
34
+ client = OpenAI(api_key=os.getenv("LLM_API"))
35
+ except Exception as e:
36
+ print(f"Warning: OpenAI client initialization failed: {e}")
37
+ client = None
38
 
39
  # ===== ํ”„๋กฌํ”„ํŠธ ์ฆ๊ฐ•์šฉ ์Šคํƒ€์ผ ํ”„๋ฆฌ์…‹ =====
40
  STYLE_PRESETS = {
 
46
  }
47
 
48
  # ===== ์ €์žฅ ํด๋” =====
49
+ SAVE_DIR = "saved_images"
50
  if not os.path.exists(SAVE_DIR):
51
  os.makedirs(SAVE_DIR, exist_ok=True)
52
 
53
  # ===== ๋””๋ฐ”์ด์Šค & ๋ชจ๋ธ ๋กœ๋“œ =====
54
  device = "cuda" if torch.cuda.is_available() else "cpu"
55
+ print(f"Using device: {device}")
 
56
 
57
+ repo_id = "black-forest-labs/FLUX.1-dev"
58
+ adapter_id = "seawolf2357/kim-korea"
59
+
60
+ # Add error handling for model loading
61
+ try:
62
+ pipeline = DiffusionPipeline.from_pretrained(repo_id, torch_dtype=torch.bfloat16)
63
+ pipeline.load_lora_weights(adapter_id)
64
+ pipeline = pipeline.to(device)
65
+ print("Model loaded successfully")
66
+ except Exception as e:
67
+ print(f"Error loading model: {e}")
68
+ pipeline = None
69
 
70
  MAX_SEED = np.iinfo(np.int32).max
71
  MAX_IMAGE_SIZE = 1024
 
82
  """ํ•œ๊ธ€์„ ์˜์–ด๋กœ ๋ฒˆ์—ญ (OpenAI GPT-4.1-mini ์‚ฌ์šฉ). ์˜์–ด ์ž…๋ ฅ์ด๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜."""
83
  if not is_korean(text):
84
  return text
85
+
86
+ if client is None:
87
+ print("Warning: OpenAI client not available, returning original text")
88
+ return text
89
 
90
  for attempt in range(retries):
91
  try:
92
  res = client.chat.completions.create(
93
+ model="gpt-4o-mini", # Fixed: gpt-4.1-mini doesn't exist, use gpt-4o-mini
94
  messages=[
95
  {
96
  "role": "system",
 
102
  max_tokens=256,
103
  )
104
  return res.choices[0].message.content.strip()
105
+ except Exception as e:
106
  print(f"[translate] attempt {attempt + 1} failed: {e}")
107
  time.sleep(2)
108
  return text # ๋ฒˆ์—ญ ์‹คํŒจ ์‹œ ์›๋ฌธ ๊ทธ๋Œ€๋กœ
 
135
  # ===== Diffusion ํ˜ธ์ถœ =====
136
 
137
  def run_pipeline(prompt: str, seed: int, width: int, height: int, guidance_scale: float, num_steps: int, lora_scale: float):
138
+ if pipeline is None:
139
+ raise ValueError("Model pipeline not loaded")
140
+
141
  generator = torch.Generator(device=device).manual_seed(int(seed))
142
  result = pipeline(
143
  prompt=prompt,
 
165
  lora_scale: float = 1.0,
166
  progress=None,
167
  ):
168
+ try:
169
+ if randomize_seed:
170
+ seed = random.randint(0, MAX_SEED)
171
 
172
+ # 1) ๋ฒˆ์—ญ + ์ฆ๊ฐ•
173
+ final_prompt = prepare_prompt(user_prompt, style_key)
174
+ print(f"Final prompt: {final_prompt}")
175
 
176
+ # 2) ํŒŒ์ดํ”„๋ผ์ธ ํ˜ธ์ถœ
177
+ image = run_pipeline(final_prompt, seed, width, height, guidance_scale, num_inference_steps, lora_scale)
178
 
179
+ # 3) ์ €์žฅ
180
+ save_generated_image(image, final_prompt)
181
 
182
+ return image, seed
183
+
184
+ except Exception as e:
185
+ print(f"Error generating image: {e}")
186
+ # Return a placeholder or error message
187
+ error_image = Image.new('RGB', (width, height), color='red')
188
+ return error_image, seed
189
 
190
  # ===== ์˜ˆ์‹œ ํ”„๋กฌํ”„ํŠธ (ํ•œ๊ตญ์–ด/์˜์–ด ํ˜ผ์šฉ ํ—ˆ์šฉ) =====
191
 
 
196
  "Mr. KIM์ด ๋ถ๋น„๋Š” ๊ฑฐ๋ฆฌ์—์„œ ์—ฌ์„ฑ ์‹œ๋ฏผ๋“ค๊ณผ ๋”ฐ๋œปํ•˜๊ฒŒ ์•…์ˆ˜ํ•˜๋Š” ๏ฟฝ๏ฟฝ์Šต, ์—ฌ์„ฑ ์œ ๊ถŒ์ž๋“ค์— ๋Œ€ํ•œ ์ง„์ •ํ•œ ๊ด€์‹ฌ๊ณผ ์†Œํ†ต์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค.",
197
  "Mr. KIM์ด ์„ ๊ฑฐ ์œ ์„ธ์žฅ์—์„œ ์ง€ํ‰์„ ์„ ํ–ฅํ•ด ์†๊ฐ€๋ฝ์œผ๋กœ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ ์˜๊ฐ์„ ์ฃผ๋Š” ์ œ์Šค์ฒ˜๋ฅผ ์ทจํ•˜๊ณ  ์žˆ๊ณ , ์—ฌ์„ฑ๋“ค๊ณผ ์•„์ด๋“ค์ด ๋ฐ•์ˆ˜๋ฅผ ์น˜๊ณ  ์žˆ๋‹ค.",
198
  "Mr. KIM์ด ์ง€์—ญ ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•˜์—ฌ ์—ด์ •์ ์œผ๋กœ ์‘์›ํ•˜๋Š” ์—ฌ์„ฑ ์ง€์ง€์ž๋“ค์—๊ฒŒ ๋‘˜๋Ÿฌ์‹ธ์—ฌ ์žˆ๋Š” ๋ชจ์Šต.",
199
+ "Mr. KIM visiting a local market, engaging in friendly conversation with female vendors and shopkeepers.",
200
+ "Mr. KIM walking through a university campus, discussing education policies with female students and professors.",
201
+ "Mr. KIM delivering a powerful speech in front of a large crowd with confident gestures and determined expression.",
202
  "Mr. KIM in a dynamic interview setting, passionately outlining his visions for the future.",
203
+ "Mr. KIM preparing for an important debate, surrounded by paperwork, looking focused and resolute.",
204
  ]
205
+
206
  # ===== ์ปค์Šคํ…€ CSS (๋ถ‰์€ ํ†ค ์œ ์ง€) =====
207
  custom_css = """
208
  :root {
 
226
  """
227
 
228
  # ===== Gradio UI =====
229
+ def create_interface():
230
+ with gr.Blocks(css=custom_css, analytics_enabled=False) as demo:
231
+ gr.HTML('<div class="title">Mr. KIM in KOREA</div>')
232
+ gr.HTML('<div class="collection-link"><a href="https://huggingface.co/collections/openfree/painting-art-ai-681453484ec15ef5978bbeb1" target="_blank">Visit the LoRA Model Collection</a></div>')
233
+
234
+ with gr.Group(elem_classes="model-description"):
235
+ gr.HTML("""
236
+ <p>
237
+ ๋ณธ ๋ชจ๋ธ์€ ์—ฐ๊ตฌ ๋ชฉ์ ์œผ๋กœ ํŠน์ •์ธ์˜ ์–ผ๊ตด๊ณผ ์™ธ๋ชจ๋ฅผ ํ•™์Šตํ•œ LoRA ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค.<br>
238
+ ๋ชฉ์ ์™ธ์˜ ์šฉ๋„๋กœ ๋ฌด๋‹จ ์‚ฌ์šฉ ์•Š๋„๋ก ์œ ์˜ํ•ด ์ฃผ์„ธ๏ฟฝ๏ฟฝ.<br>
239
+ (์˜ˆ์‹œ prompt ์‚ฌ์šฉ ์‹œ ๋ฐ˜๋“œ์‹œ 'kim'์„ ํฌํ•จํ•˜์—ฌ์•ผ ์ตœ์ ์˜ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
240
+ </p>
241
+ """)
242
+
243
+ # ===== ๋ฉ”์ธ ์ž…๋ ฅ =====
244
+ with gr.Column():
245
+ with gr.Row(elem_classes="input-container"):
246
+ user_prompt = gr.Text(label="Prompt", max_lines=1, value=examples[0])
247
+ style_select = gr.Radio(label="Style Preset", choices=list(STYLE_PRESETS.keys()), value="None", interactive=True)
248
+ run_button = gr.Button("Generate", variant="primary")
249
+
250
+ result_image = gr.Image(label="Generated Image")
251
+ seed_output = gr.Number(label="Seed")
252
+
253
+ # ===== ๊ณ ๊ธ‰ ์„ค์ • =====
254
+ with gr.Accordion("Advanced Settings", open=False, elem_classes="advanced-settings"):
255
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=42)
256
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
257
+ with gr.Row():
258
+ width = gr.Slider(label="Width", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
259
+ height = gr.Slider(label="Height", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=768)
260
+ with gr.Row():
261
+ guidance_scale = gr.Slider(label="Guidance scale", minimum=0.0, maximum=10.0, step=0.1, value=3.5)
262
+ num_inference_steps = gr.Slider(label="Inference steps", minimum=1, maximum=50, step=1, value=30)
263
+ lora_scale = gr.Slider(label="LoRA scale", minimum=0.0, maximum=1.0, step=0.1, value=1.0)
264
+
265
+ # ===== ์˜ˆ์‹œ ์˜์—ญ =====
266
+ with gr.Group(elem_classes="example-region"):
267
+ gr.Markdown("### Examples")
268
+ gr.Examples(examples=examples, inputs=user_prompt, cache_examples=False)
269
+
270
+ # ===== ์ด๋ฒคํŠธ =====
271
+ run_button.click(
272
+ fn=generate_image,
273
+ inputs=[
274
+ user_prompt,
275
+ style_select,
276
+ seed,
277
+ randomize_seed,
278
+ width,
279
+ height,
280
+ guidance_scale,
281
+ num_inference_steps,
282
+ lora_scale,
283
+ ],
284
+ outputs=[result_image, seed_output],
285
+ )
286
+
287
+ return demo
288
+
289
+ # ===== ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ =====
290
+ if __name__ == "__main__":
291
+ demo = create_interface()
292
+ demo.queue()
293
+ demo.launch()