version 1
This commit is contained in:
101
ui_fragments/tab1_asset_generation.py
Normal file
101
ui_fragments/tab1_asset_generation.py
Normal file
@ -0,0 +1,101 @@
|
||||
# utils/tab1_asset_generation.py
|
||||
|
||||
import streamlit as st
|
||||
|
||||
|
||||
@st.fragment
|
||||
def render_tab(project, callbacks):
|
||||
"""
|
||||
渲染「素材生成」標籤頁的 UI。
|
||||
|
||||
這個函式負責處理所有與音效生成和字幕檔生成相關的介面元件。
|
||||
|
||||
Args:
|
||||
project: 存放專案狀態和路徑的物件。
|
||||
callbacks: 存放按鈕回呼函式的物件。
|
||||
"""
|
||||
# --- 音效生成區塊 ---
|
||||
with st.container(border=True):
|
||||
st.subheader("音效生成")
|
||||
|
||||
# 步驟 3.1
|
||||
st.markdown("##### 步驟 3.1: 生成單句音訊")
|
||||
st.button("執行生成", on_click=callbacks.callback_generate_sentence_audio)
|
||||
|
||||
st.divider()
|
||||
|
||||
# 步驟 3.2
|
||||
st.markdown("##### 步驟 3.2: 組合完整音訊")
|
||||
can_concatenate = project.has_sentence_audio()
|
||||
|
||||
if not can_concatenate:
|
||||
st.info("請先執行步驟 3.1 以生成單句音訊。")
|
||||
|
||||
st.button("執行組合", on_click=callbacks.callback_concatenate_audio, disabled=not can_concatenate)
|
||||
|
||||
if project.has_combined_audio():
|
||||
st.session_state.operation_status = {
|
||||
"success": True,
|
||||
"message": "🎉 完整音訊已組合成功!"
|
||||
}
|
||||
st.audio(str(project.paths['combined_audio']))
|
||||
|
||||
audio_management_fragment(project,callbacks)
|
||||
|
||||
st.divider()
|
||||
|
||||
# --- 字幕生成區塊 ---
|
||||
with st.container(border=True):
|
||||
st.subheader("步驟 4: 生成 ASS 字幕檔")
|
||||
can_generate_ass = project.has_sentence_audio()
|
||||
|
||||
if not can_generate_ass:
|
||||
st.info("請先執行步驟 3.1 以生成字幕所需的時間戳。")
|
||||
|
||||
st.button("📝 生成 .ass 字幕檔", on_click=callbacks.callback_generate_subtitles, disabled=not can_generate_ass)
|
||||
|
||||
st.divider()
|
||||
|
||||
|
||||
@st.fragment
|
||||
def audio_management_fragment(project,callbacks):
|
||||
"""A self-contained fragment for managing and deleting project audio files."""
|
||||
with st.expander("🎧 管理專案音訊素材"):
|
||||
paths = project.paths
|
||||
|
||||
audio_dir = paths["audio"]
|
||||
output_dir = paths["output"]
|
||||
|
||||
audio_files = []
|
||||
if audio_dir.exists():
|
||||
audio_files.extend(sorted(audio_dir.glob('*.wav')))
|
||||
if output_dir.exists():
|
||||
audio_files.extend(sorted(output_dir.glob('*.wav')))
|
||||
|
||||
if not audio_files:
|
||||
st.info("專案的 `audio` 和 `output` 資料夾中目前沒有音訊檔。")
|
||||
else:
|
||||
all_selected = all(st.session_state.get(f"delete_audio_cb_{f.name}", False) for f in audio_files)
|
||||
if st.session_state.get('select_all_audios', False) != all_selected:
|
||||
st.session_state.select_all_audios = all_selected
|
||||
|
||||
st.markdown("勾選您想要刪除的音訊檔案,然後點擊下方的按鈕。")
|
||||
|
||||
st.checkbox(
|
||||
"全選/取消全選",
|
||||
key="select_all_audios",
|
||||
on_change=callbacks.toggle_all_audio_checkboxes,
|
||||
args=(audio_files,)
|
||||
)
|
||||
|
||||
with st.form("delete_audios_form"):
|
||||
for audio_file in audio_files:
|
||||
file_size_kb = audio_file.stat().st_size / 1024
|
||||
label = f"**{audio_file.parent.name}/{audio_file.name}** ({file_size_kb:.2f} KB)"
|
||||
st.checkbox(label, key=f"delete_audio_cb_{audio_file.name}")
|
||||
|
||||
submitted = st.form_submit_button("🟥 確認刪除選取的音訊", use_container_width=True, type="primary")
|
||||
|
||||
if submitted:
|
||||
callbacks.callback_delete_selected_audios(paths)
|
||||
st.rerun(scope="fragment")
|
||||
Reference in New Issue
Block a user