Spaces:
Sleeping
Sleeping
import streamlit as st | |
import edge_tts | |
import tempfile | |
import os | |
import asyncio | |
# Dictionary of voices with language and voice details | |
language_dict = { | |
'English-Jenny (Female)': 'en-US-JennyNeural', | |
'English-Guy (Male)': 'en-US-GuyNeural', | |
'English-Ana (Female)': 'en-US-AnaNeural', | |
'English-Aria (Female)': 'en-US-AriaNeural', | |
'English-Christopher (Male)': 'en-US-ChristopherNeural', | |
'English-Eric (Male)': 'en-US-EricNeural', | |
'English-Michelle (Female)': 'en-US-MichelleNeural', | |
'English-Roger (Male)': 'en-US-RogerNeural', | |
'Spanish (Mexican)-Dalia (Female)': 'es-MX-DaliaNeural', | |
'Spanish (Mexican)-Jorge (Male)': 'es-MX-JorgeNeural', | |
'Korean-Sun-Hi (Female)': 'ko-KR-SunHiNeural', | |
'Korean-InJoon (Male)': 'ko-KR-InJoonNeural', | |
'Thai-Premwadee (Female)': 'th-TH-PremwadeeNeural', | |
'Thai-Niwat (Male)': 'th-TH-NiwatNeural', | |
'Vietnamese-HoaiMy (Female)': 'vi-VN-HoaiMyNeural', | |
'Vietnamese-NamMinh (Male)': 'vi-VN-NamMinhNeural', | |
'Japanese-Nanami (Female)': 'ja-JP-NanamiNeural', | |
'Japanese-Keita (Male)': 'ja-JP-KeitaNeural', | |
'French-Denise (Female)': 'fr-FR-DeniseNeural', | |
'French-Eloise (Female)': 'fr-FR-EloiseNeural', | |
'French-Henri (Male)': 'fr-FR-HenriNeural', | |
'Brazilian-Francisca (Female)': 'pt-BR-FranciscaNeural', | |
'Brazilian-Antonio (Male)': 'pt-BR-AntonioNeural', | |
'Indonesian-Ardi (Male)': 'id-ID-ArdiNeural', | |
'Indonesian-Gadis (Female)': 'id-ID-GadisNeural', | |
'Hebrew-Avri (Male)': 'he-IL-AvriNeural', | |
'Hebrew-Hila (Female)': 'he-IL-HilaNeural', | |
'Italian-Isabella (Female)': 'it-IT-IsabellaNeural', | |
'Italian-Diego (Male)': 'it-IT-DiegoNeural', | |
'Italian-Elsa (Female)': 'it-IT-ElsaNeural', | |
'Dutch-Colette (Female)': 'nl-NL-ColetteNeural', | |
'Dutch-Fenna (Female)': 'nl-NL-FennaNeural', | |
'Dutch-Maarten (Male)': 'nl-NL-MaartenNeural', | |
'Malay-Osman (Male)': 'ms-MY-OsmanNeural', | |
'Malay-Yasmin (Female)': 'ms-MY-YasminNeural', | |
'Norwegian-Pernille (Female)': 'nb-NO-PernilleNeural', | |
'Norwegian-Finn (Male)': 'nb-NO-FinnNeural', | |
'Swedish-Sofie (Female)': 'sv-SE-SofieNeural', | |
'Swedish-Mattias (Male)': 'sv-SE-MattiasNeural', | |
'Arabic-Hamed (Male)': 'ar-SA-HamedNeural', | |
'Arabic-Zariyah (Female)': 'ar-SA-ZariyahNeural', | |
'Greek-Athina (Female)': 'el-GR-AthinaNeural', | |
'Greek-Nestoras (Male)': 'el-GR-NestorasNeural', | |
'German-Katja (Female)': 'de-DE-KatjaNeural', | |
'German-Amala (Female)': 'de-DE-AmalaNeural', | |
'German-Conrad (Male)': 'de-DE-ConradNeural', | |
'German-Killian (Male)': 'de-DE-KillianNeural', | |
'Afrikaans-Adri (Female)': 'af-ZA-AdriNeural', | |
'Afrikaans-Willem (Male)': 'af-ZA-WillemNeural', | |
'Ethiopian-Ameha (Male)': 'am-ET-AmehaNeural', | |
'Ethiopian-Mekdes (Female)': 'am-ET-MekdesNeural', | |
'Arabic (UAE)-Fatima (Female)': 'ar-AE-FatimaNeural', | |
'Arabic (UAE)-Hamdan (Male)': 'ar-AE-HamdanNeural', | |
'Arabic (Bahrain)-Ali (Male)': 'ar-BH-AliNeural', | |
'Arabic (Bahrain)-Laila (Female)': 'ar-BH-LailaNeural', | |
'Arabic (Algeria)-Ismael (Male)': 'ar-DZ-IsmaelNeural', | |
'Arabic (Egypt)-Salma (Female)': 'ar-EG-SalmaNeural', | |
'Arabic (Egypt)-Shakir (Male)': 'ar-EG-ShakirNeural', | |
'Arabic (Iraq)-Bassel (Male)': 'ar-IQ-BasselNeural', | |
'Arabic (Iraq)-Rana (Female)': 'ar-IQ-RanaNeural', | |
'Arabic (Jordan)-Sana (Female)': 'ar-JO-SanaNeural', | |
'Arabic (Jordan)-Taim (Male)': 'ar-JO-TaimNeural', | |
'Arabic (Kuwait)-Fahed (Male)': 'ar-KW-FahedNeural', | |
'Arabic (Kuwait)-Noura (Female)': 'ar-KW-NouraNeural', | |
'Arabic (Lebanon)-Layla (Female)': 'ar-LB-LaylaNeural', | |
'Arabic (Lebanon)-Rami (Male)': 'ar-LB-RamiNeural', | |
'Arabic (Libya)-Iman (Female)': 'ar-LY-ImanNeural', | |
'Arabic (Libya)-Omar (Male)': 'ar-LY-OmarNeural', | |
'Arabic (Morocco)-Jamal (Male)': 'ar-MA-JamalNeural', | |
'Arabic (Morocco)-Mouna (Female)': 'ar-MA-MounaNeural', | |
'Arabic (Oman)-Abdullah (Male)': 'ar-OM-AbdullahNeural', | |
'Arabic (Oman)-Aysha (Female)': 'ar-OM-AyshaNeural', | |
'Arabic (Qatar)-Amal (Female)': 'ar-QA-AmalNeural', | |
'Arabic (Qatar)-Moaz (Male)': 'ar-QA-MoazNeural', | |
'Arabic (Syria)-Amany (Female)': 'ar-SY-AmanyNeural', | |
'Arabic (Syria)-Laith (Male)': 'ar-SY-LaithNeural', | |
'Arabic (Tunisia)-Hedi (Male)': 'ar-TN-HediNeural', | |
'Arabic (Tunisia)-Reem (Female)': 'ar-TN-ReemNeural', | |
'Arabic (Yemen)-Maryam (Female)': 'ar-YE-MaryamNeural', | |
'Arabic (Yemen)-Saleh (Male)': 'ar-YE-SalehNeural', | |
'Azerbaijani-Babek (Male)': 'az-AZ-BabekNeural', | |
'Azerbaijani-Banu (Female)': 'az-AZ-BanuNeural', | |
'Bulgarian-Borislav (Male)': 'bg-BG-BorislavNeural', | |
'Bulgarian-Kalina (Female)': 'bg-BG-KalinaNeural', | |
'Bengali (Bangladesh)-Nabanita (Female)': 'bn-BD-NabanitaNeural', | |
'Bengali (Bangladesh)-Pradeep (Male)': 'bn-BD-PradeepNeural', | |
'Bengali (India)-Bashkar (Male)': 'bn-IN-BashkarNeural', | |
'Bengali (India)-Tanishaa (Female)': 'bn-IN-TanishaaNeural', | |
'Bosniak (Bosnia and Herzegovina)-Goran (Male)': 'bs-BA-GoranNeural', | |
'Bosniak (Bosnia and Herzegovina)-Vesna (Female)': 'bs-BA-VesnaNeural', | |
'Catalan (Spain)-Joana (Female)': 'ca-ES-JoanaNeural', | |
'Catalan (Spain)-Enric (Male)': 'ca-ES-EnricNeural', | |
'Czech (Czech Republic)-Antonin (Male)': 'cs-CZ-AntoninNeural', | |
'Czech (Czech Republic)-Vlasta (Female)': 'cs-CZ-VlastaNeural', | |
'Welsh (UK)-Aled (Male)': 'cy-GB-AledNeural', | |
'Welsh (UK)-Nia (Female)': 'cy-GB-NiaNeural', | |
'Danish (Denmark)-Christel (Female)': 'da-DK-ChristelNeural', | |
'Danish (Denmark)-Jeppe (Male)': 'da-DK-JeppeNeural', | |
'German (Austria)-Ingrid (Female)': 'de-AT-IngridNeural', | |
'German (Austria)-Jonas (Male)': 'de-AT-JonasNeural', | |
'German (Switzerland)-Jan (Male)': 'de-CH-JanNeural', | |
'German (Switzerland)-Leni (Female)': 'de-CH-LeniNeural', | |
'English (Australia)-Natasha (Female)': 'en-AU-NatashaNeural', | |
'English (Australia)-William (Male)': 'en-AU-WilliamNeural', | |
'English (Canada)-Clara (Female)': 'en-CA-ClaraNeural', | |
'English (Canada)-Liam (Male)': 'en-CA-LiamNeural', | |
'English (UK)-Libby (Female)': 'en-GB-LibbyNeural', | |
'English (UK)-Maisie (Female)': 'en-GB-MaisieNeural', | |
'English (UK)-Ryan (Male)': 'en-GB-RyanNeural', | |
'English (UK)-Sonia (Female)': 'en-GB-SoniaNeural', | |
'English (UK)-Thomas (Male)': 'en-GB-ThomasNeural', | |
'English (Hong Kong)-Sam (Male)': 'en-HK-SamNeural', | |
'English (Hong Kong)-Yan (Female)': 'en-HK-YanNeural', | |
'English (Ireland)-Connor (Male)': 'en-IE-ConnorNeural', | |
'English (Ireland)-Emily (Female)': 'en-IE-EmilyNeural', | |
'English (India)-Neerja (Female)': 'en-IN-NeerjaNeural', | |
'English (India)-Prabhat (Male)': 'en-IN-PrabhatNeural', | |
'English (Kenya)-Asilia (Female)': 'en-KE-AsiliaNeural', | |
'English (Kenya)-Chilemba (Male)': 'en-KE-ChilembaNeural', | |
'English (Nigeria)-Abeo (Male)': 'en-NG-AbeoNeural', | |
'English (Nigeria)-Ezinne (Female)': 'en-NG-EzinneNeural', | |
'English (New Zealand)-Mitchell (Male)': 'en-NZ-MitchellNeural', | |
'English (Philippines)-James (Male)': 'en-PH-JamesNeural', | |
'English (Philippines)-Rosa (Female)': 'en-PH-RosaNeural', | |
'English (Singapore)-Luna (Female)': 'en-SG-LunaNeural', | |
'English (Singapore)-Wayne (Male)': 'en-SG-WayneNeural', | |
'English (Tanzania)-Elimu (Male)': 'en-TZ-ElimuNeural', | |
'English (Tanzania)-Imani (Female)': 'en-TZ-ImaniNeural', | |
'English (South Africa)-Leah (Female)': 'en-ZA-LeahNeural', | |
'English (South Africa)-Luke (Male)': 'en-ZA-LukeNeural', | |
'Spanish (Argentina)-Elena (Female)': 'es-AR-ElenaNeural', | |
'Spanish (Argentina)-Tomas (Male)': 'es-AR-TomasNeural', | |
'Spanish (Bolivia)-Marcelo (Male)': 'es-BO-MarceloNeural', | |
'Spanish (Bolivia)-Sofia (Female)': 'es-BO-SofiaNeural', | |
'Spanish (Colombia)-Gonzalo (Male)': 'es-CO-GonzaloNeural', | |
'Spanish (Colombia)-Salome (Female)': 'es-CO-SalomeNeural', | |
'Spanish (Costa Rica)-Juan (Male)': 'es-CR-JuanNeural', | |
'Spanish (Costa Rica)-Maria (Female)': 'es-CR-MariaNeural', | |
'Spanish (Cuba)-Belkys (Female)': 'es-CU-BelkysNeural', | |
'Spanish (Dominican Republic)-Emilio (Male)': 'es-DO-EmilioNeural', | |
'Spanish (Dominican Republic)-Ramona (Female)': 'es-DO-RamonaNeural', | |
'Spanish (Ecuador)-Andrea (Female)': 'es-EC-AndreaNeural', | |
'Spanish (Ecuador)-Luis (Male)': 'es-EC-LuisNeural', | |
'Spanish (Spain)-Alvaro (Male)': 'es-ES-AlvaroNeural', | |
'Spanish (Spain)-Elvira (Female)': 'es-ES-ElviraNeural', | |
'Spanish (Equatorial Guinea)-Teresa (Female)': 'es-GQ-TeresaNeural', | |
'Spanish (Guatemala)-Andres (Male)': 'es-GT-AndresNeural', | |
'Spanish (Guatemala)-Marta (Female)': 'es-GT-MartaNeural', | |
'Spanish (Honduras)-Carlos (Male)': 'es-HN-CarlosNeural', | |
'Spanish (Honduras)-Karla (Female)': 'es-HN-KarlaNeural', | |
'Spanish (Nicaragua)-Federico (Male)': 'es-NI-FedericoNeural', | |
'Spanish (Nicaragua)-Yolanda (Female)': 'es-NI-YolandaNeural', | |
'Spanish (Panama)-Margarita (Female)': 'es-PA-MargaritaNeural', | |
'Spanish (Panama)-Roberto (Male)': 'es-PA-RobertoNeural', | |
'Spanish (Peru)-Alex (Male)': 'es-PE-AlexNeural', | |
'Spanish (Peru)-Camila (Female)': 'es-PE-CamilaNeural', | |
'Spanish (Puerto Rico)-Karina (Female)': 'es-PR-KarinaNeural', | |
'Spanish (Puerto Rico)-Victor (Male)': 'es-PR-VictorNeural', | |
'Spanish (Paraguay)-Mario (Male)': 'es-PY-MarioNeural', | |
'Spanish (Paraguay)-Tania (Female)': 'es-PY-TaniaNeural', | |
'Spanish (El Salvador)-Lorena (Female)': 'es-SV-LorenaNeural', | |
'Spanish (El Salvador)-Rodrigo (Male)': 'es-SV-RodrigoNeural', | |
'Spanish (United States)-Alonso (Male)': 'es-US-AlonsoNeural', | |
'Spanish (United States)-Paloma (Female)': 'es-US-PalomaNeural', | |
'Spanish (Uruguay)-Mateo (Male)': 'es-UY-MateoNeural', | |
'Spanish (Uruguay)-Valentina (Female)': 'es-UY-ValentinaNeural', | |
'Spanish (Venezuela)-Paola (Female)': 'es-VE-PaolaNeural', | |
'Spanish (Venezuela)-Sebastian (Male)': 'es-VE-SebastianNeural', | |
'Estonian (Estonia)-Anu (Female)': 'et-EE-AnuNeural', | |
'Estonian (Estonia)-Kert (Male)': 'et-EE-KertNeural', | |
'Persian (Iran)-Dilara (Female)': 'fa-IR-DilaraNeural', | |
'Persian (Iran)-Farid (Male)': 'fa-IR-FaridNeural', | |
'Finnish (Finland)-Harri (Male)': 'fi-FI-HarriNeural', | |
'Finnish (Finland)-Noora (Female)': 'fi-FI-NooraNeural', | |
'French (Belgium)-Charline (Female)': 'fr-BE-CharlineNeural', | |
'French (Belgium)-Gerard (Male)': 'fr-BE-GerardNeural', | |
'French (Canada)-Sylvie (Female)': 'fr-CA-SylvieNeural', | |
'French (Canada)-Antoine (Male)': 'fr-CA-AntoineNeural', | |
'French (Canada)-Jean (Male)': 'fr-CA-JeanNeural', | |
'French (Switzerland)-Ariane (Female)': 'fr-CH-ArianeNeural', | |
'French (Switzerland)-Fabrice (Male)': 'fr-CH-FabriceNeural', | |
'Irish (Ireland)-Colm (Male)': 'ga-IE-ColmNeural', | |
'Irish (Ireland)-Orla (Female)': 'ga-IE-OrlaNeural', | |
'Galician (Spain)-Roi (Male)': 'gl-ES-RoiNeural', | |
'Galician (Spain)-Sabela (Female)': 'gl-ES-SabelaNeural', | |
'Gujarati (India)-Dhwani (Female)': 'gu-IN-DhwaniNeural', | |
'Gujarati (India)-Niranjan (Male)': 'gu-IN-NiranjanNeural', | |
'Hindi (India)-Madhur (Male)': 'hi-IN-MadhurNeural', | |
'Hindi (India)-Swara (Female)': 'hi-IN-SwaraNeural', | |
'Croatian (Croatia)-Gabrijela (Female)': 'hr-HR-GabrijelaNeural', | |
'Croatian (Croatia)-Srecko (Male)': 'hr-HR-SreckoNeural', | |
'Hungarian (Hungary)-Noemi (Female)': 'hu-HU-NoemiNeural', | |
'Hungarian (Hungary)-Tamas (Male)': 'hu-HU-TamasNeural', | |
'Icelandic (Iceland)-Gudrun (Female)': 'is-IS-GudrunNeural', | |
'Icelandic (Iceland)-Gunnar (Male)': 'is-IS-GunnarNeural', | |
'Javanese (Indonesia)-Dimas (Male)': 'jv-ID-DimasNeural', | |
'Javanese (Indonesia)-Siti (Female)': 'jv-ID-SitiNeural', | |
'Georgian (Georgia)-Eka (Female)': 'ka-GE-EkaNeural', | |
'Georgian (Georgia)-Giorgi (Male)': 'ka-GE-GiorgiNeural', | |
'Kazakh (Kazakhstan)-Aigul (Female)': 'kk-KZ-AigulNeural', | |
'Kazakh (Kazakhstan)-Daulet (Male)': 'kk-KZ-DauletNeural', | |
'Khmer (Cambodia)-Piseth (Male)': 'km-KH-PisethNeural', | |
'Khmer (Cambodia)-Sreymom (Female)': 'km-KH-SreymomNeural', | |
'Kannada (India)-Gagan (Male)': 'kn-IN-GaganNeural', | |
'Kannada (India)-Sapna (Female)': 'kn-IN-SapnaNeural', | |
'Lao (Laos)-Chanthavong (Male)': 'lo-LA-ChanthavongNeural', | |
'Lao (Laos)-Keomany (Female)': 'lo-LA-KeomanyNeural', | |
'Lithuanian (Lithuania)-Leonas (Male)': 'lt-LT-LeonasNeural', | |
'Lithuanian (Lithuania)-Ona (Female)': 'lt-LT-OnaNeural', | |
'Latvian (Latvia)-Everita (Female)': 'lv-LV-EveritaNeural', | |
'Latvian (Latvia)-Nils (Male)': 'lv-LV-NilsNeural', | |
'Macedonian (North Macedonia)-Aleksandar (Male)': 'mk-MK-AleksandarNeural', | |
'Macedonian (North Macedonia)-Marija (Female)': 'mk-MK-MarijaNeural', | |
'Malayalam (India)-Midhun (Male)': 'ml-IN-MidhunNeural', | |
'Malayalam (India)-Sobhana (Female)': 'ml-IN-SobhanaNeural', | |
'Mongolian (Mongolia)-Bataa (Male)': 'mn-MN-BataaNeural', | |
'Mongolian (Mongolia)-Yesui (Female)': 'mn-MN-YesuiNeural', | |
'Marathi (India)-Aarohi (Female)': 'mr-IN-AarohiNeural', | |
'Marathi (India)-Manohar (Male)': 'mr-IN-ManoharNeural', | |
'Maltese (Malta)-Grace (Female)': 'mt-MT-GraceNeural', | |
'Maltese (Malta)-Joseph (Male)': 'mt-MT-JosephNeural', | |
'Burmese (Myanmar)-Nilar (Female)': 'my-MM-NilarNeural', | |
'Burmese (Myanmar)-Thiha (Male)': 'my-MM-ThihaNeural', | |
'Nepali (Nepal)-Hemkala (Female)': 'ne-NP-HemkalaNeural', | |
'Nepali (Nepal)-Sagar (Male)': 'ne-NP-SagarNeural', | |
'Dutch (Belgium)-Arnaud (Male)': 'nl-BE-ArnaudNeural', | |
'Dutch (Belgium)-Dena (Female)': 'nl-BE-DenaNeural', | |
'Polish (Poland)-Marek (Male)': 'pl-PL-MarekNeural', | |
'Polish (Poland)-Zofia (Female)': 'pl-PL-ZofiaNeural', | |
'Pashto (Afghanistan)-Gul Nawaz (Male)': 'ps-AF-Gul' | |
} | |
# Organize voices by language | |
language_groups = {} | |
for voice_name, voice_code in language_dict.items(): | |
language = voice_name.split('-')[0].strip() | |
if language not in language_groups: | |
language_groups[language] = [] | |
language_groups[language].append(voice_name) | |
# Comprehensive CSS for dark theme and three-dot menu | |
st.markdown(""" | |
<style> | |
/* Main container and background */ | |
.main { | |
background-color: #000000 !important; | |
padding: 20px; | |
border-radius: 8px; | |
min-height: 100vh; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
} | |
/* Override Streamlit's default white backgrounds */ | |
.stApp { | |
background-color: #000000 !important; | |
} | |
.st-emotion-cache-1gv3atu { | |
background-color: #000000 !important; | |
} | |
/* Style for text area */ | |
.stTextArea > div > div > textarea { | |
background-color: #1a1a1a; | |
color: #ffffff; | |
border: 1px solid #333333; | |
border-radius: 8px; | |
} | |
/* Style for dropdowns */ | |
.stSelectbox > div > div > select { | |
background-color: #1a1a1a; | |
color: #ffffff; | |
border: 1px solid #333333; | |
border-radius: 8px; | |
} | |
/* Style for buttons */ | |
.stButton > button { | |
background-color: #1f77b4; | |
color: #ffffff; | |
border-radius: 8px; | |
border: none; | |
padding: 10px 20px; | |
margin-left: auto; | |
margin-right: auto; | |
display: block; | |
} | |
.stDownloadButton > button { | |
background-color: #1f77b4; | |
color: #ffffff; | |
border-radius: 8px; | |
border: none; | |
padding: 10px 20px; | |
margin-left: auto; | |
margin-right: auto; | |
display: block; | |
} | |
/* Center audio player */ | |
.stAudio { | |
display: flex; | |
justify-content: center; | |
} | |
/* Style text and labels */ | |
h1, p, label, .stMarkdown, .stSpinner, .stError, .stWarning { | |
color: #ffffff !important; | |
text-align: center; | |
} | |
/* Style the three-dot menu */ | |
.st-emotion-cache-1j0y6p8 { | |
background-color: #000000 !important; | |
color: #ffffff !important; | |
} | |
.st-emotion-cache-1j0y6p8 svg { | |
fill: #ffffff !important; | |
} | |
.st-emotion-cache-1j0y6p8:hover { | |
background-color: #1a1a1a !important; | |
} | |
.st-emotion-cache-1h0l5z3 { /* Menu dropdown */ | |
background-color: #000000 !important; | |
color: #ffffff !important; | |
border: 1px solid #333333; | |
border-radius: 8px; | |
} | |
.st-emotion-cache-1h0l5z3 a { | |
color: #ffffff !important; | |
} | |
/* Override sidebar and other elements */ | |
.st-emotion-cache-1r4v8oq, .st-emotion-cache-10trblm { | |
background-color: #000000 !important; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
async def text_to_speech_edge(text, voice): | |
communicate = edge_tts.Communicate(text, voice) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file: | |
tmp_path = tmp_file.name | |
await communicate.save(tmp_path) | |
return tmp_path | |
def main(): | |
# Center the title and description with white text | |
#st.markdown("<h1 style='text-align: center; color: #ffffff;'>Text-to-Speech Converter</h1>", unsafe_allow_html=True) | |
#st.markdown("<p style='text-align: center; color: #ffffff;'>Enter text and select a language and voice to generate an MP3 audio file.</p>", unsafe_allow_html=True) | |
# Input text area, centered | |
with st.container(): | |
input_text = st.text_area("Input Text", height=150, placeholder="Enter the text you want to convert to speech...", key="input_text") | |
# Side-by-side dropdowns for language and voice | |
col1, col2 = st.columns(2) | |
with col1: | |
languages = sorted(language_groups.keys()) | |
selected_language = st.selectbox("Select Language", languages, index=languages.index("English") if "English" in languages else 0) | |
with col2: | |
voices = language_groups.get(selected_language, []) | |
selected_voice = st.selectbox("Select Voice", voices, index=0) | |
# Center the button with container width | |
with st.container(): | |
if st.button("Generate Audio", use_container_width=True): | |
if input_text and selected_voice: | |
with st.spinner("Generating audio... Please wait!"): | |
voice_code = language_dict.get(selected_voice, "en-US-JennyNeural") | |
try: | |
loop = asyncio.new_event_loop() | |
asyncio.set_event_loop(loop) | |
audio_path = loop.run_until_complete(text_to_speech_edge(input_text, voice_code)) | |
# Display audio player, centered | |
st.audio(audio_path, format="audio/mp3") | |
# Provide download link, centered | |
with open(audio_path, "rb") as file: | |
st.download_button( | |
label="Download MP3", | |
data=file, | |
file_name="output.mp3", | |
mime="audio/mp3", | |
use_container_width=True | |
) | |
# Clean up temporary file | |
os.unlink(audio_path) | |
except Exception as e: | |
st.error(f"Error generating audio: {str(e)}") | |
else: | |
st.warning("Please enter text and select a voice.") | |
if __name__ == "__main__": | |
main() |