Isshi14 commited on
Commit
a245ad8
Β·
verified Β·
1 Parent(s): fbe59b1

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -108
app.py CHANGED
@@ -39,19 +39,14 @@ def process_document(
39
  progress=gr.Progress(),
40
  ):
41
  """
42
- Full pipeline:
43
- upload β†’ extract β†’ RAG β†’ script (mode-specific) β†’ audio
44
-
45
- Args:
46
- file : Gradio uploaded file object (.name attribute)
47
- delivery_mode : "Summary" | "Podcast" | "Song / Rap"
48
- song_rap_sub : "Song" | "Rap" (only relevant for Song/Rap mode)
49
 
50
  Returns:
51
- (script_text, audio_file_path, status_markdown)
 
52
  """
53
 
54
- # ── Validate input ───────────────────────────────────────────────────────
55
  if file is None:
56
  raise gr.Error("Please upload a PDF or TXT file first.")
57
 
@@ -106,7 +101,6 @@ def process_document(
106
  progress(0.80, desc="πŸŽ™οΈ Synthesising audio…")
107
 
108
  is_podcast = delivery_mode.strip().lower() == "podcast"
109
-
110
  if is_podcast:
111
  audio_path, engine = generate_audio_podcast(script)
112
  else:
@@ -115,23 +109,7 @@ def process_document(
115
  logger.info("Audio generated via %s: %s", engine, audio_path)
116
  progress(1.00, desc="βœ… Done!")
117
 
118
- # ── Build status card ─────────────────────────────────────────────────
119
- mode_icon = {"summary": "πŸ“‹", "podcast": "πŸŽ™οΈ", "song / rap": "🎡"}.get(
120
- delivery_mode.lower(), "🎧"
121
- )
122
- status = (
123
- f"### βœ… Generation complete!\n\n"
124
- f"| | |\n|---|---|\n"
125
- f"| {mode_icon} **Mode** | {delivery_mode}"
126
- + (f" β€” {song_rap_sub}" if "song" in delivery_mode.lower() or "rap" in delivery_mode.lower() else "")
127
- + f" |\n"
128
- f"| πŸ“„ **Document** | {os.path.basename(file_path)} |\n"
129
- f"| 🧩 **Chunks** | {chunk_count} |\n"
130
- f"| ✍️ **Script length** | {len(script):,} chars |\n"
131
- f"| πŸ”Š **Voice engine** | {engine} |\n"
132
- )
133
-
134
- return script, audio_path, status
135
 
136
  except gr.Error:
137
  raise
@@ -152,16 +130,31 @@ def _mode_progress_label(mode: str, sub_mode: str) -> str:
152
 
153
 
154
  # ══════════════════════════════════════════════════════════════════════════════
155
- # Conditional UI visibility helpers
156
  # ══════════════════════════════════════════════════════════════════════════════
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  def _on_mode_change(mode: str):
159
- """
160
- Return visibility updates for mode-specific sub-controls.
161
- Called whenever the delivery mode radio changes.
162
- """
163
- show_song_rap = "song" in mode.lower() or "rap" in mode.lower()
164
- return gr.update(visible=show_song_rap)
165
 
166
 
167
  # ══════════════════════════════════════════════════════════════════════════════
@@ -171,7 +164,6 @@ def _on_mode_change(mode: str):
171
  def build_ui() -> gr.Blocks:
172
 
173
  css = """
174
- /* ── Header ─────────────────────────────────────────────── */
175
  .main-header { text-align: center; margin-bottom: 1rem; }
176
  .main-header h1 {
177
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -183,25 +175,14 @@ def build_ui() -> gr.Blocks:
183
  }
184
  .main-header p { color: #6b7280; font-size: 1.1rem; }
185
 
186
- /* ── Mode selector card ──────────────────────────────────── */
187
  .mode-card {
188
  background: linear-gradient(135deg, #f8f7ff 0%, #f0edff 100%);
189
  border: 1px solid #e0d9ff;
190
  border-radius: 12px;
191
  padding: 1rem 1.25rem;
192
  margin-top: 0.5rem;
 
193
  }
194
- .mode-card h3 { color: #4c3d99; margin-bottom: 0.5rem; }
195
-
196
- /* ── Status ──────────────────────────────────────────────── */
197
- .status-box {
198
- border-left: 3px solid #667eea;
199
- padding-left: 1rem;
200
- margin: 0.5rem 0;
201
- }
202
-
203
- /* ── Sub-mode row ────────────────────────────────────────── */
204
- .sub-mode-row { margin-top: 0.5rem; }
205
  """
206
 
207
  with gr.Blocks(
@@ -220,12 +201,9 @@ def build_ui() -> gr.Blocks:
220
 
221
  with gr.Row(equal_height=False):
222
 
223
- # ════════════════════════════════════════════════════════════════
224
- # LEFT COLUMN β€” Upload + Mode Selector
225
- # ════════════════════════════════════════════════════════════════
226
  with gr.Column(scale=1):
227
 
228
- # ── Upload ───────────────────────────────────────────────
229
  gr.Markdown("### πŸ“€ Upload Document")
230
  file_input = gr.File(
231
  label="Upload a PDF or TXT file",
@@ -233,7 +211,7 @@ def build_ui() -> gr.Blocks:
233
  type="filepath",
234
  )
235
 
236
- # ── Delivery Mode Selector ───────────────────────────────
237
  gr.HTML('<div class="mode-card">')
238
  gr.Markdown("### 🎨 Choose Audio Experience")
239
 
@@ -241,42 +219,27 @@ def build_ui() -> gr.Blocks:
241
  choices=["Summary", "Podcast", "Song / Rap"],
242
  value="Summary",
243
  label=None,
244
- elem_id="delivery-mode-radio",
245
  )
246
 
247
- # Song / Rap sub-option β€” hidden unless Song/Rap selected
248
- with gr.Row(visible=False, elem_classes=["sub-mode-row"]) as song_rap_row:
249
  song_rap_sub = gr.Radio(
250
  choices=["Song", "Rap"],
251
  value="Rap",
252
  label="Style",
253
- scale=1,
254
  )
255
 
256
- # Mode description (updates on change)
257
- mode_description = gr.Markdown(
258
- value=_mode_description("Summary"),
259
- elem_id="mode-desc",
260
- )
261
 
262
- gr.HTML("</div>") # close .mode-card
263
 
264
- # ── Generate Button ──────────────────────────────────────
265
  generate_btn = gr.Button(
266
  "πŸŽ™οΈ Generate Audio",
267
  variant="primary",
268
  size="lg",
269
  )
270
 
271
- # ── Status ───────────────────────────────────────────────
272
- status_output = gr.Markdown(
273
- value="*Upload a document, choose your audio experience, then click Generate.*",
274
- elem_classes=["status-box"],
275
- )
276
-
277
- # ════════════════════════════════════════════════════════════════
278
- # RIGHT COLUMN β€” Audio + Script Output
279
- # ════════════════════════════════════════════════════════════════
280
  with gr.Column(scale=1):
281
 
282
  gr.Markdown("### 🎧 Generated Audio")
@@ -302,56 +265,25 @@ def build_ui() -> gr.Blocks:
302
  "</center>"
303
  )
304
 
305
- # ════════════════════════════════════════════════════════════════════
306
- # Event wiring
307
- # ════════════════════════════════════════════════════════════════════
308
 
309
- # Show/hide Song-Rap sub-option + update description when mode changes
310
  delivery_mode.change(
311
- fn=_on_mode_change_full,
312
  inputs=[delivery_mode],
313
  outputs=[song_rap_row, mode_description],
314
  )
315
 
316
- # Generate button click
317
  generate_btn.click(
318
  fn=process_document,
319
  inputs=[file_input, delivery_mode, song_rap_sub],
320
- outputs=[script_output, audio_output, status_output],
321
  )
322
 
323
  return app
324
 
325
 
326
- # ── Mode description helper ───────────────────────────────────────────────────
327
-
328
- def _mode_description(mode: str) -> str:
329
- descriptions = {
330
- "Summary": (
331
- "*πŸ“‹ **Summary** β€” A clear, structured spoken narration covering "
332
- "the intro, key points, and conclusion. Single voice, neutral tone.*"
333
- ),
334
- "Podcast": (
335
- "*πŸŽ™οΈ **Podcast** β€” A two-host conversation. Host 1 guides and "
336
- "asks questions; Host 2 explains and elaborates. Dual voices.*"
337
- ),
338
- "Song / Rap": (
339
- "*🎡 **Song / Rap** β€” Key ideas transformed into a rhythmic, "
340
- "memorable format. Choose Song for smooth flow or Rap for punchy lines.*"
341
- ),
342
- }
343
- return descriptions.get(mode, "")
344
-
345
-
346
- def _on_mode_change_full(mode: str):
347
- """Return (song_rap_row visibility, description markdown)."""
348
- show_sub = "song" in mode.lower() or "rap" in mode.lower()
349
- return gr.update(visible=show_sub), _mode_description(mode)
350
-
351
-
352
- # ══════════════════════════════════════════════════════════════════════════════
353
- # Entry point
354
- # ══════════════════════════════════════════════════════════════════════════════
355
 
356
  if __name__ == "__main__":
357
  logger.info("Starting VoiceVerse AI…")
 
39
  progress=gr.Progress(),
40
  ):
