Opera8 commited on
Commit
aa3f413
·
verified ·
1 Parent(s): e4723b8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -208
app.py CHANGED
@@ -235,11 +235,9 @@ def infer(
235
  return result, seed, get_success_html("تصویر با موفقیت ویرایش شد.")
236
 
237
  except Exception as e:
238
- # اگر خطا مربوط به Quota باشد، اجازه می‌دهیم خود سیستم خطا را تولید کند تا JS آن را بگیرد
239
- # یا اگر Exception معمولی باشد آن را نشان می‌دهیم
240
  error_str = str(e)
241
  if "quota" in error_str.lower() or "exceeded" in error_str.lower():
242
- raise e # اجازه می‌دهیم خطای اصلی بالا برود تا شامل اعداد زمان باشد
243
  return None, seed, get_error_html(f"خطا در پردازش: {error_str}")
244
 
245
  @spaces.GPU(duration=30)
@@ -267,75 +265,7 @@ async (image) => {
267
  }
268
  """
269
 
270
- # --- جاوااسکریپت سراسری (تزریق پیام خطای جدید و تم روشن) ---
271
- js_global_content = """
272
- <script>
273
- document.addEventListener('DOMContentLoaded', () => {
274
- // 1. Force Light Mode
275
- const forceLight = () => {
276
- const body = document.querySelector('body');
277
- if (body) {
278
- body.classList.remove('dark');
279
- body.style.backgroundColor = '#f5f7fa';
280
- body.style.color = '#333333';
281
- }
282
- document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
283
- };
284
- forceLight();
285
- setInterval(forceLight, 1000);
286
-
287
- // 2. NEW GPU Quota Replacer (Hourglass Style)
288
- const observer = new MutationObserver((mutations) => {
289
- mutations.forEach((mutation) => {
290
- if (mutation.addedNodes.length) {
291
- mutation.addedNodes.forEach((node) => {
292
- // فقط روی المان‌های مربوط به خطای گرادیو کار کن
293
- if (node.nodeType === 1 && (node.classList.contains('toast-body') || node.classList.contains('error'))) {
294
- const originalText = node.innerText;
295
-
296
- // Regex برای پیدا کردن اعداد زمان
297
- const regex = /(\d+)s requested vs. (\d+)s left/;
298
- const match = originalText.match(regex);
299
-
300
- // اگر متن خطا مربوط به Quota بود و قبلا ترجمه نشده بود
301
- if (match && !node.dataset.translated) {
302
- const requested = match[1];
303
- const left = match[2];
304
-
305
- // **ساخت کارت HTML زیبا**
306
- const prettyHtml = `
307
- <div style="display: flex; align-items: center; gap: 15px; font-family: 'Tahoma', sans-serif; direction: rtl; padding: 10px;">
308
- <div style="font-size: 2.5em; color: #dc3545;">⏳</div>
309
- <div>
310
- <h4 style="margin: 0; color: #5a6268; font-weight: bold;">ظرفیت سرور تکمیل است!</h4>
311
- <p style="margin: 5px 0 0 0; color: #6c757d; font-size: 0.9em;">
312
- سهمیه رایگان GPU شما برای پردازش یک ویدیوی <b>${requested} ثانیه‌ای</b> کافی نیست.
313
- </p>
314
- <div style="background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 5px; padding: 5px 8px; margin-top: 10px; font-size: 0.85em;">
315
- اعتبار باقیمانده: <b>${left} ثانیه</b>
316
- </div>
317
- </div>
318
- </div>
319
- `;
320
-
321
- // جایگزینی محتوای قدیمی با کارت جدید
322
- node.innerHTML = prettyHtml;
323
-
324
- // جلوگیری از ترجمه مجدد
325
- node.dataset.translated = 'true';
326
- }
327
- }
328
- });
329
- }
330
- });
331
- });
332
-
333
- observer.observe(document.body, { childList: true, subtree: true });
334
- });
335
- </script>
336
- """
337
-
338
- # --- CSS ---
339
  css_code = """
340
  <style>
341
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
@@ -350,6 +280,21 @@ css_code = """
350
  --block-label-text-color: #374151 !important;
351
  --block-title-text-color: #111827 !important;
352
  --input-background-fill: #ffffff !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  color-scheme: light !important;
354
  }
355
 
@@ -360,159 +305,212 @@ body {
360
  padding: 10px;
361
  }
362
 
363
- #col-container {
364
- margin: 0 auto;
365
- max-width: 980px;
366
- direction: rtl;
367
- text-align: right;
368
- padding: 30px;
369
- background: #ffffff !important;
370
- border-radius: 24px;
371
- box-shadow: 0 10px 40px -10px rgba(0,0,0,0.08);
372
- border: 1px solid rgba(255,255,255,0.8);
373
  }
374
-
375
- #main-title h1 {
376
- font-size: 2.4em !important;
377
- text-align: center;
378
- color: #1a202c !important;
379
- margin-bottom: 15px;
380
- font-weight: 800;
381
- background: -webkit-linear-gradient(45deg, #2563eb, #1e40af);
382
- -webkit-background-clip: text;
383
- -webkit-text-fill-color: transparent;
384
  }
385
 
386
- #main-description {
387
- text-align: center;
388
- font-size: 1.15em;
389
- color: #4b5563 !important;
390
- margin-bottom: 40px;
391
- line-height: 1.6;
392
- }
393
-
394
- .gr-input-label, span.label-wrap, label span {
395
- font-weight: 700 !important;
396
- color: #374151 !important;
397
- font-size: 0.95em !important;
398
- margin-bottom: 8px !important;
399
- }
400
-
401
- textarea, input[type="text"] {
402
- border: 2px solid #e2e8f0 !important;
403
- border-radius: 12px !important;
404
- background-color: #ffffff !important;
405
- color: #111827 !important;
406
- padding: 12px !important;
407
- transition: all 0.3s ease;
408
  font-family: 'Vazirmatn', sans-serif !important;
409
  }
410
-
411
- textarea:focus, input[type="text"]:focus {
412
- border-color: #3b82f6 !important;
413
- box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important;
414
- outline: none;
415
- }
416
-
417
- .gr-dropdown {
418
- background: #ffffff !important;
419
- border-radius: 12px !important;
420
- }
421
-
422
- .primary-btn, button.primary {
423
- background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
424
- border: none !important;
425
- color: white !important;
426
- font-weight: 700 !important;
427
- font-size: 1.1em !important;
428
- padding: 14px 28px !important;
429
- border-radius: 14px !important;
430
- box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3) !important;
431
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
432
- cursor: pointer !important;
433
- width: 100%;
434
- margin-top: 15px;
435
- }
436
-
437
- .primary-btn:hover, button.primary:hover {
438
- transform: translateY(-2px);
439
- box-shadow: 0 8px 25px rgba(16, 185, 129, 0.45) !important;
440
- }
441
-
442
- .primary-btn:active, button.primary:active {
443
- transform: translateY(1px);
444
- }
445
-
446
- #download-btn {
447
- background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
448
- box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important;
449
- }
450
- #download-btn:hover {
451
- box-shadow: 0 8px 25px rgba(59, 130, 246, 0.45) !important;
452
- }
453
-
454
- .gradio-container .prose table,
455
- .gradio-container table {
456
- background-color: #ffffff !important;
457
- color: #111827 !important;
458
- border: 1px solid #e5e7eb !important;
459
- border-radius: 12px !important;
460
- overflow: hidden !important;
461
- width: 100% !important;
462
- margin-top: 20px !important;
463
- }
464
-
465
- .gradio-container thead th {
466
- background-color: #f3f4f6 !important;
467
- color: #374151 !important;
468
- font-weight: 700 !important;
469
- border-bottom: 2px solid #e5e7eb !important;
470
- padding: 12px !important;
471
- text-align: right !important;
472
- }
473
-
474
- .gradio-container tbody tr {
475
- background-color: #ffffff !important;
476
- border-bottom: 1px solid #f3f4f6 !important;
477
- }
478
-
479
- .gradio-container tbody tr:hover {
480
- background-color: #f9fafb !important;
481
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
 
483
- .gradio-container tbody td {
484
- background-color: #ffffff !important;
485
- color: #374151 !important;
486
- padding: 10px !important;
487
  }
 
 
488
 
489
- .gradio-container tbody td span,
490
- .gradio-container tbody td p {
491
- color: #374151 !important;
492
- }
 
 
 
 
 
 
 
 
 
 
 
 
493
 
494
- footer { display: none !important; }
495
- .flagging { display: none !important; }
 
 
 
 
 
 
 
 
 
 
 
 
496
 
497
- /* استایل Toast برای راست چین کردن */
498
- .toast-body {
499
- direction: rtl !important;
500
- text-align: right !important;
501
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
 
503
- @media (prefers-color-scheme: dark) {
504
- body, .gradio-container, .prose, table, tr, td, th {
505
- background-color: #ffffff !important;
506
- color: #333333 !important;
507
- }
508
- }
509
- </style>
510
  """
511
 
512
  # ادغام CSS و JS
513
  combined_html = css_code + js_global_content
514
 
515
- # استفاده از gr.Blocks بدون پارامتر js
516
  with gr.Blocks() as demo:
517
  # تزریق کدها به عنوان HTML
518
  gr.HTML(combined_html)
 
235
  return result, seed, get_success_html("تصویر با موفقیت ویرایش شد.")
236
 
237
  except Exception as e:
 
 
238
  error_str = str(e)
239
  if "quota" in error_str.lower() or "exceeded" in error_str.lower():
240
+ raise e
241
  return None, seed, get_error_html(f"خطا در پردازش: {error_str}")
242
 
243
  @spaces.GPU(duration=30)
 
265
  }
