import gradio as gr import config import lora_loader import prompt_enhancer from image_utils import load_image_from_url def render_column_inputs(): with gr.Column(scale=4): input_image_component = gr.Image( type="pil", label="🖼️ Input Image", sources=["upload", "clipboard"], height=240 ) with gr.Row(): image_url_input = gr.Textbox( label="🌐 Load Input Image from URL", placeholder="e.g. https://example.com/image.jpg", value="", scale=3 ) load_image_btn = gr.Button("📥 Load Image", variant="secondary", scale=1) load_image_btn.click( fn=load_image_from_url, inputs=[image_url_input], outputs=[input_image_component] ) with gr.Accordion("✨ Base Prompt & Style Modifiers", open=True): prompt_input = gr.Textbox( label="✨ Base Prompt", value=config.default_prompt_i2v, lines=3, max_lines=6, placeholder="Describe global style, lighting, or overall video mood...", info="💡 Note: If Prompt Relay is enabled, Base Prompt is ignored (Prompt Relay takes full control)." ) with gr.Row(): describe_image_btn = gr.Button("🔍 Describe Image (CPU ~1s)", variant="secondary") enhance_prompt_btn = gr.Button("✨ Auto-Enhance Prompt (CPU)", variant="secondary") describe_image_btn.click( fn=prompt_enhancer.describe_image, inputs=[input_image_component], outputs=[prompt_input] ) enhance_prompt_btn.click( fn=prompt_enhancer.enhance_prompt, inputs=[prompt_input], outputs=[prompt_input] ) duration_seconds_input = gr.Slider( minimum=config.MIN_DURATION, maximum=config.MAX_DURATION, step=0.1, value=4.0, label="⏱️ Duration (seconds)", info=f"Set to 4.0s for direct 65-frame model generation." ) motion_extension_dropdown = gr.Dropdown( choices=[ "⚡ Real-Time RIFE Interpolation (32/64 FPS Ultra-Smooth)", "🔂 Ending-Only Boomerang Loop (Real Speed, Tail 1.5s Loop)", "🔂 Classic Full Boomerang Loop (100% Real-Speed Forward+Reverse)", "🌊 Adaptive Motion Speed Ramping (Ease-In/Out Curve)", "🐢 Cinematic Slow-Motion (16 FPS RIFE Time-Stretch)" ], value="⚡ Real-Time RIFE Interpolation (32/64 FPS Ultra-Smooth)", label="🎬 Motion Extension & Loop Technique", info="Choose Real-Time RIFE (Default), Ending-Only Boomerang, Classic Boomerang, or Speed Ramping." ) frame_multi = gr.Dropdown( choices=[ (f"16 FPS (Original Duration)", config.FIXED_FPS), (f"32 FPS (2x RIFE -> Converts 2s GPU to 4s Video)", config.FIXED_FPS*2), (f"64 FPS (4x RIFE -> Converts 2s GPU to 8s Video)", config.FIXED_FPS*4), ], value=config.FIXED_FPS, label="🎬 Video Fluidity & RIFE Extension (FPS)", info="Select 32 FPS (2x RIFE) to extend 2s GPU output into a smooth 4s video on CPU (0 GPU quota)." ) noise_temperature_slider = gr.Slider( minimum=0.1, maximum=2.0, step=0.05, value=1.0, label="🌡️ Noise Temperature", info="Scales initial noise variance (0.5 = focused & smooth, 1.0 = standard, 1.5 = high visual randomness)." ) with gr.Accordion("🔗 Custom Civitai / Direct LoRA URL & CPU Cache", open=False): with gr.Row(): cached_lora_dropdown = gr.Dropdown( label="📦 Pre-Downloaded / Cached LoRAs (CPU Storage)", choices=lora_loader.list_cached_loras(), value="(None / Disable)", scale=3, info="Select any previously downloaded LoRA from CPU cache" ) refresh_cached_lora_btn = gr.Button("🔄 Refresh List", variant="secondary", scale=1) custom_lora_url_input = gr.Textbox( label="Civitai / Direct LoRA Download URL (New Download)", placeholder="e.g. https://civitai.red/api/download/models/2098405?fileId=1994044", value="", info="Paste any Civitai or direct HTTP/HTTPS .safetensors link to download to CPU cache" ) custom_lora_scale_input = gr.Slider( label="Custom LoRA Weight Scale", minimum=0.0, maximum=2.0, step=0.05, value=1.0, info="Strength of the custom LoRA effect" ) with gr.Row(): download_lora_btn = gr.Button("📥 Pre-Download LoRA to Cache (CPU)", variant="secondary") download_status_box = gr.HTML() download_lora_btn.click( fn=lora_loader.download_custom_lora_ui_action, inputs=[custom_lora_url_input], outputs=[download_status_box, cached_lora_dropdown] ) refresh_cached_lora_btn.click( fn=lambda: gr.update(choices=lora_loader.list_cached_loras()), inputs=None, outputs=[cached_lora_dropdown] ) with gr.Row(): safe_mode_checkbox = gr.Checkbox( label="🛠️ Safe Mode", value=False, info="Requests extra processing buffer time to prevent timeout." ) generate_button = gr.Button("🚀 Generate Video", variant="primary", elem_id="generate-btn") extra_gpu_buffer_slider = gr.Slider( label="⚡ Extra GPU Reservation Buffer (Seconds)", minimum=0, maximum=10, step=1, value=3, info="Manually add 0-10 extra seconds to ZeroGPU time reservation to prevent timeout during heavy processing" ) return { "input_image_component": input_image_component, "image_url_input": image_url_input, "load_image_btn": load_image_btn, "prompt_input": prompt_input, "describe_image_btn": describe_image_btn, "enhance_prompt_btn": enhance_prompt_btn, "duration_seconds_input": duration_seconds_input, "motion_extension_dropdown": motion_extension_dropdown, "frame_multi": frame_multi, "noise_temperature_slider": noise_temperature_slider, "cached_lora_dropdown": cached_lora_dropdown, "custom_lora_url_input": custom_lora_url_input, "custom_lora_scale_input": custom_lora_scale_input, "extra_gpu_buffer_slider": extra_gpu_buffer_slider, "safe_mode_checkbox": safe_mode_checkbox, "generate_button": generate_button }