import streamlit as st import asyncio from dotenv import load_dotenv load_dotenv() from typing import Union from config import languages, voice_names, default_speaker_1, default_speaker_2, articles from script_generation import MarkdownToScrip, ScriptConfig, PodScript from audio_generation import ScriptToAudio, AudioConfig # Generators config script_config = ScriptConfig() audio_config = AudioConfig() # UI initial state for key in ["generation_started", "script_ready", "audio_ready", "pending_generation", "audio_generation_started"]: st.session_state.setdefault(key, False) # Async helpers async def generate_script(article: str, language: str, voice1: str, voice2: str): generator = MarkdownToScrip(script_config) return await generator.run(article, language, voice1, voice2) async def generate_audio(script: PodScript, voice1: str, voice2: str): generator = ScriptToAudio(audio_config) return await generator.run(script, voice1, voice2) # Sync wrappers for Streamlit def generate_script_sync(article: str, language: str, voice1: str, voice2: str) -> Union[PodScript, None]: return asyncio.run(generate_script(article, language, voice1, voice2)) def generate_audio_sync(script: PodScript, voice1: str, voice2: str): return asyncio.run(generate_audio(script,voice1, voice2)) def render_form(): """Render the form for article selection and voice configuration.""" with st.form("generation_form"): article = st.selectbox("Article", options=articles, format_func=lambda x: x[0]) language = st.selectbox("Langue de sortie", languages, index=0) voice1 = st.selectbox("Voix Speaker 1", voice_names, index=default_speaker_1) voice2 = st.selectbox("Voix Speaker 2", voice_names, index=default_speaker_2) submitted = st.form_submit_button("📜 Générer le script") if submitted: st.session_state["generation_started"] = True st.session_state["pending_generation"] = True st.session_state["article"] = article[1] st.session_state["language"] = language st.session_state["voice1"] = voice1 st.session_state["voice2"] = voice2 st.rerun() def render_script_panel(): """Render the panel displaying the generated podcast script.""" st.markdown("### 🎧 Script du podcast") podscript: PodScript = st.session_state["script"] html = """
""" for line in podscript.conversation: html += f"

{line.speaker} : {line.text}

" html += "
" st.markdown(html, unsafe_allow_html=True) def render_audio_panel(): """Render the panel for audio generation and playback.""" is_generating = st.session_state.get("audio_generation_started", False) is_done = st.session_state.get("audio_ready", False) # Disable the button if already generating or done generate_audio_disabled = is_generating or is_done # Display the button to generate audio col1, col2, col3 = st.columns([1, 2, 1]) with col2: clicked = st.button("🎙️ Générer l'audio", key="generate_audio_btn", disabled=generate_audio_disabled) if clicked: st.session_state["audio_generation_started"] = True st.rerun() # Generate audio if not already done if is_generating and not is_done: with st.spinner("Génération de l’audio en cours...", show_time=True): st.markdown(""" > Cela peut prendre un minute, merci de patienter 🙂. """) audio_path = generate_audio_sync( st.session_state["script"], st.session_state["voice1"], st.session_state["voice2"], ) st.session_state["audio_path"] = audio_path st.session_state["audio_ready"] = True st.session_state["audio_generation_started"] = False st.rerun() if is_done: st.markdown("### 🔊 Podcast généré") st.audio(st.session_state["audio_path"]) def render_sidebar(): with st.sidebar: st.title("🎙️ UpVoice") st.markdown("Génèrez un podcast à partir d’un article tech") content = """ * Pour le moment la génération est limitée à un podscast de ~3 minutes. * L'audio est générée via [ gpt4o-mini-tts](https://platform.openai.com/docs/models/gpt-4o-mini-tts), d'autres modèles de génération seront bientôt proposés. * N'hésitez pas à visiter 👉 [Le Blog by Younup](https://www.younup.fr/blog) pour plus de contenu tech !. """ st.markdown(f"""

{content}

""", unsafe_allow_html=True) # Reset if st.session_state["generation_started"]: if st.button("🔄 Nouvelle génération"): for key in ["generation_started", "script_ready", "audio_ready", "pending_generation", "script", "audio_path", "audio_generation_started"]: st.session_state.pop(key, None) st.rerun() def main(): st.set_page_config(page_title="UpVoice 🎙️", layout="wide") render_sidebar() # Affiche formulaire si aucune génération encore if not st.session_state["generation_started"]: render_form() # Si soumission validée, mais script pas encore généré if st.session_state.get("pending_generation"): with st.spinner("Génération du script en cours...", show_time=True): st.markdown(""" > Cela peut prendre une trentaine de seconde, merci de patienter 🙂. """) st.session_state["script"] = generate_script_sync( st.session_state["article"], st.session_state["language"], st.session_state["voice1"], st.session_state["voice2"] ) st.session_state["script_ready"] = True st.session_state["pending_generation"] = False st.rerun() # Affichage script et bouton audio if st.session_state.get("script_ready"): col1, col2 = st.columns([1, 1]) with col1: render_script_panel() with col2: render_audio_panel() if __name__ == "__main__": main()