Opera8 commited on
Commit
acf802e
·
verified ·
1 Parent(s): 6687486

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -200
app.py CHANGED
@@ -236,187 +236,118 @@ def infer_example(input_image, prompt, lora_adapter):
236
  res, s, status = infer(input_image, prompt, lora_adapter, 0, True, 1.0, 4, "خودکار (پیش‌فرض)", 1024, 1024)
237
  return res, s, status
238
 
239
- # --- جاوااسکریپت و HTML ---
240
- # در اینجا از setInterval برای بررسی مداوم وجود پیام خطا استفاده می‌کنیم
241
- # و به محض پیدا شدن، آن را مخفی و مودال خودمان را نشان می‌دهیم.
242
-
243
- html_js_modal_code = """
244
  <style>
245
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
246
 
 
247
  :root, .dark, body, .gradio-container {
248
  --body-background-fill: #f5f7fa !important;
249
  --body-text-color: #1f2937 !important;
250
  --background-fill-primary: #ffffff !important;
251
- --background-fill-secondary: #f3f4f6 !important;
252
- --border-color-primary: #e5e7eb !important;
253
- --block-background-fill: #ffffff !important;
254
- --block-label-text-color: #374151 !important;
255
- --block-title-text-color: #111827 !important;
256
- --input-background-fill: #ffffff !important;
257
  color-scheme: light !important;
258
  }
259
 
260
  body {
261
  font-family: 'Vazirmatn', sans-serif !important;
262
  background-color: #f5f7fa !important;
263
- margin: 0;
264
- padding: 10px;
265
  }
266
 
267
- /* استایل مودال خطای سفارشی - طراحی شده برای دیده شدن قطعی */
268
  #custom-quota-modal {
269
- display: none; /* پیش‌فرض مخفی */
270
- position: fixed;
271
- z-index: 2147483647; /* بالاترین لایه ممکن */
272
- left: 0;
273
- top: 0;
274
- width: 100%;
275
- height: 100%;
276
- overflow: auto;
277
- background-color: rgba(0,0,0,0.8);
278
- backdrop-filter: blur(5px);
279
- justify-content: center;
280
- align-items: center;
281
- direction: rtl;
282
  }
283
 
284
  .quota-modal-content {
285
- background-color: #fefefe;
286
- margin: auto;
287
- padding: 30px;
288
- border: 1px solid #888;
289
- width: 85%;
290
- max-width: 400px;
291
- border-radius: 20px;
292
- text-align: center;
293
- box-shadow: 0 4px 20px rgba(0,0,0,0.5);
294
- position: relative;
295
- animation: animatetop 0.4s;
296
- }
297
-
298
- @keyframes animatetop {
299
- from {top: -300px; opacity: 0}
300
- to {top: 0; opacity: 1}
301
  }
302
 
303
- .quota-icon { font-size: 50px; display: block; margin-bottom: 15px; }
304
- .quota-title { font-size: 22px; font-weight: bold; color: #e11d48; margin-bottom: 10px; }
305
- .quota-text { font-size: 16px; color: #333; margin-bottom: 25px; line-height: 1.6; }
306
- .quota-btn {
307
- background-color: #e11d48;
308
- color: white;
309
- padding: 12px 24px;
310
- border: none;
311
- border-radius: 10px;
312
- cursor: pointer;
313
- font-size: 16px;
314
- font-family: 'Vazirmatn', sans-serif;
315
- width: 100%;
316
- }
317
- .quota-btn:hover { background-color: #be123c; }
318
-
319
- /* استایل سایر اجزا */
320
- #col-container {
321
- margin: 0 auto;
322
- max-width: 980px;
323
- direction: rtl;
324
- text-align: right;
325
- padding: 30px;
326
- background: #ffffff !important;
327
- border-radius: 24px;
328
- box-shadow: 0 10px 40px -10px rgba(0,0,0,0.08);
329
- border: 1px solid rgba(255,255,255,0.8);
330
- }
331
 
332
- .primary-btn {
333
- background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
334
- border: none !important;
335
- color: white !important;
336
- font-weight: 700 !important;
337
- font-size: 1.1em !important;
338
- padding: 14px 28px !important;
339
- border-radius: 14px !important;
340
- }
341
 
342
- /* مخفی کردن شدید پیام‌های خطای پیش‌فرض گرادیو */
343
- .toast-wrap, .toast-error, .error, .toast {
344
- display: none !important;
345
- visibility: hidden !important;
 
346
  opacity: 0 !important;
 
 
 
 
347
  }
 
 
 
 
 
 
 
348
  </style>
349
 
350
- <!-- کد HTML مودال -->
351
  <div id="custom-quota-modal">
352
- <div class="quota-modal-content">
353
- <span class="quota-icon">✈️</span>
354
- <div class="quota-title">محدودیت استفاده از سرور</div>
355
- <div class="quota-text">
356
- سهمیه گرافیک رایگان شما تمام شده است.
357
- <br><br>
358
- برای ادامه، لطفاً <b>حالت هواپیما (Airplane Mode)</b> گوشی خود را یک‌بار روشن و خاموش کنید تا IP تغییر کند، سپس دوباره تلاش کنید.
 
 
359
  </div>
360
- <button class="quota-btn" onclick="document.getElementById('custom-quota-modal').style.display='none'">متوجه شدم</button>
361
- </div>
362
  </div>
363
 
364
  <script>
365
- // اسکریپت جاوااسکریپت برای مانیتورینگ خطا
366
- (function() {
367
- // 1. Force Light Mode
368
- function forceLightMode() {
369
- document.body.classList.remove('dark');
370
- document.body.style.backgroundColor = '#f5f7fa';
371
- document.body.style.color = '#333';
372
- document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
373
- }
374
 
375
- // 2. Error Monitor Loop (Polling) - بسیار قدرتمندتر از Observer
376
- setInterval(() => {
377
- forceLightMode();
378
-
379
- // جستجو در تمام المان‌های صفحه برای پیدا کردن متن خطا
380
- // ما دنبال المان‌هایی می‌گردیم که حاوی متن "exceeded your GPU quota" باشند
381
- const allElements = document.body.getElementsByTagName("*");
382
-
383
- for (let i = 0; i < allElements.length; i++) {
384
- const el = allElements[i];
385
 
386
- // بررسی متن داخل المان (فقط نودهای متنی مستقیم یا کانتینرهای خطا)
387
- if (el.shadowRoot) continue; // از شدو روت‌ها می‌گذریم
388
-
389
- if (el.innerText && el.innerText.includes("exceeded your GPU quota")) {
390
- // اگر خطا پیدا شد:
391
-
392
- // 1. مخفی کردن المان والد (معمولا toast-wrap یا error-box)
393
- // سعی می‌کنیم والد مناسب را پیدا کنیم تا کل باکس مخفی شود
394
- let parent = el;
395
- let foundContainer = false;
396
- // تا 5 سطح بالا می‌رویم تا کانتینر اصلی را پیدا کنیم
397
- for(let j=0; j<5; j++) {
398
- if (parent.classList.contains('toast-wrap') || parent.classList.contains('error')) {
399
- parent.style.display = 'none';
400
- foundContainer = true;
401
- break;
402
- }
403
- if(parent.parentElement) parent = parent.parentElement;
404
- }
405
- if (!foundContainer) el.style.display = 'none'; // اگر کانتینر پیدا نشد، خود المان را مخفی کن
406
-
407
- // 2. نمایش مودال سفارشی
408
- const modal = document.getElementById('custom-quota-modal');
409
- if (modal && modal.style.display !== 'flex') {
410
- modal.style.display = 'flex';
411
- }
412
- }
413
  }
414
-
415
- }, 500); // هر نیم ثانیه چک می‌کند
416
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
417
 
418
- // PostMessage Function
419
- async function sendImageToParent(image) {
 
420
  if (!image) { alert("لطفاً ابتدا تصویر را تولید کنید."); return; }
421
  let fileUrl = image.url;
422
  if (fileUrl && !fileUrl.startsWith('http')) {
@@ -424,14 +355,12 @@ async function sendImageToParent(image) {
424
  } else if (!fileUrl && image.path) {
425
  fileUrl = window.location.origin + "/file=" + image.path;
426
  }
427
- console.log("Sending download request for:", fileUrl);
428
  window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fileUrl }, '*');
429
  }
430
- </script>
431
  """
