Redesign one-click tab as single compact page

Wrap workflow in one panel with side-by-side input columns, inline options, embedded history accordion, and fixed tab bar distribution.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-12 19:22:52 +08:00
parent ca49b2feed
commit d63cb318b2
+136 -88
View File
@@ -654,8 +654,10 @@ gradio-app,
.pipeline-steps > div,
.pipeline-output-row,
.pipeline-output-row > div,
.pipeline-input-row,
.pipeline-input-row > div {
.oneclick-input-grid,
.oneclick-input-grid > div,
.oneclick-result-grid,
.oneclick-result-grid > div {
flex-direction: column !important;
width: 100% !important;
}
@@ -1019,56 +1021,23 @@ gradio-app,
border-color: #374151 !important;
}
.gradio-container .tab-nav button {
color: #9ca3af !important;
font-weight: 600 !important;
font-size: 0.95rem !important;
padding: 10px 18px !important;
}
/* 主导航 Tab 均匀分布 */
.gradio-container .main-nav-tabs > .tab-nav,
.gradio-container .tabs.main-nav-tabs > .tab-nav {
/* 主导航 Tab 均匀分布(兼容 Gradio 4/5 */
.gradio-container .tab-nav {
display: flex !important;
width: 100% !important;
gap: 0 !important;
flex-wrap: nowrap !important;
}
.gradio-container .main-nav-tabs > .tab-nav button,
.gradio-container .tabs.main-nav-tabs > .tab-nav button {
flex: 1 1 25% !important;
.gradio-container .tab-nav button {
flex: 1 1 0 !important;
min-width: 0 !important;
text-align: center !important;
justify-content: center !important;
border-radius: 0 !important;
}
/* 一键生成:上传区与转写区等大 */
.pipeline-input-row {
align-items: stretch !important;
gap: 12px !important;
}
.pipeline-input-row > .gr-column,
.pipeline-input-row > div {
flex: 1 1 50% !important;
min-width: 0 !important;
width: 50% !important;
display: flex !important;
flex-direction: column !important;
}
.pipeline-input-row .block,
.pipeline-input-row .form {
flex: 1 1 auto !important;
height: 100% !important;
}
.pipeline-input-row .audio-container,
.pipeline-input-row .upload-container {
flex: 1 1 auto !important;
min-height: 220px !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
}
.pipeline-input-row textarea {
min-height: 220px !important;
height: 100% !important;
color: #9ca3af !important;
font-weight: 600 !important;
font-size: 0.95rem !important;
padding: 10px 12px !important;
}
.gradio-container .tab-nav button.selected {
color: #ffffff !important;
@@ -1076,6 +1045,74 @@ gradio-app,
border-bottom: 3px solid #3b82f6 !important;
}
/* 一键生成:单页工作区 */
.oneclick-panel {
border: 1px solid #374151 !important;
border-radius: 12px !important;
padding: 16px 18px 18px !important;
background: #111827 !important;
width: 100% !important;
box-sizing: border-box !important;
}
.oneclick-hint {
color: #94a3b8 !important;
font-size: 0.88rem !important;
margin: 0 0 12px 0 !important;
padding: 0 !important;
}
.oneclick-hint p { margin: 0 !important; color: #94a3b8 !important; }
.oneclick-input-grid {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
gap: 12px !important;
width: 100% !important;
margin-bottom: 10px !important;
}
.oneclick-input-grid > .column,
.oneclick-input-grid > .gr-column {
flex: 1 1 0 !important;
min-width: 0 !important;
}
.oneclick-input-grid .audio-container,
.oneclick-input-grid .upload-container {
min-height: 200px !important;
}
.oneclick-input-grid textarea {
min-height: 200px !important;
}
.oneclick-options-row {
align-items: center !important;
gap: 12px !important;
margin: 4px 0 10px !important;
}
.oneclick-options-row .accordion,
.oneclick-options-row .gr-accordion {
margin: 0 !important;
width: 100% !important;
}
.oneclick-result-grid {
display: flex !important;
flex-direction: row !important;
gap: 12px !important;
width: 100% !important;
}
.oneclick-result-grid > .column,
.oneclick-result-grid > .gr-column {
flex: 1 1 0 !important;
min-width: 0 !important;
}
.oneclick-result-grid textarea {
min-height: 140px !important;
}
@media (max-width: 768px) {
.oneclick-input-grid,
.oneclick-result-grid {
flex-direction: column !important;
}
}
.gradio-container button.primary,
.gradio-container .primary {
background: #2563eb !important;
@@ -1355,41 +1392,64 @@ def build_app() -> gr.Blocks:
with gr.Tabs(elem_classes=["main-nav-tabs"]):
# ---- Tab 1: 一键生成(默认首页)----
with gr.Tab("一键生成"):
gr.HTML(MIC_HINT_HTML)
gr.Markdown(
"上传碎碎念录音,系统自动完成 **识别 润色 合成** 全流程。"
)
with gr.Row(equal_height=True, elem_classes=["pipeline-input-row"]):
pipe_audio = gr.Audio(
label="复盘录音",
type="filepath",
sources=["upload", "microphone"],
scale=1,
with gr.Group(elem_classes=["oneclick-panel"]):
gr.Markdown(
"上传录音或粘贴转写 → 自动 **识别 · 润色 · 合成**",
elem_classes=["oneclick-hint"],
)
pipe_manual = gr.Textbox(
label="或手动输入转写(跳过识别)",
lines=8,
placeholder="若已有转写文本,可直接粘贴,留空则走 Whisper 识别",
scale=1,
elem_classes=["bright-input"],
with gr.Row(elem_classes=["oneclick-input-grid"]):
with gr.Column(scale=1, min_width=200):
pipe_audio = gr.Audio(
label="复盘录音",
type="filepath",
sources=["upload", "microphone"],
)
with gr.Column(scale=1, min_width=200):
pipe_manual = gr.Textbox(
label="或手动输入转写(跳过识别)",
lines=6,
placeholder="已有转写可直接粘贴,留空则 Whisper 识别",
elem_classes=["bright-input"],
)
with gr.Row(elem_classes=["oneclick-options-row"]):
skip_polish_cb = gr.Checkbox(
label="跳过 Gemma4 润色(仅测试 TTS)",
value=False,
scale=0,
)
with gr.Column(scale=1):
with gr.Accordion("🎚️ 配音音色", open=False):
pipe_voice = gr.Radio(
label="配音音色(本地 ChatTTS",
choices=voice_choice_labels(),
value=default_voice_label(),
elem_classes=["voice-radio"],
)
pipeline_btn = gr.Button(
"▶ 启动全流程", variant="primary", size="lg"
)
skip_polish_cb = gr.Checkbox(
label="跳过 Gemma4 润色(仅测试 TTS)",
value=False,
)
with gr.Accordion("🎚️ 配音音色", open=False):
pipe_voice = gr.Radio(
label="配音音色(本地 ChatTTS",
choices=voice_choice_labels(),
value=default_voice_label(),
elem_classes=["voice-radio"],
pipeline_log = gr.Textbox(
label="流水线日志", lines=3, interactive=False
)
pipeline_btn = gr.Button("▶ 启动全流程", variant="primary", size="lg")
pipeline_log = gr.Textbox(label="流水线日志", lines=6, interactive=False)
with gr.Row(elem_classes=["pipeline-output-row"]):
pipe_raw = gr.Textbox(label="转写原文", lines=6)
pipe_polished = gr.Textbox(label="润色稿", lines=6)
pipe_player = _voice_player_block()
with gr.Row(elem_classes=["oneclick-result-grid"]):
with gr.Column(scale=1):
pipe_raw = gr.Textbox(label="转写原文", lines=5)
with gr.Column(scale=1):
pipe_polished = gr.Textbox(label="润色稿", lines=5)
pipe_player = _voice_player_block()
with gr.Accordion("📂 配音历史", open=False):
with gr.Row():
history_select = gr.Dropdown(
label="历史配音",
choices=list_voice_history(),
value=None,
interactive=True,
scale=4,
)
history_refresh_btn = gr.Button(
"🔄 刷新", scale=0, min_width=100
)
history_player = _voice_player_block()
# ---- Tab 2: 分步流水线 ----
with gr.Tab("分步流水线"):
@@ -1517,18 +1577,6 @@ def build_app() -> gr.Blocks:
[lock_log, speaker_status],
)
with gr.Accordion("📂 配音历史(本地保留,可随时试听下载)", open=True):
with gr.Row():
history_select = gr.Dropdown(
label="历史配音",
choices=list_voice_history(),
value=None,
interactive=True,
scale=4,
)
history_refresh_btn = gr.Button("🔄 刷新", scale=0, min_width=100)
history_player = _voice_player_block()
history_refresh_btn.click(ui_history_dropdown, outputs=[history_select])
history_select.change(ui_history_play, history_select, history_player)
demo.load(ui_initial_history, outputs=[history_select, history_player])