kcipxo / app.py
jklee8212's picture
Upload app.py with huggingface_hub
88d3bc9 verified
import gradio as gr
import numpy as np
import tempfile
import os
from gtts import gTTS
import librosa
def text_to_speech(text, language="ko"):
"""Convert text to speech using Google TTS"""
if not text.strip():
return None, None
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as fp:
temp_filename = fp.name
tts = gTTS(text=text, lang=language, slow=False)
tts.save(temp_filename)
# Load the audio for visualization and playback
y, sr = librosa.load(temp_filename, sr=None)
return temp_filename, (sr, y)
def clear_outputs():
return None, None
css = """
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(255, 215, 0, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(255, 215, 0, 0);
}
}
.playing-audio {
animation: pulse 1.5s infinite;
border: 2px solid #FFD700 !important;
background-color: rgba(255, 215, 0, 0.1) !important;
}
/* μ‹ μ„ΈλŒ€ μŠ€νƒ€μΌ μŒμ„± λ°•μŠ€ */
.gradio-audio {
background: linear-gradient(135deg, #50C878, #4CBB17) !important;
border-radius: 15px !important;
padding: 15px !important;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2) !important;
transition: all 0.3s ease !important;
}
.gradio-audio:hover {
transform: translateY(-5px) !important;
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.25) !important;
}
/* μ˜€λ””μ˜€ ν”Œλ ˆμ΄μ–΄ μŠ€νƒ€μΌλ§ */
audio {
border-radius: 30px !important;
background-color: rgba(255, 255, 255, 0.2) !important;
width: 100% !important;
}
/* λ ˆμ΄λΈ” μŠ€νƒ€μΌ */
.gradio-audio label {
color: white !important;
font-weight: bold !important;
font-size: 1.1em !important;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
margin-bottom: 10px !important;
}
/* μŒμ„± νŒŒν˜• μ»¨ν…Œμ΄λ„ˆ */
.gradio-audio .waveform-container {
background-color: rgba(255, 255, 255, 0.1) !important;
border-radius: 10px !important;
padding: 5px !important;
}
/* 빨간색 λ²„νŠΌ μŠ€νƒ€μΌ */
.red-button {
background-color: #FF0000 !important;
color: white !important;
border: none !important;
font-weight: bold !important;
}
.red-button:hover {
background-color: #CC0000 !important;
}
"""
with gr.Blocks(theme=gr.themes.Soft(primary_hue="green"), css=css) as demo:
gr.Markdown("# ν•œκ΅­μ–΄ ν…μŠ€νŠΈ μŒμ„± λ³€ν™˜ (TTS)")
with gr.Row():
with gr.Column(scale=3):
text_input = gr.Textbox(
placeholder="λ³€ν™˜ν•  ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”...",
label="ν…μŠ€νŠΈ μž…λ ₯",
lines=5
)
with gr.Row():
lang_selector = gr.Dropdown(
choices=["ko", "en", "ja", "zh-CN", "fr", "es", "de"],
value="ko",
label="μ–Έμ–΄ 선택",
info="ko: ν•œκ΅­μ–΄, en: μ˜μ–΄, ja: 일본어, zh-CN: 쀑ꡭ어, fr: ν”„λž‘μŠ€μ–΄, es: μŠ€νŽ˜μΈμ–΄, de: 독일어"
)
btn = gr.Button("μŒμ„± μ°½μ‘°", elem_classes=["red-button"])
clear_btn = gr.Button("μ΄ˆκΈ°ν™”")
with gr.Column(scale=3):
audio_output = gr.Audio(label="μƒμ„±λœ μŒμ„±", type="filepath")
waveform = gr.Audio(label="νŒŒν˜•", type="numpy", visible=True)
# Add JavaScript for audio playback animation
audio_js = """
function setupAudioAnimation() {
const audioElements = document.querySelectorAll('audio');
audioElements.forEach(audio => {
audio.addEventListener('play', () => {
const audioContainer = audio.closest('.gradio-audio');
if (audioContainer) {
audioContainer.classList.add('playing-audio');
}
});
audio.addEventListener('pause', () => {
const audioContainer = audio.closest('.gradio-audio');
if (audioContainer) {
audioContainer.classList.remove('playing-audio');
}
});
audio.addEventListener('ended', () => {
const audioContainer = audio.closest('.gradio-audio');
if (audioContainer) {
audioContainer.classList.remove('playing-audio');
}
});
});
}
// Setup initial elements
setupAudioAnimation();
// Setup observer for dynamically added elements
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.addedNodes.length) {
setupAudioAnimation();
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
"""
demo.load(None, js=audio_js)
btn.click(
fn=text_to_speech,
inputs=[text_input, lang_selector],
outputs=[audio_output, waveform]
)
clear_btn.click(
fn=clear_outputs,
inputs=[],
outputs=[audio_output, waveform]
)
gr.Markdown("""
### μ‚¬μš© 방법
1. λ³€ν™˜ν•˜κ³  싢은 ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”
2. μ–Έμ–΄λ₯Ό μ„ νƒν•˜μ„Έμš” (κΈ°λ³Έ: ν•œκ΅­μ–΄)
3. 'μŒμ„± μ°½μ‘°' λ²„νŠΌμ„ ν΄λ¦­ν•˜μ„Έμš”
4. μƒμ„±λœ μŒμ„±μ„ λ“€μ–΄λ³΄μ„Έμš”
""")
if __name__ == '__main__':
demo.launch()