Opera8 commited on
Commit
ad7f495
·
verified ·
1 Parent(s): 9a1edaf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +289 -122
app.py CHANGED
@@ -1529,7 +1529,7 @@ css = """
1529
  width: fit-content;
1530
  font-family: sans-serif;
1531
  }
1532
- .toggle-container input[type="radio"] {
1533
  display: none;
1534
  }
1535
  .toggle-container label {
@@ -1557,11 +1557,11 @@ css = """
1557
  z-index: 1;
1558
  }
1559
  /* When "True" is checked */
1560
- #true:checked ~ label[for="true"] {
1561
  color: #ffd6ff; /* light pink text */
1562
  }
1563
  /* When "False" is checked */
1564
- #false:checked ~ label[for="false"] {
1565
  color: #ffd6ff; /* light pink text */
1566
  }
1567
  /* Move highlight to right side when False is checked */
@@ -1920,7 +1920,7 @@ css += """
1920
  }
1921
 
1922
  /* show tick ONLY for selected item */
1923
- .cd-item[data-selected="true"]::after{
1924
  opacity: 1;
1925
  }
1926
 
@@ -2179,13 +2179,13 @@ css += """
2179
  }
2180
 
2181
  /* dim others while hovering */
2182
- .pg-card[data-dim="true"] .pg-img{
2183
  opacity: 0.35;
2184
  filter: saturate(0.9);
2185
  }
2186
 
2187
  /* keep hovered/active crisp */
2188
- .pg-card[data-active="true"] .pg-img{
2189
  opacity: 1.0;
2190
  filter: none;
2191
  }
