import os # Fix Streamlit permission issues by redirecting HOME and XDG_CONFIG_HOME to writable path cwd = os.getcwd() os.environ.setdefault('XDG_CONFIG_HOME', cwd) os.environ.setdefault('HOME', cwd) import streamlit as st from pathlib import Path # Determine BASE_DIR relative to this script's location SCRIPT_DIR = Path(__file__).resolve().parent # Assuming project structure: project_root/src/streamlit_app.py and project_root/tts_smaples BASE_DIR = SCRIPT_DIR.parent / "tts_smaples" @st.cache_data def get_providers_and_voices(base_dir: Path): """ Scan the base_dir for subfolders (providers) and .wav files under each. Returns a dict: { provider_name: [voice_filename1.wav, ...], ... } """ providers = {} if not base_dir.is_dir(): return providers for provider in sorted([p for p in base_dir.iterdir() if p.is_dir()]): voices = sorted([f.name for f in provider.iterdir() if f.is_file() and f.suffix.lower() == ".wav"] ) if voices: providers[provider.name] = voices return providers # Main app def main(): # Configure page for better mobile experience st.set_page_config(page_title="TTS 範例播放器", layout="wide") st.title("🎵 TTS 範例播放器") # Short introduction for non-tech users st.markdown( """ **此範例示範 TTS 播放以下句子: > 八和和牛燒肉專門店。沒有將就,只有講究! 請在側邊欄選擇 TTS 提供者與語音,然後播放範例音檔。 """ ) providers = get_providers_and_voices(BASE_DIR) if not providers: st.warning(f"未找到任何 TTS 提供者資料夾 `{BASE_DIR}`,請確認資料夾存在,且包含 .wav 檔案。") parent = BASE_DIR.parent if parent.exists(): st.info(f"上層資料夾內容 `{parent}`: {sorted([p.name for p in parent.iterdir()])}") return # Sidebar for selection st.sidebar.header("選擇 TTS 範例") provider_list = sorted(providers.keys()) provider = st.sidebar.selectbox("提供者", options=provider_list) voices = providers.get(provider, []) if not voices: st.sidebar.info(f"提供者 `{provider}` 底下沒有 .wav 檔案。") return voice = st.sidebar.selectbox("語音", options=voices) # Main area shows single playback st.markdown(f"### 播放中:**{provider} / {voice}**") file_path = BASE_DIR / provider / voice if file_path.is_file(): try: audio_bytes = file_path.read_bytes() st.audio(audio_bytes, format="audio/wav") except Exception as e: st.error(f"載入音訊時出錯: {e}") else: st.error(f"找不到檔案: `{file_path}`") if __name__ == "__main__": main()