ginipick commited on
Commit
dffede6
·
verified ·
1 Parent(s): 90c293b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +221 -46
app.py CHANGED
@@ -5,15 +5,16 @@ import os
5
 
6
  # 환경변수에서 API 키 로드
7
  FIREWORKS_API_KEY = os.getenv("FIREWORKS_API_KEY", "")
 
8
 
9
- def enhance_prompt(prompt: str, api_key: str) -> str:
10
  """
11
  Fireworks AI LLM API를 사용하여 프롬프트를 증강합니다.
12
  """
13
  if not prompt.strip():
14
  return "❌ 프롬프트를 입력해주세요."
15
 
16
- if not api_key.strip():
17
  return "❌ Fireworks API 키를 입력해주세요."
18
 
19
  system_message = """You are a professional prompt engineer specializing in AI image and video generation.
@@ -55,7 +56,7 @@ Respond ONLY with the enhanced prompt, no explanations or additional text."""
55
  headers = {
56
  "Accept": "application/json",
57
  "Content-Type": "application/json",
58
- "Authorization": f"Bearer {api_key}"
59
  }
60
 
61
  try:
@@ -73,13 +74,147 @@ Respond ONLY with the enhanced prompt, no explanations or additional text."""
73
  except requests.exceptions.Timeout:
74
  return "❌ API 요청 시간 초과. 다시 시도해주세요."
75
  except requests.exceptions.HTTPError as e:
76
- return f"❌ API 오류: {e.response.status_code} - {e.response.text}"
77
  except requests.exceptions.RequestException as e:
78
  return f"❌ 네트워크 오류: {str(e)}"
79
  except Exception as e:
80
  return f"❌ 오류 발생: {str(e)}"
81
 
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  # Example prompts
84
  examples = [
85
  ["한복을 입은 여성이 전통 한옥 마당에서 부채를 들고 있다"],
@@ -90,7 +225,7 @@ examples = [
90
  ]
91
 
92
  # Build the Gradio interface
93
- with gr.Blocks(title="AI 프롬프트 증강기", theme=gr.themes.Soft(primary_hue="teal", secondary_hue="cyan")) as demo:
94
 
95
  gr.HTML("""
96
  <div style="text-align: center; padding: 20px 0;">