432
 
433
  with gr.Blocks() as demo:
434
- gr.HTML(html_js_modal_code)
435
 
436
  with gr.Column(elem_id="col-container"):
437
  gr.Markdown("# **ویرایشگر هوشمند آلفا**", elem_id="main-title")
@@ -443,64 +372,32 @@ with gr.Blocks() as demo:
443
  with gr.Row(equal_height=True):
444
  with gr.Column():
445
  input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=320)
446
-
447
- prompt = gr.Text(
448
- label="دستور ویرایش (به فارسی)",
449
- show_label=True,
450
- placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...",
451
- rtl=True,
452
- lines=3
453
- )
454
-
455
  status_box = gr.HTML(label="وضعیت")
456
-
457
  run_button = gr.Button("✨ شروع پردازش و ساخت تصویر", variant="primary", elem_classes="primary-btn")
458
 
459
  with gr.Column():
460
  output_image = gr.Image(label="تصویر نهایی", interactive=False, format="png", height=380)
461
-
462
  download_button = gr.Button("📥 دانلود و ذخیره تصویر", variant="secondary", elem_id="download-btn", elem_classes="primary-btn")
463
 
464
  with gr.Row():
465
- lora_adapter = gr.Dropdown(
466
- label="انتخاب سبک ویرایش (LoRA)",
467
- choices=list(LORA_MAPPING.keys()),
468
- value="تبدیل عکس به انیمه"
469
- )
470
 
