Opera8 commited on
Commit
c7971eb
·
verified ·
1 Parent(s): 063609b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +318 -48
app.py CHANGED
@@ -34,10 +34,11 @@ print("Loading Safety Checker...")
34
  safety_classifier = pipeline("image-classification", model="Falconsai/nsfw_image_detection", device=-1)
35
 
36
  def is_image_nsfw(image):
 
37
  try:
38
  results = safety_classifier(image)
39
  for result in results:
40
- if result['label'] == 'nsfw' and result['score'] > 0.8:
41
  return True
42
  return False
43
  except Exception as e:
@@ -105,7 +106,7 @@ LORA_MAPPING = {
105
  "افزایش کیفیت (Upscale)": "upscale-image"
106
  }
107
 
108
- ASPECT_RATIOS = [
109
  "خودکار (پیش‌فرض)",
110
  "۱:۱ (مربع - 1024x1024)",
111
  "۱۶:۹ (افقی - 1344x768)",
@@ -165,12 +166,29 @@ def update_dimensions_on_upload(image):
165
 
166
  return new_width, new_height
167
 
 
168
  def toggle_custom_dimensions(value):
169
  if value == "شخصی‌سازی (Custom)":
170
  return gr.update(visible=True), gr.update(visible=True)
171
  else:
172
  return gr.update(visible=False), gr.update(visible=False)
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  @spaces.GPU(duration=30)
175
  def infer(
176
  input_image,
@@ -186,14 +204,16 @@ def infer(
186
  progress=gr.Progress(track_tqdm=True)
187
  ):
188
  if input_image is None:
189
- raise gr.Error("لطفاً یک تصویر برای ویرایش بارگذاری کنید.")
190
 
 
191
  if is_image_nsfw(input_image):
192
- raise gr.Error("تصویر ورودی دارای محتوای نامناسب تشخیص داده شد.")
193
 
 
194
  english_prompt = translate_prompt(prompt)
195
  if not check_text_safety(english_prompt):
196
- raise gr.Error("متن درخواست شامل کلمات غیرمجاز است.")
197
 
198
  adapter_internal_name = LORA_MAPPING.get(lora_adapter_persian)
199
  if adapter_internal_name:
@@ -210,6 +230,7 @@ def infer(
210
 
211
  original_image = input_image.convert("RGB")
212
 
 
213
  selection_value = ASPECT_RATIOS_MAP.get(aspect_ratio_selection)
214
 
215
  if selection_value == "Custom":
@@ -220,84 +241,333 @@ def infer(
220
  else:
221
  width, height = selection_value
222
 
223
- result = pipe(
224
- image=original_image,
225
- prompt=english_prompt,
226
- negative_prompt=final_negative_prompt,
227
- height=height,
228
- width=width,
229
- num_inference_steps=steps,
230
- generator=generator,
231
- true_cfg_scale=guidance_scale,
232
- ).images[0]
233
-
234
- if is_image_nsfw(result):
235
- raise gr.Error("تصویر تولید شده حاوی محتوای نامناسب بود و حذف شد.")
 
 
 
 
236
 
237
- return result, seed
 
238
 
239
  @spaces.GPU(duration=30)
240
  def infer_example(input_image, prompt, lora_adapter):
241
- input_pil = input_image.convert("RGB")
242
- guidance_scale = 1.0
243
- steps = 4
244
- result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps, "خودکار (پیش‌فرض)", 1024, 1024)
245
- return result, seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
- # --- تنظیمات HTML ---
248
  html_code = """
249
  <style>
250
- /* CSS Styles (Same as before for Gradio UI) */
251
- /* ... (مخفی برای کوتاه شدن، همان استایل‌های قبلی اینجا قرار می‌گیرد) ... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  footer { display: none !important; }
253
  .flagging { display: none !important; }
 
 
 
 
 
 
 
254
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  """
256
 
257
  with gr.Blocks() as demo:
258
  gr.HTML(html_code)
259
 
260
  with gr.Column(elem_id="col-container"):
261
- gr.Markdown("# **ویرایشگر هوشمند آلفا**")
262
-
 
 
 
 
263
  with gr.Row(equal_height=True):
264
  with gr.Column():
265
  input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=320)
266
- prompt = gr.Text(label="دستور ویرایش", placeholder="متن فارسی...", rtl=True, lines=3)
267
- run_button = gr.Button("✨ شروع پردازش", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
268
 
269
  with gr.Column():
270
- output_image = gr.Image(label="خروجی", interactive=False, format="png", height=380)
 
 
271
 
272
  with gr.Row():
273
- lora_adapter = gr.Dropdown(label="سبک", choices=list(LORA_MAPPING.keys()), value="تبدیل عکس به انیمه")
 
 
 
 
274
 
275
- with gr.Accordion("تنظیمات", open=False):
276
- aspect_ratio_selection = gr.Dropdown(label="ابعاد", choices=ASPECT_RATIOS, value="خودکار (پیش‌فرض)")
 
 
 
 
 
 
 
277
  with gr.Row():
278
- custom_width = gr.Slider(label="عرض", minimum=256, maximum=2048, step=8, value=1024, visible=False)
279
- custom_height = gr.Slider(label="ارتفاع", minimum=256, maximum=2048, step=8, value=1024, visible=False)
280
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
281
- randomize_seed = gr.Checkbox(label="Seed تصادفی", value=True)
282
- guidance_scale = gr.Slider(label="Guidance", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
283
- steps = gr.Slider(label="Steps", minimum=1, maximum=50, step=1, value=4)
284
-
285
- aspect_ratio_selection.change(toggle_custom_dimensions, aspect_ratio_selection, [custom_width, custom_height])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
  gr.Examples(
288
  examples=[
289
  ["examples/1.jpg", "تبدیل به انیمه کن.", "تبدیل عکس به انیمه"],
290
- # ... سایر نمونه‌ها
 
 
 
 
 
 
 
 
 
291
  ],
292
- inputs=[input_image, prompt, lora_adapter]
 
 
 
 
293
  )
294
 
295
- # *** نکته مهم: اضافه کردن api_name ***
296
  run_button.click(
297
  fn=infer,
298
  inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps, aspect_ratio_selection, custom_width, custom_height],
299
- outputs=[output_image, seed],
300
- api_name="predict" # این خط کلید اتصال به فایل HTML است
 
 
 
 
 
 
301
  )
302
 
303
  if __name__ == "__main__":
 
34
  safety_classifier = pipeline("image-classification", model="Falconsai/nsfw_image_detection", device=-1)
35
 
36
  def is_image_nsfw(image):
37
+ if image is None: return False
38
  try:
39
  results = safety_classifier(image)
40
  for result in results:
41
+ if result['label'] == 'nsfw' and result['score'] > 0.75: # کمی سخت‌گیرتر
42
  return True
43
  return False
44
  except Exception as e:
 
106
  "افزایش کیفیت (Upscale)": "upscale-image"
107
  }
108
 
109
+ ASPECT_RATIOS_LIST = [
110
  "خودکار (پیش‌فرض)",
111
  "۱:۱ (مربع - 1024x1024)",
112
  "۱۶:۹ (افقی - 1344x768)",
 
166
 
167
  return new_width, new_height
168
 
169
+ # تابع برای نمایش/مخفی کردن اسلایدرهای ابعاد
170
  def toggle_custom_dimensions(value):
171
  if value == "شخصی‌سازی (Custom)":
172
  return gr.update(visible=True), gr.update(visible=True)
173
  else:
174
  return gr.update(visible=False), gr.update(visible=False)
175
 
176
+ def get_error_html(message):
177
+ return f"""
178
+ <div style="background-color: #fee2e2; border: 1px solid #ef4444; color: #b91c1c; padding: 12px; border-radius: 8px; text-align: center; margin-bottom: 10px; font-weight: bold; display: flex; align-items: center; justify-content: center; gap: 8px;">
179
+ <span style="font-size: 1.2em;">⛔</span>
180
+ {message}
181
+ </div>
182
+ """
183
+
184
+ def get_success_html(message):
185
+ return f"""
186
+ <div style="background-color: #dcfce7; border: 1px solid #22c55e; color: #15803d; padding: 12px; border-radius: 8px; text-align: center; margin-bottom: 10px; font-weight: bold; display: flex; align-items: center; justify-content: center; gap: 8px;">
187
+ <span style="font-size: 1.2em;">✅</span>
188
+ {message}
189
+ </div>
190
+ """
191
+
192
  @spaces.GPU(duration=30)
193
  def infer(
194
  input_image,
 
204
  progress=gr.Progress(track_tqdm=True)
205
  ):
206
  if input_image is None:
207
+ return None, seed, get_error_html("لطفاً ابتدا یک تصویر بارگذاری کنید.")
208
 
209
+ # 1. بررسی امنیت تصویر ورودی
210
  if is_image_nsfw(input_image):
211
+ return None, seed, get_error_html("تصویر ورودی دارای محتوای نامناسب است و پردازش نمی‌شود.")
212
 
213
+ # 2. ترجمه و بررسی متن
214
  english_prompt = translate_prompt(prompt)
215
  if not check_text_safety(english_prompt):
216
+ return None, seed, get_error_html("متن درخواست شامل کلمات غیرمجاز یا غیراخلاقی است.")
217
 
218
  adapter_internal_name = LORA_MAPPING.get(lora_adapter_persian)
219
  if adapter_internal_name:
 
230
 
231
  original_image = input_image.convert("RGB")
232
 
233
+ # --- منطق ابعاد ---
234
  selection_value = ASPECT_RATIOS_MAP.get(aspect_ratio_selection)
235
 
236
  if selection_value == "Custom":
 
241
  else:
242
  width, height = selection_value
243
 
244
+ try:
245
+ result = pipe(
246
+ image=original_image,
247
+ prompt=english_prompt,
248
+ negative_prompt=final_negative_prompt,
249
+ height=height,
250
+ width=width,
251
+ num_inference_steps=steps,
252
+ generator=generator,
253
+ true_cfg_scale=guidance_scale,
254
+ ).images[0]
255
+
256
+ # 4. بررسی امنیت تصویر خروجی
257
+ if is_image_nsfw(result):
258
+ return None, seed, get_error_html("تصویر تولید شده حاوی محتوای نامناسب بود و حذف شد.")
259
+
260
+ return result, seed, get_success_html("تصویر با موفقیت ویرایش شد.")
261
 
262
+ except Exception as e:
263
+ return None, seed, get_error_html(f"خطا در پردازش: {str(e)}")
264
 
265
  @spaces.GPU(duration=30)
266
  def infer_example(input_image, prompt, lora_adapter):
267
+ # برای نمونه‌ها
268
+ res, s, status = infer(input_image, prompt, lora_adapter, 0, True, 1.0, 4, "خودکار (پیش‌فرض)", 1024, 1024)
269
+ return res, s, status
270
+
271
+ # --- جاوااسکریپت ---
272
+ js_post_message = """
273
+ async (image) => {
274
+ if (!image) {
275
+ alert("لطفاً ابتدا تصویر را تولید کنید.");
276
+ return;
277
+ }
278
+ let fileUrl = image.url;
279
+ if (fileUrl && !fileUrl.startsWith('http')) {
280
+ fileUrl = window.location.origin + fileUrl;
281
+ } else if (!fileUrl && image.path) {
282
+ fileUrl = window.location.origin + "/file=" + image.path;
283
+ }
284
+ console.log("Sending download request for:", fileUrl);
285
+ window.parent.postMessage({
286
+ type: 'DOWNLOAD_REQUEST',
287
+ url: fileUrl
288
+ }, '*');
289
+ }
290
+ """
291
 
 
292
  html_code = """
293
  <style>
294
+ @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
295
+
296
+ :root, .dark, body, .gradio-container {
297
+ --body-background-fill: #f5f7fa !important;
298
+ --body-text-color: #1f2937 !important;
299
+ --background-fill-primary: #ffffff !important;
300
+ --background-fill-secondary: #f3f4f6 !important;
301
+ --border-color-primary: #e5e7eb !important;
302
+ --block-background-fill: #ffffff !important;
303
+ --block-label-text-color: #374151 !important;
304
+ --block-title-text-color: #111827 !important;
305
+ --input-background-fill: #ffffff !important;
306
+ color-scheme: light !important;
307
+ }
308
+
309
+ body {
310
+ font-family: 'Vazirmatn', sans-serif !important;
311
+ background-color: #f5f7fa !important;
312
+ margin: 0;
313
+ padding: 10px;
314
+ }
315
+
316
+ #col-container {
317
+ margin: 0 auto;
318
+ max-width: 980px;
319
+ direction: rtl;
320
+ text-align: right;
321
+ padding: 30px;
322
+ background: #ffffff !important;
323
+ border-radius: 24px;
324
+ box-shadow: 0 10px 40px -10px rgba(0,0,0,0.08);
325
+ border: 1px solid rgba(255,255,255,0.8);
326
+ }
327
+
328
+ #main-title h1 {
329
+ font-size: 2.4em !important;
330
+ text-align: center;
331
+ color: #1a202c !important;
332
+ margin-bottom: 15px;
333
+ font-weight: 800;
334
+ background: -webkit-linear-gradient(45deg, #2563eb, #1e40af);
335
+ -webkit-background-clip: text;
336
+ -webkit-text-fill-color: transparent;
337
+ }
338
+
339
+ #main-description {
340
+ text-align: center;
341
+ font-size: 1.15em;
342
+ color: #4b5563 !important;
343
+ margin-bottom: 40px;
344
+ line-height: 1.6;
345
+ }
346
+
347
+ .gr-input-label, span.label-wrap, label span {
348
+ font-weight: 700 !important;
349
+ color: #374151 !important;
350
+ font-size: 0.95em !important;
351
+ margin-bottom: 8px !important;
352
+ }
353
+
354
+ textarea, input[type="text"] {
355
+ border: 2px solid #e2e8f0 !important;
356
+ border-radius: 12px !important;
357
+ background-color: #ffffff !important;
358
+ color: #111827 !important;
359
+ padding: 12px !important;
360
+ font-family: 'Vazirmatn', sans-serif !important;
361
+ }
362
+
363
+ textarea:focus, input[type="text"]:focus {
364
+ border-color: #3b82f6 !important;
365
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important;
366
+ outline: none;
367
+ }
368
+
369
+ .gr-dropdown {
370
+ background: #ffffff !important;
371
+ border-radius: 12px !important;
372
+ }
373
+
374
+ .primary-btn, button.primary {
375
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
376
+ border: none !important;
377
+ color: white !important;
378
+ font-weight: 700 !important;
379
+ font-size: 1.1em !important;
380
+ padding: 14px 28px !important;
381
+ border-radius: 14px !important;
382
+ box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3) !important;
383
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
384
+ cursor: pointer !important;
385
+ width: 100%;
386
+ margin-top: 15px;
387
+ }
388
+
389
+ .primary-btn:hover, button.primary:hover {
390
+ transform: translateY(-2px);
391
+ box-shadow: 0 8px 25px rgba(16, 185, 129, 0.45) !important;
392
+ }
393
+
394
+ #download-btn {
395
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
396
+ box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important;
397
+ }
398
+ #download-btn:hover {
399
+ box-shadow: 0 8px 25px rgba(59, 130, 246, 0.45) !important;
400
+ }
401
+
402
+ .gradio-container .prose table,
403
+ .gradio-container table {
404
+ background-color: #ffffff !important;
405
+ color: #111827 !important;
406
+ border: 1px solid #e5e7eb !important;
407
+ border-radius: 12px !important;
408
+ overflow: hidden !important;
409
+ width: 100% !important;
410
+ margin-top: 20px !important;
411
+ }
412
+
413
+ .gradio-container thead th {
414
+ background-color: #f3f4f6 !important;
415
+ color: #374151 !important;
416
+ font-weight: 700 !important;
417
+ border-bottom: 2px solid #e5e7eb !important;
418
+ padding: 12px !important;
419
+ text-align: right !important;
420
+ }
421
+
422
+ .gradio-container tbody tr {
423
+ background-color: #ffffff !important;
424
+ border-bottom: 1px solid #f3f4f6 !important;
425
+ }
426
+
427
+ .gradio-container tbody tr:hover {
428
+ background-color: #f9fafb !important;
429
+ }
430
+
431
+ .gradio-container tbody td {
432
+ background-color: #ffffff !important;
433
+ color: #374151 !important;
434
+ padding: 10px !important;
435
+ }
436
+
437
  footer { display: none !important; }
438
  .flagging { display: none !important; }
439
+
440
+ @media (prefers-color-scheme: dark) {
441
+ body, .gradio-container, .prose, table, tr, td, th {
442
+ background-color: #ffffff !important;
443
+ color: #333333 !important;
444
+ }
445
+ }
446
  </style>
447
+
448
+ <script>
449
+ function forceLightMode() {
450
+ const body = document.querySelector('body');
451
+ if (body) {
452
+ body.classList.remove('dark');
453
+ body.style.backgroundColor = '#f5f7fa';
454
+ body.style.color = '#333333';
455
+ }
456
+ document.querySelectorAll('.dark').forEach(el => {
457
+ el.classList.remove('dark');
458
+ });
459
+ }
460
+ forceLightMode();
461
+ setInterval(forceLightMode, 1000);
462
+ document.addEventListener('DOMContentLoaded', forceLightMode);
463
+ </script>
464
  """
465
 
466
  with gr.Blocks() as demo:
467
  gr.HTML(html_code)
468
 
469
  with gr.Column(elem_id="col-container"):
470
+ gr.Markdown("# **ویرایشگر هوشمند آلفا**", elem_id="main-title")
471
+ gr.Markdown(
472
+ "با هوش مصنوعی آلفا تصاویر تونو به مدل های مختلف ویرایش کنید.",
473
+ elem_id="main-description"
474
+ )
475
+
476
  with gr.Row(equal_height=True):
477
  with gr.Column():
478
  input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=320)
479
+
480
+ prompt = gr.Text(
481
+ label="دستور ویرایش (به فارسی)",
482
+ show_label=True,
483
+ placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...",
484
+ rtl=True,
485
+ lines=3
486
+ )
487
+
488
+ # --- اضافه کردن بخش نمایش وضعیت (پیام‌ها) ---
489
+ status_box = gr.HTML(label="وضعیت")
490
+
491
+ run_button = gr.Button("✨ شروع پردازش و ساخت تصویر", variant="primary", elem_classes="primary-btn")
492
 
493
  with gr.Column():
494
+ output_image = gr.Image(label="تصویر نهایی", interactive=False, format="png", height=380)
495
+
496
+ download_button = gr.Button("📥 دانلود و ذخیره تصویر", variant="secondary", elem_id="download-btn", elem_classes="primary-btn")
497
 
498
  with gr.Row():
499
+ lora_adapter = gr.Dropdown(
500
+ label="انتخاب سبک ویرایش (LoRA)",
501
+ choices=list(LORA_MAPPING.keys()),
502
+ value="تبدیل عکس به انیمه"
503
+ )
504
 
505
+ with gr.Accordion("تنظیمات پیشرفته", open=False, visible=True):
506
+ aspect_ratio_selection = gr.Dropdown(
507
+ label="ابعاد تصویر خروجی",
508
+ choices=ASPECT_RATIOS_LIST,
509
+ value="خودکار (پیش‌فرض)",
510
+ interactive=True
511
+ )
512
+
513
+ # اسلایدرها به طور پیش‌فرض مخفی هستند
514
  with gr.Row():
515
+ custom_width = gr.Slider(
516
+ label="عرض دلخواه (Width)",
517
+ minimum=256, maximum=2048, step=8, value=1024,
518
+ visible=False
519
+ )
520
+ custom_height = gr.Slider(
521
+ label="ارتفاع دلخواه (Height)",
522
+ minimum=256, maximum=2048, step=8, value=1024,
523
+ visible=False
524
+ )
525
+
526
+ seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
527
+ randomize_seed = gr.Checkbox(label="استفاده از Seed تصادفی", value=True)
528
+ guidance_scale = gr.Slider(label="میزان وفاداری به متن (Guidance Scale)", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
529
+ steps = gr.Slider(label="تعداد مراحل پردازش (Steps)", minimum=1, maximum=50, step=1, value=4)
530
+
531
+ # --- اتصال رویداد برای نمایش/مخفی کردن ابعاد شخصی ---
532
+ aspect_ratio_selection.change(
533
+ fn=toggle_custom_dimensions,
534
+ inputs=aspect_ratio_selection,
535
+ outputs=[custom_width, custom_height]
536
+ )
537
 
538
  gr.Examples(
539
  examples=[
540
  ["examples/1.jpg", "تبدیل به انیمه کن.", "تبدیل عکس به انیمه"],
541
+ ["examples/5.jpg", "سایه‌ها را حذف کن و نورپردازی نرم به تصویر بده.", "اصلاح نور و سایه"],
542
+ ["examples/4.jpg", "از فیلتر ساعت طلایی با پخش نور ملایم استفاده کن.", "نورپردازی مجدد (Relight)"],
543
+ ["examples/2.jpeg", "دوربین را ۴۵ درجه به سمت چپ بچرخان.", "تغییر زاویه دید"],
544
+ ["examples/7.jpg", "منبع نور را از سمت راست عقب قرار بده.", "نورپردازی چند زاویه‌ای"],
545
+ ["examples/10.jpeg", "کیفیت تصویر را افزایش بده (Upscale).", "افزایش کیفیت (Upscale)"],
546
+ ["examples/7.jpg", "منبع نور را از پایین بتابان.", "نورپردازی چند زاویه‌ای"],
547
+ ["examples/2.jpeg", "زاویه دوربین را به نمای بالا گوشه راست تغییر بده.", "تغییر زاویه دید"],
548
+ ["examples/9.jpg", "دوربین کمی به جلو حرکت می‌کند در حالی که نور خورشید از میان ابرها می‌تابد و درخششی نرم اطراف شبح شخصیت در مه ایجاد می‌کند. سبک سینمایی واقعی.", "صحنه بعدی (سینمایی)"],
549
+ ["examples/8.jpg", "جزئیات پوست سوژه را برجسته‌تر و طبیعی‌تر کن.", "روتوش پوست"],
550
+ ["examples/6.jpg", "دوربین را به نمای پایین به بالا تغییر بده.", "تغییر زاویه دید"],
551
  ],
552
+ inputs=[input_image, prompt, lora_adapter],
553
+ outputs=[output_image, seed, status_box], # خروجی وضعیت اضافه شد
554
+ fn=infer_example,
555
+ cache_examples=False,
556
+ label="نمونه‌ها (برای تست کلیک کنید)"
557
  )
558
 
559
+ # اتصال دکمه اجرا (خروجی‌ها: تصویر، سید، پیام وضعیت)
560
  run_button.click(
561
  fn=infer,
562
  inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps, aspect_ratio_selection, custom_width, custom_height],
563
+ outputs=[output_image, seed, status_box]
564
+ )
565
+
566
+ download_button.click(
567
+ fn=None,
568
+ inputs=[output_image],
569
+ outputs=None,
570
+ js=js_post_message
571
  )
572
 
573
  if __name__ == "__main__":