41
  """
42
+ Full pipeline: upload β†’ extract β†’ RAG β†’ script (mode-specific) β†’ audio.
 
 
 
 
 
 
43
 
44
  Returns:
45
+ (script_text, audio_file_path)
46
+ β€” no status card; technical details are logged server-side only.
47
  """
48
 
49
+ # ── Validate ─────────────────────────────────────────────────────────────
50
  if file is None:
51
  raise gr.Error("Please upload a PDF or TXT file first.")
52
 
 
101
  progress(0.80, desc="πŸŽ™οΈ Synthesising audio…")
102
 
103
  is_podcast = delivery_mode.strip().lower() == "podcast"
 
104
  if is_podcast:
105
  audio_path, engine = generate_audio_podcast(script)
106
  else:
 
109
  logger.info("Audio generated via %s: %s", engine, audio_path)
110
  progress(1.00, desc="βœ… Done!")
111
 
112
+ return script, audio_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  except gr.Error:
115
  raise
 
130
 
131
 
132
  # ══════════════════════════════════════════════════════════════════════════════
133
+ # UI helpers
134
  # ══════════════════════════════════════════════════════════════════════════════
135
 
136
+ def _mode_description(mode: str) -> str:
137
+ descriptions = {
138
+ "Summary": (
139
+ "*πŸ“‹ **Summary** β€” A clear, structured spoken narration covering "
140
+ "the intro, key points, and conclusion. Single voice, neutral tone.*"
141
+ ),
142
+ "Podcast": (
143
+ "*πŸŽ™οΈ **Podcast** β€” A two-host conversation. Host 1 guides and "
144
+ "asks questions; Host 2 explains and elaborates. Dual voices.*"
145
+ ),
146
+ "Song / Rap": (
147
+ "*🎡 **Song / Rap** β€” Key ideas transformed into a rhythmic, "
148
+ "memorable format. Choose Song for smooth flow or Rap for punchy lines.*"
149
+ ),
150
+ }
151
+ return descriptions.get(mode, "")
152
+
153
+
154
  def _on_mode_change(mode: str):
