ahanbose commited on
Commit
5e3415b
Β·
verified Β·
1 Parent(s): 4976eed

Update src/ui/state.py

Browse files
Files changed (1) hide show
  1. src/ui/state.py +29 -43
src/ui/state.py CHANGED
@@ -2,15 +2,12 @@
2
  ui/state.py
3
  ──────────────────────────────────────────────────────────────────────────────
4
  VoiceVerse Pro β€” Centralised Session State & Config Contracts
5
-
6
- All UI modules share these typed dataclasses instead of reading
7
- st.session_state keys directly. This makes every stage independently
8
- testable and the data-flow explicit.
9
  """
10
 
11
  from __future__ import annotations
12
 
13
  from dataclasses import dataclass, field
 
14
  from typing import List, Optional
15
 
16
  from modules import RetrievedContext, IngestedFile
@@ -18,7 +15,16 @@ from modules.tts_engine import TTSBackend
18
 
19
 
20
  # ──────────────────────────────────────────────────────────────────────────────
21
- # Sidebar configuration β€” produced by ui/sidebar.py, consumed by all stages
 
 
 
 
 
 
 
 
 
22
  # ──────────────────────────────────────────────────────────────────────────────
23
 
24
  @dataclass
@@ -26,6 +32,9 @@ class SidebarConfig:
26
  # Auth
27
  hf_token: str = ""
28
 
 
 
 
29
  # RAG
30
  top_k: int = 4
31
  chunk_size: int = 1000
@@ -39,11 +48,15 @@ class SidebarConfig:
39
 
40
  # TTS
41
  tts_backend: TTSBackend = TTSBackend.SPEECHT5
 
42
  speaker_id: int = 7306
 
 
 
43
 
44
 
45
  # ──────────────────────────────────────────────────────────────────────────────
46
- # Pipeline state β€” persisted in st.session_state, mutated by each stage
47
  # ──────────────────────────────────────────────────────────────────────────────
48
 
49
  @dataclass
@@ -60,68 +73,41 @@ class PipelineState:
60
  """
61
  stage: int = 0
62
 
63
- # Stage β‘  outputs
64
  ingested_files: List[IngestedFile] = field(default_factory=list)
65
  total_chunks: int = 0
66
-
67
- # Stage β‘‘ outputs
68
  retrieved_context: Optional[RetrievedContext] = None
69
-
70
- # Stage β‘’ outputs
71
  generated_script: Optional[str] = None
72
-
73
- # Stage β‘£ outputs
74
  audio_bytes: Optional[bytes] = None
75
  audio_format: str = "audio/wav"
76
 
77
- # ── Helpers ───────────────────────────────────────────────────────────────
78
-
79
  def reset_from(self, stage: int) -> None:
80
- """Clear all state at and after `stage`."""
81
  if stage <= 1:
82
- self.ingested_files = []
83
- self.total_chunks = 0
84
- self.stage = 0
85
  if stage <= 2:
86
  self.retrieved_context = None
87
- if self.stage >= 2:
88
- self.stage = 1
89
  if stage <= 3:
90
  self.generated_script = None
91
- if self.stage >= 3:
92
- self.stage = 2
93
  if stage <= 4:
94
- self.audio_bytes = None
95
- self.audio_format = "audio/wav"
96
- if self.stage >= 4:
97
- self.stage = 3
98
 
99
  @property
100
- def has_index(self) -> bool:
101
- return self.stage >= 1
102
-
103
  @property
104
- def has_context(self) -> bool:
105
- return self.stage >= 2 and self.retrieved_context is not None
106
-
107
  @property
108
- def has_script(self) -> bool:
109
- return self.stage >= 3 and self.generated_script is not None
110
-
111
  @property
112
- def has_audio(self) -> bool:
113
- return self.stage >= 4 and self.audio_bytes is not None
114
 
115
 
116
  # ──────────────────────────────────────────────────────────────────────────────
117
- # Session state bootstrap (call once in app.py)
118
  # ──────────────────────────────────────────────────────────────────────────────
119
 
120
  def get_pipeline_state() -> PipelineState:
