JairoDanielMT commited on
Commit
67002a7
1 Parent(s): 296ec00

Upload 6 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # usar imagen base de Python 3.10
2
+ FROM python:3.10
3
+
4
+ # instalar dependencias de Python
5
+ RUN pip install pandas numpy nltk moviepy pydub transformers pydantic pytest whisperx fastapi uvicorn
6
+
7
+ # instalar paquete especial whisperx desde GitHub
8
+ RUN pip install git+https://github.com/m-bain/whisperx.git
9
+
10
+ # instalar paquetes de PyTorch para CUDA 12.1
11
+ RUN pip install torch==1.10.0+cu121 torchvision==0.11.1+cu121 torchaudio==0.10.0+cu121 -f https://download.pytorch.org/whl/torch_stable.html
12
+
13
+ # instalar utilidades básicas
14
+ RUN apt-get update && apt-get install -y \
15
+ curl \
16
+ git \
17
+ unzip \
18
+ wget \
19
+ zip \
20
+ git-lfs \
21
+ ffmpeg
22
+
23
+ # copiar archivos de la aplicación
24
+ COPY . /app
25
+ # copiar todos los archivos de la aplicación
26
+
27
+ COPY . .
28
+ # establecer directorio de trabajo
29
+ WORKDIR /app
30
+
31
+ # instalar dependencias de Python desde requirements.txt
32
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
33
+
34
+ # cambiar permisos de archivos necesarios
35
+ RUN chmod -R 777 /app
36
+
37
+ # definir comando predeterminado para iniciar la aplicación
38
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pyannote.audio import Pipeline
2
+ from pydub import AudioSegment
3
+ import whisperx
4
+ import torch
5
+ import json
6
+ import os
7
+ from fastapi import FastAPI, File, UploadFile
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from pydub.utils import mediainfo
10
+ import subprocess
11
+ from dotenv import load_dotenv
12
+
13
+ # cargar el archivo .env
14
+ load_dotenv()
15
+
16
+ # Inicializar la aplicación
17
+ app = FastAPI()
18
+
19
+ # Configurar CORS
20
+ app.add_middleware(
21
+ CORSMiddleware,
22
+ allow_origins=["*"],
23
+ allow_credentials=True,
24
+ allow_methods=["*"],
25
+ allow_headers=["*"],
26
+ )
27
+
28
+
29
+ # Carga de token y verificación de disponibilidad de GPU
30
+ hf_token = os.getenv("HF_TOKEN")
31
+
32
+ device = "cuda" if torch.cuda.is_available() else "cpu"
33
+
34
+ # Tipo de cómputo #"float32" o "float16" si se desea utilizar la aceleración de la GPU o "float32" si se desea utilizar la CPU.
35
+ compute_type = "float32" if device == "cuda" else "float32"
36
+
37
+ # Transcripción
38
+ print("Descargando el modelo...")
39
+ model = whisperx.load_model(
40
+ "large-v2", device, language="es", compute_type=compute_type
41
+ )
42
+ print("¡Modelo descargado con éxito!")
43
+
44
+
45
+ def transcribe_wav(audio):
46
+ """
47
+ Transcribe un archivo de audio WAV y devuelve el texto transrito.
48
+ """
49
+ resultado = model.transcribe(audio, language="es", batch_size=28)
50
+ return "\n".join([segment["text"] for segment in resultado["segments"]])
51
+
52
+
53
+ def segment_and_transcribe_audio(audio_entrada: str) -> dict:
54
+ """
55
+ Segmenta y transcribe el archivo de audio de entrada.
56
+
57
+ Parameters:
58
+ :param audio_entrada: str: Ruta al archivo de audio de entrada.
59
+
60
+ Returns:
61
+ dict: Diccionario que contiene las transcripciones para cada segmento de parlante.
62
+ """
63
+ transcriptions = {}
64
+
65
+ if not os.path.exists(audio_entrada):
66
+ raise FileNotFoundError("El archivo de audio no existe.")
67
+
68
+ audio_info = mediainfo(audio_entrada)
69
+ duration_s = audio_info.get("duration")
70
+ if duration_s is None:
71
+ raise ValueError("No se pudo obtener la duración del archivo de audio.")
72
+
73
+ duration_s = float(duration_s)
74
+ print(f"Duración del audio: {duration_s} s")
75
+ if duration_s < 10:
76
+ raise ValueError(
77
+ f"La duración del audio es demasiado corta para realizar una transcripción. Duración: {duration_s} s"
78
+ )
79
+
80
+ # Cargar el archivo de audio usando whisperx.load_audio
81
+ audio = whisperx.load_audio(audio_entrada)
82
+
83
+ # Realizar la transcripción completa del audio
84
+ transcripcion_completa = transcribe_wav(audio)
85
+ transcriptions["full"] = transcripcion_completa
86
+
87
+ # Inicializar el pipeline de diarización de parlantes
88
+ pipeline = Pipeline.from_pretrained(
89
+ "pyannote/speaker-diarization-3.1", use_auth_token=hf_token
90
+ )
91
+ pipeline.to(torch.device(device))
92
+
93
+ # Realizar la diarización de los parlantes en el audio
94
+ with open(audio_entrada, "rb") as f:
95
+ diarization = pipeline(f)
96
+
97
+ # Escribir los resultados de la diarización en un archivo de texto
98
+ with open("audio.txt", "w") as lab:
99
+ diarization.write_lab(lab)
100
+
101
+ # Leer los resultados de la diarización desde el archivo de texto
102
+ with open("audio.txt", "r") as file:
103
+ lines = file.readlines()
104
+
105
+ # Procesar los resultados de la diarización
106
+ data = []
107
+ for line in lines:
108
+ parts = line.strip().split()
109
+ data.append(
110
+ {"start": float(parts[0]), "end": float(parts[1]), "speaker": parts[2]}
111
+ )
112
+
113
+ # Guardar los resultados de la diarización en un archivo JSON
114
+ with open("audio.json", "w") as file:
115
+ json.dump(data, file, indent=4)
116
+
117
+ # Cargar el archivo de audio original usando AudioSegment
118
+ audio_segment = AudioSegment.from_wav(audio_entrada)
119
+
120
+ # Leer los resultados de la diarización desde el archivo JSON
121
+ with open("audio.json", "r") as file:
122
+ diarization = json.load(file)
123
+
124
+ # Segmentar el audio en base a los resultados de la diarización
125
+ segments = {}
126
+ for segment in diarization:
127
+ speaker = segment["speaker"]
128
+ if speaker not in segments:
129
+ segments[speaker] = []
130
+ start = int(segment["start"] * 1000)
131
+ end = int(segment["end"] * 1000)
132
+ segments[speaker].append(audio_segment[start:end])
133
+
134
+ # Transcribir cada segmento de parlante y guardar los resultados
135
+ for speaker, segs in segments.items():
136
+ result = sum(segs, AudioSegment.empty())
137
+ result.export(f"{speaker}.wav", format="wav")
138
+ transcriptions[speaker] = transcribe_wav(f"{speaker}.wav")
139
+
140
+ # Eliminar los archivos temporales creados
141
+ os.remove("audio.txt")
142
+ os.remove(audio_entrada)
143
+ os.remove("audio.json")
144
+ for speaker in segments.keys():
145
+ os.remove(f"{speaker}.wav")
146
+
147
+ return transcriptions
148
+
149
+
150
+ @app.get("/")
151
+ def read_root():
152
+ return {"message": "¡Bienvenido a la API de transcripción de audio!"}
153
+
154
+
155
+ @app.post("/transcribe")
156
+ def transcribe_audio(audio: UploadFile = File(...)):
157
+ """
158
+ Transcribe un archivo de audio y devuelve el texto transcrito.
159
+
160
+ Parameters:
161
+ :param audio: UploadFile: Archivo de audio a transcribir.
162
+
163
+ Returns:
164
+ JSONResponse: Respuesta JSON que contiene el texto transcrito.
165
+ """
166
+ # Guardar el archivo de audio en wav con la libreria AudioSegment
167
+ audio_segment = AudioSegment.from_file(audio.file)
168
+ audio_segment.export("audio.wav", format="wav")
169
+ return segment_and_transcribe_audio("audio.wav")
170
+
171
+
172
+ # if __name__ == "__main__":
173
+
174
+ # subprocess.run(
175
+ # ["uvicorn", "app:app", "--host", "localhost", "--port", "7860", "--reload"]
176
+ # )
requirements.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pandas
2
+ numpy
3
+ nltk
4
+ moviepy
5
+ pydub
6
+ transformers
7
+ pydantic
8
+ pytest
9
+ whisperx
10
+ fastapi
11
+ uvicorn
12
+ python-dotenv
13
+ python-multipart
results/Captura de pantalla 2024-02-14 230343.png ADDED
results/Que nadie sepa mi sufrir - Julio Jaramillo (Letra).mp3 ADDED
Binary file (979 kB). View file
 