155
+ """Show/hide Song/Rap sub-radio and update description text."""
156
+ show_sub = "song" in mode.lower() or "rap" in mode.lower()
157
+ return gr.update(visible=show_sub), _mode_description(mode)
 
 
 
158
 
159
 
160
  # ══════════════════════════════════════════════════════════════════════════════
 
164
  def build_ui() -> gr.Blocks:
165
 
166
  css = """
 
167
  .main-header { text-align: center; margin-bottom: 1rem; }
168
  .main-header h1 {
169
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
175
  }
176
  .main-header p { color: #6b7280; font-size: 1.1rem; }
177
 
 
178
  .mode-card {
179
  background: linear-gradient(135deg, #f8f7ff 0%, #f0edff 100%);
180
  border: 1px solid #e0d9ff;
181
  border-radius: 12px;
182
  padding: 1rem 1.25rem;
183
  margin-top: 0.5rem;
184
+ margin-bottom: 0.75rem;
185
  }
 
 
 
 
 
 
 
 
 
 
 
186
  """
187
 
188
  with gr.Blocks(
 
201
 
202
  with gr.Row(equal_height=False):
203
 
204
+ # ── LEFT COLUMN β€” Upload + Mode Selector ─────────────────────────
 
 
205
  with gr.Column(scale=1):
206
 
 
207
  gr.Markdown("### πŸ“€ Upload Document")
208
  file_input = gr.File(
209
  label="Upload a PDF or TXT file",
 
211
  type="filepath",
212
  )
213
 
214
+ # Delivery Mode card
215
  gr.HTML('<div class="mode-card">')
216
  gr.Markdown("### 🎨 Choose Audio Experience")
217
 
 
219
  choices=["Summary", "Podcast", "Song / Rap"],
220
  value="Summary",
221
  label=None,
 
222
  )
223
 
224
+ # Sub-option: Song vs Rap β€” hidden until Song/Rap is chosen
225
+ with gr.Row(visible=False) as song_rap_row:
226
  song_rap_sub = gr.Radio(
227
  choices=["Song", "Rap"],
228
  value="Rap",
229
  label="Style",
 
230
  )
231
 
232
+ mode_description = gr.Markdown(value=_mode_description("Summary"))
 
 
 
 
233
 
234
+ gr.HTML("</div>")
235
 
 
236
  generate_btn = gr.Button(
237
  "πŸŽ™οΈ Generate Audio",
238
  variant="primary",
239
  size="lg",
240
  )
241
 
242
+ # ── RIGHT COLUMN β€” Audio + Script Output ──────────────────────────
 
 
 
 
 
 
 
 
243
  with gr.Column(scale=1):
244
 
245
  gr.Markdown("### 🎧 Generated Audio")
 
265
  "</center>"
266
  )
267
 
268
+ # ── Event wiring ─────────────────────────────────────────────────────
 
 
269
 
 
270
  delivery_mode.change(
271
+ fn=_on_mode_change,
272
  inputs=[delivery_mode],
273
  outputs=[song_rap_row, mode_description],
274
  )
275
 
276
+ # outputs: script first, then audio β€” matches return order in process_document
277
  generate_btn.click(
278
  fn=process_document,
279
  inputs=[file_input, delivery_mode, song_rap_sub],
280
+ outputs=[script_output, audio_output],
281
  )
282
 
283
  return app
284
 
285
 
286
+ # ── Entry point ───────────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
  if __name__ == "__main__":
289
  logger.info("Starting VoiceVerse AI…")