Update app.py
Browse files
app.py
CHANGED
@@ -14,6 +14,7 @@ import pandas as pd
|
|
14 |
import time
|
15 |
import os
|
16 |
from huggingface_hub import HfApi
|
|
|
17 |
|
18 |
# Set up logging
|
19 |
logging.basicConfig(level=logging.INFO)
|
@@ -253,118 +254,66 @@ def update_voice2_options(lang):
|
|
253 |
|
254 |
@app.callback(
|
255 |
[Output("script-output", "value"),
|
256 |
-
Output("script-progress", "value")
|
257 |
-
|
258 |
-
[State("content-input", "value"),
|
259 |
-
State("duration", "value"),
|
260 |
-
State("num-hosts", "value")],
|
261 |
-
prevent_initial_call=True
|
262 |
-
)
|
263 |
-
def generate_script(n_clicks, content, duration, num_hosts):
|
264 |
-
if n_clicks is None:
|
265 |
-
raise PreventUpdate
|
266 |
-
try:
|
267 |
-
for i in range(10):
|
268 |
-
time.sleep(0.5) # Simulate progress
|
269 |
-
pass
|
270 |
-
script = generate_podcast_script(content, duration, num_hosts) # Remove api_key parameter
|
271 |
-
model = genai.GenerativeModel('gemini-2.5-pro-preview-03-25')
|
272 |
-
return script, 100
|
273 |
-
except Exception as e:
|
274 |
-
logger.error(f"Error generating script: {str(e)}")
|
275 |
-
return f"Error: {str(e)}", 0
|
276 |
-
|
277 |
-
@app.callback(
|
278 |
-
[Output("audio-output", "children"),
|
279 |
Output("download-audio", "data"),
|
280 |
Output("podcast-progress", "value")],
|
281 |
-
Input("generate-
|
282 |
-
|
|
|
|
|
|
|
283 |
State("voice1-select", "value"),
|
284 |
State("voice2-select", "value"),
|
285 |
-
State("
|
286 |
prevent_initial_call=True
|
287 |
)
|
|
|
|
|
|
|
288 |
|
289 |
-
|
290 |
-
[Output("audio-output", "children"),
|
291 |
-
Output("download-audio", "data"),
|
292 |
-
Output("podcast-progress", "value")],
|
293 |
-
Input("generate-podcast-btn", "n_clicks"),
|
294 |
-
[State("api-key-input", "value"),
|
295 |
-
State("script-output", "value"),
|
296 |
-
State("voice1-select", "value"),
|
297 |
-
State("voice2-select", "value"),
|
298 |
-
State("num-hosts", "value")],
|
299 |
-
prevent_initial_call=True
|
300 |
-
)
|
301 |
-
def render_and_download_podcast(n_clicks, api_key, script, voice1, voice2, num_hosts):
|
302 |
-
if n_clicks is None:
|
303 |
raise PreventUpdate
|
304 |
-
try:
|
305 |
-
# Run the async function in a synchronous context
|
306 |
-
sample_rate, audio_data = asyncio.run(render_podcast(script, voice1, voice2, num_hosts)) # Remove api_key parameter
|
307 |
-
# Convert numpy array to WAV
|
308 |
-
wav_audio = AudioSegment(
|
309 |
-
audio_data.tobytes(),
|
310 |
-
frame_rate=sample_rate,
|
311 |
-
sample_width=audio_data.dtype.itemsize,
|
312 |
-
channels=1
|
313 |
-
)
|
314 |
-
|
315 |
-
# Convert WAV to MP3
|
316 |
-
buffer = io.BytesIO()
|
317 |
-
wav_audio.export(buffer, format="mp3")
|
318 |
-
buffer.seek(0)
|
319 |
-
mp3_bytes = buffer.getvalue()
|
320 |
-
|
321 |
-
# Create base64 audio for playback
|
322 |
-
audio_base64 = base64.b64encode(mp3_bytes).decode('utf-8')
|
323 |
-
audio_src = f"data:audio/mp3;base64,{audio_base64}"
|
324 |
-
|
325 |
-
return html.Audio(src=audio_src, controls=True), dcc.send_bytes(mp3_bytes, "podcast.mp3"), 100
|
326 |
-
except Exception as e:
|
327 |
-
logger.error(f"Error rendering podcast: {str(e)}")
|
328 |
-
return html.Div(f"Error: {str(e)}"), None, 0
|
329 |
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
)
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
return {"display": "none"}, {"display": "none"}
|
340 |
|
341 |
-
|
342 |
-
Output("content-input", "value"),
|
343 |
-
Input("document-upload", "contents"),
|
344 |
-
State("document-upload", "filename"),
|
345 |
-
prevent_initial_call=True
|
346 |
-
)
|
347 |
-
def update_content(contents, filename):
|
348 |
-
if contents is not None:
|
349 |
-
content_type, content_string = contents.split(',')
|
350 |
-
decoded = base64.b64decode(content_string)
|
351 |
try:
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
except Exception as e:
|
366 |
-
logger.error(f"Error
|
367 |
-
return
|
|
|
|
|
368 |
|
369 |
# Run the app
|
370 |
if __name__ == '__main__':
|
|
|
14 |
import time
|
15 |
import os
|
16 |
from huggingface_hub import HfApi
|
17 |
+
from dash import callback_context
|
18 |
|
19 |
# Set up logging
|
20 |
logging.basicConfig(level=logging.INFO)
|
|
|
254 |
|
255 |
@app.callback(
|
256 |
[Output("script-output", "value"),
|
257 |
+
Output("script-progress", "value"),
|
258 |
+
Output("audio-output", "children"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
Output("download-audio", "data"),
|
260 |
Output("podcast-progress", "value")],
|
261 |
+
[Input("generate-btn", "n_clicks"),
|
262 |
+
Input("generate-podcast-btn", "n_clicks")],
|
263 |
+
[State("content-input", "value"),
|
264 |
+
State("duration", "value"),
|
265 |
+
State("num-hosts", "value"),
|
266 |
State("voice1-select", "value"),
|
267 |
State("voice2-select", "value"),
|
268 |
+
State("script-output", "value")],
|
269 |
prevent_initial_call=True
|
270 |
)
|
271 |
+
def generate_script_and_podcast(generate_clicks, podcast_clicks, content, duration, num_hosts, voice1, voice2, script):
|
272 |
+
ctx = callback_context
|
273 |
+
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]
|
274 |
|
275 |
+
if not ctx.triggered:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
raise PreventUpdate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
|
278 |
+
if triggered_id == "generate-btn":
|
279 |
+
try:
|
280 |
+
for i in range(10):
|
281 |
+
time.sleep(0.5) # Simulate progress
|
282 |
+
script = generate_podcast_script(content, duration, num_hosts)
|
283 |
+
return script, 100, dash.no_update, dash.no_update, dash.no_update
|
284 |
+
except Exception as e:
|
285 |
+
logger.error(f"Error generating script: {str(e)}")
|
286 |
+
return f"Error: {str(e)}", 0, dash.no_update, dash.no_update, dash.no_update
|
|
|
287 |
|
288 |
+
elif triggered_id == "generate-podcast-btn":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
try:
|
290 |
+
# Run the async function in a synchronous context
|
291 |
+
sample_rate, audio_data = asyncio.run(render_podcast(script, voice1, voice2, num_hosts))
|
292 |
+
|
293 |
+
# Convert numpy array to WAV
|
294 |
+
wav_audio = AudioSegment(
|
295 |
+
audio_data.tobytes(),
|
296 |
+
frame_rate=sample_rate,
|
297 |
+
sample_width=audio_data.dtype.itemsize,
|
298 |
+
channels=1
|
299 |
+
)
|
300 |
+
|
301 |
+
# Convert WAV to MP3
|
302 |
+
buffer = io.BytesIO()
|
303 |
+
wav_audio.export(buffer, format="mp3")
|
304 |
+
buffer.seek(0)
|
305 |
+
mp3_bytes = buffer.getvalue()
|
306 |
+
|
307 |
+
# Create base64 audio for playback
|
308 |
+
audio_base64 = base64.b64encode(mp3_bytes).decode('utf-8')
|
309 |
+
audio_src = f"data:audio/mp3;base64,{audio_base64}"
|
310 |
+
|
311 |
+
return dash.no_update, dash.no_update, html.Audio(src=audio_src, controls=True), dcc.send_bytes(mp3_bytes, "podcast.mp3"), 100
|
312 |
except Exception as e:
|
313 |
+
logger.error(f"Error rendering podcast: {str(e)}")
|
314 |
+
return dash.no_update, dash.no_update, html.Div(f"Error: {str(e)}"), None, 0
|
315 |
+
|
316 |
+
return dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update
|
317 |
|
318 |
# Run the app
|
319 |
if __name__ == '__main__':
|