Spaces:
Paused
Paused
File size: 8,404 Bytes
1030ba2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# ui/layout.py
# This file defines the Gradio UI layout for the goan application.
import gradio as gr
from gradio_modal import Modal
# Import workspace manager to get the default output folder path
from . import workspace as workspace_manager
def create_ui():
"""
Creates the Gradio UI layout and returns a dictionary of all UI components.
This separation of layout from logic makes the main script cleaner.
"""
# Define a dictionary to hold all UI components, which will be returned.
components = {}
css = """
#queue_df { font-size: 0.85rem; }
#queue_df th:nth-child(1), #queue_df td:nth-child(1) { width: 5%; }
#queue_df th:nth-child(2), #queue_df td:nth-child(2) { width: 10%; }
#queue_df th:nth-child(3), #queue_df td:nth-child(3) { width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#queue_df th:nth-child(4), #queue_df td:nth-child(4) { width: 8%; }
#queue_df th:nth-child(5), #queue_df td:nth-child(5) { width: 8%; }
#queue_df th:nth-child(6), #queue_df td:nth-child(6) { width: 10%; text-align: center; }
#queue_df th:nth-child(7), #queue_df td:nth-child(7),
#queue_df th:nth-child(8), #queue_df td:nth-child(8),
#queue_df th:nth-child(9), #queue_df td:nth-child(9),
#queue_df th:nth-child(10), #queue_df td:nth-child(10) { width: 4%; cursor: pointer; text-align: center; }
#queue_df td:hover { background-color: #f0f0f0; }
.gradio-container { max-width: 95% !important; margin: auto !important; }
"""
block = gr.Blocks(css=css, title="goan").queue()
components['block'] = block
with block:
# The app_state dictionary holds all transient state for the UI
app_state = gr.State({
"queue_state": {"queue": [], "next_id": 1, "processing": False, "editing_task_id": None},
"last_completed_video_path": None
})
components['app_state'] = app_state
gr.Markdown('# goan (Powered by FramePack)')
with Modal(visible=False) as metadata_modal:
components['metadata_modal'] = metadata_modal
gr.Markdown("Image has saved parameters. Overwrite current creative settings?")
with gr.Row():
components['cancel_metadata_btn'] = gr.Button("No")
components['confirm_metadata_btn'] = gr.Button("Yes, Apply", variant="primary")
# --- Start of layout structure ---
# TOP ZONE: A row with two columns.
# Column 1 (scale=1): Image input and primary queue actions.
# Column 2 (scale=2): Prompting.
with gr.Row():
# Column 1: Input Image & Primary Actions
with gr.Column(scale=1, min_width=300):
components['input_image_gallery_ui'] = gr.Gallery(type="pil", label="Input Image(s)", height=220)
components['add_task_button'] = gr.Button("Add to Queue", variant="secondary")
components['process_queue_button'] = gr.Button("▶️ Process Queue", variant="primary")
components['abort_task_button'] = gr.Button("⏹️ Abort", variant="stop", interactive=True) # default to active on startup in case service is still running
components['cancel_edit_task_button'] = gr.Button("Cancel Edit", visible=False, variant="secondary")
# Column 2: Prompts
with gr.Column(scale=2, min_width=600):
components['prompt_ui'] = gr.Textbox(label="Prompt", lines=10)
components['n_prompt_ui'] = gr.Textbox(label="Negative Prompt", lines=4)
# MIDDLE ZONE: Full-width task queue display and file operations
with gr.Group():
gr.Markdown("## Task Queue")
components['queue_df_display_ui'] = gr.DataFrame(headers=["ID", "Status", "Prompt", "Length", "Steps", "Input", "↑", "↓", "✖", "✎"], datatype=["number","markdown","markdown","str","number","markdown","markdown","markdown","markdown","markdown"], col_count=(10,"fixed"), interactive=False, visible=False, elem_id="queue_df")
with gr.Row():
components['save_queue_zip_b64_output'] = gr.Text(visible=False)
components['save_queue_button_ui'] = gr.DownloadButton("Save Queue", size="sm")
components['load_queue_button_ui'] = gr.UploadButton("Load Queue", file_types=[".zip"], size="sm")
components['clear_queue_button_ui'] = gr.Button("Clear Pending", size="sm", variant="stop")
# BOTTOM ZONE: A row split into two columns for Settings and Output
with gr.Row(equal_height=False):
# Column 1: All settings and parameters
with gr.Column(scale=1):
with gr.Row():
components['total_second_length_ui'] = gr.Slider(label="Video Length (s)", minimum=0.1, maximum=120, value=5.0, step=0.1)
components['seed_ui'] = gr.Number(label="Seed", value=-1, precision=0)
with gr.Accordion("Advanced Settings", open=False): # keep default closed on startup
components['total_segments_display_ui'] = gr.Markdown("Calculated Total Segments: N/A")
components['preview_frequency_ui'] = gr.Slider(label="Preview Freq.", minimum=0, maximum=100, value=5, step=1)
components['segments_to_decode_csv_ui'] = gr.Textbox(label="Preview Segments CSV", value="")
with gr.Row():
components['gs_ui'] = gr.Slider(label="Distilled CFG Start", minimum=1.0, maximum=32.0, value=10.0, step=0.01)
components['gs_schedule_shape_ui'] = gr.Radio(["Off", "Linear"], label="Variable CFG", value="Off")
components['gs_final_ui'] = gr.Slider(label="Distilled CFG End", minimum=1.0, maximum=32.0, value=10.0, step=0.01, interactive=False)
components['cfg_ui'] = gr.Slider(label="CFG (Real)", minimum=1.0, maximum=32.0, value=1.0, step=0.01)
components['steps_ui'] = gr.Slider(label="Steps", minimum=1, maximum=100, value=25, step=1)
components['rs_ui'] = gr.Slider(label="RS", minimum=0.0, maximum=32.0, value=0.0, step=0.01, visible=False)
with gr.Accordion("Debug Settings", open=False): # keep default closed on startup
components['use_teacache_ui'] = gr.Checkbox(label='Use TeaCache', value=True)
components['use_fp32_transformer_output_checkbox_ui'] = gr.Checkbox(label="Use FP32 Transformer Output", value=False)
components['gpu_memory_preservation_ui'] = gr.Slider(label="GPU Preserved (GB)", minimum=4, maximum=128, value=6.0, step=0.1)
components['mp4_crf_ui'] = gr.Slider(label="MP4 CRF", minimum=0, maximum=51, value=18, step=1)
components['latent_window_size_ui'] = gr.Slider(label="Latent Window Size", minimum=1, maximum=33, value=9, step=1, visible=False)
components['output_folder_ui_ctrl'] = gr.Textbox(label="Output Folder", value=workspace_manager.outputs_folder)
components['save_as_default_button'] = gr.Button("Save as Default", variant="secondary")
components['reset_ui_button'] = gr.Button("Save & Refresh UI", variant="secondary")
# UI and Workspace Management Buttons
with gr.Row():
components['save_workspace_button'] = gr.Button("Save Workspace", variant="secondary")
components['load_workspace_button'] = gr.Button("Load Workspace", variant="secondary")
# Column 2: Live Preview and Final Output
with gr.Column(scale=1):
gr.Markdown("## Live Preview & Output")
components['current_task_preview_image_ui'] = gr.Image(interactive=False, visible=False)
components['current_task_progress_desc_ui'] = gr.Markdown('')
components['current_task_progress_bar_ui'] = gr.HTML('')
# Set a height on the video player to help with layout stability
components['last_finished_video_ui'] = gr.Video(interactive=True, autoplay=False, height=540)
return components |