121
- """
122
- Retrieve or initialise PipelineState from st.session_state.
123
- Always returns the same object within a session.
124
- """
125
  import streamlit as st
126
  if "pipeline_state" not in st.session_state:
127
  st.session_state["pipeline_state"] = PipelineState()
 
2
  ui/state.py
3
  ──────────────────────────────────────────────────────────────────────────────
4
  VoiceVerse Pro β€” Centralised Session State & Config Contracts
 
 
 
 
5
  """
6
 
7
  from __future__ import annotations
8
 
9
  from dataclasses import dataclass, field
10
+ from enum import Enum
11
  from typing import List, Optional
12
 
13
  from modules import RetrievedContext, IngestedFile
 
15
 
16
 
17
  # ──────────────────────────────────────────────────────────────────────────────
18
+ # Output mode
19
+ # ──────────────────────────────────────────────────────────────────────────────
20
+
21
+ class OutputMode(str, Enum):
22
+ TRANSCRIPT = "Audio Transcript" # single narrator voice
23
+ PODCAST = "Podcast (2 Speakers)" # HOST (female) + GUEST (male) dialogue
24
+
25
+
26
+ # ──────────────────────────────────────────────────────────────────────────────
27
+ # Sidebar configuration
28
  # ──────────────────────────────────────────────────────────────────────────────
29
 
30
  @dataclass
 
32
  # Auth
33
  hf_token: str = ""
34
 
35
+ # Mode
36
+ output_mode: OutputMode = OutputMode.TRANSCRIPT
37
+
38
  # RAG
39
  top_k: int = 4
40
  chunk_size: int = 1000
 
48
 
49
  # TTS
50
  tts_backend: TTSBackend = TTSBackend.SPEECHT5
51
+ # Single-speaker (transcript mode)
52
  speaker_id: int = 7306
53
+ # Dual-speaker (podcast mode) β€” CMU Arctic xvectors
54
+ female_speaker_id: int = 1580 # SLT-style female
55
+ male_speaker_id: int = 7306 # BDL-style male
56
 
57
 
58
  # ──────────────────────────────────────────────────────────────────────────────
59
+ # Pipeline state
60
  # ──────────────────────────────────────────────────────────────────────────────
61
 
62
  @dataclass
 
73
  """
74
  stage: int = 0
75
 
 
76
  ingested_files: List[IngestedFile] = field(default_factory=list)
77
  total_chunks: int = 0
 
 
78
  retrieved_context: Optional[RetrievedContext] = None
 
 
79
  generated_script: Optional[str] = None
 
 
80
  audio_bytes: Optional[bytes] = None
81
  audio_format: str = "audio/wav"
82
 
 
 
83
  def reset_from(self, stage: int) -> None:
 
84
  if stage <= 1:
85
+ self.ingested_files = []; self.total_chunks = 0; self.stage = 0
 
 
86
  if stage <= 2:
87
  self.retrieved_context = None
88
+ if self.stage >= 2: self.stage = 1
 
89
  if stage <= 3:
90
  self.generated_script = None
91
+ if self.stage >= 3: self.stage = 2
 
92
  if stage <= 4:
93
+ self.audio_bytes = None; self.audio_format = "audio/wav"
94
+ if self.stage >= 4: self.stage = 3
 
 
95
 
96
  @property
97
+ def has_index(self) -> bool: return self.stage >= 1
 
 
98
  @property
99
+ def has_context(self) -> bool: return self.stage >= 2 and self.retrieved_context is not None
 
 
100
  @property
101
+ def has_script(self) -> bool: return self.stage >= 3 and self.generated_script is not None
 
 
102
  @property
103
+ def has_audio(self) -> bool: return self.stage >= 4 and self.audio_bytes is not None
 
104
 
105
 
106
  # ──────────────────────────────────────────────────────────────────────────────
107
+ # Session bootstrap
108
  # ──────────────────────────────────────────────────────────────────────────────
109
 
110
  def get_pipeline_state() -> PipelineState:
 
 
 
 
111
  import streamlit as st
112
  if "pipeline_state" not in st.session_state:
113
  st.session_state["pipeline_state"] = PipelineState()