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:
@@ -654,8 +654,10 @@ gradio-app,
|
|||||||
.pipeline-steps > div,
|
.pipeline-steps > div,
|
||||||
.pipeline-output-row,
|
.pipeline-output-row,
|
||||||
.pipeline-output-row > div,
|
.pipeline-output-row > div,
|
||||||
.pipeline-input-row,
|
.oneclick-input-grid,
|
||||||
.pipeline-input-row > div {
|
.oneclick-input-grid > div,
|
||||||
|
.oneclick-result-grid,
|
||||||
|
.oneclick-result-grid > div {
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
@@ -1019,56 +1021,23 @@ gradio-app,
|
|||||||
border-color: #374151 !important;
|
border-color: #374151 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gradio-container .tab-nav button {
|
/* 主导航 Tab 均匀分布(兼容 Gradio 4/5) */
|
||||||
color: #9ca3af !important;
|
.gradio-container .tab-nav {
|
||||||
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 {
|
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
gap: 0 !important;
|
gap: 0 !important;
|
||||||
|
flex-wrap: nowrap !important;
|
||||||
}
|
}
|
||||||
.gradio-container .main-nav-tabs > .tab-nav button,
|
.gradio-container .tab-nav button {
|
||||||
.gradio-container .tabs.main-nav-tabs > .tab-nav button {
|
flex: 1 1 0 !important;
|
||||||
flex: 1 1 25% !important;
|
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
color: #9ca3af !important;
|
||||||
/* 一键生成:上传区与转写区等大 */
|
font-weight: 600 !important;
|
||||||
.pipeline-input-row {
|
font-size: 0.95rem !important;
|
||||||
align-items: stretch !important;
|
padding: 10px 12px !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;
|
|
||||||
}
|
}
|
||||||
.gradio-container .tab-nav button.selected {
|
.gradio-container .tab-nav button.selected {
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
@@ -1076,6 +1045,74 @@ gradio-app,
|
|||||||
border-bottom: 3px solid #3b82f6 !important;
|
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 button.primary,
|
||||||
.gradio-container .primary {
|
.gradio-container .primary {
|
||||||
background: #2563eb !important;
|
background: #2563eb !important;
|
||||||
@@ -1355,41 +1392,64 @@ def build_app() -> gr.Blocks:
|
|||||||
with gr.Tabs(elem_classes=["main-nav-tabs"]):
|
with gr.Tabs(elem_classes=["main-nav-tabs"]):
|
||||||
# ---- Tab 1: 一键生成(默认首页)----
|
# ---- Tab 1: 一键生成(默认首页)----
|
||||||
with gr.Tab("一键生成"):
|
with gr.Tab("一键生成"):
|
||||||
gr.HTML(MIC_HINT_HTML)
|
with gr.Group(elem_classes=["oneclick-panel"]):
|
||||||
gr.Markdown(
|
gr.Markdown(
|
||||||
"上传碎碎念录音,系统自动完成 **识别 → 润色 → 合成** 全流程。"
|
"上传录音或粘贴转写 → 自动 **识别 · 润色 · 合成**",
|
||||||
)
|
elem_classes=["oneclick-hint"],
|
||||||
with gr.Row(equal_height=True, elem_classes=["pipeline-input-row"]):
|
|
||||||
pipe_audio = gr.Audio(
|
|
||||||
label="复盘录音",
|
|
||||||
type="filepath",
|
|
||||||
sources=["upload", "microphone"],
|
|
||||||
scale=1,
|
|
||||||
)
|
)
|
||||||
pipe_manual = gr.Textbox(
|
with gr.Row(elem_classes=["oneclick-input-grid"]):
|
||||||
label="或手动输入转写(跳过识别)",
|
with gr.Column(scale=1, min_width=200):
|
||||||
lines=8,
|
pipe_audio = gr.Audio(
|
||||||
placeholder="若已有转写文本,可直接粘贴,留空则走 Whisper 识别",
|
label="复盘录音",
|
||||||
scale=1,
|
type="filepath",
|
||||||
elem_classes=["bright-input"],
|
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(
|
pipeline_log = gr.Textbox(
|
||||||
label="跳过 Gemma4 润色(仅测试 TTS)",
|
label="流水线日志", lines=3, interactive=False
|
||||||
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_btn = gr.Button("▶ 启动全流程", variant="primary", size="lg")
|
with gr.Row(elem_classes=["oneclick-result-grid"]):
|
||||||
pipeline_log = gr.Textbox(label="流水线日志", lines=6, interactive=False)
|
with gr.Column(scale=1):
|
||||||
with gr.Row(elem_classes=["pipeline-output-row"]):
|
pipe_raw = gr.Textbox(label="转写原文", lines=5)
|
||||||
pipe_raw = gr.Textbox(label="转写原文", lines=6)
|
with gr.Column(scale=1):
|
||||||
pipe_polished = gr.Textbox(label="润色稿", lines=6)
|
pipe_polished = gr.Textbox(label="润色稿", lines=5)
|
||||||
pipe_player = _voice_player_block()
|
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: 分步流水线 ----
|
# ---- Tab 2: 分步流水线 ----
|
||||||
with gr.Tab("分步流水线"):
|
with gr.Tab("分步流水线"):
|
||||||
@@ -1517,18 +1577,6 @@ def build_app() -> gr.Blocks:
|
|||||||
[lock_log, speaker_status],
|
[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_refresh_btn.click(ui_history_dropdown, outputs=[history_select])
|
||||||
history_select.change(ui_history_play, history_select, history_player)
|
history_select.change(ui_history_play, history_select, history_player)
|
||||||
demo.load(ui_initial_history, outputs=[history_select, history_player])
|
demo.load(ui_initial_history, outputs=[history_select, history_player])
|
||||||
|
|||||||
Reference in New Issue
Block a user