diff --git a/acestep/ui/gradio/events/__init__.py b/acestep/ui/gradio/events/__init__.py index 177b4b58..936a7eea 100644 --- a/acestep/ui/gradio/events/__init__.py +++ b/acestep/ui/gradio/events/__init__.py @@ -423,7 +423,7 @@ def setup_event_handlers(demo, dit_handler, llm_handler, dataset_handler, datase generation_section["custom_mode_group"], generation_section["generate_btn"], generation_section["simple_sample_created"], - generation_section["optional_params_accordion"], + generation_section["optional_params_section"], generation_section["task_type"], generation_section["src_audio_row"], generation_section["repainting_group"], @@ -692,7 +692,7 @@ def setup_event_handlers(demo, dit_handler, llm_handler, dataset_handler, datase generation_section["custom_mode_group"], generation_section["generate_btn"], generation_section["simple_sample_created"], - generation_section["optional_params_accordion"], + generation_section["optional_params_section"], generation_section["task_type"], generation_section["src_audio_row"], generation_section["repainting_group"], diff --git a/acestep/ui/gradio/events/generation/mode_ui.py b/acestep/ui/gradio/events/generation/mode_ui.py index 1b61bba4..468a5414 100644 --- a/acestep/ui/gradio/events/generation/mode_ui.py +++ b/acestep/ui/gradio/events/generation/mode_ui.py @@ -145,7 +145,7 @@ def compute_mode_ui_updates(mode: str, llm_handler=None, previous_mode: str = "C gr.update(visible=show_custom_group), # 1: custom_mode_group generate_btn_update, # 2: generate_btn False, # 3: simple_sample_created - gr.Accordion(visible=show_optional, open=False), # 4: optional_params_accordion + gr.Column(visible=show_optional), # 4: optional_params_section gr.update(value=task_type, elem_classes=["has-info-container"]), # 5: task_type gr.update(visible=show_src_audio), # 6: src_audio_row gr.update(visible=show_repainting), # 7: repainting_group diff --git a/acestep/ui/gradio/help_content.py b/acestep/ui/gradio/help_content.py index 49df6672..12127de1 100644 --- a/acestep/ui/gradio/help_content.py +++ b/acestep/ui/gradio/help_content.py @@ -8,6 +8,7 @@ space and can be placed inside any existing row or header without creating extra blank rows. """ +from pathlib import Path import gradio as gr from acestep.ui.gradio.i18n import t @@ -181,7 +182,7 @@ def create_help_button(section_key: str) -> gr.HTML: """, - elem_classes=["help-inline-container"], + elem_classes=["help-inline-container", "no-grow"], ) return html @@ -190,108 +191,5 @@ def create_help_button(section_key: str) -> gr.HTML: # --------------------------------------------------------------------------- # CSS to be injected into the main Blocks CSS string. # --------------------------------------------------------------------------- -HELP_MODAL_CSS = """ -/* ---- Inline help button container ---- */ -.help-inline-container { - min-height: 0 !important; - padding: 0 !important; - margin: 0 !important; - display: inline-flex !important; - align-items: center !important; - flex-shrink: 0 !important; - max-width: 32px !important; - min-width: 32px !important; - overflow: visible !important; -} - -.help-inline-wrapper { - display: inline-flex; - align-items: center; - line-height: 1; -} - -/* ---- Inline help button ---- */ -.help-inline-btn { - width: 22px; - height: 22px; - border-radius: 50%; - border: 1.5px solid var(--border-color-primary, #555); - background: transparent; - color: var(--body-text-color-subdued, #888); - font-size: 12px; - font-weight: 600; - line-height: 20px; - text-align: center; - cursor: pointer; - padding: 0; - transition: all 0.15s ease; - flex-shrink: 0; -} -.help-inline-btn:hover { - background: var(--color-accent, #4a9eff); - color: #fff; - border-color: var(--color-accent, #4a9eff); - transform: scale(1.1); -} - -/* ---- Modal overlay ---- */ -.help-modal-overlay { - position: fixed; - top: 0; left: 0; right: 0; bottom: 0; - background: rgba(0,0,0,0.5); - z-index: 100000; - display: flex; - justify-content: center; - align-items: center; -} - -.help-modal-content { - background: var(--background-fill-primary, #fff); - color: var(--body-text-color, #222); - border-radius: 12px; - max-width: 640px; - width: 90%; - max-height: 80vh; - display: flex; - flex-direction: column; - box-shadow: 0 20px 60px rgba(0,0,0,0.3); - position: relative; -} - -.help-modal-close { - position: absolute; - top: 12px; right: 16px; - background: none; - border: none; - font-size: 20px; - cursor: pointer; - color: var(--body-text-color, #222); - z-index: 1; - opacity: 0.6; -} -.help-modal-close:hover { opacity: 1; } - -.help-modal-body { - padding: 28px 32px; - overflow-y: auto; - line-height: 1.7; - font-size: 0.92rem; -} -.help-modal-body h3 { margin: 16px 0 8px; font-size: 1.15rem; } -.help-modal-body h4 { margin: 12px 0 6px; font-size: 1.0rem; } -.help-modal-body pre { - background: var(--background-fill-secondary, #f5f5f5); - padding: 10px; - border-radius: 6px; - overflow-x: auto; - font-size: 0.85rem; -} -.help-modal-body code { - background: var(--background-fill-secondary, #f5f5f5); - padding: 1px 4px; - border-radius: 3px; - font-size: 0.88em; -} -.help-modal-body ul { margin: 6px 0; } -.help-modal-body li { margin: 3px 0; } -""" +css_file = Path(__file__).parent / "interfaces" / "css" / "help_modal.css" +HELP_MODAL_CSS = css_file.read_text() diff --git a/acestep/ui/gradio/interfaces/__init__.py b/acestep/ui/gradio/interfaces/__init__.py index 5e0508be..6b67d20e 100644 --- a/acestep/ui/gradio/interfaces/__init__.py +++ b/acestep/ui/gradio/interfaces/__init__.py @@ -1,27 +1,10 @@ """ Gradio UI Components Module Contains all Gradio interface component definitions and layouts - -Layout: - ┌──────────────────────────────────────┐ - │ Header │ - ├──────────────────────────────────────┤ - │ Dataset Explorer (hidden accordion) │ - ├──────────────────────────────────────┤ - │ Settings (accordion, collapsed) │ - │ ├─ Service Configuration │ - │ ├─ DiT Parameters │ - │ ├─ LM Parameters │ - │ └─ Output / Automation │ - ├──────────────────────────────────────┤ - │ ┌─ Generation ─┬─ Training ──────┐ │ - │ │ Mode Radio │ Dataset/LoRA │ │ - │ │ Inputs │ │ │ - │ │ Results │ │ │ - │ └───────────────┴────────────────┘ │ - └──────────────────────────────────────┘ """ +from pathlib import Path import gradio as gr +from acestep.ui.gradio.interfaces.theme import AceStepTheme from acestep.ui.gradio.i18n import get_i18n, t from acestep.ui.gradio.interfaces.dataset import create_dataset_section from acestep.ui.gradio.interfaces.generation import ( @@ -54,263 +37,80 @@ def create_gradio_interface(dit_handler, llm_handler, dataset_handler, init_para # Check if running in service mode (hide training tab) service_mode = init_params is not None and init_params.get('service_mode', False) - - with gr.Blocks( - title=t("app.title"), - theme=gr.themes.Soft(), - css=""" - .main-header { - text-align: center; - margin-bottom: 2rem; - } - .section-header { - background: linear-gradient(90deg, #4CAF50, #45a049); - color: white; - padding: 10px; - border-radius: 5px; - margin: 10px 0; - } - .lm-hints-row { - align-items: stretch; - } - .lm-hints-col { - display: flex; - } - .lm-hints-col > div { - flex: 1; - display: flex; - } - .lm-hints-btn button { - height: 100%; - width: 100%; - } - /* Position Audio time labels lower to avoid scrollbar overlap */ - .component-wrapper > .timestamps { - transform: translateY(15px); - } - /* Equal-height row for instrumental checkbox + enhance lyrics button */ - .instrumental-row { - align-items: stretch !important; - } - .instrumental-row > div { - display: flex !important; - align-items: stretch !important; - } - .instrumental-row > div > div { - flex: 1; - display: flex; - align-items: center; - } - .instrumental-row button { - height: 100% !important; - min-height: 42px; - } - /* Ensure buttons in instrumental-row fill height */ - .instrumental-row > div > button { - height: 100% !important; - min-height: 42px; - } - /* Two-line icon buttons: emoji on top, text below */ - .icon-btn-wrap button, .icon-btn-wrap > button { - word-spacing: 100vw; - text-align: center; - line-height: 1.4; - } - - /* --- On-hover Tooltips --- */ - /* Safely ensure parents don't clip the tooltips using the container class */ - .has-info-container { - overflow: visible !important; - contain: none !important; - } - - /* Ensure immediate flex parents (like rows, accordions) also allow overflow if they contain an info container */ - .row:has(.has-info-container), - .column:has(.has-info-container), - .form:has(.has-info-container), - .accordion:has(.has-info-container), - .tabs:has(.has-info-container), - .gr-block:has(.has-info-container), - .gr-box:has(.has-info-container) { - overflow: visible !important; - contain: none !important; - } - - /* Hide info text by default and format as tooltip. - In Gradio 6, info is often a div following the span[data-testid="block-info"]. */ - .has-info-container span[data-testid="block-info"] + div, - .has-info-container span[data-testid="block-info"] + span, - .checkbox-container + div { - display: none; - position: absolute; - background: rgba(25, 25, 25, 0.98); - color: #ffffff; - padding: 12px 16px; - border-radius: 10px; - font-size: 0.85rem; - z-index: 999999; - max-width: 320px; - min-width: 180px; - box-shadow: 0 8px 25px rgba(0,0,0,0.5); - pointer-events: none; - line-height: 1.5; - margin-top: 6px; - border: 1px solid rgba(255,255,255,0.15); - backdrop-filter: blur(10px); - left: 0; - font-weight: 400; - text-transform: none; - } - /* Prevent tooltip CSS from hiding content inside .no-tooltip components */ - .no-tooltip span[data-testid="block-info"] + div, - .no-tooltip span[data-testid="block-info"] + span { - display: block !important; - position: static !important; - background: none !important; - padding: 0 !important; - border: none !important; - box-shadow: none !important; - backdrop-filter: none !important; - max-width: none !important; - min-width: 0 !important; - z-index: auto !important; - pointer-events: auto !important; - margin-top: 0 !important; - color: inherit !important; - font-size: inherit !important; - line-height: inherit !important; - font-weight: inherit !important; - text-transform: inherit !important; - border-radius: 0 !important; - } - .no-tooltip span[data-testid="block-info"]::after { - display: none !important; - } + theme = AceStepTheme() - /* Show tooltips on hover of the label area or the icon */ - .has-info-container span[data-testid="block-info"]:hover + div, - .has-info-container span[data-testid="block-info"]:hover + span, - .checkbox-container:hover + div { - display: block !important; - } + main_css_file = Path(__file__).parent / "css" / "main.css" + main_css = main_css_file.read_text() - /* High-res info icon using SVG, appended to the label text */ - .has-info-container span[data-testid="block-info"]::after, - .checkbox-container:has(+ div) .label-text::after { - content: ""; - display: inline-block; - width: 14px; - height: 14px; - margin-left: 8px; - vertical-align: middle; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a9eff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-size: contain; - opacity: 0.6; - transition: opacity 0.2s, transform 0.2s; - cursor: help; - } + utils_css_file = Path(__file__).parent / "css" / "utils.css" + utils_css = utils_css_file.read_text() - /* Hide original Gradio info icon if present */ - .has-info-container span[data-testid="block-info"] svg, - .has-info-container span[data-testid="block-info"]::before { - display: none !important; - } + with gr.Blocks( + title=t("app.title"), + theme=theme, + css = utils_css + main_css + HELP_MODAL_CSS, + ) as demo: - .has-info-container span[data-testid="block-info"]:hover::after, - .checkbox-container:hover .label-text::after { - opacity: 1; - transform: scale(1.15); - } + with gr.Row(equal_height=True, elem_classes=["main-header-container"]): + create_help_button("getting_started") + gr.HTML(f""" +
+

{t("app.title")}

+

{t("app.subtitle")}

+
+ """, elem_classes=["no-grow"]) - /* --- Auto-toggle checkbox row --- */ - /* Compact row of Auto checkboxes that mirrors the field row above */ - .auto-toggles-row { - margin-top: -8px !important; - margin-bottom: 0 !important; - padding: 0 !important; - gap: 16px !important; - min-height: 0 !important; - } - .auto-toggle { - text-align: center !important; - } - .auto-toggle label { - font-size: 0.8rem !important; - gap: 4px !important; - white-space: nowrap !important; - cursor: pointer !important; - opacity: 0.5; - transition: opacity 0.15s; - justify-content: center !important; - } - .auto-toggle:hover label { - opacity: 1; - } - .auto-toggle input[type="checkbox"] { - width: 13px !important; - height: 13px !important; - } - """ + HELP_MODAL_CSS, - ) as demo: - - gr.HTML(f""" -
-

{t("app.title")}

-

{t("app.subtitle")}

-
- """) - create_help_button("getting_started") - # Dataset Explorer Section (hidden) dataset_section = create_dataset_section(dataset_handler) - - # ═══════════════════════════════════════════ - # Top-level: Settings (contains Service Config + Advanced Settings) - # ═══════════════════════════════════════════ - settings_section = create_advanced_settings_section( - dit_handler, llm_handler, init_params=init_params, language=language - ) - - # ═══════════════════════════════════════════ - # Tabs: Generation | Training - # ═══════════════════════════════════════════ - with gr.Tabs(): - # --- Generation Tab --- - with gr.Tab(t("generation.tab_title")): - gen_section = create_generation_tab_section( + + with gr.Row(elem_classes=["gap-6"]): + with gr.Column(scale=1): + # ═══════════════════════════════════════════ + # Sidebar: Settings (contains Service Config + Advanced Settings) + # ═══════════════════════════════════════════ + settings_section = create_advanced_settings_section( dit_handler, llm_handler, init_params=init_params, language=language ) - - # Results Section (inside the Generation tab, wrapped for visibility control) - with gr.Column(visible=True) as results_wrapper: - results_section = create_results_section(dit_handler) - # Store the wrapper in gen_section so event handlers can toggle it - gen_section["results_wrapper"] = results_wrapper - - # --- Training Tab --- - with gr.Tab(t("training.tab_title"), visible=not service_mode): - training_section = create_training_section( - dit_handler, llm_handler, init_params=init_params + with gr.Column(scale=9): + # ═══════════════════════════════════════════ + # Tabs: Generation | Training + # ═══════════════════════════════════════════ + with gr.Tabs(): + # --- Generation Tab --- + with gr.Tab(t("generation.tab_title")): + gen_section = create_generation_tab_section( + dit_handler, llm_handler, init_params=init_params, language=language + ) + + # Results Section (inside the Generation tab, wrapped for visibility control) + with gr.Column(visible=True) as results_wrapper: + results_section = create_results_section(dit_handler) + # Store the wrapper in gen_section so event handlers can toggle it + gen_section["results_wrapper"] = results_wrapper + + # --- Training Tab --- + with gr.Tab(t("training.tab_title"), visible=not service_mode): + training_section = create_training_section( + dit_handler, llm_handler, init_params=init_params + ) + + # ═══════════════════════════════════════════ + # Merge all generation-related component dicts for event wiring + # ═══════════════════════════════════════════ + # The event handlers expect a single "generation_section" dict with all + # components from settings (service config + advanced) and generation tab. + generation_section = {} + generation_section.update(settings_section) + generation_section.update(gen_section) + + # Connect event handlers + setup_event_handlers( + demo, dit_handler, llm_handler, dataset_handler, + dataset_section, generation_section, results_section ) - - # ═══════════════════════════════════════════ - # Merge all generation-related component dicts for event wiring - # ═══════════════════════════════════════════ - # The event handlers expect a single "generation_section" dict with all - # components from settings (service config + advanced) and generation tab. - generation_section = {} - generation_section.update(settings_section) - generation_section.update(gen_section) - - # Connect event handlers - setup_event_handlers( - demo, dit_handler, llm_handler, dataset_handler, - dataset_section, generation_section, results_section - ) - - # Connect training event handlers - setup_training_event_handlers(demo, dit_handler, llm_handler, training_section) - + + # Connect training event handlers + setup_training_event_handlers(demo, dit_handler, llm_handler, training_section) + return demo diff --git a/acestep/ui/gradio/interfaces/css/help_modal.css b/acestep/ui/gradio/interfaces/css/help_modal.css new file mode 100644 index 00000000..eb43659e --- /dev/null +++ b/acestep/ui/gradio/interfaces/css/help_modal.css @@ -0,0 +1,126 @@ +/* ---- Inline help button container ---- */ +.help-inline-container { + min-height: 0 !important; + padding: 0 !important; + margin: 0 !important; + display: inline-flex !important; + align-items: center !important; + flex-shrink: 0 !important; + max-width: 32px !important; + min-width: 32px !important; + overflow: visible !important; +} + +.help-inline-wrapper { + display: inline-flex; + align-items: center; + line-height: 1; +} + +/* ---- Inline help button ---- */ +.help-inline-btn { + width: 22px; + height: 22px; + border-radius: 50%; + border: 1.5px solid var(--border-color-primary, #555); + background: transparent; + color: var(--body-text-color-subdued, #888); + font-size: 12px; + font-weight: 600; + line-height: 20px; + text-align: center; + cursor: pointer; + padding: 0; + transition: all 0.15s ease; + flex-shrink: 0; +} + +.help-inline-btn:hover { + color: var(--color-accent, #4a9eff); + border-color: var(--color-accent, #4a9eff); + transform: scale(1.1); +} + +/* ---- Modal overlay ---- */ +.help-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 100000; + display: flex; + justify-content: center; + align-items: center; +} + +.help-modal-content { + background: var(--background-fill-primary, #fff); + color: var(--body-text-color, #222); + border-radius: 12px; + max-width: 640px; + width: 90%; + max-height: 80vh; + display: flex; + flex-direction: column; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + position: relative; +} + +.help-modal-close { + position: absolute; + top: 12px; + right: 16px; + background: none; + border: none; + font-size: 20px; + cursor: pointer; + color: var(--body-text-color, #222); + z-index: 1; + opacity: 0.6; +} + +.help-modal-close:hover { + opacity: 1; +} + +.help-modal-body { + padding: 28px 32px; + overflow-y: auto; + line-height: 1.7; + font-size: 0.92rem; +} + +.help-modal-body h3 { + margin: 16px 0 8px; + font-size: 1.15rem; +} + +.help-modal-body h4 { + margin: 12px 0 6px; + font-size: 1.0rem; +} + +.help-modal-body pre { + background: var(--background-fill-secondary, #f5f5f5); + padding: 10px; + border-radius: 6px; + overflow-x: auto; + font-size: 0.85rem; +} + +.help-modal-body code { + background: var(--background-fill-secondary, #f5f5f5); + padding: 1px 4px; + border-radius: 3px; + font-size: 0.88em; +} + +.help-modal-body ul { + margin: 6px 0; +} + +.help-modal-body li { + margin: 3px 0; +} \ No newline at end of file diff --git a/acestep/ui/gradio/interfaces/css/main.css b/acestep/ui/gradio/interfaces/css/main.css new file mode 100644 index 00000000..7e6c0d35 --- /dev/null +++ b/acestep/ui/gradio/interfaces/css/main.css @@ -0,0 +1,277 @@ +.main-header { + text-align: center; + margin-bottom: 2rem; +} + +.section-header { + background: linear-gradient(90deg, #4CAF50, #45a049); + color: white; + padding: 10px; + border-radius: 5px; + margin: 10px 0; +} + +.lm-hints-row { + align-items: stretch; +} + +.lm-hints-col { + display: flex; +} + +.lm-hints-col>div { + flex: 1; + display: flex; +} + +.lm-hints-btn button { + height: 100%; + width: 100%; +} + +/* Position Audio time labels lower to avoid scrollbar overlap */ +.component-wrapper>.timestamps { + transform: translateY(15px); +} + +/* Ensure buttons in instrumental-row fill height */ +.instrumental-row>div>button { + height: 100% !important; + min-height: 42px; +} + +/* Two-line icon buttons: emoji on top, text below */ +.icon-btn-wrap button, +.icon-btn-wrap>button { + word-spacing: 100vw; + text-align: center; + line-height: 1.4; +} + +/* --- On-hover Tooltips --- */ +/* Safely ensure parents don't clip the tooltips using the container class */ +.has-info-container { + overflow: visible !important; + contain: none !important; +} + +/* Ensure immediate flex parents (like rows, accordions) also allow overflow if they contain an info container */ +.row:has(.has-info-container), +.column:has(.has-info-container), +.form:has(.has-info-container), +.accordion:has(.has-info-container), +.tabs:has(.has-info-container), +.gr-block:has(.has-info-container), +.gr-box:has(.has-info-container) { + overflow: visible !important; + contain: none !important; +} + +/* Hide info text by default and format as tooltip. + In Gradio 6, info is often a div following the span[data-testid="block-info"]. */ +.has-info-container span[data-testid="block-info"]+div, +.has-info-container span[data-testid="block-info"]+span, +.checkbox-container+div { + display: none; + position: absolute; + background: rgba(25, 25, 25, 0.98); + color: #ffffff; + padding: 12px 16px; + border-radius: 10px; + font-size: 0.85rem; + z-index: 999999; + max-width: 320px; + min-width: 180px; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.5); + pointer-events: none; + line-height: 1.5; + margin-top: 6px; + border: 1px solid rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + left: 0; + font-weight: 400; + text-transform: none; +} + +/* Prevent tooltip CSS from hiding content inside .no-tooltip components */ +.no-tooltip span[data-testid="block-info"]+div, +.no-tooltip span[data-testid="block-info"]+span { + display: block !important; + position: static !important; + background: none !important; + padding: 0 !important; + border: none !important; + box-shadow: none !important; + backdrop-filter: none !important; + max-width: none !important; + min-width: 0 !important; + z-index: auto !important; + pointer-events: auto !important; + margin-top: 0 !important; + color: inherit !important; + font-size: inherit !important; + line-height: inherit !important; + font-weight: inherit !important; + text-transform: inherit !important; + border-radius: 0 !important; +} + +.no-tooltip span[data-testid="block-info"]::after { + display: none !important; +} + +/* Show tooltips on hover of the label area or the icon */ +.has-info-container span[data-testid="block-info"]:hover+div, +.has-info-container span[data-testid="block-info"]:hover+span, +.checkbox-container:hover+div { + display: block !important; +} + +/* High-res info icon using SVG, appended to the label text */ +.has-info-container span[data-testid="block-info"]::after, +.checkbox-container:has(+ div) .label-text::after { + content: ""; + display: inline-block; + width: 14px; + height: 14px; + margin-left: 8px; + vertical-align: middle; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a9eff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-size: contain; + opacity: 0.6; + transition: opacity 0.2s, transform 0.2s; + cursor: help; +} + +/* Hide original Gradio info icon if present */ +.has-info-container span[data-testid="block-info"] svg, +.has-info-container span[data-testid="block-info"]::before { + display: none !important; +} + +.has-info-container span[data-testid="block-info"]:hover::after, +.checkbox-container:hover .label-text::after { + opacity: 1; + transform: scale(1.15); +} + +/* --- Auto-toggle checkbox row --- */ +/* Compact row of Auto checkboxes that mirrors the field row above */ +.auto-toggles-row { + margin-top: -8px !important; + margin-bottom: 0 !important; + padding: 0 !important; + gap: 16px !important; + min-height: 0 !important; +} + +.auto-toggle label { + font-size: 0.8rem !important; + gap: 4px !important; + white-space: nowrap !important; + cursor: pointer !important; + justify-content: center !important; +} + +.auto-toggle:hover label { + opacity: 1; +} + +.auto-toggle { + padding: 0; + padding-top: 25px; +} + +.auto-toggle input[type="checkbox"] { + width: 13px !important; + height: 13px !important; +} + +.fillable { + padding-inline-start: 16px !important; +} + +.has-info::after { + width: 16px; + height: 16px; + opacity: 0.75; +} + +body:not(.dark) .has-info::after { + filter: saturate(0) brightness(0); +} + +body.dark .has-info::after { + filter: saturate(0) brightness(2); +} + +body.dark input[type="range"]::-webkit-slider-runnable-track, +body.dark input[type="range"]::-moz-range-track { + background: var(--neutral-600); +} + +.btn-generate { + min-width: 500px; + padding: var(--size-3); + margin-top: var(--size-4) !important; + margin-bottom: var(--size-4) !important; +} + +.btn-primary-important:not(:disabled) { + background: #5f00a6; + color: white; +} + +.btn-primary-important:not(:disabled):hover { + background: #6d00bf; +} + +body.dark .btn-primary-important:disabled { + background: white; +} + +.main-header-container { + justify-content: center; + gap: var(--size-4); +} + +.main-header-container .help-inline-btn { + width: 30px; + height: 30px; +} + +.optional-params-container .form { + background: transparent; +} + +.optional-param-setting-row { + align-items: center; + justify-content: space-between; +} + +.optional-param-setting { + overflow: visible !important; + contain: none !important; + margin: 0; + padding: 0; +} + +body:not(.dark) { + --color-accent: black; +} + +@media (max-width: 1024px) { + .btn-generate { + min-width: 100%; + padding: var(--size-2); + margin-top: var(--size-3) !important; + margin-bottom: var(--size-3) !important; + } +} + +@media (max-width: 480px) { + .main-header-container { + gap: 0; + } +} \ No newline at end of file diff --git a/acestep/ui/gradio/interfaces/css/utils.css b/acestep/ui/gradio/interfaces/css/utils.css new file mode 100644 index 00000000..ba81a9bb --- /dev/null +++ b/acestep/ui/gradio/interfaces/css/utils.css @@ -0,0 +1,141 @@ +.no-grow { + flex: 0 0 auto !important; + width: auto !important; + display: inline-block !important; +} + +.bg-fill { + background: var(--block-background-fill); +} + +.text-center { + text-align: center; +} + +.margin-auto { + margin: 0 auto; +} + +.justify-content-center { + justify-content: center; +} + +.justify-content-start { + justify-content: flex-start; +} + +.justify-content-end { + justify-content: flex-end; +} + +.justify-content-between { + justify-content: space-between; +} + +.align-items-center { + align-items: center; +} + +.align-self-center { + align-self: center; +} + +.align-self-start { + align-self: flex-start; +} + +.align-self-end { + align-self: flex-end; +} + +.justify-self-center { + justify-self: center; +} + +.p-0 { + padding: 0; +} + +.p-1 { + padding: var(--size-1); +} + +.p-2 { + padding: var(--size-2); +} + +.p-3 { + padding: var(--size-3); +} + +.p-4 { + padding: var(--size-4); +} + +.ps-3 { + padding-inline-start: var(--size-3); +} + +.ps-4 { + padding-inline-start: var(--size-4); +} + +.pe-3 { + padding-inline-end: var(--size-3); +} + +.pe-4 { + padding-inline-end: var(--size-4); +} + +.gap-1 { + gap: var(--size-1); +} + +.gap-2 { + gap: var(--size-2); +} + +.gap-3 { + gap: var(--size-3); +} + +.gap-4 { + gap: var(--size-4); +} + +.gap-5 { + gap: var(--size-5); +} + +.gap-6 { + gap: var(--size-6); +} + +.m-0 { + margin: 0; +} + +.me-1 { + margin-inline-end: var(--size-1); +} + +.me-2 { + margin-inline-end: var(--size-2); +} + +.mt-md { + margin-top: var(--spacing-md); +} + +.mt-xl { + margin-top: var(--spacing-xl); +} + +.mb-1 { + margin-bottom: var(--size-1); +} + +.mb-2 { + margin-bottom: var(--size-2); +} \ No newline at end of file diff --git a/acestep/ui/gradio/interfaces/generation.py b/acestep/ui/gradio/interfaces/generation.py index dc99d433..aefb60bb 100644 --- a/acestep/ui/gradio/interfaces/generation.py +++ b/acestep/ui/gradio/interfaces/generation.py @@ -196,12 +196,12 @@ def _create_service_config_content(dit_handler, llm_handler, defaults, init_para ) # Checkboxes - with gr.Row(): + with gr.Column(): init_llm_value = init_params.get('init_llm', init_lm_default) if service_pre_initialized else init_lm_default lm_info_text = t("service.init_llm_info") if not gpu_config.available_lm_models: lm_info_text += " ⚠️ LM not available for this GPU tier (VRAM too low)" - init_llm_checkbox = gr.Checkbox(label=t("service.init_llm_label"), value=init_llm_value, info=lm_info_text) + init_llm_checkbox = gr.Checkbox(label=t("service.init_llm_label"), value=init_llm_value, info=lm_info_text, elem_classes=["has-info-container"]) flash_attn_available = dit_handler.is_flash_attention_available(device_value) use_flash_attention_value = init_params.get('use_flash_attention', flash_attn_available) if service_pre_initialized else flash_attn_available @@ -248,7 +248,9 @@ def _create_service_config_content(dit_handler, llm_handler, defaults, init_para init_btn = gr.Button(t("service.init_btn"), variant="primary", size="lg") init_status_value = init_params.get('init_status', '') if service_pre_initialized else '' - init_status = gr.Textbox(label=t("service.status_label"), interactive=False, lines=3, value=init_status_value) + + with gr.Row(): + init_status = gr.Textbox(label=t("service.status_label"), interactive=False, lines=3, value=init_status_value, elem_classes=["has-info-container"]) return { "service_config_accordion": service_config_accordion, @@ -308,9 +310,8 @@ def create_advanced_settings_section(dit_handler, llm_handler, init_params=None, else: _ui_config = get_ui_control_config(True) - # Auto-expand Settings when service is not yet initialized so users can init - settings_open = not service_pre_initialized - with gr.Accordion(t("generation.advanced_settings"), open=settings_open) as advanced_settings_accordion: + with gr.Column() as advanced_settings_section: + gr.HTML(f'

{t("generation.advanced_settings")}

') # ═══════════════════════════════════════════ # Service Configuration (sub-accordion) @@ -324,13 +325,17 @@ def create_advanced_settings_section(dit_handler, llm_handler, init_params=None, # ═══════════════════════════════════════════ with gr.Accordion("🔧 LoRA Adapter", open=False, elem_classes=["has-info-container"]): with gr.Row(): - lora_path = gr.Textbox(label="LoRA Path", placeholder="./lora_output/final/adapter", info="Path to trained LoRA adapter directory", scale=3) - load_lora_btn = gr.Button("📥 Load LoRA", variant="secondary", scale=1) - unload_lora_btn = gr.Button("🗑️ Unload", variant="secondary", scale=1) + with gr.Column(): + lora_path = gr.Textbox(label="LoRA Path", placeholder="./lora_output/final/adapter", info="Path to trained LoRA adapter directory", scale=3, elem_classes=["has-info-container"]) + load_lora_btn = gr.Button("📥 Load LoRA", variant="secondary", scale=1) + unload_lora_btn = gr.Button("🗑️ Unload", variant="secondary", scale=1) + with gr.Row(): + with gr.Column(): + use_lora_checkbox = gr.Checkbox(label="Use LoRA", value=False, info="Enable LoRA adapter for inference", scale=1, elem_classes=["has-info-container"]) + lora_scale_slider = gr.Slider(minimum=0.0, maximum=1.0, value=1.0, step=0.05, label="LoRA Scale", info="LoRA influence strength (0=disabled, 1=full)", scale=2, elem_classes=["has-info-container"]) + with gr.Row(): - use_lora_checkbox = gr.Checkbox(label="Use LoRA", value=False, info="Enable LoRA adapter for inference", scale=1) - lora_scale_slider = gr.Slider(minimum=0.0, maximum=1.0, value=1.0, step=0.05, label="LoRA Scale", info="LoRA influence strength (0=disabled, 1=full)", scale=2) - lora_status = gr.Textbox(label="LoRA Status", value="No LoRA loaded", interactive=False, lines=1, elem_classes=["no-tooltip"]) + lora_status = gr.Textbox(label="LoRA Status", value="No LoRA loaded", interactive=False, lines=1, elem_classes=["no-tooltip"]) # ═══════════════════════════════════════════ # DiT Diffusion Parameters (with help button) @@ -411,16 +416,19 @@ def create_advanced_settings_section(dit_handler, llm_handler, init_params=None, lines=2, ) with gr.Row(): - use_cot_metas = gr.Checkbox(label=t("generation.cot_metas_label"), value=True, info=t("generation.cot_metas_info"), scale=1, elem_classes=["has-info-container"]) - use_cot_language = gr.Checkbox(label=t("generation.cot_language_label"), value=True, info=t("generation.cot_language_info"), scale=1, elem_classes=["has-info-container"]) - constrained_decoding_debug = gr.Checkbox( - label=t("generation.constrained_debug_label"), value=False, - info=t("generation.constrained_debug_info"), scale=1, - interactive=not service_mode, - ) + with gr.Column(): + use_cot_metas = gr.Checkbox(label=t("generation.cot_metas_label"), value=True, info=t("generation.cot_metas_info"), scale=1, elem_classes=["has-info-container"]) + use_cot_language = gr.Checkbox(label=t("generation.cot_language_label"), value=True, info=t("generation.cot_language_info"), scale=1, elem_classes=["has-info-container"]) + constrained_decoding_debug = gr.Checkbox( + label=t("generation.constrained_debug_label"), value=False, + info=t("generation.constrained_debug_info"), scale=1, + interactive=not service_mode, + elem_classes=["has-info-container"] + ) with gr.Row(): - allow_lm_batch = gr.Checkbox(label=t("generation.parallel_thinking_label"), value=True, info=t("generation.parallel_thinking_info"), scale=1, elem_classes=["has-info-container"]) - use_cot_caption = gr.Checkbox(label=t("generation.caption_rewrite_label"), value=False, info=t("generation.caption_rewrite_info"), scale=1, elem_classes=["has-info-container"]) + with gr.Column(): + allow_lm_batch = gr.Checkbox(label=t("generation.parallel_thinking_label"), value=True, info=t("generation.parallel_thinking_info"), scale=1, elem_classes=["has-info-container"]) + use_cot_caption = gr.Checkbox(label=t("generation.caption_rewrite_label"), value=False, info=t("generation.caption_rewrite_info"), scale=1, elem_classes=["has-info-container"]) # ═══════════════════════════════════════════ # Audio Output & Post-processing @@ -441,10 +449,11 @@ def create_advanced_settings_section(dit_handler, llm_handler, init_params=None, scale=1, visible=not service_mode, ) with gr.Row(): - enable_norm_val = init_params.get("enable_normalization", True) if service_pre_initialized else True - norm_db_val = init_params.get("normalization_db", -1.0) if service_pre_initialized else -1.0 - enable_normalization = gr.Checkbox(label=t("gen.enable_normalization"), value=enable_norm_val, info=t("gen.enable_normalization_info"), elem_classes=["has-info-container"]) - normalization_db = gr.Slider(label=t("gen.normalization_db"), minimum=-10.0, maximum=0.0, step=0.1, value=norm_db_val, info=t("gen.normalization_db_info"), elem_classes=["has-info-container"]) + with gr.Column(): + enable_norm_val = init_params.get("enable_normalization", True) if service_pre_initialized else True + norm_db_val = init_params.get("normalization_db", -1.0) if service_pre_initialized else -1.0 + enable_normalization = gr.Checkbox(label=t("gen.enable_normalization"), value=enable_norm_val, info=t("gen.enable_normalization_info"), elem_classes=["has-info-container"]) + normalization_db = gr.Slider(label=t("gen.normalization_db"), minimum=-10.0, maximum=0.0, step=0.1, value=norm_db_val, info=t("gen.normalization_db_info"), elem_classes=["has-info-container"]) with gr.Row(): latent_shift_val = init_params.get("latent_shift", 0.0) if service_pre_initialized else 0.0 latent_rescale_val = init_params.get("latent_rescale", 1.0) if service_pre_initialized else 1.0 @@ -460,7 +469,7 @@ def create_advanced_settings_section(dit_handler, llm_handler, init_params=None, # Merge service components into the return dict result = { - "advanced_settings_accordion": advanced_settings_accordion, + "advanced_settings_section": advanced_settings_section, "inference_steps": inference_steps, "guidance_scale": guidance_scale, "infer_method": infer_method, @@ -598,7 +607,10 @@ def create_generation_tab_section(dit_handler, llm_handler, init_params=None, la with gr.Row(equal_height=True): create_sample_btn = gr.Button( - t("generation.create_sample_btn"), variant="primary", size="lg", + t("generation.create_sample_btn"), + variant="primary", + elem_classes=["btn-primary-important", "btn-generate", "no-grow", "margin-auto"], + size="lg", ) simple_sample_created = gr.State(value=False) @@ -677,7 +689,8 @@ def create_generation_tab_section(dit_handler, llm_handler, init_params=None, la audio_cover_strength = gr.Slider( minimum=0.0, maximum=1.0, value=1.0, step=0.01, label=t("generation.codes_strength_label"), - info=t("generation.codes_strength_info"), elem_classes=["has-info-container"], + info=t("generation.codes_strength_info"), + elem_classes=["has-info-container"], visible=True, ) @@ -693,46 +706,135 @@ def create_generation_tab_section(dit_handler, llm_handler, init_params=None, la # --- Custom Mode: Reference Audio | (Caption + Enhance) | (Lyrics + Instrumental + Enhance) | 🎲 --- with gr.Group(visible=True, elem_classes=["has-info-container"]) as custom_mode_group: - create_help_button("generation_custom") - with gr.Row(equal_height=True): - # Left: Reference Audio - with gr.Column(scale=2, min_width=200): - reference_audio = gr.Audio( - label=t("generation.reference_audio"), - type="filepath", - show_label=True, - ) - - # Middle: Caption column + Lyrics column - with gr.Column(scale=8): - with gr.Row(equal_height=True): - # Caption sub-column + with gr.Row(elem_classes=["bg-fill", "p-3", "gap-3", "align-items-center", "mt-xl", "mb-2"]): + gr.HTML( + f'

{t("generation.tab_title")}

', + elem_classes=["no-grow"] + ) + create_help_button("generation_custom") + + with gr.Row(elem_classes=["justify-content-end"]): + sample_btn = gr.Button(t("generation.sample_btn"), variant="secondary", size="sm", elem_classes=["no-grow"]) # random example button + + with gr.Column(): + with gr.Row(elem_classes=["gap-3", "ps-4", "pe-4"]): + # Left: Reference Audio + with gr.Column(scale=1, min_width=200, elem_classes=["align-self-center"]): + reference_audio = gr.Audio( + label=t("generation.reference_audio"), + type="filepath", + show_label=True, + ) + + with gr.Column(scale=2, elem_classes=["gap-2"]): + # Caption with gr.Column(scale=1): + with gr.Row(elem_classes=["ps-3", "pe-3", "gap-4", "bg-fill", "align-items-center", "justify-content-between"]): + gr.HTML(f'
{t("generation.caption_label")}
', elem_classes="no-grow") + format_caption_btn = gr.Button(t("generation.format_caption_btn"), variant="secondary", size="sm", elem_classes="no-grow") + captions = gr.Textbox( + show_label=False, label=t("generation.caption_label"), placeholder=t("generation.caption_placeholder"), lines=12, max_lines=12, ) - with gr.Row(elem_classes="instrumental-row"): - format_caption_btn = gr.Button(t("generation.format_caption_btn"), variant="secondary", size="sm") - # Lyrics sub-column + + # Lyrics with gr.Column(scale=1): + with gr.Row(elem_classes=["bg-fill", "ps-3", "pe-3", "justify-content-between", "align-items-center"]): + with gr.Row(elem_classes=["gap-4", "align-items-center"]): + gr.HTML( + f'
{t("generation.lyrics_label")}
', + elem_classes="no-grow" + ) + + instrumental_checkbox = gr.Checkbox( + label=t("generation.instrumental_label"), + value=False, + scale=0, + elem_classes="p-0" + ) + + format_lyrics_btn = gr.Button(t("generation.format_lyrics_btn"), variant="secondary", size="sm", elem_classes="no-grow") + lyrics = gr.Textbox( + show_label=False, label=t("generation.lyrics_label"), placeholder=t("generation.lyrics_placeholder"), lines=12, max_lines=12, ) - with gr.Row(elem_classes="instrumental-row"): - instrumental_checkbox = gr.Checkbox( - label=t("generation.instrumental_label"), value=False, scale=1, + + with gr.Column(elem_classes=["has-info-container", "optional-params-container"], scale=1) as optional_params_section: + with gr.Row(): + gr.HTML(f'

{t("generation.optional_params")}

') + reset_all_auto_btn = gr.Button(t("generation.reset_all_auto"), variant="secondary", size="sm", elem_classes=["no-grow"]) + + with gr.Column(elem_classes=["gap-2"]): + with gr.Row(elem_classes=["optional-param-setting-row"]): + bpm_auto = gr.Checkbox(label=t("generation.bpm_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) + bpm = gr.Number( + label=t("generation.bpm_label"), + value=None, + step=1, + info=t("generation.bpm_info"), + elem_classes=["optional-param-setting", "has-info-container"], + interactive=False ) - format_lyrics_btn = gr.Button(t("generation.format_lyrics_btn"), variant="secondary", size="sm", scale=2) - # Right column: 🎲 Random - with gr.Column(scale=1, min_width=80, elem_classes="icon-btn-wrap"): - sample_btn = gr.Button(t("generation.sample_btn"), variant="primary", size="lg") + with gr.Row(elem_classes=["optional-param-setting-row"]): + key_auto = gr.Checkbox(label=t("generation.key_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) + key_scale = gr.Textbox( + label=t("generation.keyscale_label"), + placeholder=t("generation.keyscale_placeholder"), + value="", + info=t("generation.keyscale_info"), + elem_classes=["optional-param-setting", "has-info-container"], + interactive=False + ) + + with gr.Row(elem_classes=["optional-param-setting-row"]): + timesig_auto = gr.Checkbox(label=t("generation.timesig_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) + time_signature = gr.Dropdown( + choices=["", "2", "3", "4", "6", "N/A"], + value="", + label=t("generation.timesig_label"), + allow_custom_value=True, + info=t("generation.timesig_info"), + elem_classes=["optional-param-setting", "has-info-container"], + interactive=False + ) + + with gr.Row(elem_classes=["optional-param-setting-row"]): + vocal_lang_auto = gr.Checkbox(label=t("generation.vocal_lang_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) + vocal_language = gr.Dropdown( + choices=[(lang if lang != "unknown" else "Instrumental / auto", lang) for lang in VALID_LANGUAGES], value="unknown", + label=t("generation.vocal_language_label"), + info=t("generation.vocal_language_info"), + allow_custom_value=True, + elem_classes=["optional-param-setting", "has-info-container"], + interactive=False, + ) + + with gr.Row(elem_classes=["optional-param-setting-row"]): + duration_auto = gr.Checkbox(label=t("generation.duration_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) + audio_duration = gr.Number( + label=t("generation.duration_label"), value=-1, minimum=-1, + maximum=float(max_duration), step=0.1, + info=t("generation.duration_info") + f" (Max: {max_duration}s / {max_duration // 60} min)", + elem_classes=["optional-param-setting", "has-info-container"], + interactive=False, + ) + + batch_size_input = gr.Number( + label=t("generation.batch_size_label"), value=default_batch_size, + minimum=1, maximum=max_batch_size, step=1, + info=t("generation.batch_size_info") + f" (Max: {max_batch_size})", + elem_classes=["has-info-container", "no-grow", "p-0", "align-self-end", "m-0"], + interactive=not service_mode, + ) # --- Repainting controls (also used for Lego stem area) --- with gr.Group(visible=False) as repainting_group: @@ -742,58 +844,28 @@ def create_generation_tab_section(dit_handler, llm_handler, init_params=None, la repainting_start = gr.Number(label=t("generation.repainting_start"), value=0.0, step=0.1) repainting_end = gr.Number(label=t("generation.repainting_end"), value=-1, minimum=-1, step=0.1) - # --- Optional Parameters (collapsed by default) --- - with gr.Accordion(t("generation.optional_params"), open=False, visible=True, elem_classes=["has-info-container"]) as optional_params_accordion: - with gr.Row(): - bpm = gr.Number(label=t("generation.bpm_label"), value=None, step=1, info=t("generation.bpm_info"), elem_classes=["has-info-container"], interactive=False) - key_scale = gr.Textbox(label=t("generation.keyscale_label"), placeholder=t("generation.keyscale_placeholder"), value="", info=t("generation.keyscale_info"), elem_classes=["has-info-container"], interactive=False) - time_signature = gr.Dropdown(choices=["", "2", "3", "4", "6", "N/A"], value="", label=t("generation.timesig_label"), allow_custom_value=True, info=t("generation.timesig_info"), elem_classes=["has-info-container"], interactive=False) - vocal_language = gr.Dropdown( - choices=[(lang if lang != "unknown" else "Instrumental / auto", lang) for lang in VALID_LANGUAGES], value="unknown", - label=t("generation.vocal_language_label"), - info=t("generation.vocal_language_info"), - allow_custom_value=True, - elem_classes=["has-info-container"], - interactive=False, - ) - with gr.Row(elem_classes=["auto-toggles-row"]): - bpm_auto = gr.Checkbox(label=t("generation.bpm_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) - key_auto = gr.Checkbox(label=t("generation.key_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) - timesig_auto = gr.Checkbox(label=t("generation.timesig_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) - vocal_lang_auto = gr.Checkbox(label=t("generation.vocal_lang_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) - with gr.Row(): - audio_duration = gr.Number( - label=t("generation.duration_label"), value=-1, minimum=-1, - maximum=float(max_duration), step=0.1, - info=t("generation.duration_info") + f" (Max: {max_duration}s / {max_duration // 60} min)", elem_classes=["has-info-container"], - interactive=False, - ) - batch_size_input = gr.Number( - label=t("generation.batch_size_label"), value=default_batch_size, - minimum=1, maximum=max_batch_size, step=1, - info=t("generation.batch_size_info") + f" (Max: {max_batch_size})", elem_classes=["has-info-container"], - interactive=not service_mode, - ) - with gr.Row(elem_classes=["auto-toggles-row"]): - duration_auto = gr.Checkbox(label=t("generation.duration_auto_label"), value=True, container=False, elem_classes=["auto-toggle"]) - gr.HTML("") # spacer to align with batch_size column - reset_all_auto_btn = gr.Button(t("generation.reset_all_auto"), variant="secondary", size="sm") - # --- Generate Button Row (hidden in Simple mode) --- generate_btn_interactive = init_params.get('enable_generate', False) if service_pre_initialized else False - with gr.Row(equal_height=True, visible=True) as generate_btn_row: - with gr.Column(scale=1, variant="compact"): - think_checkbox = gr.Checkbox(label=t("generation.think_label"), value=lm_initialized, scale=1, interactive=lm_initialized) - auto_score = gr.Checkbox(label=t("generation.auto_score_label"), value=False, scale=1, interactive=not service_mode) - with gr.Column(scale=18): - generate_btn = gr.Button(t("generation.generate_btn"), variant="primary", size="lg", interactive=generate_btn_interactive) - with gr.Column(scale=1, variant="compact"): + + with gr.Column(visible=True) as generate_btn_row: + with gr.Row(elem_classes=["bg-fill", "justify-content-center"]): + think_checkbox = gr.Checkbox(label=t("generation.think_label"), value=lm_initialized, scale=0, interactive=lm_initialized) + auto_score = gr.Checkbox(label=t("generation.auto_score_label"), value=False, scale=0, interactive=not service_mode) autogen_checkbox = gr.Checkbox( - label=t("generation.autogen_label"), value=False, scale=1, + label=t("generation.autogen_label"), value=False, scale=0, interactive=not service_mode, ) - auto_lrc = gr.Checkbox(label=t("generation.auto_lrc_label"), value=False, scale=1, interactive=not service_mode) - + auto_lrc = gr.Checkbox(label=t("generation.auto_lrc_label"), value=False, scale=0, interactive=not service_mode) + + with gr.Row(elem_classes=["justify-content-center"]): + generate_btn = gr.Button( + t("generation.generate_btn"), + variant="primary", + elem_classes=["btn-primary-important", "btn-generate", "no-grow"], + size="lg", + interactive=generate_btn_interactive + ) + return { "generation_mode": generation_mode, "task_type": task_type, @@ -834,7 +906,7 @@ def create_generation_tab_section(dit_handler, llm_handler, init_params=None, la "vocal_language": vocal_language, "format_caption_btn": format_caption_btn, "format_lyrics_btn": format_lyrics_btn, - "optional_params_accordion": optional_params_accordion, + "optional_params_section": optional_params_section, "bpm": bpm, "key_scale": key_scale, "time_signature": time_signature, diff --git a/acestep/ui/gradio/interfaces/result.py b/acestep/ui/gradio/interfaces/result.py index 1a489148..9036b972 100644 --- a/acestep/ui/gradio/interfaces/result.py +++ b/acestep/ui/gradio/interfaces/result.py @@ -36,7 +36,7 @@ def _create_audio_column(n, visible=True): ) save_btn = gr.Button( t("results.save_btn"), - variant="primary", size="sm", scale=1 + variant="secondary", size="sm", scale=1 ) with gr.Accordion(t("results.details_accordion"), open=False, visible=True) as details_accordion: codes_display = gr.Textbox( @@ -144,7 +144,7 @@ def create_results_section(dit_handler) -> dict: ) next_batch_btn = gr.Button( t("results.next_btn"), - variant="primary", interactive=False, scale=1, size="sm" + variant="secondary", interactive=False, scale=1, size="sm" ) # One-click restore parameters button diff --git a/acestep/ui/gradio/interfaces/theme.py b/acestep/ui/gradio/interfaces/theme.py new file mode 100644 index 00000000..a7139102 --- /dev/null +++ b/acestep/ui/gradio/interfaces/theme.py @@ -0,0 +1,127 @@ +from __future__ import annotations +from typing import Iterable +import gradio as gr +from gradio.themes.utils import colors, fonts, sizes + + +class AceStepTheme(gr.themes.Base): + def __init__( + self, + *, + primary_hue: colors.Color | str = colors.slate, + secondary_hue: colors.Color | str = colors.indigo, + neutral_hue: colors.Color | str = colors.gray, + spacing_size: sizes.Size | str = sizes.spacing_md, + radius_size: sizes.Size | str = sizes.radius_md, + text_size: sizes.Size | str = sizes.text_md, + font: fonts.Font + | str + | Iterable[fonts.Font | str] = ( + fonts.LocalFont("Montserrat"), + "ui-sans-serif", + "system-ui", + "sans-serif", + ), + font_mono: fonts.Font + | str + | Iterable[fonts.Font | str] = ( + fonts.LocalFont("IBM Plex Mono"), + "ui-monospace", + "Consolas", + "monospace", + ), + ): + super().__init__( + primary_hue=primary_hue, + secondary_hue=secondary_hue, + neutral_hue=neutral_hue, + spacing_size=spacing_size, + radius_size=radius_size, + text_size=text_size, + font=font, + font_mono=font_mono, + ) + + super().set( + # Custom values + button_primary_background_fill="*neutral_950", + button_primary_background_fill_dark="*primary_100", + button_primary_text_color_dark="*neutral_950", + button_secondary_background_fill="*primary_200", + button_secondary_text_color="*neutral_950", + body_background_fill="#f3f4f5", + block_background_fill_dark="#0f1624", + input_background_fill_dark="*neutral_800", + block_border_color="white", + block_border_color_dark="#0f1624", + slider_color="*neutral_800", + slider_color_dark="*primary_200", + color_accent="white", + + # The rest of the values were taken from Gradio's Soft theme + # Colors + background_fill_primary="*neutral_50", + + # Shadows + shadow_drop="0 1px 4px 0 rgb(0 0 0 / 0.1)", + shadow_drop_lg="0 2px 5px 0 rgb(0 0 0 / 0.1)", + + # Block Labels + block_background_fill="white", + block_label_padding="*spacing_sm *spacing_md", + block_label_radius="*radius_md", + block_label_text_size="*text_md", + block_label_text_weight="600", + block_label_text_color="*primary_500", + block_label_text_color_dark="white", + + block_title_radius="*block_label_radius", + block_title_padding="*block_label_padding", + block_title_background_fill="*block_label_background_fill", + block_title_text_weight="600", + block_title_text_color="*primary_500", + block_title_text_color_dark="white", + block_label_margin="*spacing_md", + + # Inputs + input_background_fill="white", + input_border_color="*neutral_50", + input_shadow="*shadow_drop", + input_shadow_focus="*shadow_drop_lg", + checkbox_shadow="none", + + # Buttons + shadow_spread="6px", + button_primary_shadow="*shadow_drop_lg", + button_primary_shadow_hover="*shadow_drop_lg", + button_primary_shadow_active="*shadow_inset", + button_secondary_shadow="*shadow_drop_lg", + button_secondary_shadow_hover="*shadow_drop_lg", + button_secondary_shadow_active="*shadow_inset", + checkbox_label_shadow="*shadow_drop_lg", + button_primary_background_fill_hover_dark="*primary_500", + button_primary_text_color="white", + button_secondary_background_fill_hover_dark="*primary_500", + button_cancel_background_fill="*button_secondary_background_fill", + button_cancel_background_fill_hover="*button_secondary_background_fill_hover", + button_cancel_background_fill_hover_dark="*button_secondary_background_fill_hover", + button_cancel_text_color="*button_secondary_text_color", + checkbox_label_background_fill_selected="*primary_500", + checkbox_label_background_fill_selected_dark="*primary_600", + checkbox_border_width="1px", + checkbox_border_color="*neutral_100", + checkbox_border_color_dark="*neutral_600", + checkbox_background_color_selected="*primary_600", + checkbox_background_color_selected_dark="*primary_700", + checkbox_border_color_focus="*primary_500", + checkbox_border_color_focus_dark="*primary_600", + checkbox_border_color_selected="*primary_600", + checkbox_border_color_selected_dark="*primary_700", + checkbox_label_text_color_selected="white", + + # Borders + block_border_width="0px", + panel_border_width="1px", + ) + +theme = AceStepTheme() \ No newline at end of file diff --git a/acestep/ui/gradio/interfaces/training.py b/acestep/ui/gradio/interfaces/training.py index 8dd1fecc..fd118b64 100644 --- a/acestep/ui/gradio/interfaces/training.py +++ b/acestep/ui/gradio/interfaces/training.py @@ -61,7 +61,7 @@ def create_training_section(dit_handler, llm_handler, init_params=None) -> dict: info=t("training.load_dataset_info"), elem_classes=["has-info-container"], scale=3, ) - load_json_btn = gr.Button(t("training.load_btn"), variant="primary", scale=1) + load_json_btn = gr.Button(t("training.load_btn"), variant="secondary", scale=1) load_json_status = gr.Textbox( label=t("training.load_status"), interactive=False, @@ -487,6 +487,7 @@ def create_training_section(dit_handler, llm_handler, init_params=None) -> dict: t("training.start_training_btn"), variant="primary", size="lg", + elem_classes=["btn-primary-important"] ) with gr.Column(scale=1): stop_training_btn = gr.Button( @@ -522,7 +523,7 @@ def create_training_section(dit_handler, llm_handler, init_params=None) -> dict: value="./lora_output/final_lora", placeholder="./lora_output/my_lora", ) - export_lora_btn = gr.Button(t("training.export_lora_btn"), variant="secondary") + export_lora_btn = gr.Button(t("training.export_lora_btn"), variant="primary") export_status = gr.Textbox( label=t("training.export_status"), @@ -674,6 +675,7 @@ def create_training_section(dit_handler, llm_handler, init_params=None) -> dict: "Start LoKr Training", variant="primary", size="lg", + elem_classes=["btn-primary-important"] ) with gr.Column(scale=1): stop_lokr_training_btn = gr.Button( @@ -709,7 +711,7 @@ def create_training_section(dit_handler, llm_handler, init_params=None) -> dict: value="./lokr_output/final_lokr", placeholder="./lokr_output/my_lokr", ) - export_lokr_btn = gr.Button("📦 Export LoKr", variant="secondary") + export_lokr_btn = gr.Button("📦 Export LoKr", variant="primary") with gr.Row(): lokr_export_epoch = gr.Dropdown(