VSPAN commited on
Commit
d61fa63
·
verified ·
1 Parent(s): 3a70757

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -217
app.py CHANGED
@@ -4,11 +4,6 @@ import asyncio
4
  import tempfile
5
  import re
6
  import emoji
7
- from flask import Flask, request, jsonify, render_template_string, send_from_directory, abort
8
- import os
9
-
10
- app = Flask(__name__)
11
-
12
  # Функция для очистки текста от нежелательных символов и эмодзи
13
  def clean_text(text):
14
  # Удаление указанных символов
@@ -16,18 +11,16 @@ def clean_text(text):
16
  # Удаление эмодзи
17
  text = emoji.replace_emoji(text, replace='')
18
  return text
19
-
20
  # Get all available voices
21
  async def get_voices():
22
  voices = await edge_tts.list_voices()
23
  return {f"{v['ShortName']} - {v['Locale']} ({v['Gender']})": v['ShortName'] for v in voices}
24
-
25
  # Text-to-speech function
26
  async def text_to_speech(text, voice, rate, pitch):
27
  if not text.strip():
28
- return None, "Пожалуйста, введите текст для озвучки."
29
  if not voice:
30
- return None, "Пожалуйста, выберите голос."
31
 
32
  # Очистка текста
33
  text = clean_text(text)
@@ -41,215 +34,39 @@ async def text_to_speech(text, voice, rate, pitch):
41
  try:
42
  await communicate.save(tmp_path)
43
  except Exception as e:
44
- return None, f"Произошла ошибка при конвертации текста в речь: {str(e)}"
45
  return tmp_path, None
46
-
47
- # HTML шаблон
48
- HTML_TEMPLATE = """
49
- <!DOCTYPE html>
50
- <html lang="ru">
51
- <head>
52
- <meta charset="UTF-8">
53
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
54
- <title>Озвучка с музыкальной атмосферой</title>
55
- <style>
56
- body {
57
- background-color: white;
58
- color: #FF6347; /* Томатный оранжевый */
59
- font-family: Arial, sans-serif;
60
- margin: 0;
61
- padding: 0;
62
- }
63
-
64
- header {
65
- background-color: #FF6347;
66
- color: white;
67
- padding: 10px 20px;
68
- text-align: center;
69
- }
70
-
71
- .container {
72
- padding: 20px;
73
- }
74
-
75
- .audio-control {
76
- position: fixed;
77
- bottom: 20px;
78
- left: 20px;
79
- background-color: white;
80
- border: 1px solid #FF6347;
81
- padding: 10px;
82
- border-radius: 5px;
83
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
84
- }
85
-
86
- button {
87
- background-color: #FF6347;
88
- color: white;
89
- border: none;
90
- padding: 10px 20px;
91
- border-radius: 5px;
92
- cursor: pointer;
93
- margin-top: 10px;
94
- }
95
-
96
- button:hover {
97
- background-color: #FF4500; /* Темный томатный оранжевый */
98
- }
99
- </style>
100
- </head>
101
- <body>
102
- <header>
103
- <h1>Озвучка с музыкальной атмосферой</h1>
104
- </header>
105
- <div class="container">
106
- <textarea id="text-input" rows="5" placeholder="Введите текст для озвучки"></textarea>
107
- <br>
108
- <select id="voice-select">
109
- <!-- Опции будут заполнены через JavaScript -->
110
- </select>
111
- <br>
112
- <label for="rate-slider">Скорость озвучки:</label>
113
- <input type="range" id="rate-slider" min="-50" max="50" value="0" step="1">
114
- <br>
115
- <label for="pitch-slider">Тон озвучки:</label>
116
- <input type="range" id="pitch-slider" min="-20" max="20" value="0" step="1">
117
- <br>
118
- <button onclick="generateAudio()">Озвучить</button>
119
- <br>
120
- <audio id="audio-player" controls style="display:none;"></audio>
121
- </div>
122
- <div class="audio-control">
123
- <label for="atmosphere-select">Атмосфера:</label>
124
- <select id="atmosphere-select">
125
- <option value="dynamic">Динамичная</option>
126
- <option value="calm">Спокойная</option>
127
- </select>
128
- <br>
129
- <button onclick="toggleMusic()">Выключить музыку</button>
130
- <audio id="background-music" loop></audio>
131
- </div>
132
- <script>
133
- let voices = [];
134
- let currentMusic = null;
135
-
136
- document.addEventListener('DOMContentLoaded', () => {
137
- fetch('/get_voices')
138
- .then(response => response.json())
139
- .then(data => {
140
- voices = data;
141
- const voiceSelect = document.getElementById('voice-select');
142
- Object.keys(voices).forEach(key => {
143
- const option = document.createElement('option');
144
- option.value = voices[key];
145
- option.textContent = key;
146
- voiceSelect.appendChild(option);
147
- });
148
- });
149
-
150
- const atmosphereSelect = document.getElementById('atmosphere-select');
151
- atmosphereSelect.addEventListener('change', () => {
152
- changeMusic(atmosphereSelect.value);
153
- });
154
-
155
- changeMusic(atmosphereSelect.value); // Устанавливаем музыку по умолчанию
156
- });
157
-
158
- function generateAudio() {
159
- const text = document.getElementById('text-input').value;
160
- const voice = document.getElementById('voice-select').value;
161
- const rate = document.getElementById('rate-slider').value;
162
- const pitch = document.getElementById('pitch-slider').value;
163
-
164
- if (!text.trim()) {
165
- alert('Пожалуйста, введите текст для озвучки.');
166
- return;
167
- }
168
- if (!voice) {
169
- alert('Пожалуйста, выберите голос.');
170
- return;
171
- }
172
-
173
- fetch('/tts', {
174
- method: 'POST',
175
- headers: {
176
- 'Content-Type': 'application/json'
177
- },
178
- body: JSON.stringify({ text, voice, rate, pitch })
179
- })
180
- .then(response => response.json())
181
- .then(data => {
182
- if (data.warning) {
183
- alert(data.warning);
184
- } else {
185
- const audioPlayer = document.getElementById('audio-player');
186
- audioPlayer.src = data.audio;
187
- audioPlayer.style.display = 'block';
188
- audioPlayer.play();
189
- audioPlayer.addEventListener('ended', () => {
190
- document.getElementById('background-music').play();
191
- });
192
- }
193
- });
194
- }
195
-
196
- function changeMusic(atmosphere) {
197
- const backgroundMusic = document.getElementById('background-music');
198
- backgroundMusic.src = `/music/${atmosphere}.mp3`;
199
- backgroundMusic.play();
200
- currentMusic = atmosphere;
201
- }
202
-
203
- function toggleMusic() {
204
- const backgroundMusic = document.getElementById('background-music');
205
- if (backgroundMusic.paused) {
206
- backgroundMusic.play();
207
- document.querySelector('.audio-control button').textContent = 'Выключить музыку';
208
- } else {
209
- backgroundMusic.pause();
210
- document.querySelector('.audio-control button').textContent = 'Включить музыку';
211
- }
212
- }
213
- </script>
214
- </body>
215
- </html>
216
- """
217
-
218
- @app.route('/get_voices', methods=['GET'])
219
- async def get_voices_route():
220
  voices = await get_voices()