266
  """
267
 
268
+ # --- CSS به‌روزرسانی شده (شامل استایل‌های جدید راهنمای IP) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  css_code = """
270
  <style>
271
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
 
280
  --block-label-text-color: #374151 !important;
281
  --block-title-text-color: #111827 !important;
282
  --input-background-fill: #ffffff !important;
283
+
284
+ /* متغیرهای جدید برای راهنمای IP */
285
+ --guide-bg: rgba(255, 255, 255, 0.98);
286
+ --guide-border: rgba(102, 126, 234, 0.2);
287
+ --guide-text-title: #2d3748;
288
+ --guide-text-body: #4a5568;
289
+ --guide-accent: #667eea;
290
+ --primary-gradient-guide: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
291
+ --success-gradient-guide: linear-gradient(135deg, #56ab2f 0%, #a8e063 100%);
292
+ --radius-md-guide: 12px;
293
+ --radius-lg-guide: 20px;
294
+ --shadow-xl: 0 20px 25px -5px rgba(26, 32, 44, 0.07), 0 8px 10px -6px rgba(26, 32, 44, 0.05);
295
+ --shadow-sm: 0 1px 2px 0 rgba(26, 32, 44, 0.03);
296
+ --shadow-md: 0 4px 6px -1px rgba(26, 32, 44, 0.05);
297
+
298
  color-scheme: light !important;
299
  }
