File size: 2,801 Bytes
52ecdb7
fa15b27
 
 
 
 
e2a7a26
dd2fbb6
e2a7a26
dd2fbb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52ecdb7
be99f64
16a76a8
 
 
52ecdb7
 
16a76a8
 
 
be99f64
52ecdb7
 
be99f64
52ecdb7
 
16a76a8
dd2fbb6
 
16a76a8
52ecdb7
 
be99f64
16a76a8
dd2fbb6
16a76a8
52ecdb7
 
 
16a76a8
52ecdb7
 
16a76a8
52ecdb7
be99f64
16a76a8
dd2fbb6
 
fa15b27
dd2fbb6
fa15b27
 
16a76a8
fa15b27
16a76a8
52ecdb7
 
be99f64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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()