File size: 4,758 Bytes
3fc4dbc
6bf2879
 
 
3fc4dbc
6bf2879
 
 
 
 
 
3fc4dbc
6bf2879
 
 
 
 
 
 
 
 
3fc4dbc
 
6bf2879
 
 
 
7e5fab5
 
 
6bf2879
 
 
 
 
7e5fab5
6bf2879
 
 
 
 
 
7e5fab5
6bf2879
 
 
 
 
 
 
7e5fab5
6bf2879
 
 
 
 
7e5fab5
6bf2879
 
 
 
 
 
 
7e5fab5
6bf2879
7e5fab5
 
6bf2879
7e5fab5
 
6bf2879
 
7e5fab5
6bf2879
 
 
7e5fab5
 
 
 
 
 
 
 
6bf2879
 
 
 
 
 
 
 
 
 
7e5fab5
6bf2879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e5fab5
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""
app.py
──────────────────────────────────────────────────────────────────────────────
VoiceVerse Pro β€” Streamlit Orchestrator  (2026 Stable Build)

This file is intentionally thin. Its only jobs are:
  1. Configure the Streamlit page
  2. Inject global CSS
  3. Render the header and stage tracker
  4. Delegate every pipeline stage to its own UI module
  5. Provide a debug panel for development

All business logic lives in  modules/
All UI rendering logic lives in  ui/

Pipeline flow:
  ui.sidebar         β†’ SidebarConfig
  ui.stage_upload    β†’ PipelineState.stage 0 β†’ 1
  ui.stage_retrieve  β†’ PipelineState.stage 1 β†’ 2
  ui.stage_generate  β†’ PipelineState.stage 2 β†’ 3
  ui.stage_audio     β†’ PipelineState.stage 3 β†’ 4
"""

import logging
import os
import sys

# ── Path fix: ensure the project root is on sys.path regardless of where
#    `streamlit run` is invoked from. Without this, `import ui` and
#    `import modules` fail when the CWD is not the project root.
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

import streamlit as st
from dotenv import load_dotenv

load_dotenv()   # loads .env β†’ os.environ before any module reads env vars

from ui import (
    get_pipeline_state,
    inject_css,
    render_header,
    render_stage_tracker,
    render_mode_selector,
    sidebar,
    stage_upload,
    stage_retrieve,
    stage_generate,
    stage_audio,
)

# ── Logging ───────────────────────────────────────────────────────────────────
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
)

# ── Page config (must be first Streamlit call) ────────────────────────────────
st.set_page_config(
    page_title="VoiceVerse Pro",
    page_icon="πŸŽ™οΈ",
    layout="wide",
    initial_sidebar_state="expanded",
)

# ── Global styles ─────────────────────────────────────────────────────────────
inject_css()

# ── Session state ─────────────────────────────────────────────────────────────
state = get_pipeline_state()

# ── Sidebar β†’ typed SidebarConfig ────────────────────────────────────────────
config = sidebar.render(current_stage=state.stage)

# ── Header + stage tracker ────────────────────────────────────────────────────
render_header()
render_stage_tracker(state.stage)

# ── Mode selector (prominent main-area toggle) ────────────────────────────────
selected_mode = render_mode_selector()

# Sync the session-state selection back into config so all stages see it
from ui.state import OutputMode
config.output_mode = OutputMode(selected_mode)

# ── Two-column layout ─────────────────────────────────────────────────────────
col_left, col_right = st.columns([1, 1.3], gap="large")

with col_left:
    stage_upload.render(state, config)
    stage_retrieve.render(state, config)

with col_right:
    stage_generate.render(state, config)
    stage_audio.render(state, config)

# ── Debug panel ───────────────────────────────────────────────────────────────
st.divider()
with st.expander("πŸ› οΈ Debug & System Info", expanded=False):
    import sys, platform
    st.markdown(
        f"**Python:** `{sys.version}`  \n"
        f"**Platform:** `{platform.platform()}`  \n"
        f"**Pipeline Stage:** `{state.stage}`  \n"
        f"**Chunks Indexed:** `{state.total_chunks}`  \n"
        f"**Context Retrieved:** `{state.has_context}`  \n"
        f"**Script Generated:** `{state.has_script}`  \n"
        f"**Audio Ready:** `{state.has_audio}`"
    )
    if st.button("πŸ”„ Reset All State"):
        for k in list(st.session_state.keys()):
            del st.session_state[k]
        st.rerun()