jklee8212 commited on
Commit
88d3bc9
Β·
verified Β·
1 Parent(s): 99e4987

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +158 -0
app.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import tempfile
4
+ import os
5
+ from gtts import gTTS
6
+ import librosa
7
+ def text_to_speech(text, language="ko"):
8
+ """Convert text to speech using Google TTS"""
9
+ if not text.strip():
10
+ return None, None
11
+ with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as fp:
12
+ temp_filename = fp.name
13
+ tts = gTTS(text=text, lang=language, slow=False)
14
+ tts.save(temp_filename)
15
+ # Load the audio for visualization and playback
16
+ y, sr = librosa.load(temp_filename, sr=None)
17
+ return temp_filename, (sr, y)
18
+ def clear_outputs():
19
+ return None, None
20
+ css = """
21
+ @keyframes pulse {
22
+ 0% {
23
+ box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.7);
24
+ }
25
+ 70% {
26
+ box-shadow: 0 0 0 10px rgba(255, 215, 0, 0);
27
+ }
28
+ 100% {
29
+ box-shadow: 0 0 0 0 rgba(255, 215, 0, 0);
30
+ }
31
+ }
32
+ .playing-audio {
33
+ animation: pulse 1.5s infinite;
34
+ border: 2px solid #FFD700 !important;
35
+ background-color: rgba(255, 215, 0, 0.1) !important;
36
+ }
37
+ /* μ‹ μ„ΈλŒ€ μŠ€νƒ€μΌ μŒμ„± λ°•μŠ€ */
38
+ .gradio-audio {
39
+ background: linear-gradient(135deg, #50C878, #4CBB17) !important;
40
+ border-radius: 15px !important;
41
+ padding: 15px !important;
42
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2) !important;
43
+ transition: all 0.3s ease !important;
44
+ }
45
+ .gradio-audio:hover {
46
+ transform: translateY(-5px) !important;
47
+ box-shadow: 0 12px 25px rgba(0, 0, 0, 0.25) !important;
48
+ }
49
+ /* μ˜€λ””μ˜€ ν”Œλ ˆμ΄μ–΄ μŠ€νƒ€μΌλ§ */
50
+ audio {
51
+ border-radius: 30px !important;
52
+ background-color: rgba(255, 255, 255, 0.2) !important;
53
+ width: 100% !important;
54
+ }
55
+ /* λ ˆμ΄λΈ” μŠ€νƒ€μΌ */
56
+ .gradio-audio label {
57
+ color: white !important;
58
+ font-weight: bold !important;
59
+ font-size: 1.1em !important;
60
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
61
+ margin-bottom: 10px !important;
62
+ }
63
+ /* μŒμ„± νŒŒν˜• μ»¨ν…Œμ΄λ„ˆ */
64
+ .gradio-audio .waveform-container {
65
+ background-color: rgba(255, 255, 255, 0.1) !important;
66
+ border-radius: 10px !important;
67
+ padding: 5px !important;
68
+ }
69
+ /* 빨간색 λ²„νŠΌ μŠ€νƒ€μΌ */
70
+ .red-button {
71
+ background-color: #FF0000 !important;
72
+ color: white !important;
73
+ border: none !important;
74
+ font-weight: bold !important;
75
+ }
76
+ .red-button:hover {
77
+ background-color: #CC0000 !important;
78
+ }
79
+ """
80
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="green"), css=css) as demo:
81
+ gr.Markdown("# ν•œκ΅­μ–΄ ν…μŠ€νŠΈ μŒμ„± λ³€ν™˜ (TTS)")
82
+ with gr.Row():
83
+ with gr.Column(scale=3):
84
+ text_input = gr.Textbox(
85
+ placeholder="λ³€ν™˜ν•  ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”...",
86
+ label="ν…μŠ€νŠΈ μž…λ ₯",
87
+ lines=5
88
+ )
89
+ with gr.Row():
90
+ lang_selector = gr.Dropdown(
91
+ choices=["ko", "en", "ja", "zh-CN", "fr", "es", "de"],
92
+ value="ko",
93
+ label="μ–Έμ–΄ 선택",
94
+ info="ko: ν•œκ΅­μ–΄, en: μ˜μ–΄, ja: 일본어, zh-CN: 쀑ꡭ어, fr: ν”„λž‘μŠ€μ–΄, es: μŠ€νŽ˜μΈμ–΄, de: 독일어"
95
+ )
96
+ btn = gr.Button("μŒμ„± μ°½μ‘°", elem_classes=["red-button"])
97
+ clear_btn = gr.Button("μ΄ˆκΈ°ν™”")
98
+ with gr.Column(scale=3):
99
+ audio_output = gr.Audio(label="μƒμ„±λœ μŒμ„±", type="filepath")
100
+ waveform = gr.Audio(label="νŒŒν˜•", type="numpy", visible=True)
101
+ # Add JavaScript for audio playback animation
102
+ audio_js = """
103
+ function setupAudioAnimation() {
104
+ const audioElements = document.querySelectorAll('audio');
105
+ audioElements.forEach(audio => {
106
+ audio.addEventListener('play', () => {
107
+ const audioContainer = audio.closest('.gradio-audio');
108
+ if (audioContainer) {
109
+ audioContainer.classList.add('playing-audio');
110
+ }
111
+ });
112
+ audio.addEventListener('pause', () => {
113
+ const audioContainer = audio.closest('.gradio-audio');
114
+ if (audioContainer) {
115
+ audioContainer.classList.remove('playing-audio');
116
+ }
117
+ });
118
+ audio.addEventListener('ended', () => {
119
+ const audioContainer = audio.closest('.gradio-audio');
120
+ if (audioContainer) {
121
+ audioContainer.classList.remove('playing-audio');
122
+ }
123
+ });
124
+ });
125
+ }
126
+ // Setup initial elements
127
+ setupAudioAnimation();
128
+ // Setup observer for dynamically added elements
129
+ const observer = new MutationObserver((mutations) => {
130
+ for (const mutation of mutations) {
131
+ if (mutation.addedNodes.length) {
132
+ setupAudioAnimation();
133
+ }
134
+ }
135
+ });
136
+ observer.observe(document.body, { childList: true, subtree: true });
137
+ """
138
+ demo.load(None, js=audio_js)
139
+ btn.click(
140
+ fn=text_to_speech,
141
+ inputs=[text_input, lang_selector],
142
+ outputs=[audio_output, waveform]
143
+ )
144
+ clear_btn.click(
145
+ fn=clear_outputs,
146
+ inputs=[],
147
+ outputs=[audio_output, waveform]
148
+ )
149
+ gr.Markdown("""
150
+ ### μ‚¬μš© 방법
151
+ 1. λ³€ν™˜ν•˜κ³  싢은 ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”
152
+ 2. μ–Έμ–΄λ₯Ό μ„ νƒν•˜μ„Έμš” (κΈ°λ³Έ: ν•œκ΅­μ–΄)
153
+ 3. 'μŒμ„± μ°½μ‘°' λ²„νŠΌμ„ ν΄λ¦­ν•˜μ„Έμš”
154
+ 4. μƒμ„±λœ μŒμ„±μ„ λ“€μ–΄λ³΄μ„Έμš”
155
+ """)
156
+
157
+ if __name__ == '__main__':
158
+ demo.launch()