Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,77 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
import random
|
3 |
-
import re
|
4 |
import string
|
5 |
-
import
|
6 |
-
import
|
7 |
-
|
|
|
|
|
8 |
|
9 |
app = Flask(__name__)
|
10 |
|
11 |
-
# Define
|
12 |
-
file_folder = '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
def filter_text(text):
|
15 |
-
|
16 |
-
filtered_text = re.sub(r'[^\w\s,.\(\):\u00C0-\u00FF]', '',
|
17 |
filtered_text = filtered_text.replace('\n', ' ')
|
18 |
-
|
19 |
-
return filtered_text[:500]
|
20 |
|
21 |
-
def convert_text_to_speech(
|
22 |
-
|
23 |
random_name = ''.join(random.choices(string.ascii_letters + string.digits, k=8)) + '.wav'
|
24 |
-
output_file = os.path.join(
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
return None
|
36 |
else:
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
@app.route('/')
|
40 |
def index():
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
app.logger.info("Contents of current folder: %s", os.listdir(file_folder))
|
45 |
return render_template('index.html', model_options=model_options)
|
46 |
|
47 |
@app.route('/convert', methods=['POST'])
|
|
|
48 |
def convert_text():
|
49 |
-
text = request.form
|
50 |
-
model = request.form
|
51 |
-
|
52 |
-
if not text or not model:
|
53 |
-
return jsonify({'error': 'Invalid request'}), 400
|
54 |
-
|
55 |
output_file = convert_text_to_speech(text, model)
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
|
|
66 |
with open(output_file, 'rb') as audio_file:
|
67 |
audio_content = audio_file.read()
|
68 |
-
|
69 |
audio_base64 = base64.b64encode(audio_content).decode('utf-8')
|
70 |
-
|
71 |
response = jsonify({'audio_base64': audio_base64})
|
72 |
-
return response
|
73 |
else:
|
74 |
-
|
|
|
|
|
75 |
|
76 |
if __name__ == '__main__':
|
77 |
-
|
|
|
|
1 |
+
import logging
|
2 |
+
from flask import Flask, render_template, request, jsonify, after_this_request
|
3 |
+
from functools import wraps
|
4 |
+
from io import BytesIO
|
5 |
+
import base64
|
6 |
+
import subprocess
|
7 |
import os
|
8 |
import random
|
|
|
9 |
import string
|
10 |
+
import re
|
11 |
+
import sys
|
12 |
+
|
13 |
+
# Configuraci贸n del registro
|
14 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
15 |
|
16 |
app = Flask(__name__)
|
17 |
|
18 |
+
# Define el directorio donde se guardan los archivos
|
19 |
+
file_folder = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__)))
|
20 |
+
temp_audio_folder = os.path.join(file_folder, 'output')
|
21 |
+
model_folder = os.path.join(file_folder, 'models')
|
22 |
+
piper_binary_path = os.path.join(file_folder,'piper')
|
23 |
+
|
24 |
+
# Define los nombres asignados a modelos espec铆ficos
|
25 |
+
model_names = {
|
26 |
+
"Espa帽ol M茅xico | Claude": "es_MX-claude-14947-epoch-high.onnx",
|
27 |
+
"Espa帽ol M茅xico | Cortana v1": "es_MX-cortana-19669-epoch-high.onnx",
|
28 |
+
"Espa帽ol M茅xico | TheGevy": "es_MX-gevy-10196-epoch-high.onnx",
|
29 |
+
"English United States Example": "en_US-ljspeech-high.onnx"
|
30 |
+
}
|
31 |
|
32 |
def filter_text(text):
|
33 |
+
filtered_text = text.replace('(', ',').replace(')', ',').replace('?', ',').replace('驴', ',').replace(':', ',')
|
34 |
+
filtered_text = re.sub(r'[^\w\s,.\(\):\u00C0-\u00FF]', '', filtered_text)
|
35 |
filtered_text = filtered_text.replace('\n', ' ')
|
36 |
+
return filtered_text
|
|
|
37 |
|
38 |
+
def convert_text_to_speech(text, model):
|
39 |
+
filtered_text = filter_text(text)
|
40 |
random_name = ''.join(random.choices(string.ascii_letters + string.digits, k=8)) + '.wav'
|
41 |
+
output_file = os.path.join(temp_audio_folder, random_name)
|
42 |
+
|
43 |
+
if os.path.isfile(piper_binary_path):
|
44 |
+
if model in model_names:
|
45 |
+
model_path = os.path.join(model_folder, model_names[model])
|
46 |
+
if os.path.isfile(model_path):
|
47 |
+
# Construye el comando para ejecutar Piper
|
48 |
+
command = f'echo "{filtered_text}" | "{piper_binary_path}" -m {model_path} -f {output_file}'
|
49 |
+
try:
|
50 |
+
subprocess.run(command, shell=True, check=True)
|
51 |
+
return output_file
|
52 |
+
except subprocess.CalledProcessError as e:
|
53 |
+
logging.error(f"Error al ejecutar el comando: {e}")
|
54 |
+
return None
|
55 |
+
else:
|
56 |
+
logging.error(f"Modelo '{model}' no encontrado en la ubicaci贸n especificada.")
|
57 |
+
return None
|
58 |
+
else:
|
59 |
+
logging.error(f"No se ha asignado un modelo para el nombre '{model}'.")
|
60 |
return None
|
61 |
else:
|
62 |
+
logging.error(f"No se encontr贸 el binario de Piper en la ubicaci贸n especificada.")
|
63 |
+
return None
|
64 |
+
|
65 |
+
# Define una funci贸n decoradora para restringir el acceso a la ruta /convert
|
66 |
+
def restrict_access(func):
|
67 |
+
@wraps(func)
|
68 |
+
def wrapper(*args, **kwargs):
|
69 |
+
# Verifica si la solicitud se hizo desde la p谩gina index.html
|
70 |
+
referer = request.headers.get("Referer")
|
71 |
+
if referer and referer.endswith("/"):
|
72 |
+
# Permite el acceso a la funci贸n si la solicitud proviene de la p谩gina index.html
|
73 |
+
return func(*args, **kwargs)
|
74 |
+
else:
|
75 |
+
# Devuelve un mensaje de error o redirecciona a otra p谩gina
|
76 |
+
return "Acceso no autorizado", 403 # C贸digo de respuesta HTTP 403 - Forbidden
|
77 |
+
return wrapper
|
78 |
|
79 |
@app.route('/')
|
80 |
def index():
|
81 |
+
model_options = list(model_names.keys())
|
82 |
+
# Registra el contenido de la carpeta actual
|
83 |
+
logging.info("Contents of current folder: %s", os.listdir(file_folder))
|
|
|
84 |
return render_template('index.html', model_options=model_options)
|
85 |
|
86 |
@app.route('/convert', methods=['POST'])
|
87 |
+
@restrict_access
|
88 |
def convert_text():
|
89 |
+
text = request.form['text']
|
90 |
+
model = request.form['model']
|
|
|
|
|
|
|
|
|
91 |
output_file = convert_text_to_speech(text, model)
|
92 |
+
|
93 |
+
@after_this_request
|
94 |
+
def remove_file(response):
|
95 |
+
try:
|
96 |
+
os.remove(output_file)
|
97 |
+
logging.info("Audio file deleted: %s", output_file)
|
98 |
+
except Exception as error:
|
99 |
+
logging.error("Error deleting file: %s", error)
|
100 |
+
return response
|
101 |
+
|
102 |
+
if output_file is not None:
|
103 |
with open(output_file, 'rb') as audio_file:
|
104 |
audio_content = audio_file.read()
|
105 |
+
|
106 |
audio_base64 = base64.b64encode(audio_content).decode('utf-8')
|
107 |
+
|
108 |
response = jsonify({'audio_base64': audio_base64})
|
|
|
109 |
else:
|
110 |
+
response = jsonify({'error': 'Error al convertir texto a voz'})
|
111 |
+
|
112 |
+
return response
|
113 |
|
114 |
if __name__ == '__main__':
|
115 |
+
logging.info("Se est谩 iniciando la aplicaci贸n.")
|
116 |
+
app.run(host='0.0.0.0', port=7860, debug=False)
|