@@ -2283,6 +2283,153 @@ div.footer {
2283
  .api-logo, .built-with {
2284
  display: none !important;
2285
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2286
  """
2287
 
2288
 
@@ -2325,7 +2472,7 @@ def apply_example(idx: str):
2325
  idx = int(idx)
2326
 
2327
  # Read the example row from your list
2328
- img, prompt_txt, cam, res, mode, vid, aud, end_img = examples_list[idx]
2329
 
2330
  img_path = img if img else None
2331
  vid_path = vid if vid else None
@@ -2359,7 +2506,7 @@ def apply_example(idx: str):
2359
 
2360
  with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2361
 
2362
- # Updated Header to Persian
2363
  gr.HTML(
2364
  """
2365
  <div style="text-align: center; padding: 20px;">
@@ -2370,6 +2517,115 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2370
  با پشتیبانی از صدا و دو تصویر
2371
  </p>
2372
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2373
  """
2374
  )
2375
 
@@ -2377,7 +2633,7 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2377
  with gr.Row(elem_id="mode-row"):
2378
  # Updated choices to Persian
2379
  radioanimated_mode = RadioAnimated(
2380
- choices=["تبدیل تصویر به ویدیو", "تکمیل فریم‌های میانی"],
2381
  value="تبدیل تصویر به ویدیو",
2382
  elem_id="radioanimated_mode"
2383
  )
@@ -2448,7 +2704,7 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2448
  # Hidden real audio input (backend value)
2449
  audio_input = gr.File(
2450
  label="Audio (Optional)",
2451
- file_types=["audio"],
2452
  type="filepath",
2453
  elem_id="audio_input_hidden",
2454
  )
@@ -2491,13 +2747,15 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2491
 
2492
  with gr.Row(elem_id="controls-row"):
2493
 
 
2494
  duration_ui = CameraDropdown(
2495
- choices=["3s", "5s", "10s"],
2496
  value="5s",
2497
  title="مدت زمان ویدیو",
2498
  elem_id="duration_ui"
2499
  )
2500
 
 
2501
  duration = gr.Slider(
2502
  label="Duration (seconds)",
2503
  minimum=1.0,
@@ -2521,11 +2779,7 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2521
 
2522
 
2523
  resolution_ui = CameraDropdown(
2524
- choices=[
2525
- {"label": "16:9", "value": "16:9", "icon": ICON_16_9},
2526
- {"label": "1:1", "value": "1:1", "icon": ICON_1_1},
2527
- {"label": "9:16", "value": "9:16", "icon": ICON_9_16},
2528
- ],
2529
  value="16:9",
2530
  title="ابعاد تصویر",
2531
  elem_id="resolution_ui"
@@ -2536,7 +2790,7 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2536
  height = gr.Number(label="Height", value=DEFAULT_1_STAGE_HEIGHT, precision=0, visible=False)
2537
 
2538
  camera_ui = CameraDropdown(
2539
- choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES],
2540
  value="No LoRA",
2541
  title="افکت دوربین (LoRA)",
2542
  elem_id="camera_ui",
@@ -2545,12 +2799,12 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2545
  # Hidden real dropdown (backend value)
2546
  camera_lora = gr.Dropdown(
2547
  label="Camera Control LoRA",
2548
- choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES],
2549
  value="No LoRA",
2550
  visible=False
2551
  )
2552
 
2553
- generate_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient")
2554
 
2555
 
2556
  camera_ui.change(
@@ -2563,7 +2817,7 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2563
  radioanimated_mode.change(
2564
  fn=on_mode_change,
2565
  inputs=radioanimated_mode,
2566
- outputs=[input_video, end_frame],
2567
  api_visibility="private",
2568
  )
2569
 
@@ -2571,13 +2825,13 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2571
  duration_ui.change(
2572
  fn=apply_duration,
2573
  inputs=duration_ui,
2574
- outputs=[duration],
2575
  api_visibility="private"
2576
  )
2577
  resolution_ui.change(
2578
  fn=apply_resolution,
2579
  inputs=resolution_ui,
2580
- outputs=[width, height],
2581
  api_visibility="private"
2582
  )
2583
  prompt_ui.change(
@@ -2590,107 +2844,27 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2590
 
2591
  generate_btn.click(
2592
  fn=generate_video,
2593
- inputs=[
2594
- first_frame,
2595
- end_frame,
2596
- prompt,
2597
- duration,
2598
- input_video,
2599
- radioanimated_mode,
2600
- enhance_prompt,
2601
- seed,
2602
- randomize_seed,
2603
- height,
2604
- width,
2605
- camera_lora,
2606
- audio_input
2607
- ],
2608
- outputs=[output_video]
2609
  )
2610
 
2611
  # Updated Examples to use Persian modes
2612
- examples_list = [
2613
- [
2614
- "examples/supergirl-2.png",
2615
- "A fuzzy puppet superhero character resembling a female puppet with blonde hair and a blue superhero suit sleeping in bed and just waking up, she gradually gets up, rubbing her eyes and looking at her dog that just popped on the bed. the scene feels chaotic, comedic, and emotional with expressive puppet reactions, cinematic lighting, smooth camera motion, shallow depth of field, and high-quality puppet-style animation",
2616
- "Static",
2617
- "16:9",
2618
- "تبدیل تصویر به ویدیو",
2619
- None,
2620
- "examples/supergirl.m4a",
2621
- None,
2622
- ],
2623
- [
2624
- "examples/frame3.png",
2625
- "a woman in a white dress standing in a supermarket, looking at a stack of pomegranates, she picks one and takes a bite, the camera zooms in to a close up of the pomegranate seeds. A calm music is playing in the supermarket and you can hear her taking a bite.",
2626
- "Zoom In",
2627
- "16:9",
2628
- "تکمیل فریم‌های میانی",
2629
- None,
2630
- None,
2631
- "examples/frame4.png",
2632
- ],
2633
- [
2634
- "examples/supergirl.png",
2635
- "A fuzzy puppet superhero character resembling a female puppet with blonde hair and a blue superhero suit stands inside an icy cave made of frozen walls and icicles, she looks panicked and frantic, rapidly turning her head left and right and scanning the cave while waving her arms and shouting angrily and desperately, mouthing the words “where the hell is my dog,” her movements exaggerated and puppet-like with high energy and urgency, suddenly a second puppet dog bursts into frame from the side, jumping up excitedly and tackling her affectionately while licking her face repeatedly, she freezes in surprise and then breaks into relief and laughter as the dog continues licking her, the scene feels chaotic, comedic, and emotional with expressive puppet reactions, cinematic lighting, smooth camera motion, shallow depth of field, and high-quality puppet-style animation",
2636
- "No LoRA",
2637
- "16:9",
2638
- "تبدیل تصویر به ویدیو",
2639
- None,
2640
- None,
2641
- None,
2642
- ],
2643
- [
2644
- "examples/highland.png",
2645
- "Realistic POV selfie-style video in a snowy, foggy field. Two shaggy Highland cows with long curved horns stand ahead. The camera is handheld and slightly shaky. The woman filming talks nervously and excitedly in a vlog tone: \"Oh my god guys… look how big those horns are… I’m kinda scared.\" The cow on the left walks toward the camera in a cute, bouncy, hopping way, curious and gentle. Snow crunches under its hooves, breath visible in the cold air. The horns look massive from the POV. As the cow gets very close, its wet nose with slight dripping fills part of the frame. She laughs nervously but reaches out and pets the cow. The cow makes deep, soft, interesting mooing and snorting sounds, calm and friendly. Ultra-realistic, natural lighting, immersive audio, documentary-style realism.",
2646
- "No LoRA",
2647
- "16:9",
2648
- "تبدیل تصویر به ویدیو",
2649
- None,
2650
- None,
2651
- None,
2652
- ],
2653
- [
2654
- "examples/wednesday.png",
2655
- "A cinematic dolly out of Wednesday Addams frozen mid-dance on a dark, blue-lit ballroom floor as students move indistinctly behind her, their footsteps and muffled music reduced to a distant, underwater thrum; the audio foregrounds her steady breathing and the faint rustle of fabric as she slowly raises one arm, never breaking eye contact with the camera, then after a deliberately long silence she speaks in a flat, dry, perfectly controlled voice, “I don’t dance… I vibe code,” each word crisp and unemotional, followed by an abrupt cutoff of her voice as the background sound swells slightly, reinforcing the deadpan humor, with precise lip sync, minimal facial movement, stark gothic lighting, and cinematic realism.",
2656
- "Zoom Out",
2657
- "16:9",
2658
- "تبدیل تصویر به ویدیو",
2659
- None,
2660
- None,
2661
- None,
2662
- ],
2663
- [
2664
- "examples/astronaut.png",
2665
- "An astronaut hatches from a fragile egg on the surface of the Moon, the shell cracking and peeling apart in gentle low-gravity motion. Fine lunar dust lifts and drifts outward with each movement, floating in slow arcs before settling back onto the ground. The astronaut pushes free in a deliberate, weightless motion, small fragments of the egg tumbling and spinning through the air. In the background, the deep darkness of space subtly shifts as stars glide with the camera's movement, emphasizing vast depth and scale. The camera performs a smooth, cinematic slow push-in, with natural parallax between the foreground dust, the astronaut, and the distant starfield. Ultra-realistic detail, physically accurate low-gravity motion, cinematic lighting, and a breath-taking, movie-like shot.",
2666
- "Static",
2667
- "1:1",
2668
- "تبدیل تصویر به ویدیو",
2669
- None,
2670
- None,
2671
- None,
2672
- ],
2673
  ]
2674
 
 
2675
  examples_obj = create_examples(
2676
  examples=examples_list,
2677
  fn=generate_video_example,
2678
- inputs=[first_frame, prompt_ui, camera_ui, resolution_ui, radioanimated_mode, input_video, audio_input, end_frame],
2679
- outputs = [output_video],
2680
  label="نمونه‌ها",
2681
  cache_examples=True,
2682
  visible=False
2683
  )
2684
 
2685
  preset_gallery = PresetGallery(
2686
- items=[
2687
- {"thumb": "examples/supergirl-2.png", "label": "تصویر و صدا به ویدیو"},
2688
- {"thumb": "examples/frame3.png", "label": "تصویر اول و آخر"},
2689
- {"thumb": "examples/supergirl.png", "label": "تصویر به ویدیو (عروسک)"},
2690
- {"thumb": "examples/highland.png", "label": "تصویر به ویدیو (گاو)"},
2691
- {"thumb": "examples/wednesday.png", "label": "تصویر به ویدیو (ونزدی)"},
2692
- {"thumb": "examples/astronaut.png", "label": "تصویر به ویدیو (فضانورد)"},
2693
- ],
2694
  title="برای شروع روی یکی از نمونه‌ها کلیک کنید",
2695
  )
2696
 
@@ -2708,23 +2882,16 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2708
  api_visibility="private",
2709
  )
2710
 
 
 
 
2711
  preset_gallery.change(
2712
  fn=apply_example,
2713
  inputs=preset_gallery,
2714
- outputs=[
2715
- first_frame,
2716
- prompt_ui,
2717
- camera_ui,
2718
- resolution_ui,
2719
- radioanimated_mode,
2720
- input_video,
2721
- audio_input,
2722
- audio_ui,
2723
- end_frame,
2724
- output_video # Clears the output video
2725
- ],
2726
  api_visibility="private",
2727
  )
 
2728
 
2729
  if __name__ == "__main__":
2730
- demo.launch(ssr_mode=False, mcp_server=True, css=css, allowed_paths=["./examples"])
 
1529
  width: fit-content;
1530
  font-family: sans-serif;
1531
  }
1532
+ .toggle-container input {
1533
  display: none;
1534
  }
1535
  .toggle-container label {
 
1557
  z-index: 1;
1558
  }
1559
  /* When "True" is checked */
1560
+ #true:checked ~ label {
1561
  color: #ffd6ff; /* light pink text */
1562
  }
1563
  /* When "False" is checked */
1564
+ #false:checked ~ label {
1565
  color: #ffd6ff; /* light pink text */
1566
  }
1567
  /* Move highlight to right side when False is checked */
 
1920
  }
1921
 
1922
  /* show tick ONLY for selected item */
1923
+ .cd-item::after{
1924
  opacity: 1;
1925
  }
1926
 
 
2179
  }
2180
 
2181
  /* dim others while hovering */
2182
+ .pg-card .pg-img{
2183
  opacity: 0.35;
2184
  filter: saturate(0.9);
2185
  }
2186
 
2187
  /* keep hovered/active crisp */
2188
+ .pg-card .pg-img{
2189
  opacity: 1.0;
2190
  filter: none;
2191
  }
 
2283
  .api-logo, .built-with {
2284
  display: none !important;
2285
  }
2286
+
2287
+ /* --- IP Reset Guide CSS (مودال) --- */
2288
+ :root {
2289
+ --guide-bg: rgba(255, 255, 255, 0.98);
2290
+ --guide-border: rgba(102, 126, 234, 0.2);
2291
+ --guide-text-title: #2d3748;
2292
+ --guide-text-body: #4a5568;
2293
+ --guide-accent: #667eea;
2294
+ --primary-gradient-guide: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2295
+ --success-gradient-guide: linear-gradient(135deg, #56ab2f 0%, #a8e063 100%);
2296
+ --radius-md-guide: 12px;
2297
+ --radius-lg-guide: 16px;
2298
+ --shadow-sm: 0 1px 2px 0 rgba(26, 32, 44, 0.03);
2299
+ --shadow-md: 0 4px 6px -1px rgba(26, 32, 44, 0.05), 0 2px 4px -2px rgba(26, 32, 44, 0.04);
2300
+ --shadow-xl: 0 20px 25px -5px rgba(26, 32, 44, 0.07), 0 8px 10px -6px rgba(26, 32, 44, 0.05);
2301
+ }
2302
+
2303
+ @keyframes float {
2304
+ 0%, 100% { transform: translateY(0px); }
2305
+ 50% { transform: translateY(-10px); }
2306
+ }
2307
+ @keyframes slideInUp {
2308
+ from { opacity: 0; transform: translateY(30px); }
2309
+ to { opacity: 1; transform: translateY(0); }
2310
+ }
2311
+
2312
+ .ip-reset-guide-container {
2313
+ text-align: right;
2314
+ direction: rtl;
2315
+ background: var(--guide-bg);
2316
+ backdrop-filter: blur(10px);
2317
+ padding: 20px;
2318
+ border-radius: var(--radius-lg-guide);
2319
+ box-shadow: var(--shadow-xl);
2320
+ border: 1px solid var(--guide-border);
2321
+ animation: slideInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1) both;
2322
+ width: 90%;
2323
+ max-width: 420px;
2324
+ max-height: 90vh;
2325
+ overflow-y: auto;
2326
+ position: relative;
2327
+ box-sizing: border-box;
2328
+ font-family: 'Vazirmatn', sans-serif !important;
2329
+ }
2330
+ .ip-reset-guide-container::before {
2331
+ content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: var(--primary-gradient-guide);
2332
+ }
2333
+ .guide-header { display: flex; align-items: center; margin-bottom: 15px; }
2334
+ .guide-header-icon { width: 45px; height: 45px; margin-left: 15px; animation: float 3s ease-in-out infinite; flex-shrink: 0; }
2335
+ .guide-header h2 { font-size: 1.2rem; color: var(--guide-text-title); font-weight: 700; margin: 0; }
2336
+ .guide-header p { color: var(--guide-text-body); font-size: 0.8rem; margin-top: 3px; margin-bottom: 0; }
2337
+
2338
+ .guide-content { font-size: 0.9rem; color: var(--guide-text-body); line-height: 1.6; }
2339
+
2340
+ .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: 12px; margin: 12px 0; position: relative; overflow: hidden; }
2341
+ .info-card p { font-size: 0.85rem; line-height: 1.6; margin: 0; }
2342
+ .info-card::before { content: ''; position: absolute; top: 0; right: 0; width: 3px; height: 100%; background: var(--primary-gradient-guide); }
2343
+ .info-card-header { display: flex; align-items: center; margin-bottom: 8px; }
2344
+ .info-card-icon { width: 18px; height: 18px; margin-left: 8px; }
2345
+ .info-card-title { font-weight: 600; color: var(--guide-text-title); font-size: 0.95rem; }
2346
+
2347
+ .summary-section { margin-top: 12px; padding: 12px; 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; }
2348
+ .summary-section::before { content: ''; position: absolute; top: 0; right: 0; width: 3px; height: 100%; background: var(--success-gradient-guide); }
2349
+ .summary-header { display: flex; align-items: center; margin-bottom: 8px; }
2350
+ .summary-icon { width: 18px; height: 18px; margin-left: 8px; }
2351
+ .summary-title { font-weight: 600; color: #2f5a33; font-size: 0.95rem; }
2352
+ .summary-text { color: #2f5a33; font-size: 0.85rem; line-height: 1.6; }
2353
+
2354
+ .video-button-container { text-align: center; margin: 20px 0 15px 0; width: 100%; }
2355
+ .elegant-video-button {
2356
+ display: inline-flex !important;
2357
+ align-items: center;
2358
+ justify-content: center;
2359
+ padding: 10px 20px !important;
2360
+ background-color: #fff !important;
2361
+ color: var(--guide-accent) !important;
2362
+ border: 1px solid #e2e8f0 !important;
2363
+ text-decoration: none;
2364
+ border-radius: 50px !important;
2365
+ font-weight: 600 !important;
2366
+ font-size: 0.9rem !important;
2367
+ cursor: pointer !important;
2368
+ font-family: inherit;
2369
+ transition: all 0.3s ease !important;
2370
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05) !important;
2371
+ width: auto !important;
2372
+ }
2373
+ .elegant-video-button:hover {
2374
+ background: var(--primary-gradient-guide) !important;
2375
+ color: white !important;
2376
+ border-color: transparent !important;
2377
+ transform: translateY(-2px);
2378
+ box-shadow: 0 6px 16px rgba(102, 126, 234, 0.3) !important;
2379
+ }
2380
+ .elegant-video-button-icon { width: 18px; height: 18px; margin-left: 8px; fill: currentColor; }
2381
+
2382
+ .guide-actions {
2383
+ display: flex !important;
2384
+ gap: 12px !important;
2385
+ margin-top: 20px;
2386
+ padding-top: 20px;
2387
+ border-top: 1px solid #e2e8f0;
2388
+ width: 100% !important;
2389
+ }
2390
+ .action-button {
2391
+ padding: 12px 15px !important;
2392
+ border: none !important;
2393
+ border-radius: 12px !important;
2394
+ font-size: 0.95rem !important;
2395
+ font-weight: 600 !important;
2396
+ cursor: pointer !important;
2397
+ flex: 1 !important;
2398
+ transition: all 0.3s ease !important;
2399
+ display: flex !important;
2400
+ align-items: center;
2401
+ justify-content: center;
2402
+ font-family: inherit;
2403
+ height: 48px !important;
2404
+ }
2405
+ .action-button-icon { width: 20px; height: 20px; margin-right: 0; margin-left: 8px; }
2406
+
2407
+ .back-button {
2408
+ background: white !important;
2409
+ color: var(--guide-text-body) !important;
2410
+ border: 2px solid #e2e8f0 !important;
2411
+ }
2412
+ .back-button:hover {
2413
+ background: #f7fafc !important;
2414
+ border-color: var(--guide-accent) !important;
2415
+ transform: translateY(-2px);
2416
+ box-shadow: var(--shadow-md) !important;
2417
+ }
2418
+
2419
+ .retry-button {
2420
+ background: var(--primary-gradient-guide) !important;
2421
+ color: white !important;
2422
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3) !important;
2423
+ }
2424
+ .retry-button:hover {
2425
+ transform: translateY(-2px);
2426
+ box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4) !important;
2427
+ }
2428
+
2429
+ /* Force toast transparency for cleaner Custom Modal */
2430
+ .toast-body { direction: rtl !important; text-align: right !important; background: transparent !important; box-shadow: none !important; border: none !important; padding: 0 !important; max-width: 100% !important; width: auto !important; }
2431
+ .toast-wrap { background: transparent !important; border: none !important; box-shadow: none !important; }
2432
+
2433
  """
2434
 
2435
 
 
2472
  idx = int(idx)
2473
 
2474
  # Read the example row from your list
2475
+ img, prompt_txt, cam, res, mode, vid, aud, end_img = examples_list
2476
 
2477
  img_path = img if img else None
2478
  vid_path = vid if vid else None
 
2506
 
2507
  with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
2508
 
2509
+ # Updated Header to Persian + Injecting Global Javascript for GPU Quota Scanner
2510
  gr.HTML(
2511
  """
2512
  <div style="text-align: center; padding: 20px;">
 
2517
  با پشتیبانی از صدا و دو تصویر
2518
  </p>
2519
  </div>
2520
+
2521
+ <script>
2522
+ document.addEventListener('DOMContentLoaded', () => {
2523
+ // RETRY FUNCTION
2524
+ window.retryGeneration = function() {
2525
+ const modal = document.getElementById('custom-quota-modal');
2526
+ if (modal) modal.remove();
2527
+
2528
+ const runBtn = document.getElementById('generate-btn'); // Using the ID of our generate button
2529
+ if(runBtn) runBtn.click();
2530
+ };
2531
+
2532
+ // Close function
2533
+ window.closeErrorModal = function() {
2534
+ const modal = document.getElementById('custom-quota-modal');
2535
+ if (modal) modal.remove();
2536
+ };
2537
+
2538
+ // SHOW MODAL FUNCTION
2539
+ const showQuotaModal = () => {
2540
+ if (document.getElementById('custom-quota-modal')) return;
2541
+
2542
+ const modalHtml = `
2543
+ <div id="custom-quota-modal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); backdrop-filter: blur(5px); z-index: 99999; display: flex; align-items: center; justify-content: center; font-family: 'Vazirmatn', sans-serif;">
2544
+ <div class="ip-reset-guide-container">
2545
+ <div class="guide-header">
2546
+ <svg class="guide-header-icon" viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
2547
+ <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>
2548
+ <circle cx="50" cy="50" r="45" fill="url(#grad1)" opacity="0.1"></circle>
2549
+ <circle cx="50" cy="50" r="35" fill="none" stroke="url(#grad1)" stroke-width="2" opacity="0.3"></circle>
2550
+ <path d="M35 50 L45 60 L65 40" stroke="url(#grad1)" stroke-width="4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path>
2551
+ <circle cx="65" cy="35" r="8" fill="#fee140"></circle>
2552
+ <path d="M62 35 L68 35 M65 32 L65 38" stroke="white" stroke-width="2" stroke-linecap="round"></path>
2553
+ </svg>
2554
+ <div>
2555
+ <h2>یک قدم تا ساخت ویدیوهای جدید</h2>
2556
+ <p>نیازمند تغییر نقطه دستیابی</p>
2557
+ </div>
2558
+ </div>
2559
+
2560
+ <div class="guide-content">
2561
+ <div class="info-card">
2562
+ <div class="info-card-header">
2563
+ <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>
2564
+ <span class="info-card-title">راه حل سریع</span>
2565
+ </div>
2566
+ <p>طبق ویدیو آموزشی پایین بین نقطه دستیابی جابجا شوید تلاش مجدد بزنید تا ویدیوها مجدداً تولید بشه.</p>
2567
+ </div>
2568
+
2569
+ <div class="summary-section">
2570
+ <div class="summary-header">
2571
+ <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>
2572
+ <span class="summary-title">خلاصه راهنما</span>
2573
+ </div>
2574
+ <div class="summary-text">هربار که این صفحه را مشاهده کردید: از اینترنت سیم‌کارت استفاده کنید، VPN را خاموش کرده و طبق ویدیو آموزشی پایین نقطه دستیابی رو تغییر دهید. «تلاش مجدد» کلیک کنید. با این روش ساده می‌توانید به صورت نامحدود ویدیو بسازید! ☘️</div>
2575
+ </div>
2576
+
2577
+ <div class="video-button-container">
2578
+ <button onclick="parent.postMessage({ type: 'NAVIGATE_TO_URL', url: '#/nav/online/news/getSingle/1149635/eyJpdiI6IjhHVGhPQWJwb3E0cjRXbnFWTW5BaUE9PSIsInZhbHVlIjoiS1V0dTdvT21wbXAwSXZaK1RCTG1pVXZqdlFJa1hXV1RKa2FLem9zU3pXMjd5MmlVOGc2YWY0NVdNR3h3Smp1aSIsIm1hYyI6IjY1NTA5ZDYzMjAzMTJhMGQyMWQ4NjA4ZDgyNGZjZDVlY2MyNjdiMjA2NWYzOWRjY2M4ZmVjYWRlMWNlMWQ3ODEiLCJ0YWciOiIifQ==/21135210' }, '*')" class="elegant-video-button">
2579
+ <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>
2580
+ <span>دیدن ویدیو آموزشی استفاده نامحدود</span>
2581
+ </button>
2582
+ </div>
2583
+ </div>
2584
+
2585
+ <div class="guide-actions">
2586
+ <button class="action-button back-button" onclick="window.closeErrorModal()">
2587
+ <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>
2588
+ <span>بازگشت</span>
2589
+ </button>
2590
+ <button class="action-button retry-button" onclick="window.retryGeneration()">
2591
+ <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>
2592
+ <span>تلاش مجدد</span>
2593
+ </button>
2594
+ </div>
2595
+ </div>
2596
+ </div>
2597
+ `;
2598
+
2599
+ document.body.insertAdjacentHTML('beforeend', modalHtml);
2600
+
2601
+ // Auto close after 15 seconds
2602
+ setTimeout(() => {
2603
+ window.closeErrorModal();
2604
+ }, 15000);
2605
+ };
2606
+
2607
+ // ERROR SCANNER
2608
+ setInterval(() => {
2609
+ const potentialErrors = document.querySelectorAll('.toast-body, .error, .toast-wrap, .eta-bar, div');
2610
+
2611
+ potentialErrors.forEach(el => {
2612
+ const text = el.innerText || "";
2613
+ if (text.toLowerCase().includes('quota') || text.toLowerCase().includes('exceeded')) {
2614
+
2615
+ showQuotaModal();
2616
+
2617
+ // Immediately hide the Gradio error
2618
+ el.style.display = 'none';
2619
+ el.style.opacity = '0';
2620
+ el.innerText = '';
2621
+
2622
+ const parentWrap = el.closest('.toast-wrap');
2623
+ if(parentWrap) parentWrap.style.display = 'none';
2624
+ }
2625
+ });
2626
+ }, 100);
2627
+ });
2628
+ </script>
2629
  """
2630
  )
2631
 
 
2633
  with gr.Row(elem_id="mode-row"):
2634
  # Updated choices to Persian
2635
  radioanimated_mode = RadioAnimated(
2636
+ choices=,
2637
  value="تبدیل تصویر به ویدیو",
2638
  elem_id="radioanimated_mode"
2639
  )
 
2704
  # Hidden real audio input (backend value)
2705
  audio_input = gr.File(
2706
  label="Audio (Optional)",
2707
+ file_types=,
2708
  type="filepath",
2709
  elem_id="audio_input_hidden",
2710
  )
 
2747
 
2748
  with gr.Row(elem_id="controls-row"):
2749
 
2750
+ # REMOVED 15s from choices
2751
  duration_ui = CameraDropdown(
2752
+ choices=,
2753
  value="5s",
2754
  title="مدت زمان ویدیو",
2755
  elem_id="duration_ui"
2756
  )
2757
 
2758
+ # Reduced maximum to 10.0
2759
  duration = gr.Slider(
2760
  label="Duration (seconds)",
2761
  minimum=1.0,
 
2779
 
2780
 
2781
  resolution_ui = CameraDropdown(
2782
+ choices=,
 
 
 
 
2783
  value="16:9",
2784
  title="ابعاد تصویر",
2785
  elem_id="resolution_ui"
 
2790
  height = gr.Number(label="Height", value=DEFAULT_1_STAGE_HEIGHT, precision=0, visible=False)
2791
 
2792
  camera_ui = CameraDropdown(
2793
+ choices=,
2794
  value="No LoRA",
2795
  title="افکت دوربین (LoRA)",
2796
  elem_id="camera_ui",
 
2799
  # Hidden real dropdown (backend value)
2800
  camera_lora = gr.Dropdown(
2801
  label="Camera Control LoRA",
2802
+ choices=,
2803
  value="No LoRA",
2804
  visible=False
2805
  )
2806
 
2807
+ generate_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient", elem_id="generate-btn")
2808
 
2809
 
2810
  camera_ui.change(
 
2817
  radioanimated_mode.change(
2818
  fn=on_mode_change,
2819
  inputs=radioanimated_mode,
2820
+ outputs=,
2821
  api_visibility="private",
2822
  )
2823
 
 
2825
  duration_ui.change(
2826
  fn=apply_duration,
2827
  inputs=duration_ui,
2828
+ outputs=,
2829
  api_visibility="private"
2830
  )
2831
  resolution_ui.change(
2832
  fn=apply_resolution,
2833
  inputs=resolution_ui,
2834
+ outputs=,
2835
  api_visibility="private"
2836
  )
2837
  prompt_ui.change(
 
2844
 
2845
  generate_btn.click(
2846
  fn=generate_video,
2847
+ inputs=,
2848
+ outputs=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2849
  )
2850
 
2851
  # Updated Examples to use Persian modes
2852
+ examples_list = [,,,,,,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2853
  ]
2854
 
2855
+ # Create examples object just for caching/display, logic handled manually below
2856
  examples_obj = create_examples(
2857
  examples=examples_list,
2858
  fn=generate_video_example,
2859
+ inputs=,
2860
+ outputs =,
2861
  label="نمونه‌ها",
2862
  cache_examples=True,
2863
  visible=False
2864
  )
2865
 
2866
  preset_gallery = PresetGallery(
2867
+ items=,
 
 
 
 
 
 
 
2868
  title="برای شروع روی یکی از نمونه‌ها کلیک کنید",
2869
  )
2870
 
 
2882
  api_visibility="private",
2883
  )
2884
 
2885
+ # REMOVED the run_cached_example_by_index logic.
2886
+ # Just populate the fields.
2887
+
2888
  preset_gallery.change(
2889
  fn=apply_example,
2890
  inputs=preset_gallery,
2891
+ outputs=,
 
 
 
 
 
 
 
 
 
 
 
2892
  api_visibility="private",
2893
  )
2894
+ # The .then() block is removed, so generation won't start automatically.
2895
 
2896
  if __name__ == "__main__":
2897
+ demo.launch(ssr_mode=False, mcp_server=True, css=css, allowed_paths=)