300
 
 
305
  padding: 10px;
306
  }
307
 
308
+ /* انیمیشن‌های مورد نیاز */
309
+ @keyframes float {
310
+ 0%, 100% { transform: translateY(0px); }
311
+ 50% { transform: translateY(-10px); }
 
 
 
 
 
 
312
  }
313
+ @keyframes slideInUp {
314
+ from { opacity: 0; transform: translateY(30px); }
315
+ to { opacity: 1; transform: translateY(0); }
 
 
 
 
 
 
 
316
  }
317
 
318
+ /* استایل‌های اصلی کانتینر راهنمای IP */
319
+ .ip-reset-guide-container {
320
+ text-align: right;
321
+ background: var(--guide-bg);
322
+ backdrop-filter: blur(10px);
323
+ padding: 40px;
324
+ border-radius: var(--radius-lg-guide);
325
+ box-shadow: var(--shadow-xl);
326
+ border: 1px solid var(--guide-border);
327
+ animation: slideInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1) both;
328
+ width: 100%;
329
+ position: relative;
330
+ overflow: hidden;
331
+ box-sizing: border-box;
 
 
 
 
 
 
 
 
332
  font-family: 'Vazirmatn', sans-serif !important;
333
  }
334
+ .ip-reset-guide-container::before {
335
+ content: '';
336
+ position: absolute;
337
+ top: 0; left: 0; right: 0;
338
+ height: 5px;
339
+ background: var(--primary-gradient-guide);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  }
341
+ .guide-header { display: flex; align-items: center; margin-bottom: 30px; direction: rtl; }
342
+ .guide-header-icon { width: 60px; height: 60px; margin-left: 20px; animation: float 3s ease-in-out infinite; }
343
+ .guide-header h2 { font-size: 1.5rem; color: var(--guide-text-title); font-weight: 700; margin: 0; }
344
+ .guide-header p { color: var(--guide-text-body); font-size: 0.8rem; margin-top: 5px; margin-bottom: 0; }
345
+ .guide-content { font-size: 0.95rem; color: var(--guide-text-body); line-height: 1.8; direction: rtl; }
346
+ .info-card { background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); border: 1px solid rgba(102, 126, 234, 0.2); border-radius: var(--radius-md-guide); padding: 20px; margin: 20px 0; position: relative; overflow: hidden; }
347
+ .info-card p { font-size: 0.85rem; line-height: 1.7; margin: 0; }
348
+ .info-card::before { content: ''; position: absolute; top: 0; right: 0; width: 4px; height: 100%; background: var(--primary-gradient-guide); }
349
+ .info-card-header { display: flex; align-items: center; margin-bottom: 12px; }
350
+ .info-card-icon { width: 24px; height: 24px; margin-left: 12px; }
351
+ .info-card-title { font-weight: 600; color: var(--guide-text-title); font-size: 1rem; }
352
+ .summary-section { margin-top: 25px; padding: 20px; border-radius: var(--radius-md-guide); background: linear-gradient(135deg, #56ab2f15 0%, #a8e06315 100%); border: 1px solid rgba(86, 171, 47, 0.2); position: relative; overflow: hidden; }
353
+ .summary-section::before { content: ''; position: absolute; top: 0; right: 0; width: 4px; height: 100%; background: var(--success-gradient-guide); }
354
+ .summary-header { display: flex; align-items: center; margin-bottom: 10px; }
355
+ .summary-icon { width: 24px; height: 24px; margin-left: 10px; }
356
+ .summary-title { font-weight: 600; color: #2f5a33; font-size: 1rem; }
357
+ .summary-text { color: #2f5a33; font-size: 0.9rem; line-height: 1.7; }
358
+ .video-button-container { text-align: center; margin: 25px 0 10px 0; }
359
+ .elegant-video-button { display: inline-flex; align-items: center; justify-content: center; padding: 7px 18px; background-color: #f0f2f5; color: var(--guide-accent); border: 1px solid #e2e8f0; text-decoration: none; border-radius: var(--radius-md-guide); font-weight: 600; font-size: 0.8rem; cursor: pointer; font-family: inherit; transition: all 0.3s ease; box-shadow: var(--shadow-sm); }
360
+ .elegant-video-button:hover { background: var(--primary-gradient-guide); color: white; border-color: transparent; transform: translateY(-2px); box-shadow: 0 6px 16px rgba(102, 126, 234, 0.3); }
361
+ .elegant-video-button-icon { width: 16px; height: 16px; margin-left: 8px; fill: currentColor; }
362
+ .guide-actions { display: flex; gap: 15px; margin-top: 30px; padding-top: 25px; border-top: 1px solid #e2e8f0; direction: rtl; }
363
+ .action-button { padding: 14px 24px; border: none; border-radius: var(--radius-md-guide); font-size: 0.95rem; font-weight: 600; cursor: pointer; flex: 1; transition: var(--transition-smooth); position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; font-family: inherit; }
364
+ .action-button-icon { width: 20px; height: 20px; margin-right: 0; margin-left: 8px; }
365
+ .back-button { background: white; color: var(--guide-text-body); border: 2px solid #e2e8f0; flex: 0.4; }
366
+ .back-button:hover { background: #f7fafc; border-color: var(--guide-accent); transform: translateY(-2px); box-shadow: var(--shadow-md); }
367
+ .retry-button { background: var(--primary-gradient-guide); color: white; flex: 0.6; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); }
368
+ .retry-button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); }
369
+
370
+ /* --- استایل‌های قبلی --- */
371
+ #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 -10px rgba(0,0,0,0.08); border: 1px solid rgba(255,255,255,0.8); }
372
+ #main-title h1 { font-size: 2.4em !important; text-align: center; color: #1a202c !important; margin-bottom: 15px; font-weight: 800; background: -webkit-linear-gradient(45deg, #2563eb, #1e40af); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
373
+ #main-description { text-align: center; font-size: 1.15em; color: #4b5563 !important; margin-bottom: 40px; line-height: 1.6; }
374
+ .gr-input-label, span.label-wrap, label span { font-weight: 700 !important; color: #374151 !important; font-size: 0.95em !important; margin-bottom: 8px !important; }
375
+ textarea, input[type="text"] { border: 2px solid #e2e8f0 !important; border-radius: 12px !important; background-color: #ffffff !important; color: #111827 !important; padding: 12px !important; transition: all 0.3s ease; font-family: 'Vazirmatn', sans-serif !important; }
376
+ textarea:focus, input[type="text"]:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important; outline: none; }
377
+ .gr-dropdown { background: #ffffff !important; border-radius: 12px !important; }
378
+ .primary-btn, button.primary { background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important; border: none !important; color: white !important; font-weight: 700 !important; font-size: 1.1em !important; padding: 14px 28px !important; border-radius: 14px !important; box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3) !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; cursor: pointer !important; width: 100%; margin-top: 15px; }
379
+ .primary-btn:hover, button.primary:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(16, 185, 129, 0.45) !important; }
380
+ #download-btn { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important; }
381
+ #download-btn:hover { box-shadow: 0 8px 25px rgba(59, 130, 246, 0.45) !important; }
382
+ .toast-body { direction: rtl !important; text-align: right !important; padding: 0 !important; border: none !important; background: transparent !important; box-shadow: none !important;}
383
+ .toast-wrap { border: none !important; background: transparent !important; box-shadow: none !important; }
384
 
385
+ @media (prefers-color-scheme: dark) {
386
+ body, .gradio-container, .prose, table, tr, td, th { background-color: #ffffff !important; color: #333333 !important; }
 
 
387
  }
388
+ </style>
389
+ """
390
 
391
+ # --- جاوااسکریپت سراسری (تزریق پیام خطای جدید پیشرفته) ---
392
+ js_global_content = """
393
+ <script>
394
+ document.addEventListener('DOMContentLoaded', () => {
395
+ // 1. Force Light Mode
396
+ const forceLight = () => {
397
+ const body = document.querySelector('body');
398
+ if (body) {
399
+ body.classList.remove('dark');
400
+ body.style.backgroundColor = '#f5f7fa';
401
+ body.style.color = '#333333';
402
+ }
403
+ document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
404
+ };
405
+ forceLight();
406
+ setInterval(forceLight, 1000);
407
 
408
+ // 2. NEW ADVANCED GPU Quota Replacer
409
+ const observer = new MutationObserver((mutations) => {
410
+ mutations.forEach((mutation) => {
411
+ if (mutation.addedNodes.length) {
412
+ mutation.addedNodes.forEach((node) => {
413
+ // Check for Gradio error toasts
414
+ if (node.nodeType === 1) {
415
+ // Look for the toast container or body
416
+ let targetNode = node.classList.contains('toast-body') ? node : node.querySelector('.toast-body');
417
+
418
+ // Also check simple class structure in case Gradio updates
419
+ if (!targetNode && (node.classList.contains('toast') || node.classList.contains('error'))) {
420
+ targetNode = node;
421
+ }
422
 
423
+ if (targetNode) {
424
+ const textContent = targetNode.innerText || "";
425
+
426
+ // If it's a Quota error
427
+ if (textContent.includes("exceeded your GPU quota") || textContent.includes("Quota Exceeded")) {
428
+
429
+ // The exact HTML structure requested by the user
430
+ const newHtml = `
431
+ <div class="ip-reset-guide-container">
432
+ <div class="guide-header">
433
+ <svg class="guide-header-icon" viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
434
+ <defs><lineargradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color: #667eea; stop-opacity: 1;"></stop><stop offset="100%" style="stop-color: #764ba2; stop-opacity: 1;"></stop></lineargradient></defs>
435
+ <circle cx="50" cy="50" r="45" fill="url(#grad1)" opacity="0.1"></circle>
436
+ <circle cx="50" cy="50" r="35" fill="none" stroke="url(#grad1)" stroke-width="2" opacity="0.3"></circle>
437
+ <path d="M35 50 L45 60 L65 40" stroke="url(#grad1)" stroke-width="4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path>
438
+ <circle cx="65" cy="35" r="8" fill="#fee140"></circle>
439
+ <path d="M62 35 L68 35 M65 32 L65 38" stroke="white" stroke-width="2" stroke-linecap="round"></path>
440
+ </svg>
441
+ <div>
442
+ <h2>یک قدم تا ساخت تصاویر جدید</h2>
443
+ <p>نیازمند تغییر نقطه دستیابی</p>
444
+ </div>
445
+ </div>
446
+ <div class="guide-content">
447
+ <div class="info-card">
448
+ <div class="info-card-header">
449
+ <svg class="info-card-icon" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="#667eea" opacity="0.2"></path><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" stroke="#667eea" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
450
+ <span class="info-card-title">راه حل سریع</span>
451
+ </div>
452
+ <p>طبق ویدیو آموزشی پایین بین نقطه دستیابی جابجا شوید تلاش مجدد بزنید تا تصاویر مجدداً تولید بشه.</p>
453
+ </div>
454
+ <div class="summary-section">
455
+ <div class="summary-header">
456
+ <svg class="summary-icon" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="#56ab2f" opacity="0.2"></circle><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" stroke="#56ab2f" stroke-width="2"></path><path d="M9 12l2 2 4-4" stroke="#56ab2f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
457
+ <span class="summary-title">خلاصه راهنما</span>
458
+ </div>
459
+ <div class="summary-text">هربار که این صفحه را مشاهده کردید: از اینترنت سیم‌کارت استفاده کنید، VPN را خاموش کرده و طبق ویدیو آموزشی پایین نقطه دستیابی رو تغییر دهید. «تلاش مجدد» کلیک کنید. با این روش ساده می‌توانید به صورت نامحدود تصویر بسازید! ☘️</div>
460
+ </div>
461
+ <div class="video-button-container">
462
+ <button onclick="window.open('https://www.aparat.com/v/your_video_id_here', '_blank')" class="elegant-video-button">
463
+ <svg class="elegant-video-button-icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M8 5v14l11-7z"></path></svg>
464
+ <span>دیدن ویدیو آموزشی استفاده نامحدود</span>
465
+ </button>
466
+ </div>
467
+ </div>
468
+ <div class="guide-actions">
469
+ <button class="action-button back-button" onclick="this.closest('.toast-wrap').remove()">
470
+ <svg class="action-button-icon" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19 12H5M12 19l-7-7 7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
471
+ <span>بازگشت</span>
472
+ </button>
473
+ <button class="action-button retry-button" onclick="this.closest('.toast-wrap').remove()">
474
+ <svg class="action-button-icon" viewbox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M23 4v6h-6M1 20v-6h6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
475
+ <span>تلاش مجدد</span>
476
+ </button>
477
+ </div>
478
+ </div>
479
+ `;
480
+
481
+ // Replace content
482
+ targetNode.innerHTML = newHtml;
483
+
484
+ // Clean up parent styles to allow full-width transparent display
485
+ let wrapper = targetNode.closest('.toast-wrap');
486
+ if(wrapper) {
487
+ wrapper.style.backgroundColor = 'transparent';
488
+ wrapper.style.boxShadow = 'none';
489
+ wrapper.style.border = 'none';
490
+ wrapper.style.maxWidth = '100%';
491
+ wrapper.style.width = 'auto';
492
+ }
493
+ targetNode.style.backgroundColor = 'transparent';
494
+ targetNode.style.padding = '0';
495
+ targetNode.style.boxShadow = 'none';
496
+ targetNode.style.border = 'none';
497
+ }
498
+ }
499
+ }
500
+ });
501
+ }
502
+ });
503
+ });
504
 
505
+ observer.observe(document.body, { childList: true, subtree: true });
506
+ });
507
+ </script>
 
 
 
 
508
  """
509
 
510
  # ادغام CSS و JS
511
  combined_html = css_code + js_global_content
512
 
513
+ # استفاده از gr.Blocks
514
  with gr.Blocks() as demo:
515
  # تزریق کدها به عنوان HTML
516
  gr.HTML(combined_html)