471
  with gr.Accordion("تنظیمات پیشرفته", open=False, visible=True):
472
- aspect_ratio_selection = gr.Dropdown(
473
- label="ابعاد تصویر خروجی",
474
- choices=ASPECT_RATIOS_LIST,
475
- value="خودکار (پیش‌فرض)",
476
- interactive=True
477
- )
478
-
479
  with gr.Row(visible=False) as custom_dims_row:
480
- custom_width = gr.Slider(
481
- label="عرض دلخواه (Width)",
482
- minimum=256, maximum=2048, step=8, value=1024
483
- )
484
- custom_height = gr.Slider(
485
- label="ارتفاع دلخواه (Height)",
486
- minimum=256, maximum=2048, step=8, value=1024
487
- )
488
-
489
  seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
490
  randomize_seed = gr.Checkbox(label="استفاده از Seed تصادفی", value=True)
491
  guidance_scale = gr.Slider(label="میزان وفاداری به متن (Guidance Scale)", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
492
  steps = gr.Slider(label="تعداد مراحل پردازش (Steps)", minimum=1, maximum=50, step=1, value=4)
493
 
494
  def toggle_row(choice):
495
- if choice == "شخصی‌سازی (Custom)":
496
- return gr.update(visible=True)
497
  return gr.update(visible=False)
498
 
499
- aspect_ratio_selection.change(
500
- fn=toggle_row,
501
- inputs=aspect_ratio_selection,
502
- outputs=custom_dims_row
503
- )
504
 
505
  gr.Examples(
506
  examples=[
@@ -523,19 +420,8 @@ with gr.Blocks() as demo:
523
  label="نمونه‌ها (برای تست کلیک کنید)"
524
  )
525
 
526
- run_button.click(
527
- fn=infer,
528
- inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps, aspect_ratio_selection, custom_width, custom_height],
529
- outputs=[output_image, seed, status_box],
530
- api_name="predict"
531
- )
532
-
533
- download_button.click(
534
- fn=None,
535
- inputs=[output_image],
536
- outputs=None,
537
- js="sendImageToParent"
538
- )
539
 
540
  if __name__ == "__main__":
541
  demo.queue(max_size=30).launch(show_error=True)
 
236
  res, s, status = infer(input_image, prompt, lora_adapter, 0, True, 1.0, 4, "خودکار (پیش‌فرض)", 1024, 1024)
237
  return res, s, status
238
 
239
+ # --- جاوااسکریپت و CSS بسیار قوی برای مودال ---
240
+ html_code = """
 
 
 
241
  <style>
242
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
243
 
244
+ /* تم روشن اجباری */
245
  :root, .dark, body, .gradio-container {
246
  --body-background-fill: #f5f7fa !important;
247
  --body-text-color: #1f2937 !important;
248
  --background-fill-primary: #ffffff !important;
 
 
 
 
 
 
249
  color-scheme: light !important;
250
  }
251
 
252
  body {
253
  font-family: 'Vazirmatn', sans-serif !important;
254
  background-color: #f5f7fa !important;
255
+ margin: 0; padding: 10px;
 
256
  }
257
 
258
+ /* استایل مودال */
259
  #custom-quota-modal {
260
+ position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
261
+ background-color: rgba(0, 0, 0, 0.85);
262
+ backdrop-filter: blur(8px);
263
+ z-index: 9999999; /* Z-Index بسیار بالا */
264
+ display: none;
265
+ justify-content: center; align-items: center; direction: rtl;
 
 
 
 
 
 
 
266
  }
267
 
268
  .quota-modal-content {
269
+ background-color: white; padding: 40px; border-radius: 24px;
270
+ width: 90%; max-width: 450px; text-align: center;
271
+ box-shadow: 0 20px 60px rgba(0,0,0,0.4);
272
+ animation: slideIn 0.4s ease-out;
 
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
 
275
+ .quota-icon { font-size: 72px; margin-bottom: 25px; display: block; animation: float 3s infinite; }
276
+ .quota-title { font-size: 1.6em; font-weight: 900; color: #e11d48; margin-bottom: 15px; }
277
+ .quota-text { font-size: 1.15em; color: #374151; line-height: 1.8; margin-bottom: 30px; }
278
+ .quota-btn { background: #e11d48; color: white; border: none; padding: 14px 35px; border-radius: 14px; font-weight: bold; cursor: pointer; width: 100%; font-family: 'Vazirmatn'; font-size: 1.1em; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
+ @keyframes slideIn { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
281
+ @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
 
 
 
 
 
 
 
282
 
283
+ /*
284
+ نکته کلیدی: مخفی کردن بصری (نامرئی کردن) کانتینر خطا به جای حذف آن
285
+ این باعث میشه JS بتونه متنش رو بخونه ولی کاربر نبینه
286
+ */
287
+ .toast-wrap {
288
  opacity: 0 !important;
289
+ visibility: hidden !important;
290
+ pointer-events: none !important;
291
+ position: absolute !important;
292
+ top: -9999px !important;
293
  }
294
+
295
+ /* استایل‌های عمومی */
296
+ #col-container { margin: 0 auto; max-width: 980px; direction: rtl; text-align: right; padding: 30px; background: #ffffff !important; border-radius: 24px; box-shadow: 0 10px 40px rgba(0,0,0,0.08); }
297
+ #main-title h1 { font-size: 2.4em !important; text-align: center; color: #1a202c !important; margin-bottom: 15px; }
298
+ .primary-btn { background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important; color: white !important; font-weight: bold; padding: 14px; border-radius: 14px; box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3); width: 100%; margin-top: 15px; border: none; }
299
+ #download-btn { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; margin-top: 10px; }
300
+ footer, .flagging { display: none !important; }
301
  </style>
302
 
 
303
  <div id="custom-quota-modal">
304
+ <div class="quota-modal-content">
305
+ <span class="quota-icon">✈️</span>
306
+ <div class="quota-title">محدودیت استفاده</div>
307
+ <div class="quota-text">
308
+ ظرفیت استفاده رایگان تکمیل شده است.
309
+ <br><br>
310
+ برای ادامه، لطفاً <b>حالت هواپیما (Airplane Mode)</b> را یکبار روشن و خاموش کنید تا IP تغییر کند و سپس مجدد تلاش کنید.
311
+ </div>
312
+ <button class="quota-btn" onclick="document.getElementById('custom-quota-modal').style.display='none'">متوجه شدم</button>
313
  </div>
 
 
314
  </div>
315
 
316
  <script>
317
+ // اسکریپت شناسایی خطا
318
+ function checkQuotaError() {
319
+ // جستجو در تمام متن صفحه
320
+ const bodyText = document.body.innerText || document.body.textContent;
 
 
 
 
 
321
 
322
+ // اگر متن خطا پیدا شد
323
+ if (bodyText.includes("exceeded your GPU quota") || bodyText.includes("GPU quota")) {
324
+ const modal = document.getElementById('custom-quota-modal');
325
+ if (modal && modal.style.display !== 'flex') {
326
+ modal.style.display = 'flex';
 
 
 
 
 
327
 
328
+ // تلاش برای حذف متن خطا از DOM (اختیاری، چون CSS مخفیش کرده)
329
+ document.querySelectorAll('.toast-wrap').forEach(el => el.innerHTML = '');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  }
331
+ }
332
+ }
333
+
334
+ // چک کردن هر 500 میلی‌ثانیه (بسیار سریع)
335
+ setInterval(checkQuotaError, 500);
336
+
337
+ // فورس لایت مود
338
+ function forceLight() {
339
+ document.body.classList.remove('dark');
340
+ document.body.style.backgroundColor = '#f5f7fa';
341
+ document.body.style.color = '#333333';
342
+ document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
343
+ }
344
+ setInterval(forceLight, 1000);
345
+ </script>
346
+ """
347
 
348
+ # جاوااسکریپت دانلود
349
+ js_post_message = """
350
+ async (image) => {
351
  if (!image) { alert("لطفاً ابتدا تصویر را تولید کنید."); return; }
352
  let fileUrl = image.url;
353
  if (fileUrl && !fileUrl.startsWith('http')) {
 
355
  } else if (!fileUrl && image.path) {
356
  fileUrl = window.location.origin + "/file=" + image.path;
357
  }
 
358
  window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fileUrl }, '*');
359
  }
 
360
  """
361
 
362
  with gr.Blocks() as demo:
363
+ gr.HTML(html_code)
364
 
365
  with gr.Column(elem_id="col-container"):
366
  gr.Markdown("# **ویرایشگر هوشمند آلفا**", elem_id="main-title")
 
372
  with gr.Row(equal_height=True):
373
  with gr.Column():
374
  input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=320)