@@ -106,43 +241,45 @@ with gr.Blocks(title="AI 프롬프트 증강기", theme=gr.themes.Soft(primary_h
106
  font-size: 24px;
107
  ">✨</div>
108
  <h1 style="
109
- font-size: 2.5rem;
110
  font-weight: 800;
111
  background: linear-gradient(135deg, #4ecdc4 0%, #45b7d1 50%, #96e6a1 100%);
112
  -webkit-background-clip: text;
113
  -webkit-text-fill-color: transparent;
114
  margin: 0;
115
- ">AI 프롬프트 증강기</h1>
116
  </div>
117
  <p style="color: #6b7280; font-size: 1.1rem; margin: 0;">
118
- 이미지 & 영상 생성을 위한 프롬프트를 AI가 자동으로 증강합니다
119
  </p>
120
  </div>
121
  """)
122
 
123
- with gr.Row():
124
- with gr.Column(scale=1):
125
- api_key_input = gr.Textbox(
126
- label="🔑 Fireworks API Key",
 
127
  placeholder="fw_...",
128
  type="password",
129
  value=FIREWORKS_API_KEY,
130
- info="Fireworks AI API 키를 입력하세요 (환경변수 FIREWORKS_API_KEY로도 설정 가능)"
 
 
 
 
 
 
 
131
  )
132
 
 
133
  with gr.Row():
134
- with gr.Column(scale=1):
135
  prompt_input = gr.Textbox(
136
  label="📝 원본 프롬프트",
137
- placeholder="이미지나 영상으로 생성하고 싶은 장면을 설명해주세요...\n예: 한복을 입은 여성이 벚꽃 아래에서 걷고 있다",
138
- lines=5,
139
- max_lines=10
140
- )
141
-
142
- enhance_btn = gr.Button(
143
- "✨ 프롬프트 증강하기",
144
- variant="primary",
145
- size="lg"
146
  )
147
 
148
  gr.Examples(
@@ -150,38 +287,76 @@ with gr.Blocks(title="AI 프롬프트 증강기", theme=gr.themes.Soft(primary_h
150
  inputs=prompt_input,
151
  label="💡 예시 프롬프트"
152
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  with gr.Row():
155
- with gr.Column(scale=1):
156
- output_text = gr.Textbox(
157
- label="🚀 증강된 프롬프트 (복사하여 사용하세요)",
158
- placeholder="증강된 프롬프트가 여기에 표시됩니다...",
159
- lines=8,
160
- max_lines=15,
161
- interactive=True
 
 
 
 
 
 
 
162
  )
163
 
164
  gr.HTML("""
165
  <div style="text-align: center; padding: 20px 0; color: #6b7280; font-size: 0.9rem;">
166
- <p>💡 <strong>팁:</strong> 증강된 프롬프트는 영어로 출력되어 대부분의 AI 이미지/영상 생성 모델과 호환됩니다.</p>
167
- <p style="margin-top: 8px;">Powered by Fireworks AI (gpt-oss-120b) | Built with Gradio</p>
168
  </div>
169
  """)
170
 
171
- # Event handlers
172
- enhance_btn.click(
173
- fn=enhance_prompt,
174
- inputs=[prompt_input, api_key_input],
175
- outputs=output_text,
176
- show_progress=True
177
- )
178
-
179
- # Allow Enter key to submit (Shift+Enter for new line)
180
- prompt_input.submit(
181
- fn=enhance_prompt,
182
- inputs=[prompt_input, api_key_input],
183
- outputs=output_text,
184
- show_progress=True
185
  )
186
 
187
 
 
5
 
6
  # 환경변수에서 API 키 로드
7
  FIREWORKS_API_KEY = os.getenv("FIREWORKS_API_KEY", "")
8
+ FAL_KEY = os.getenv("FAL_KEY", "")
9
 
10
+ def enhance_prompt(prompt: str, fireworks_key: str) -> str:
11
  """
12
  Fireworks AI LLM API를 사용하여 프롬프트를 증강합니다.
13
  """
14
  if not prompt.strip():
15
  return "❌ 프롬프트를 입력해주세요."
16
 
17
+ if not fireworks_key.strip():
18
  return "❌ Fireworks API 키를 입력해주세요."
19
 
20
  system_message = """You are a professional prompt engineer specializing in AI image and video generation.
 
56
  headers = {
57
  "Accept": "application/json",
58
  "Content-Type": "application/json",
59
+ "Authorization": f"Bearer {fireworks_key}"
60
  }
61
 
62
  try:
 
74
  except requests.exceptions.Timeout:
75
  return "❌ API 요청 시간 초과. 다시 시도해주세요."
76
  except requests.exceptions.HTTPError as e:
77
+ return f"❌ API 오류: {e.response.status_code}"
78
  except requests.exceptions.RequestException as e:
79
  return f"❌ 네트워크 오류: {str(e)}"
80
  except Exception as e:
81
  return f"❌ 오류 발생: {str(e)}"
82
 
83
 
84
+ def generate_image(prompt: str, fal_key: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
85
+ """
86
+ FAL AI의 nano-banana-pro 모델을 사용하여 이미지를 생성합니다.
87
+ """
88
+ if not prompt.strip():
89
+ return None
90
+
91
+ if not fal_key.strip():
92
+ return None
93
+
94
+ url = "https://queue.fal.run/fal-ai/nano-banana-pro"
95
+
96
+ headers = {
97
+ "Authorization": f"Key {fal_key}",
98
+ "Content-Type": "application/json"
99
+ }
100
+
101
+ payload = {
102
+ "prompt": prompt,
103
+ "num_images": 1,
104
+ "aspect_ratio": aspect_ratio,
105
+ "output_format": "png",
106
+ "resolution": resolution
107
+ }
108
+
109
+ try:
110
+ # Submit request
111
+ response = requests.post(url, headers=headers, json=payload, timeout=120)
112
+ response.raise_for_status()
113
+
114
+ data = response.json()
115
+
116
+ # 직접 결과 반환되는 경우
117
+ if "images" in data:
118
+ images = data.get("images", [])
119
+ if images and len(images) > 0:
120
+ return images[0].get("url", None)
121
+
122
+ # Queue 방식인 경우 - request_id로 결과 조회
123
+ request_id = data.get("request_id")
124
+ if request_id:
125
+ return poll_for_result(request_id, fal_key)
126
+
127
+ return None
128
+
129
+ except Exception as e:
130
+ print(f"이미지 생성 오류: {e}")
131
+ return None
132
+
133
+
134
+ def poll_for_result(request_id: str, fal_key: str, max_attempts: int = 60) -> str:
135
+ """
136
+ Queue 결과를 폴링하여 이미지 URL을 가져옵니다.
137
+ """
138
+ status_url = f"https://queue.fal.run/fal-ai/nano-banana-pro/requests/{request_id}/status"
139
+ result_url = f"https://queue.fal.run/fal-ai/nano-banana-pro/requests/{request_id}"
140
+
141
+ headers = {
142
+ "Authorization": f"Key {fal_key}",
143
+ "Content-Type": "application/json"
144
+ }
145
+
146
+ for attempt in range(max_attempts):
147
+ try:
148
+ # 상태 확인
149
+ status_response = requests.get(status_url, headers=headers, timeout=30)
150
+ status_data = status_response.json()
151
+
152
+ status = status_data.get("status", "")
153
+
154
+ if status == "COMPLETED":
155
+ # 결과 가져오기
156
+ result_response = requests.get(result_url, headers=headers, timeout=30)
157
+ result_data = result_response.json()
158
+
159
+ images = result_data.get("images", [])
160
+ if images and len(images) > 0:
161
+ return images[0].get("url", None)
162
+ return None
163
+
164
+ elif status == "FAILED":
165
+ print(f"이미지 생성 실패: {status_data}")
166
+ return None
167
+
168
+ # IN_QUEUE 또는 IN_PROGRESS - 대기
169
+ import time
170
+ time.sleep(2)
171
+
172
+ except Exception as e:
173
+ print(f"폴링 오류: {e}")
174
+ import time
175
+ time.sleep(2)
176
+
177
+ return None
178
+
179
+
180
+ def process_comparison(
181
+ original_prompt: str,
182
+ fireworks_key: str,
183
+ fal_key: str,
184
+ aspect_ratio: str,
185
+ resolution: str
186
+ ):
187
+ """
188
+ 원본 프롬프트 증강 → 두 이미지 생성 → 비교 결과 반환
189
+ """
190
+ # 1. 프롬프트 증강
191
+ yield "🔄 프롬프트 증강 중...", None, None, None
192
+
193
+ enhanced = enhance_prompt(original_prompt, fireworks_key)
194
+
195
+ if enhanced.startswith("❌"):
196
+ yield enhanced, None, None, None
197
+ return
198
+
199
+ yield f"✅ 프롬프트 증강 완료\n\n🔄 원본 프롬프트로 이미지 생성 중...", enhanced, None, None
200
+
201
+ # 2. 원본 프롬프트로 이미지 생성
202
+ original_image = generate_image(original_prompt, fal_key, aspect_ratio, resolution)
203
+
204
+ if not original_image:
205
+ yield "✅ 프롬프트 증강 완료\n\n❌ 원본 이미지 생성 실패", enhanced, None, None
206
+ else:
207
+ yield f"✅ 프롬프트 증강 완료\n✅ 원본 이미지 생성 완료\n\n🔄 증강 프롬프트로 이미지 생성 중...", enhanced, original_image, None
208
+
209
+ # 3. 증강 프롬프트로 이미지 생성
210
+ enhanced_image = generate_image(enhanced, fal_key, aspect_ratio, resolution)
211
+
212
+ if not enhanced_image:
213
+ yield "✅ 프롬프트 증강 완료\n✅ 원본 이미지 생성 완료\n\n❌ 증강 이미지 생성 실패", enhanced, original_image, None
214
+ else:
215
+ yield "✅ 모든 작업 완료!", enhanced, original_image, enhanced_image
216
+
217
+
218
  # Example prompts
219
  examples = [
220
  ["한복을 입은 여성이 전통 한옥 마당에서 부채를 들고 있다"],
 
225
  ]
226
 
227
  # Build the Gradio interface
228
+ with gr.Blocks(title="AI 프롬프트 증강기 + 이미지 비교", theme=gr.themes.Soft(primary_hue="teal", secondary_hue="cyan")) as demo:
229
 
230
  gr.HTML("""
231
  <div style="text-align: center; padding: 20px 0;">
 
241
  font-size: 24px;
242
  ">✨</div>
243
  <h1 style="
244
+ font-size: 2.2rem;
245
  font-weight: 800;
246
  background: linear-gradient(135deg, #4ecdc4 0%, #45b7d1 50%, #96e6a1 100%);
247
  -webkit-background-clip: text;
248
  -webkit-text-fill-color: transparent;
249
  margin: 0;
250
+ ">AI 프롬프트 증강기 + 이미지 비교</h1>
251
  </div>
252
  <p style="color: #6b7280; font-size: 1.1rem; margin: 0;">
253
+ 원본 vs 증강 프롬프트의 이미지 생성 결과를 비교합니다
254
  </p>
255
  </div>
256
  """)
257
 
258
+ # API Keys Section
259
+ with gr.Accordion("🔑 API Keys 설정", open=not (FIREWORKS_API_KEY and FAL_KEY)):
260
+ with gr.Row():
261
+ fireworks_key_input = gr.Textbox(
262
+ label="Fireworks API Key (프롬프트 증강용)",
263
  placeholder="fw_...",
264
  type="password",
265
  value=FIREWORKS_API_KEY,
266
+ scale=1
267
+ )
268
+ fal_key_input = gr.Textbox(
269
+ label="FAL API Key (이미지 생성용)",
270
+ placeholder="your-fal-key",
271
+ type="password",
272
+ value=FAL_KEY,
273
+ scale=1
274
  )
275
 
276
+ # Input Section
277
  with gr.Row():
278
+ with gr.Column(scale=2):
279
  prompt_input = gr.Textbox(
280
  label="📝 원본 프롬프트",
281
+ placeholder="이미지로 생성하고 싶은 장면을 설명해주세요...\n예: 한복을 입은 여성이 벚꽃 아래에서 걷고 있다",
282
+ lines=4
 
 
 
 
 
 
 
283
  )
284
 
285
  gr.Examples(
 
287
  inputs=prompt_input,
288
  label="💡 예시 프롬프트"
289
  )
290
+
291
+ with gr.Column(scale=1):
292
+ aspect_ratio = gr.Dropdown(
293
+ label="📐 비율",
294
+ choices=["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "21:9"],
295
+ value="1:1"
296
+ )
297
+ resolution = gr.Dropdown(
298
+ label="🖼️ 해상도",
299
+ choices=["1K", "2K", "4K"],
300
+ value="1K"
301
+ )
302
+
303
+ generate_btn = gr.Button(
304
+ "🚀 증강 + 이미지 생성",
305
+ variant="primary",
306
+ size="lg"
307
+ )
308
+
309
+ # Status
310
+ status_text = gr.Textbox(
311
+ label="📊 진행 상태",
312
+ interactive=False,
313
+ lines=3
314
+ )
315
+
316
+ # Enhanced Prompt Output
317
+ enhanced_output = gr.Textbox(
318
+ label="✨ 증강된 프롬프트",
319
+ placeholder="증강된 프롬프트가 여기에 표시됩니다...",
320
+ lines=4,
321
+ interactive=True
322
+ )
323
+
324
+ # Image Comparison Section
325
+ gr.HTML("""
326
+ <div style="text-align: center; padding: 15px 0 5px 0;">
327
+ <h3 style="color: #374151; margin: 0;">🖼️ 이미지 비교</h3>
328
+ </div>
329
+ """)
330
 
331
  with gr.Row():
332
+ with gr.Column():
333
+ gr.HTML("<p style='text-align: center; font-weight: 600; color: #6b7280;'>📌 원본 프롬프트 결과</p>")
334
+ original_image_output = gr.Image(
335
+ label="원본 프롬프트 이미지",
336
+ type="filepath",
337
+ show_label=False
338
+ )
339
+
340
+ with gr.Column():
341
+ gr.HTML("<p style='text-align: center; font-weight: 600; color: #10b981;'>✨ 증강 프롬프트 결과</p>")
342
+ enhanced_image_output = gr.Image(
343
+ label="증강 프롬프트 이미지",
344
+ type="filepath",
345
+ show_label=False
346
  )
347
 
348
  gr.HTML("""
349
  <div style="text-align: center; padding: 20px 0; color: #6b7280; font-size: 0.9rem;">
350
+ <p>💡 <strong>팁:</strong> 증강된 프롬프트는 상세한 시각적 요소를 포함하여 풍부한 이미지를 생성합니다.</p>
351
+ <p style="margin-top: 8px;">Powered by Fireworks AI (gpt-oss-120b) + FAL AI (nano-banana-pro)</p>
352
  </div>
353
  """)
354
 
355
+ # Event handler
356
+ generate_btn.click(
357
+ fn=process_comparison,
358
+ inputs=[prompt_input, fireworks_key_input, fal_key_input, aspect_ratio, resolution],
359
+ outputs=[status_text, enhanced_output, original_image_output, enhanced_image_output]
 
 
 
 
 
 
 
 
 
360
  )
361
 
362