results/response_1707969561662.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "full": " No te asombres si te digo lo que fuiste Una ingrata con mi pobre corazón Porque el fuego de tus lindos ojos negros Alumbraron el camino de otro amor Porque el fuego de tus lindos ojos negros Alumbraron el camino de otro amor\n amor de mis amores reina mía que me hiciste que no puedo conformarme sin poderte contemplar ya que pagaste mal mi cariño tan sincero lo que conseguirás que no te nombre nunca más amor de mis amores si dejaste de quererme no hay cuidado que la gente de eso no se enterará\n ¿Qué gano con decir que una mujer cambió mi suerte? Se burlarán de mí, que nadie sepa mi sufrir\n Y pensar que te adoraba ciegamente, que a tu lado como nunca me sentí. Y por esas cosas raras de la vida, sin el beso de tu boca yo me\n Y por esas cosas raras de la vida, sin el beso de tu boca yo me vi. Amor de mis amores, reina mía que me hiciste, que no puedo conformarme sin poderte contemplar. Ya que pagaste mal mi cariño tan sincero, lo que conseguirás que no te nombre nunca más.\n amor de mis amores si dejaste de quererme no hay cuidado que la gente de eso no se enterara que gano con decir que una mujer cambia mi suerte se burlaran de mi que nadie sepa mi sufrir",
3
+ "SPEAKER_00": " No te asombres si te digo lo que fuiste Una ingrata con mi pobre corazón Porque el fuego de tus lindos ojos negros Alumbraron el camino de otro amor Porque el fuego de tus lindos ojos negros Alumbraron el camino de otro amor\n amor de mis amores reina mía que me hiciste que no puedo conformarme sin poderte contemplar ya que pagaste mal mi cariño tan sincero lo que conseguirás que no te nombre nunca más\n amor de mis amores si dejaste de quererme no hay cuidado que la gente de eso no se enterara que gano con decir que una mujer cambio mi suerte se burlaran de mi que nadie sepa mi sufrir y pensar que te adoraba ciegamente que a tu lado como nunca me sentí y por esas cosas raras de la vida sin el beso de tu voz\n y por esas cosas raras de la vida sin el beso de tu boca yo me vi amor de mis amores reina mía que me hiciste que no puedo conformarme sin poderte contemplar ya que pagaste mal mi cariño tan sincero lo que conseguirás que no te nombre nunca más\n amor de mis amores si dejaste de quererme no hay cuidado que la gente de eso no se enterara que gano con decir que una mujer cambia mi suerte se burlaran de mi que nadie sepa mi sufrir"
4
+ }