221
- app.logger.info(f"Voices: {voices}")
222
- return jsonify(voices)
223
-
224
- @app.route('/tts', methods=['POST'])
225
- async def tts_route():
226
- data = request.get_json()
227
- text = data.get('text', '')
228
- voice = data.get('voice', '')
229
- rate = data.get('rate', 0)
230
- pitch = data.get('pitch', 0)
231
 
232
- audio, warning = await text_to_speech(text, voice, rate, pitch)
233
- if warning:
234
- app.logger.warning(f"Warning: {warning}")
235
- return jsonify({'warning': warning})
236
- else:
237
- app.logger.info(f"Audio file generated: {audio}")
238
- return jsonify({'audio': audio})
239
-
240
- @app.route('/')
241
- def index():
242
- return render_template_string(HTML_TEMPLATE)
243
-
244
- @app.route('/music/<path:path>')
245
- def serve_music(path):
246
- music_path = os.path.join('music', path)
247
- if os.path.exists(music_path):
248
- app.logger.info(f"Serving music file: {music_path}")
249
- return send_from_directory('music', path)
250
- else:
251
- app.logger.error(f"Music file not found: {music_path}")
252
- return "Файл не найден", 404
253
-
 
254
  if __name__ == "__main__":
255
- app.run(debug=True)
 
 
4
  import tempfile
5
  import re
6
  import emoji
 
 
 
 
 
7
  # Функция для очистки текста от нежелательных символов и эмодзи
8
  def clean_text(text):
9
  # Удаление указанных символов
 
11
  # Удаление эмодзи
12
  text = emoji.replace_emoji(text, replace='')
13
  return text
 
14
  # Get all available voices
15
  async def get_voices():
16
  voices = await edge_tts.list_voices()
17
  return {f"{v['ShortName']} - {v['Locale']} ({v['Gender']})": v['ShortName'] for v in voices}
 
18
  # Text-to-speech function
19
  async def text_to_speech(text, voice, rate, pitch):
20
  if not text.strip():
21
+ return None, gr.Warning("Please enter text to convert.")
22
  if not voice:
23
+ return None, gr.Warning("Please select a voice.")
24
 
25
  # Очистка текста
26
  text = clean_text(text)
 
34
  try:
35
  await communicate.save(tmp_path)
36
  except Exception as e:
37
+ return None, gr.Warning(f"An error occurred during text-to-speech conversion: {str(e)}")
38
  return tmp_path, None
39
+ # Gradio interface function
40
+ def tts_interface(text, voice, rate, pitch):
41
+ audio, warning = asyncio.run(text_to_speech(text, voice, rate, pitch))
42
+ return audio, warning
43
+ # Create Gradio application
44
+ async def create_demo():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  voices = await get_voices()
 
 
 
 
 
 
 
 
 
 
46
 
47
+ description = """
48
+ """
49
+
50
+ demo = gr.Interface(
51
+ fn=tts_interface,
52
+ inputs=[
53
+ gr.Textbox(label="Input Text", lines=5),
54
+ gr.Dropdown(choices=[""] + list(voices.keys()), label="Select Voice", value=""),
55
+ gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1),
56
+ gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
57
+ ],
58
+ outputs=[
59
+ gr.Audio(label="Generated Audio", type="filepath"),
60
+ gr.Markdown(label="Warning", visible=False)
61
+ ],
62
+ title="Edge TTS Text-to-Speech",
63
+ description=description,
64
+ article="",
65
+ analytics_enabled=False,
66
+ allow_flagging="manual"
67
+ )
68
+ return demo
69
+ # Run the application
70
  if __name__ == "__main__":
71
+ demo = asyncio.run(create_demo())
72
+ demo.launch()