375
+ prompt = gr.Text(label="دستور ویرایش (به فارسی)", show_label=True, placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...", rtl=True, lines=3)
 
 
 
 
 
 
 
 
376
  status_box = gr.HTML(label="وضعیت")
 
377
  run_button = gr.Button("✨ شروع پردازش و ساخت تصویر", variant="primary", elem_classes="primary-btn")
378
 
379
  with gr.Column():
380
  output_image = gr.Image(label="تصویر نهایی", interactive=False, format="png", height=380)
 
381
  download_button = gr.Button("📥 دانلود و ذخیره تصویر", variant="secondary", elem_id="download-btn", elem_classes="primary-btn")
382
 
383
  with gr.Row():
384
+ lora_adapter = gr.Dropdown(label="انتخاب سبک ویرایش (LoRA)", choices=list(LORA_MAPPING.keys()), value="تبدیل عکس به انیمه")
 
 
 
 
385
 
386
  with gr.Accordion("تنظیمات پیشرفته", open=False, visible=True):
387
+ aspect_ratio_selection = gr.Dropdown(label="ابعاد تصویر خروجی", choices=ASPECT_RATIOS_LIST, value="خودکار (پیش‌فرض)", interactive=True)
 
 
 
 
 
 
388
  with gr.Row(visible=False) as custom_dims_row:
389
+ custom_width = gr.Slider(label="عرض دلخواه (Width)", minimum=256, maximum=2048, step=8, value=1024)
390
+ custom_height = gr.Slider(label="ارتفاع دلخواه (Height)", minimum=256, maximum=2048, step=8, value=1024)
 
 
 
 
 
 
 
391
  seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
392
  randomize_seed = gr.Checkbox(label="استفاده از Seed تصادفی", value=True)
393
  guidance_scale = gr.Slider(label="میزان وفاداری به متن (Guidance Scale)", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
394
  steps = gr.Slider(label="تعداد مراحل پردازش (Steps)", minimum=1, maximum=50, step=1, value=4)
395
 
396
  def toggle_row(choice):
397
+ if choice == "شخصی‌سازی (Custom)": return gr.update(visible=True)
 
398
  return gr.update(visible=False)
399
 
400
+ aspect_ratio_selection.change(fn=toggle_row, inputs=aspect_ratio_selection, outputs=custom_dims_row)
 
 
 
 
401
 
402
  gr.Examples(
403
  examples=[
 
420
  label="نمونه‌ها (برای تست کلیک کنید)"
421
  )
422
 
423
+ run_button.click(fn=infer, inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps, aspect_ratio_selection, custom_width, custom_height], outputs=[output_image, seed, status_box], api_name="predict")
424
+ download_button.click(fn=None, inputs=[output_image], outputs=None, js=js_post_message)
 
 
 
 
 
 
 
 
 
 
 
425
 
426
  if __name__ == "__main__":
427
  demo.queue(max_size=30).launch(show_error=True)