Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastai.vision.all import *
|
2 |
+
import gradio as gr
|
3 |
+
|
4 |
+
from pytube import YouTube #Para descargar los videos
|
5 |
+
from pydub import AudioSegment
|
6 |
+
import pydub #Para trabajar con el audio
|
7 |
+
|
8 |
+
import os
|
9 |
+
import os.path as osp
|
10 |
+
from mlxtend.file_io import find_files
|
11 |
+
from mlxtend.utils import Counter
|
12 |
+
|
13 |
+
import re #Para la parte de normalizar
|
14 |
+
import string
|
15 |
+
import nltk
|
16 |
+
nltk.download('punkt')
|
17 |
+
nltk.download('stopwords')
|
18 |
+
from nltk.tokenize import word_tokenize
|
19 |
+
from autocorrect import Speller #Para los errores ortográficos
|
20 |
+
spell = Speller(lang='es')
|
21 |
+
from jiwer import wer #Para la métrica
|
22 |
+
|
23 |
+
# Cargamos el learner
|
24 |
+
learn = load_learner('export.pkl')
|
25 |
+
|
26 |
+
# Definimos las funciones necesarias
|
27 |
+
|
28 |
+
def cargarAudio(video, i):
|
29 |
+
video.streams.filter(only_audio=True)
|
30 |
+
audio = video.streams.get_by_itag(22)
|
31 |
+
mp4 = audio.download()
|
32 |
+
a = mp4.split('/')
|
33 |
+
titulo = a[-1]
|
34 |
+
os.rename(titulo, 'video_'+str(i)+'.mp4')
|
35 |
+
cont = 'video_'+str(i)
|
36 |
+
return cont
|
37 |
+
|
38 |
+
def transcribir(cont, model, device):
|
39 |
+
audio_outdir = "./extracted_audio"
|
40 |
+
subtitle_outdir = "./generated_subtitles"
|
41 |
+
video = cont + '.mp4'
|
42 |
+
base, ext = osp.splitext(video)
|
43 |
+
aac_file_out = osp.join(audio_outdir, osp.basename(base)) + ".aac"
|
44 |
+
os.system(f"ffmpeg -i {video} -vn -acodec copy {aac_file_out} ")
|
45 |
+
os.system(f"whisper {aac_file_out} --model {model} --language Spanish --output_dir {subtitle_outdir} --verbose False --device cuda:{device}")
|
46 |
+
f = open('./generated_subtitles/' + str(cont) + '.aac.txt','r')
|
47 |
+
trans = f.read()
|
48 |
+
transcripcion = (trans.split('\n'))[0]
|
49 |
+
return transcripcion
|
50 |
+
|
51 |
+
|
52 |
+
def numero_to_letras(numero):
|
53 |
+
indicador = [("",""),("mil","mil"),("millon","millones"),("mil","mil"),("billon","billones")]
|
54 |
+
entero = int(numero)
|
55 |
+
decimal = int(round((numero - entero)*100))
|
56 |
+
#print 'decimal : ',decimal
|
57 |
+
contador = 0
|
58 |
+
numero_letras = ""
|
59 |
+
while entero >0:
|
60 |
+
a = entero % 1000
|
61 |
+
if contador == 0:
|
62 |
+
en_letras = convierte_cifra(a,1).strip()
|
63 |
+
else :
|
64 |
+
en_letras = convierte_cifra(a,0).strip()
|
65 |
+
if a==0:
|
66 |
+
numero_letras = en_letras+" "+numero_letras
|
67 |
+
elif a==1:
|
68 |
+
if contador in (1,3):
|
69 |
+
numero_letras = indicador[contador][0]+" "+numero_letras
|
70 |
+
else:
|
71 |
+
numero_letras = en_letras+" "+indicador[contador][0]+" "+numero_letras
|
72 |
+
else:
|
73 |
+
numero_letras = en_letras+" "+indicador[contador][1]+" "+numero_letras
|
74 |
+
numero_letras = numero_letras.strip()
|
75 |
+
contador = contador + 1
|
76 |
+
entero = int(entero / 1000)
|
77 |
+
|
78 |
+
if decimal == 0:
|
79 |
+
numero_letras = numero_letras
|
80 |
+
else:
|
81 |
+
numero_letras = numero_letras+" con " + str(decimal) +"/100"
|
82 |
+
#print('numero: ',numero)
|
83 |
+
#print(numero_letras)
|
84 |
+
return numero_letras
|
85 |
+
|
86 |
+
|
87 |
+
def convierte_cifra(numero,sw):
|
88 |
+
lista_centana = ["",("cien","ciento"),"doscientos","trescientos","cuatrocientos","quinientos","seiscientos","setecientos","ochocientos","novecientos"]
|
89 |
+
lista_decena = ["",("diez","once","doce","trece","catorce","quince","dieciseis","diecisiete","dieciocho","diecinueve"),
|
90 |
+
("veinte","veinti"),("treinta","treinta y "),("cuarenta" , "cuarenta y "),
|
91 |
+
("cincuenta" , "cincuenta y "),("sesenta" , "sesenta y "),
|
92 |
+
("setenta" , "setenta y "),("ochenta" , "ochenta y "),
|
93 |
+
("noventa" , "noventa y ")
|
94 |
+
]
|
95 |
+
lista_unidad = ["",("un" , "uno"),"dos","tres","cuatro","cinco","seis","siete","ocho","nueve"]
|
96 |
+
centena = int (numero / 100)
|
97 |
+
decena = int((numero -(centena * 100))/10)
|
98 |
+
unidad = int(numero - (centena * 100 + decena * 10))
|
99 |
+
#print "centena: ",centena, "decena: ",decena,'unidad: ',unidad
|
100 |
+
|
101 |
+
texto_centena = ""
|
102 |
+
texto_decena = ""
|
103 |
+
texto_unidad = ""
|
104 |
+
|
105 |
+
#Validad las centenas
|
106 |
+
texto_centena = lista_centana[centena]
|
107 |
+
if centena == 1:
|
108 |
+
if (decena + unidad)!=0:
|
109 |
+
texto_centena = texto_centena[1]
|
110 |
+
else :
|
111 |
+
texto_centena = texto_centena[0]
|
112 |
+
|
113 |
+
#Valida las decenas
|
114 |
+
texto_decena = lista_decena[decena]
|
115 |
+
if decena == 1 :
|
116 |
+
texto_decena = texto_decena[unidad]
|
117 |
+
elif decena > 1 :
|
118 |
+
if unidad != 0 :
|
119 |
+
texto_decena = texto_decena[1]
|
120 |
+
else:
|
121 |
+
texto_decena = texto_decena[0]
|
122 |
+
#Validar las unidades
|
123 |
+
#print "texto_unidad: ",texto_unidad
|
124 |
+
if decena != 1:
|
125 |
+
texto_unidad = lista_unidad[unidad]
|
126 |
+
if unidad == 1:
|
127 |
+
texto_unidad = texto_unidad[sw]
|
128 |
+
return "%s %s %s" %(texto_centena,texto_decena,texto_unidad)
|
129 |
+
|
130 |
+
def normalizar(texto):
|
131 |
+
#print(texto)
|
132 |
+
tokens=word_tokenize(texto) #Separa el texto por palabras
|
133 |
+
#print(tokens)
|
134 |
+
texto = [w.lower() for w in tokens] #Pasamos las palabras a minúsculas
|
135 |
+
#print(texto)
|
136 |
+
texto = [texto[i].replace(' apdo.', ' apartado').replace(' art. ',' articulo ').replace(' atte.',' atentamente').replace(' avda.',' avenida').replace(' cap.',' capítulo').replace(' cía.',' compañía').replace(' coord.',' coordinador').replace(' d.',' don').replace(' dña.',' doña').replace(' dcho.',' derecho').replace(' dcha.',' derecha').replace(' depto.',' departamento').replace(' dr.',' doctor').replace(' dra.',' doctora').replace(' etc.',' etcétera').replace(' fdo.',' firmado').replace(' izqdo.',' izquierdo').replace(' izqda.',' izquierda').replace(' max.',' máximo').replace(' min.',' mínimo').replace(' núm.',' número').replace(' pág.',' página').replace(' ej.',' ejemplo').replace(' prov.',' provincia').replace(' sr.',' señor').replace(' sra.',' señora').replace(' srta.',' señorita').replace(' tfno.',' teléfono') for i in range(len(texto))] #quitamos las abreviaciones
|
137 |
+
for i in range(len(texto)):
|
138 |
+
if texto[i].isdigit() and (texto[i] not in string.punctuation):
|
139 |
+
texto[i]=numero_to_letras(int(texto[i]))
|
140 |
+
tokens2=word_tokenize(texto[i])
|
141 |
+
for j in range(len(tokens2)-1):
|
142 |
+
texto.append('a') #me añado esto simplemente para no tener problemas con el rango
|
143 |
+
for j in range(i+1, len(texto)-3):
|
144 |
+
texto[len(texto)-j+i]=texto[len(texto)-j+i-len(tokens2)+1]
|
145 |
+
for j in range(i, i+len(tokens2)-1):
|
146 |
+
texto[j+len(tokens2)-1] = texto[j]
|
147 |
+
for j in range(i, i+len(tokens2)):
|
148 |
+
texto[j]=tokens2[j-i]
|
149 |
+
tokens=[w.lower() for w in texto] #Pasamos las palabras a minúsculas por si había números
|
150 |
+
re_punc = re.compile('[%s]' % re.escape(string.punctuation))
|
151 |
+
stripped = [re_punc.sub('',w) for w in tokens]
|
152 |
+
stripped=[stripped[i].replace('¿', '').replace('¡','').replace("'",'') for i in range(len(tokens))] #quita los símbolos de puntuación que string.punctuation no tiene en cuenta
|
153 |
+
words = [word for word in stripped if word.isalpha()] #Elimina los signos de puntuación
|
154 |
+
return words
|
155 |
+
|
156 |
+
|
157 |
+
def ortografia(texto):
|
158 |
+
for word in texto:
|
159 |
+
word = spell(word)
|
160 |
+
return texto
|
161 |
+
|
162 |
+
def unir(texto):
|
163 |
+
texto_norm = ""
|
164 |
+
for i in range(len(texto)):
|
165 |
+
texto_norm = texto_norm + ' ' + texto[i]
|
166 |
+
return texto_norm
|
167 |
+
|
168 |
+
# Definimos una función que se encarga de llevar a cabo las transcripciones
|
169 |
+
|
170 |
+
def transcripcion(video, texto, device, model, i):
|
171 |
+
cont = cargarAudio(video, i)
|
172 |
+
trans = transcribir(cont, model, device)
|
173 |
+
|
174 |
+
#Calculamos la métrica con el texto sin normalizar
|
175 |
+
metrica = wer(trans, texto)
|
176 |
+
|
177 |
+
#Normalizamos el texto tanto del modelo como el original
|
178 |
+
norm = normalizar(trans)
|
179 |
+
texto_norm = normalizar(texto)
|
180 |
+
|
181 |
+
#Pasamos el corrector ortográfico tanto al texto del modelo como al original
|
182 |
+
ort = ortografia(norm)
|
183 |
+
texto_ort = ortografia(texto_norm)
|
184 |
+
|
185 |
+
#Unimos ambos textos
|
186 |
+
transcri = unir(ort)
|
187 |
+
texto_unido = unir(texto_ort)
|
188 |
+
|
189 |
+
#Calculamos la métrica con el texto normalizado
|
190 |
+
metrica_norm = wer(transcri, texto_unido)
|
191 |
+
|
192 |
+
return metrica, transcri, metrica_norm
|
193 |
+
|
194 |
+
# Creamos la interfaz y la lanzamos.
|
195 |
+
gr.Interface(fn=predict, inputs="video", outputs="text").launch(share=False)
|
196 |
+
|