Capítulo 5: Proyectos de Integración de Imagen y Audio
5.3 Transcriptor de Notas de Voz Potenciado por Whisper
En esta sección, aprenderás a crear una potente aplicación web Flask que aprovecha la API de Whisper de OpenAI para la transcripción de audio. Esta aplicación proporcionará a los usuarios una interfaz fluida para cargar archivos de audio en varios formatos (como MP3, WAV o M4A) y convertir automáticamente las palabras habladas en texto escrito preciso.
La API de Whisper, conocida por su alta precisión y soporte multilingüe, maneja la compleja tarea del reconocimiento de voz, mientras que Flask proporciona el marco web para hacer esta funcionalidad accesible a través de una interfaz de navegador. Ya sea que estés construyendo una herramienta para transcribir entrevistas, crear actas de reuniones o desarrollar una función de accesibilidad, esta aplicación demostrará cómo combinar efectivamente el desarrollo web con el procesamiento de audio impulsado por IA.
5.3.1 Lo que Construirás
La aplicación web proporciona una interfaz sofisticada e intuitiva para cargar archivos de audio, diseñada pensando en la experiencia del usuario. Cuando un usuario envía un archivo de audio, la aplicación ejecuta una serie de pasos cuidadosamente orquestados:
- Recibir el archivo de audio: La aplicación maneja de forma segura el proceso de carga de archivos, validando el formato y tamaño para garantizar la compatibilidad.
- Guardar temporalmente el archivo de audio en el servidor: Utilizando prácticas seguras de manejo de archivos, la aplicación crea una solución de almacenamiento temporal que mantiene la privacidad del usuario durante el procesamiento del archivo.
- Enviar el archivo de audio a la API de Whisper de OpenAI para transcripción: La aplicación establece una conexión segura con los servidores de OpenAI y transmite el archivo de audio utilizando protocolos estándar de la industria.
- Recibir la transcripción de la API de Whisper: La aplicación procesa la respuesta de la API, manejando cualquier error potencial y formateando la transcripción para una legibilidad óptima.
- Mostrar el texto de la transcripción en la página web: Los resultados se presentan en una interfaz limpia y bien formateada que permite una fácil lectura y la posibilidad de copiar o descargar el texto transcrito.
Esta funcionalidad versátil sirve para numerosas aplicaciones profesionales y personales, incluyendo:
- Periodistas grabando y transcribiendo entrevistas: Agiliza el proceso de entrevista proporcionando transcripciones rápidas y precisas para la redacción de artículos y verificación de fuentes
- Estudiantes capturando y transcribiendo notas de clase: Permite una mejor concentración durante las clases mientras asegura una toma de notas completa mediante transcripción automatizada
- Podcasters que necesitan transcripciones para accesibilidad y búsqueda: Mejora la accesibilidad del contenido para audiencias con dificultades auditivas y mejora el SEO a través de transcripciones navegables
- Profesionales de negocios revisando y transcribiendo grabaciones de reuniones: Facilita la documentación eficiente de reuniones y permite una fácil referencia a discusiones importantes
- Cualquier persona que necesite convertir voz a texto: Proporciona una solución universal para convertir contenido hablado en formato escrito, ya sea para notas personales, documentación o propósitos de accesibilidad
5.3.2 ¿Qué es Whisper?
Whisper representa el modelo de reconocimiento de voz de código abierto de vanguardia de OpenAI diseñado para aplicación universal. Construido sobre una arquitectura avanzada de aprendizaje automático, este sofisticado modelo transforma el lenguaje hablado en texto escrito con notable precisión. Ofrece varias ventajas clave que lo distinguen de los sistemas tradicionales de reconocimiento de voz:
- Transcripción de alta calidad: Whisper aprovecha un conjunto de datos de entrenamiento masivo que abarca miles de horas de contenido de audio diverso, incluyendo diferentes estilos de habla, condiciones ambientales y calidades de grabación. Este extenso entrenamiento le permite producir transcripciones excepcionalmente precisas, incluso en escenarios desafiantes.
- Soporte multilingüe: Una de las características más impresionantes de Whisper es su robusta capacidad multilingüe. El modelo puede entender y transcribir voz en numerosos idiomas, convirtiéndolo en una herramienta valiosa para la comunicación global y la creación de contenido. Incluso puede detectar idiomas automáticamente y manejar cambios de código entre idiomas.
- Precisión independiente del hablante: Gracias a su arquitectura avanzada de red neuronal, Whisper demuestra una notable adaptabilidad a diferentes voces, acentos y dialectos. Mantiene una precisión consistente independientemente de las características del hablante y puede filtrar eficazmente el ruido de fondo, haciéndolo confiable en aplicaciones del mundo real.
- Varios formatos de audio: La versatilidad de Whisper se extiende a sus capacidades de manejo de entrada. El modelo procesa sin problemas una amplia gama de formatos de audio, incluyendo MP3, MP4, WAV y M4A, eliminando la necesidad de conversiones complejas de formato y haciéndolo más accesible para varios casos de uso.
Interactuarás con Whisper usando el cliente Python de OpenAI a través de la función openai.Audio.transcribe()
, que proporciona una interfaz sencilla para acceder a estas potentes capacidades.
5.3.3 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga una muestra de audio: https://files.cuantum.tech/audio/recording.mp3
Necesitarás Flask, OpenAI y python-dotenv
. Abre tu terminal y ejecuta el siguiente comando:
pip install flask openai python-dotenv
Este comando instala las bibliotecas necesarias:
flask
: Un micro framework web para construir la aplicación web.openai
: La biblioteca Python de OpenAI para interactuar con la API de Whisper.python-dotenv
: Una biblioteca para cargar variables de entorno desde un archivo.env
.
Paso 2: Configurar la Estructura del Proyecto
Crea la siguiente estructura de carpetas para tu proyecto:
/whisper_transcriber
│
├── app.py
├── .env
└── templates/
└── index.html
/whisper_transcriber
: El directorio raíz de tu proyecto.app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar tu clave API de OpenAI.templates/
: Un directorio para almacenar tus plantillas HTML.templates/index.html
: La plantilla HTML para la página principal de tu aplicación.
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
en el directorio raíz de tu proyecto (/whisper_transcriber
). Añade el siguiente código a app.py
:
from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcribe(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file and displays the transcription.
"""
transcript = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", transcript=transcript, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación:
from flask import Flask, request, render_template, jsonify, make_response
: Importa los módulos necesarios de Flask.import openai
: Importa la biblioteca Python de OpenAI.import os
: Importa el móduloos
para interactuar con el sistema operativo (por ejemplo, para rutas de archivos, variables de entorno).from dotenv import load_dotenv
: Importa la funciónload_dotenv
para cargar variables de entorno desde un archivo.env
.import logging
: Importa el módulo de registro.from typing import Optional
: Importa Optional para sugerencias de tipo
- Variables de Entorno:
load_dotenv()
: Carga la clave API de OpenAI desde el archivo.env
.openai.api_key = os.getenv("OPENAI_API_KEY")
: Obtiene la clave API de OpenAI del entorno y la configura para la biblioteca OpenAI.
- Aplicación Flask:
app = Flask(__name__)
: Crea una instancia de la aplicación Flask.
- Configuración de Registro:
logging.basicConfig(level=logging.INFO)
: Configura el módulo de registro para registrar eventos en el nivel INFO.logger = logging.getLogger(__name__)
: Crea un objeto de registro.
- Función
allowed_file
:def allowed_file(filename: str) -> bool:
: Verifica si la extensión del archivo está permitida.- Devuelve verdadero si el nombre del archivo tiene una extensión de audio válida
- Función
transcribe_audio
:def transcribe_audio(file_path: str) -> Optional[str]:
: Define una función para transcribir un archivo de audio usando la API de OpenAI.Args
:file_path
(str
): La ruta al archivo de audio.
Returns
:Optional[str]
: El texto transcrito si tiene éxito,None
en caso contrario.
- La función abre el archivo de audio en modo binario (
"rb"
) y lo pasa aopenai.Audio.transcribe()
. - Registra la ruta del archivo antes de la transcripción y la longitud del texto transcrito después de una transcripción exitosa.
- Incluye manejo de errores usando un bloque
try...except
para capturar posibles excepcionesopenai.error.OpenAIError
(específicas de OpenAI) yException
general para otros errores. Si ocurre un error, registra el error y devuelveNone
.
- Ruta
index
:@app.route("/", methods=["GET", "POST"])
: Este decorador define la ruta para la página principal de la aplicación ("/"). La funciónindex()
maneja tanto peticiones GET como POST.def index():
: Esta función maneja las peticiones a la URL raíz ("/").transcript = None
: Inicializa una variable para almacenar el texto de la transcripción.error_message = None
: Inicializa una variable para almacenar cualquier mensaje de error.if request.method == "POST":
: Este bloque se ejecuta cuando el usuario envía el formulario (es decir, sube un archivo de audio).- Manejo de Archivos:
if 'audio_file' not in request.files: ...
: Verifica si elaudio_file
está presente en la petición.file = request.files['audio_file']
: Obtiene el archivo subido de la petición.if file.filename == '': ...
: Verifica si el usuario seleccionó un archivo.
if file and allowed_file(file.filename):
: Verifica si se subió un archivo y si tiene una extensión permitida.temp_file_path = ...
: Genera una ruta temporal para guardar el archivo de audio subido. Utiliza la extensión del nombre de archivo original para asegurar que el archivo se guarde con el formato correcto.file.save(temp_file_path)
: Guarda el archivo de audio subido en la ruta temporal.transcript = transcribe_audio(temp_file_path)
: Llama a la funcióntranscribe_audio()
para transcribir el archivo de audio.if not transcript: ...
: Verifica si la transcripción fue exitosa. Si no lo fue, establece un mensaje de error.os.remove(temp_file_path)
: Elimina el archivo de audio temporal después de procesarlo.
else:
: Si el tipo de archivo no está permitido, establece un mensaje de error.- La función luego renderiza la plantilla
index.html
, pasando eltranscript
yerror_message
.
- Manejo de Archivos:
- La función también renderiza la plantilla
index.html
para peticiones GET.
@app.errorhandler(500)
: Maneja errores 500.- Registra el error.
- Renderiza una página de error.
if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el directorio raíz de tu proyecto. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whisper Voice Note Transcriber</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb; /* Tailwind's gray-50 */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151; /* Tailwind's gray-700 */
}
.container {
max-width: 800px; /* Increased max-width */
width: 95%; /* Take up most of the viewport */
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem; /* Tailwind's rounded-lg */
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
text-align: center;
}
h2 {
font-size: 2.25rem; /* Tailwind's text-3xl */
font-weight: 600; /* Tailwind's font-semibold */
margin-bottom: 1.5rem; /* Tailwind's mb-6 */
color: #1e293b; /* Tailwind's gray-900 */
}
p{
color: #6b7280; /* Tailwind's gray-500 */
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem; /* Tailwind's mt-4 */
display: flex;
flex-direction: column;
align-items: center; /* Center form elements */
gap: 0.5rem; /* Tailwind's gap-2 */
}
label {
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
color: #4b5563; /* Tailwind's gray-600 */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
display: block; /* Ensure label takes full width */
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px; /* Added max-width for file input */
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
font-size: 1rem; /* Tailwind's text-base */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
color: #fff;
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
cursor: pointer;
transition: background-color 0.3s ease; /* Smooth transition */
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca; /* Tailwind's bg-indigo-700 on hover */
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
}
textarea {
width: 100%;
max-width: 600px; /* Increased max-width for textarea */
height: 200px;
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
margin-top: 1rem; /* Tailwind's mt-4 */
font-size: 1rem; /* Tailwind's text-base */
line-height: 1.5rem; /* Tailwind's leading-relaxed */
resize: vertical; /* Allow vertical resizing */
margin-left: auto;
margin-right: auto;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
}
textarea:focus {
outline: none;
border-color: #3b82f6; /* Tailwind's border-blue-500 */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
}
/* --- Error Styles --- */
.error-message {
color: #dc2626; /* Tailwind's text-red-600 */
margin-top: 1rem; /* Tailwind's mt-4 */
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"],
textarea {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Voice Note Transcriber</h2>
<p> Upload an audio file to transcribe. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Transcribe">
</form>
{% if transcript %}
<h3>📝 Transcription:</h3>
<textarea readonly>{{ transcript }}</textarea>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y establece la configuración del viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluyendo un formulario para subir archivos de audio y una sección para mostrar la transcripción.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS está actualizado con un diseño moderno.
- Diseño responsivo: El diseño se adapta mejor, especialmente en pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo del formulario y de los campos de entrada para mayor usabilidad.
- Visualización clara de errores: Los mensajes de error están estilizados para ser claramente visibles.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para manejar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga solo a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización de la transcripción:
- Se utiliza un
<textarea readonly>
para mostrar el texto transcrito. El atributoreadonly
evita que el usuario edite la transcripción.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar cualquier mensaje de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo,
recording.mp3
). - Visualiza la transcripción mostrada en la página.
5.3.4 Notas sobre Formatos de Audio y Seguridad
Whisper es compatible con una amplia gama de formatos de audio, cada uno con ventajas únicas y casos de uso específicos. Exploremos cada formato en detalle:
.mp3
- El formato estándar de la industria para audio comprimido que ofrece un excelente equilibrio entre calidad de audio y tamaño de archivo. Perfecto para la mayoría de grabaciones de voz y audio de uso general, típicamente alcanzando relaciones de compresión de 10:1 mientras mantiene una buena fidelidad de audio..mp4
- Un formato contenedor versátil utilizado principalmente para video pero igualmente capaz de manejar pistas de audio de alta calidad. Admite múltiples códecs de audio y es particularmente útil cuando se trabaja con contenido multimedia que incluye tanto elementos de video como de audio..m4a
- Un formato contenedor de audio especializado que típicamente utiliza codificación AAC. Ofrece mejor calidad de sonido que MP3 a tasas de bits similares y es particularmente adecuado para grabaciones de voz debido a su eficiente compresión de patrones de habla..wav
- El estándar de oro para la calidad de audio, proporcionando audio sin comprimir y sin pérdidas. Si bien los tamaños de archivo son significativamente más grandes, es ideal para aplicaciones profesionales donde la fidelidad del audio es crucial, como servicios de transcripción profesional o análisis de audio..webm
- Un formato moderno de código abierto diseñado específicamente para aplicaciones web. Ofrece compresión eficiente y capacidades de transmisión rápida, haciéndolo ideal para grabación y reproducción de voz basada en web.
Al implementar tu aplicación en un entorno de producción, es crucial implementar medidas de seguridad robustas. Aquí hay consideraciones detalladas de seguridad:
- Agregar validación de tamaño de archivo - Implementa límites estrictos de tamaño de archivo (recomendado: 25MB) para mantener la estabilidad del servidor. Esto previene potenciales ataques de denegación de servicio y asegura una asignación eficiente de recursos. Considera implementar indicadores de carga progresiva y carga por fragmentos para archivos más grandes.
- Automáticamente eliminar archivos temporales después de la transcripción - Implementa un sistema seguro de limpieza de archivos que elimine los archivos procesados inmediatamente después de la transcripción. Esto no solo conserva el almacenamiento del servidor sino que también garantiza la privacidad del usuario al prevenir el acceso no autorizado a los archivos de audio subidos.
- Implementar límite de frecuencia o autenticación para cargas de usuario - Implementa algoritmos sofisticados de limitación de frecuencia basados en direcciones IP o cuentas de usuario. Considera implementar autenticación OAuth2 y control de acceso basado en roles (RBAC) para gestionar efectivamente los permisos de usuario.
Esta robusta aplicación de transcripción de voz aprovecha varias tecnologías poderosas:
- Flask para la interfaz de usuario y manejo de cargas - Proporciona un marco de trabajo ligero pero potente para manejar cargas de archivos y servir la interfaz web
- Whisper para reconocimiento de voz de alta calidad - Utiliza modelos de aprendizaje automático de última generación para lograr transcripciones precisas en múltiples idiomas y acentos
- La API de OpenAI para integración perfecta - Permite fácil acceso a capacidades avanzadas de IA con rendimiento confiable y actualizaciones regulares
Esta versátil herramienta de voz a texto sirve como base para numerosas aplicaciones prácticas, incluyendo:
- Un chatbot sofisticado con capacidades de entrada por voz
- Un asistente de toma de notas inteligente que puede transcribir y organizar contenido hablado
- Un resumidor de reuniones integral que puede procesar y analizar discusiones grabadas
- Una herramienta de podcasting con IA avanzada para transcripción automática y análisis de contenido
5.3 Transcriptor de Notas de Voz Potenciado por Whisper
En esta sección, aprenderás a crear una potente aplicación web Flask que aprovecha la API de Whisper de OpenAI para la transcripción de audio. Esta aplicación proporcionará a los usuarios una interfaz fluida para cargar archivos de audio en varios formatos (como MP3, WAV o M4A) y convertir automáticamente las palabras habladas en texto escrito preciso.
La API de Whisper, conocida por su alta precisión y soporte multilingüe, maneja la compleja tarea del reconocimiento de voz, mientras que Flask proporciona el marco web para hacer esta funcionalidad accesible a través de una interfaz de navegador. Ya sea que estés construyendo una herramienta para transcribir entrevistas, crear actas de reuniones o desarrollar una función de accesibilidad, esta aplicación demostrará cómo combinar efectivamente el desarrollo web con el procesamiento de audio impulsado por IA.
5.3.1 Lo que Construirás
La aplicación web proporciona una interfaz sofisticada e intuitiva para cargar archivos de audio, diseñada pensando en la experiencia del usuario. Cuando un usuario envía un archivo de audio, la aplicación ejecuta una serie de pasos cuidadosamente orquestados:
- Recibir el archivo de audio: La aplicación maneja de forma segura el proceso de carga de archivos, validando el formato y tamaño para garantizar la compatibilidad.
- Guardar temporalmente el archivo de audio en el servidor: Utilizando prácticas seguras de manejo de archivos, la aplicación crea una solución de almacenamiento temporal que mantiene la privacidad del usuario durante el procesamiento del archivo.
- Enviar el archivo de audio a la API de Whisper de OpenAI para transcripción: La aplicación establece una conexión segura con los servidores de OpenAI y transmite el archivo de audio utilizando protocolos estándar de la industria.
- Recibir la transcripción de la API de Whisper: La aplicación procesa la respuesta de la API, manejando cualquier error potencial y formateando la transcripción para una legibilidad óptima.
- Mostrar el texto de la transcripción en la página web: Los resultados se presentan en una interfaz limpia y bien formateada que permite una fácil lectura y la posibilidad de copiar o descargar el texto transcrito.
Esta funcionalidad versátil sirve para numerosas aplicaciones profesionales y personales, incluyendo:
- Periodistas grabando y transcribiendo entrevistas: Agiliza el proceso de entrevista proporcionando transcripciones rápidas y precisas para la redacción de artículos y verificación de fuentes
- Estudiantes capturando y transcribiendo notas de clase: Permite una mejor concentración durante las clases mientras asegura una toma de notas completa mediante transcripción automatizada
- Podcasters que necesitan transcripciones para accesibilidad y búsqueda: Mejora la accesibilidad del contenido para audiencias con dificultades auditivas y mejora el SEO a través de transcripciones navegables
- Profesionales de negocios revisando y transcribiendo grabaciones de reuniones: Facilita la documentación eficiente de reuniones y permite una fácil referencia a discusiones importantes
- Cualquier persona que necesite convertir voz a texto: Proporciona una solución universal para convertir contenido hablado en formato escrito, ya sea para notas personales, documentación o propósitos de accesibilidad
5.3.2 ¿Qué es Whisper?
Whisper representa el modelo de reconocimiento de voz de código abierto de vanguardia de OpenAI diseñado para aplicación universal. Construido sobre una arquitectura avanzada de aprendizaje automático, este sofisticado modelo transforma el lenguaje hablado en texto escrito con notable precisión. Ofrece varias ventajas clave que lo distinguen de los sistemas tradicionales de reconocimiento de voz:
- Transcripción de alta calidad: Whisper aprovecha un conjunto de datos de entrenamiento masivo que abarca miles de horas de contenido de audio diverso, incluyendo diferentes estilos de habla, condiciones ambientales y calidades de grabación. Este extenso entrenamiento le permite producir transcripciones excepcionalmente precisas, incluso en escenarios desafiantes.
- Soporte multilingüe: Una de las características más impresionantes de Whisper es su robusta capacidad multilingüe. El modelo puede entender y transcribir voz en numerosos idiomas, convirtiéndolo en una herramienta valiosa para la comunicación global y la creación de contenido. Incluso puede detectar idiomas automáticamente y manejar cambios de código entre idiomas.
- Precisión independiente del hablante: Gracias a su arquitectura avanzada de red neuronal, Whisper demuestra una notable adaptabilidad a diferentes voces, acentos y dialectos. Mantiene una precisión consistente independientemente de las características del hablante y puede filtrar eficazmente el ruido de fondo, haciéndolo confiable en aplicaciones del mundo real.
- Varios formatos de audio: La versatilidad de Whisper se extiende a sus capacidades de manejo de entrada. El modelo procesa sin problemas una amplia gama de formatos de audio, incluyendo MP3, MP4, WAV y M4A, eliminando la necesidad de conversiones complejas de formato y haciéndolo más accesible para varios casos de uso.
Interactuarás con Whisper usando el cliente Python de OpenAI a través de la función openai.Audio.transcribe()
, que proporciona una interfaz sencilla para acceder a estas potentes capacidades.
5.3.3 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga una muestra de audio: https://files.cuantum.tech/audio/recording.mp3
Necesitarás Flask, OpenAI y python-dotenv
. Abre tu terminal y ejecuta el siguiente comando:
pip install flask openai python-dotenv
Este comando instala las bibliotecas necesarias:
flask
: Un micro framework web para construir la aplicación web.openai
: La biblioteca Python de OpenAI para interactuar con la API de Whisper.python-dotenv
: Una biblioteca para cargar variables de entorno desde un archivo.env
.
Paso 2: Configurar la Estructura del Proyecto
Crea la siguiente estructura de carpetas para tu proyecto:
/whisper_transcriber
│
├── app.py
├── .env
└── templates/
└── index.html
/whisper_transcriber
: El directorio raíz de tu proyecto.app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar tu clave API de OpenAI.templates/
: Un directorio para almacenar tus plantillas HTML.templates/index.html
: La plantilla HTML para la página principal de tu aplicación.
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
en el directorio raíz de tu proyecto (/whisper_transcriber
). Añade el siguiente código a app.py
:
from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcribe(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file and displays the transcription.
"""
transcript = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", transcript=transcript, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación:
from flask import Flask, request, render_template, jsonify, make_response
: Importa los módulos necesarios de Flask.import openai
: Importa la biblioteca Python de OpenAI.import os
: Importa el móduloos
para interactuar con el sistema operativo (por ejemplo, para rutas de archivos, variables de entorno).from dotenv import load_dotenv
: Importa la funciónload_dotenv
para cargar variables de entorno desde un archivo.env
.import logging
: Importa el módulo de registro.from typing import Optional
: Importa Optional para sugerencias de tipo
- Variables de Entorno:
load_dotenv()
: Carga la clave API de OpenAI desde el archivo.env
.openai.api_key = os.getenv("OPENAI_API_KEY")
: Obtiene la clave API de OpenAI del entorno y la configura para la biblioteca OpenAI.
- Aplicación Flask:
app = Flask(__name__)
: Crea una instancia de la aplicación Flask.
- Configuración de Registro:
logging.basicConfig(level=logging.INFO)
: Configura el módulo de registro para registrar eventos en el nivel INFO.logger = logging.getLogger(__name__)
: Crea un objeto de registro.
- Función
allowed_file
:def allowed_file(filename: str) -> bool:
: Verifica si la extensión del archivo está permitida.- Devuelve verdadero si el nombre del archivo tiene una extensión de audio válida
- Función
transcribe_audio
:def transcribe_audio(file_path: str) -> Optional[str]:
: Define una función para transcribir un archivo de audio usando la API de OpenAI.Args
:file_path
(str
): La ruta al archivo de audio.
Returns
:Optional[str]
: El texto transcrito si tiene éxito,None
en caso contrario.
- La función abre el archivo de audio en modo binario (
"rb"
) y lo pasa aopenai.Audio.transcribe()
. - Registra la ruta del archivo antes de la transcripción y la longitud del texto transcrito después de una transcripción exitosa.
- Incluye manejo de errores usando un bloque
try...except
para capturar posibles excepcionesopenai.error.OpenAIError
(específicas de OpenAI) yException
general para otros errores. Si ocurre un error, registra el error y devuelveNone
.
- Ruta
index
:@app.route("/", methods=["GET", "POST"])
: Este decorador define la ruta para la página principal de la aplicación ("/"). La funciónindex()
maneja tanto peticiones GET como POST.def index():
: Esta función maneja las peticiones a la URL raíz ("/").transcript = None
: Inicializa una variable para almacenar el texto de la transcripción.error_message = None
: Inicializa una variable para almacenar cualquier mensaje de error.if request.method == "POST":
: Este bloque se ejecuta cuando el usuario envía el formulario (es decir, sube un archivo de audio).- Manejo de Archivos:
if 'audio_file' not in request.files: ...
: Verifica si elaudio_file
está presente en la petición.file = request.files['audio_file']
: Obtiene el archivo subido de la petición.if file.filename == '': ...
: Verifica si el usuario seleccionó un archivo.
if file and allowed_file(file.filename):
: Verifica si se subió un archivo y si tiene una extensión permitida.temp_file_path = ...
: Genera una ruta temporal para guardar el archivo de audio subido. Utiliza la extensión del nombre de archivo original para asegurar que el archivo se guarde con el formato correcto.file.save(temp_file_path)
: Guarda el archivo de audio subido en la ruta temporal.transcript = transcribe_audio(temp_file_path)
: Llama a la funcióntranscribe_audio()
para transcribir el archivo de audio.if not transcript: ...
: Verifica si la transcripción fue exitosa. Si no lo fue, establece un mensaje de error.os.remove(temp_file_path)
: Elimina el archivo de audio temporal después de procesarlo.
else:
: Si el tipo de archivo no está permitido, establece un mensaje de error.- La función luego renderiza la plantilla
index.html
, pasando eltranscript
yerror_message
.
- Manejo de Archivos:
- La función también renderiza la plantilla
index.html
para peticiones GET.
@app.errorhandler(500)
: Maneja errores 500.- Registra el error.
- Renderiza una página de error.
if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el directorio raíz de tu proyecto. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whisper Voice Note Transcriber</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb; /* Tailwind's gray-50 */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151; /* Tailwind's gray-700 */
}
.container {
max-width: 800px; /* Increased max-width */
width: 95%; /* Take up most of the viewport */
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem; /* Tailwind's rounded-lg */
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
text-align: center;
}
h2 {
font-size: 2.25rem; /* Tailwind's text-3xl */
font-weight: 600; /* Tailwind's font-semibold */
margin-bottom: 1.5rem; /* Tailwind's mb-6 */
color: #1e293b; /* Tailwind's gray-900 */
}
p{
color: #6b7280; /* Tailwind's gray-500 */
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem; /* Tailwind's mt-4 */
display: flex;
flex-direction: column;
align-items: center; /* Center form elements */
gap: 0.5rem; /* Tailwind's gap-2 */
}
label {
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
color: #4b5563; /* Tailwind's gray-600 */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
display: block; /* Ensure label takes full width */
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px; /* Added max-width for file input */
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
font-size: 1rem; /* Tailwind's text-base */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
color: #fff;
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
cursor: pointer;
transition: background-color 0.3s ease; /* Smooth transition */
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca; /* Tailwind's bg-indigo-700 on hover */
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
}
textarea {
width: 100%;
max-width: 600px; /* Increased max-width for textarea */
height: 200px;
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
margin-top: 1rem; /* Tailwind's mt-4 */
font-size: 1rem; /* Tailwind's text-base */
line-height: 1.5rem; /* Tailwind's leading-relaxed */
resize: vertical; /* Allow vertical resizing */
margin-left: auto;
margin-right: auto;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
}
textarea:focus {
outline: none;
border-color: #3b82f6; /* Tailwind's border-blue-500 */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
}
/* --- Error Styles --- */
.error-message {
color: #dc2626; /* Tailwind's text-red-600 */
margin-top: 1rem; /* Tailwind's mt-4 */
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"],
textarea {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Voice Note Transcriber</h2>
<p> Upload an audio file to transcribe. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Transcribe">
</form>
{% if transcript %}
<h3>📝 Transcription:</h3>
<textarea readonly>{{ transcript }}</textarea>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y establece la configuración del viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluyendo un formulario para subir archivos de audio y una sección para mostrar la transcripción.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS está actualizado con un diseño moderno.
- Diseño responsivo: El diseño se adapta mejor, especialmente en pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo del formulario y de los campos de entrada para mayor usabilidad.
- Visualización clara de errores: Los mensajes de error están estilizados para ser claramente visibles.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para manejar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga solo a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización de la transcripción:
- Se utiliza un
<textarea readonly>
para mostrar el texto transcrito. El atributoreadonly
evita que el usuario edite la transcripción.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar cualquier mensaje de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo,
recording.mp3
). - Visualiza la transcripción mostrada en la página.
5.3.4 Notas sobre Formatos de Audio y Seguridad
Whisper es compatible con una amplia gama de formatos de audio, cada uno con ventajas únicas y casos de uso específicos. Exploremos cada formato en detalle:
.mp3
- El formato estándar de la industria para audio comprimido que ofrece un excelente equilibrio entre calidad de audio y tamaño de archivo. Perfecto para la mayoría de grabaciones de voz y audio de uso general, típicamente alcanzando relaciones de compresión de 10:1 mientras mantiene una buena fidelidad de audio..mp4
- Un formato contenedor versátil utilizado principalmente para video pero igualmente capaz de manejar pistas de audio de alta calidad. Admite múltiples códecs de audio y es particularmente útil cuando se trabaja con contenido multimedia que incluye tanto elementos de video como de audio..m4a
- Un formato contenedor de audio especializado que típicamente utiliza codificación AAC. Ofrece mejor calidad de sonido que MP3 a tasas de bits similares y es particularmente adecuado para grabaciones de voz debido a su eficiente compresión de patrones de habla..wav
- El estándar de oro para la calidad de audio, proporcionando audio sin comprimir y sin pérdidas. Si bien los tamaños de archivo son significativamente más grandes, es ideal para aplicaciones profesionales donde la fidelidad del audio es crucial, como servicios de transcripción profesional o análisis de audio..webm
- Un formato moderno de código abierto diseñado específicamente para aplicaciones web. Ofrece compresión eficiente y capacidades de transmisión rápida, haciéndolo ideal para grabación y reproducción de voz basada en web.
Al implementar tu aplicación en un entorno de producción, es crucial implementar medidas de seguridad robustas. Aquí hay consideraciones detalladas de seguridad:
- Agregar validación de tamaño de archivo - Implementa límites estrictos de tamaño de archivo (recomendado: 25MB) para mantener la estabilidad del servidor. Esto previene potenciales ataques de denegación de servicio y asegura una asignación eficiente de recursos. Considera implementar indicadores de carga progresiva y carga por fragmentos para archivos más grandes.
- Automáticamente eliminar archivos temporales después de la transcripción - Implementa un sistema seguro de limpieza de archivos que elimine los archivos procesados inmediatamente después de la transcripción. Esto no solo conserva el almacenamiento del servidor sino que también garantiza la privacidad del usuario al prevenir el acceso no autorizado a los archivos de audio subidos.
- Implementar límite de frecuencia o autenticación para cargas de usuario - Implementa algoritmos sofisticados de limitación de frecuencia basados en direcciones IP o cuentas de usuario. Considera implementar autenticación OAuth2 y control de acceso basado en roles (RBAC) para gestionar efectivamente los permisos de usuario.
Esta robusta aplicación de transcripción de voz aprovecha varias tecnologías poderosas:
- Flask para la interfaz de usuario y manejo de cargas - Proporciona un marco de trabajo ligero pero potente para manejar cargas de archivos y servir la interfaz web
- Whisper para reconocimiento de voz de alta calidad - Utiliza modelos de aprendizaje automático de última generación para lograr transcripciones precisas en múltiples idiomas y acentos
- La API de OpenAI para integración perfecta - Permite fácil acceso a capacidades avanzadas de IA con rendimiento confiable y actualizaciones regulares
Esta versátil herramienta de voz a texto sirve como base para numerosas aplicaciones prácticas, incluyendo:
- Un chatbot sofisticado con capacidades de entrada por voz
- Un asistente de toma de notas inteligente que puede transcribir y organizar contenido hablado
- Un resumidor de reuniones integral que puede procesar y analizar discusiones grabadas
- Una herramienta de podcasting con IA avanzada para transcripción automática y análisis de contenido
5.3 Transcriptor de Notas de Voz Potenciado por Whisper
En esta sección, aprenderás a crear una potente aplicación web Flask que aprovecha la API de Whisper de OpenAI para la transcripción de audio. Esta aplicación proporcionará a los usuarios una interfaz fluida para cargar archivos de audio en varios formatos (como MP3, WAV o M4A) y convertir automáticamente las palabras habladas en texto escrito preciso.
La API de Whisper, conocida por su alta precisión y soporte multilingüe, maneja la compleja tarea del reconocimiento de voz, mientras que Flask proporciona el marco web para hacer esta funcionalidad accesible a través de una interfaz de navegador. Ya sea que estés construyendo una herramienta para transcribir entrevistas, crear actas de reuniones o desarrollar una función de accesibilidad, esta aplicación demostrará cómo combinar efectivamente el desarrollo web con el procesamiento de audio impulsado por IA.
5.3.1 Lo que Construirás
La aplicación web proporciona una interfaz sofisticada e intuitiva para cargar archivos de audio, diseñada pensando en la experiencia del usuario. Cuando un usuario envía un archivo de audio, la aplicación ejecuta una serie de pasos cuidadosamente orquestados:
- Recibir el archivo de audio: La aplicación maneja de forma segura el proceso de carga de archivos, validando el formato y tamaño para garantizar la compatibilidad.
- Guardar temporalmente el archivo de audio en el servidor: Utilizando prácticas seguras de manejo de archivos, la aplicación crea una solución de almacenamiento temporal que mantiene la privacidad del usuario durante el procesamiento del archivo.
- Enviar el archivo de audio a la API de Whisper de OpenAI para transcripción: La aplicación establece una conexión segura con los servidores de OpenAI y transmite el archivo de audio utilizando protocolos estándar de la industria.
- Recibir la transcripción de la API de Whisper: La aplicación procesa la respuesta de la API, manejando cualquier error potencial y formateando la transcripción para una legibilidad óptima.
- Mostrar el texto de la transcripción en la página web: Los resultados se presentan en una interfaz limpia y bien formateada que permite una fácil lectura y la posibilidad de copiar o descargar el texto transcrito.
Esta funcionalidad versátil sirve para numerosas aplicaciones profesionales y personales, incluyendo:
- Periodistas grabando y transcribiendo entrevistas: Agiliza el proceso de entrevista proporcionando transcripciones rápidas y precisas para la redacción de artículos y verificación de fuentes
- Estudiantes capturando y transcribiendo notas de clase: Permite una mejor concentración durante las clases mientras asegura una toma de notas completa mediante transcripción automatizada
- Podcasters que necesitan transcripciones para accesibilidad y búsqueda: Mejora la accesibilidad del contenido para audiencias con dificultades auditivas y mejora el SEO a través de transcripciones navegables
- Profesionales de negocios revisando y transcribiendo grabaciones de reuniones: Facilita la documentación eficiente de reuniones y permite una fácil referencia a discusiones importantes
- Cualquier persona que necesite convertir voz a texto: Proporciona una solución universal para convertir contenido hablado en formato escrito, ya sea para notas personales, documentación o propósitos de accesibilidad
5.3.2 ¿Qué es Whisper?
Whisper representa el modelo de reconocimiento de voz de código abierto de vanguardia de OpenAI diseñado para aplicación universal. Construido sobre una arquitectura avanzada de aprendizaje automático, este sofisticado modelo transforma el lenguaje hablado en texto escrito con notable precisión. Ofrece varias ventajas clave que lo distinguen de los sistemas tradicionales de reconocimiento de voz:
- Transcripción de alta calidad: Whisper aprovecha un conjunto de datos de entrenamiento masivo que abarca miles de horas de contenido de audio diverso, incluyendo diferentes estilos de habla, condiciones ambientales y calidades de grabación. Este extenso entrenamiento le permite producir transcripciones excepcionalmente precisas, incluso en escenarios desafiantes.
- Soporte multilingüe: Una de las características más impresionantes de Whisper es su robusta capacidad multilingüe. El modelo puede entender y transcribir voz en numerosos idiomas, convirtiéndolo en una herramienta valiosa para la comunicación global y la creación de contenido. Incluso puede detectar idiomas automáticamente y manejar cambios de código entre idiomas.
- Precisión independiente del hablante: Gracias a su arquitectura avanzada de red neuronal, Whisper demuestra una notable adaptabilidad a diferentes voces, acentos y dialectos. Mantiene una precisión consistente independientemente de las características del hablante y puede filtrar eficazmente el ruido de fondo, haciéndolo confiable en aplicaciones del mundo real.
- Varios formatos de audio: La versatilidad de Whisper se extiende a sus capacidades de manejo de entrada. El modelo procesa sin problemas una amplia gama de formatos de audio, incluyendo MP3, MP4, WAV y M4A, eliminando la necesidad de conversiones complejas de formato y haciéndolo más accesible para varios casos de uso.
Interactuarás con Whisper usando el cliente Python de OpenAI a través de la función openai.Audio.transcribe()
, que proporciona una interfaz sencilla para acceder a estas potentes capacidades.
5.3.3 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga una muestra de audio: https://files.cuantum.tech/audio/recording.mp3
Necesitarás Flask, OpenAI y python-dotenv
. Abre tu terminal y ejecuta el siguiente comando:
pip install flask openai python-dotenv
Este comando instala las bibliotecas necesarias:
flask
: Un micro framework web para construir la aplicación web.openai
: La biblioteca Python de OpenAI para interactuar con la API de Whisper.python-dotenv
: Una biblioteca para cargar variables de entorno desde un archivo.env
.
Paso 2: Configurar la Estructura del Proyecto
Crea la siguiente estructura de carpetas para tu proyecto:
/whisper_transcriber
│
├── app.py
├── .env
└── templates/
└── index.html
/whisper_transcriber
: El directorio raíz de tu proyecto.app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar tu clave API de OpenAI.templates/
: Un directorio para almacenar tus plantillas HTML.templates/index.html
: La plantilla HTML para la página principal de tu aplicación.
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
en el directorio raíz de tu proyecto (/whisper_transcriber
). Añade el siguiente código a app.py
:
from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcribe(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file and displays the transcription.
"""
transcript = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", transcript=transcript, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación:
from flask import Flask, request, render_template, jsonify, make_response
: Importa los módulos necesarios de Flask.import openai
: Importa la biblioteca Python de OpenAI.import os
: Importa el móduloos
para interactuar con el sistema operativo (por ejemplo, para rutas de archivos, variables de entorno).from dotenv import load_dotenv
: Importa la funciónload_dotenv
para cargar variables de entorno desde un archivo.env
.import logging
: Importa el módulo de registro.from typing import Optional
: Importa Optional para sugerencias de tipo
- Variables de Entorno:
load_dotenv()
: Carga la clave API de OpenAI desde el archivo.env
.openai.api_key = os.getenv("OPENAI_API_KEY")
: Obtiene la clave API de OpenAI del entorno y la configura para la biblioteca OpenAI.
- Aplicación Flask:
app = Flask(__name__)
: Crea una instancia de la aplicación Flask.
- Configuración de Registro:
logging.basicConfig(level=logging.INFO)
: Configura el módulo de registro para registrar eventos en el nivel INFO.logger = logging.getLogger(__name__)
: Crea un objeto de registro.
- Función
allowed_file
:def allowed_file(filename: str) -> bool:
: Verifica si la extensión del archivo está permitida.- Devuelve verdadero si el nombre del archivo tiene una extensión de audio válida
- Función
transcribe_audio
:def transcribe_audio(file_path: str) -> Optional[str]:
: Define una función para transcribir un archivo de audio usando la API de OpenAI.Args
:file_path
(str
): La ruta al archivo de audio.
Returns
:Optional[str]
: El texto transcrito si tiene éxito,None
en caso contrario.
- La función abre el archivo de audio en modo binario (
"rb"
) y lo pasa aopenai.Audio.transcribe()
. - Registra la ruta del archivo antes de la transcripción y la longitud del texto transcrito después de una transcripción exitosa.
- Incluye manejo de errores usando un bloque
try...except
para capturar posibles excepcionesopenai.error.OpenAIError
(específicas de OpenAI) yException
general para otros errores. Si ocurre un error, registra el error y devuelveNone
.
- Ruta
index
:@app.route("/", methods=["GET", "POST"])
: Este decorador define la ruta para la página principal de la aplicación ("/"). La funciónindex()
maneja tanto peticiones GET como POST.def index():
: Esta función maneja las peticiones a la URL raíz ("/").transcript = None
: Inicializa una variable para almacenar el texto de la transcripción.error_message = None
: Inicializa una variable para almacenar cualquier mensaje de error.if request.method == "POST":
: Este bloque se ejecuta cuando el usuario envía el formulario (es decir, sube un archivo de audio).- Manejo de Archivos:
if 'audio_file' not in request.files: ...
: Verifica si elaudio_file
está presente en la petición.file = request.files['audio_file']
: Obtiene el archivo subido de la petición.if file.filename == '': ...
: Verifica si el usuario seleccionó un archivo.
if file and allowed_file(file.filename):
: Verifica si se subió un archivo y si tiene una extensión permitida.temp_file_path = ...
: Genera una ruta temporal para guardar el archivo de audio subido. Utiliza la extensión del nombre de archivo original para asegurar que el archivo se guarde con el formato correcto.file.save(temp_file_path)
: Guarda el archivo de audio subido en la ruta temporal.transcript = transcribe_audio(temp_file_path)
: Llama a la funcióntranscribe_audio()
para transcribir el archivo de audio.if not transcript: ...
: Verifica si la transcripción fue exitosa. Si no lo fue, establece un mensaje de error.os.remove(temp_file_path)
: Elimina el archivo de audio temporal después de procesarlo.
else:
: Si el tipo de archivo no está permitido, establece un mensaje de error.- La función luego renderiza la plantilla
index.html
, pasando eltranscript
yerror_message
.
- Manejo de Archivos:
- La función también renderiza la plantilla
index.html
para peticiones GET.
@app.errorhandler(500)
: Maneja errores 500.- Registra el error.
- Renderiza una página de error.
if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el directorio raíz de tu proyecto. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whisper Voice Note Transcriber</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb; /* Tailwind's gray-50 */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151; /* Tailwind's gray-700 */
}
.container {
max-width: 800px; /* Increased max-width */
width: 95%; /* Take up most of the viewport */
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem; /* Tailwind's rounded-lg */
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
text-align: center;
}
h2 {
font-size: 2.25rem; /* Tailwind's text-3xl */
font-weight: 600; /* Tailwind's font-semibold */
margin-bottom: 1.5rem; /* Tailwind's mb-6 */
color: #1e293b; /* Tailwind's gray-900 */
}
p{
color: #6b7280; /* Tailwind's gray-500 */
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem; /* Tailwind's mt-4 */
display: flex;
flex-direction: column;
align-items: center; /* Center form elements */
gap: 0.5rem; /* Tailwind's gap-2 */
}
label {
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
color: #4b5563; /* Tailwind's gray-600 */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
display: block; /* Ensure label takes full width */
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px; /* Added max-width for file input */
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
font-size: 1rem; /* Tailwind's text-base */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
color: #fff;
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
cursor: pointer;
transition: background-color 0.3s ease; /* Smooth transition */
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca; /* Tailwind's bg-indigo-700 on hover */
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
}
textarea {
width: 100%;
max-width: 600px; /* Increased max-width for textarea */
height: 200px;
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
margin-top: 1rem; /* Tailwind's mt-4 */
font-size: 1rem; /* Tailwind's text-base */
line-height: 1.5rem; /* Tailwind's leading-relaxed */
resize: vertical; /* Allow vertical resizing */
margin-left: auto;
margin-right: auto;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
}
textarea:focus {
outline: none;
border-color: #3b82f6; /* Tailwind's border-blue-500 */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
}
/* --- Error Styles --- */
.error-message {
color: #dc2626; /* Tailwind's text-red-600 */
margin-top: 1rem; /* Tailwind's mt-4 */
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"],
textarea {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Voice Note Transcriber</h2>
<p> Upload an audio file to transcribe. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Transcribe">
</form>
{% if transcript %}
<h3>📝 Transcription:</h3>
<textarea readonly>{{ transcript }}</textarea>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y establece la configuración del viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluyendo un formulario para subir archivos de audio y una sección para mostrar la transcripción.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS está actualizado con un diseño moderno.
- Diseño responsivo: El diseño se adapta mejor, especialmente en pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo del formulario y de los campos de entrada para mayor usabilidad.
- Visualización clara de errores: Los mensajes de error están estilizados para ser claramente visibles.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para manejar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga solo a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización de la transcripción:
- Se utiliza un
<textarea readonly>
para mostrar el texto transcrito. El atributoreadonly
evita que el usuario edite la transcripción.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar cualquier mensaje de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo,
recording.mp3
). - Visualiza la transcripción mostrada en la página.
5.3.4 Notas sobre Formatos de Audio y Seguridad
Whisper es compatible con una amplia gama de formatos de audio, cada uno con ventajas únicas y casos de uso específicos. Exploremos cada formato en detalle:
.mp3
- El formato estándar de la industria para audio comprimido que ofrece un excelente equilibrio entre calidad de audio y tamaño de archivo. Perfecto para la mayoría de grabaciones de voz y audio de uso general, típicamente alcanzando relaciones de compresión de 10:1 mientras mantiene una buena fidelidad de audio..mp4
- Un formato contenedor versátil utilizado principalmente para video pero igualmente capaz de manejar pistas de audio de alta calidad. Admite múltiples códecs de audio y es particularmente útil cuando se trabaja con contenido multimedia que incluye tanto elementos de video como de audio..m4a
- Un formato contenedor de audio especializado que típicamente utiliza codificación AAC. Ofrece mejor calidad de sonido que MP3 a tasas de bits similares y es particularmente adecuado para grabaciones de voz debido a su eficiente compresión de patrones de habla..wav
- El estándar de oro para la calidad de audio, proporcionando audio sin comprimir y sin pérdidas. Si bien los tamaños de archivo son significativamente más grandes, es ideal para aplicaciones profesionales donde la fidelidad del audio es crucial, como servicios de transcripción profesional o análisis de audio..webm
- Un formato moderno de código abierto diseñado específicamente para aplicaciones web. Ofrece compresión eficiente y capacidades de transmisión rápida, haciéndolo ideal para grabación y reproducción de voz basada en web.
Al implementar tu aplicación en un entorno de producción, es crucial implementar medidas de seguridad robustas. Aquí hay consideraciones detalladas de seguridad:
- Agregar validación de tamaño de archivo - Implementa límites estrictos de tamaño de archivo (recomendado: 25MB) para mantener la estabilidad del servidor. Esto previene potenciales ataques de denegación de servicio y asegura una asignación eficiente de recursos. Considera implementar indicadores de carga progresiva y carga por fragmentos para archivos más grandes.
- Automáticamente eliminar archivos temporales después de la transcripción - Implementa un sistema seguro de limpieza de archivos que elimine los archivos procesados inmediatamente después de la transcripción. Esto no solo conserva el almacenamiento del servidor sino que también garantiza la privacidad del usuario al prevenir el acceso no autorizado a los archivos de audio subidos.
- Implementar límite de frecuencia o autenticación para cargas de usuario - Implementa algoritmos sofisticados de limitación de frecuencia basados en direcciones IP o cuentas de usuario. Considera implementar autenticación OAuth2 y control de acceso basado en roles (RBAC) para gestionar efectivamente los permisos de usuario.
Esta robusta aplicación de transcripción de voz aprovecha varias tecnologías poderosas:
- Flask para la interfaz de usuario y manejo de cargas - Proporciona un marco de trabajo ligero pero potente para manejar cargas de archivos y servir la interfaz web
- Whisper para reconocimiento de voz de alta calidad - Utiliza modelos de aprendizaje automático de última generación para lograr transcripciones precisas en múltiples idiomas y acentos
- La API de OpenAI para integración perfecta - Permite fácil acceso a capacidades avanzadas de IA con rendimiento confiable y actualizaciones regulares
Esta versátil herramienta de voz a texto sirve como base para numerosas aplicaciones prácticas, incluyendo:
- Un chatbot sofisticado con capacidades de entrada por voz
- Un asistente de toma de notas inteligente que puede transcribir y organizar contenido hablado
- Un resumidor de reuniones integral que puede procesar y analizar discusiones grabadas
- Una herramienta de podcasting con IA avanzada para transcripción automática y análisis de contenido
5.3 Transcriptor de Notas de Voz Potenciado por Whisper
En esta sección, aprenderás a crear una potente aplicación web Flask que aprovecha la API de Whisper de OpenAI para la transcripción de audio. Esta aplicación proporcionará a los usuarios una interfaz fluida para cargar archivos de audio en varios formatos (como MP3, WAV o M4A) y convertir automáticamente las palabras habladas en texto escrito preciso.
La API de Whisper, conocida por su alta precisión y soporte multilingüe, maneja la compleja tarea del reconocimiento de voz, mientras que Flask proporciona el marco web para hacer esta funcionalidad accesible a través de una interfaz de navegador. Ya sea que estés construyendo una herramienta para transcribir entrevistas, crear actas de reuniones o desarrollar una función de accesibilidad, esta aplicación demostrará cómo combinar efectivamente el desarrollo web con el procesamiento de audio impulsado por IA.
5.3.1 Lo que Construirás
La aplicación web proporciona una interfaz sofisticada e intuitiva para cargar archivos de audio, diseñada pensando en la experiencia del usuario. Cuando un usuario envía un archivo de audio, la aplicación ejecuta una serie de pasos cuidadosamente orquestados:
- Recibir el archivo de audio: La aplicación maneja de forma segura el proceso de carga de archivos, validando el formato y tamaño para garantizar la compatibilidad.
- Guardar temporalmente el archivo de audio en el servidor: Utilizando prácticas seguras de manejo de archivos, la aplicación crea una solución de almacenamiento temporal que mantiene la privacidad del usuario durante el procesamiento del archivo.
- Enviar el archivo de audio a la API de Whisper de OpenAI para transcripción: La aplicación establece una conexión segura con los servidores de OpenAI y transmite el archivo de audio utilizando protocolos estándar de la industria.
- Recibir la transcripción de la API de Whisper: La aplicación procesa la respuesta de la API, manejando cualquier error potencial y formateando la transcripción para una legibilidad óptima.
- Mostrar el texto de la transcripción en la página web: Los resultados se presentan en una interfaz limpia y bien formateada que permite una fácil lectura y la posibilidad de copiar o descargar el texto transcrito.
Esta funcionalidad versátil sirve para numerosas aplicaciones profesionales y personales, incluyendo:
- Periodistas grabando y transcribiendo entrevistas: Agiliza el proceso de entrevista proporcionando transcripciones rápidas y precisas para la redacción de artículos y verificación de fuentes
- Estudiantes capturando y transcribiendo notas de clase: Permite una mejor concentración durante las clases mientras asegura una toma de notas completa mediante transcripción automatizada
- Podcasters que necesitan transcripciones para accesibilidad y búsqueda: Mejora la accesibilidad del contenido para audiencias con dificultades auditivas y mejora el SEO a través de transcripciones navegables
- Profesionales de negocios revisando y transcribiendo grabaciones de reuniones: Facilita la documentación eficiente de reuniones y permite una fácil referencia a discusiones importantes
- Cualquier persona que necesite convertir voz a texto: Proporciona una solución universal para convertir contenido hablado en formato escrito, ya sea para notas personales, documentación o propósitos de accesibilidad
5.3.2 ¿Qué es Whisper?
Whisper representa el modelo de reconocimiento de voz de código abierto de vanguardia de OpenAI diseñado para aplicación universal. Construido sobre una arquitectura avanzada de aprendizaje automático, este sofisticado modelo transforma el lenguaje hablado en texto escrito con notable precisión. Ofrece varias ventajas clave que lo distinguen de los sistemas tradicionales de reconocimiento de voz:
- Transcripción de alta calidad: Whisper aprovecha un conjunto de datos de entrenamiento masivo que abarca miles de horas de contenido de audio diverso, incluyendo diferentes estilos de habla, condiciones ambientales y calidades de grabación. Este extenso entrenamiento le permite producir transcripciones excepcionalmente precisas, incluso en escenarios desafiantes.
- Soporte multilingüe: Una de las características más impresionantes de Whisper es su robusta capacidad multilingüe. El modelo puede entender y transcribir voz en numerosos idiomas, convirtiéndolo en una herramienta valiosa para la comunicación global y la creación de contenido. Incluso puede detectar idiomas automáticamente y manejar cambios de código entre idiomas.
- Precisión independiente del hablante: Gracias a su arquitectura avanzada de red neuronal, Whisper demuestra una notable adaptabilidad a diferentes voces, acentos y dialectos. Mantiene una precisión consistente independientemente de las características del hablante y puede filtrar eficazmente el ruido de fondo, haciéndolo confiable en aplicaciones del mundo real.
- Varios formatos de audio: La versatilidad de Whisper se extiende a sus capacidades de manejo de entrada. El modelo procesa sin problemas una amplia gama de formatos de audio, incluyendo MP3, MP4, WAV y M4A, eliminando la necesidad de conversiones complejas de formato y haciéndolo más accesible para varios casos de uso.
Interactuarás con Whisper usando el cliente Python de OpenAI a través de la función openai.Audio.transcribe()
, que proporciona una interfaz sencilla para acceder a estas potentes capacidades.
5.3.3 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga una muestra de audio: https://files.cuantum.tech/audio/recording.mp3
Necesitarás Flask, OpenAI y python-dotenv
. Abre tu terminal y ejecuta el siguiente comando:
pip install flask openai python-dotenv
Este comando instala las bibliotecas necesarias:
flask
: Un micro framework web para construir la aplicación web.openai
: La biblioteca Python de OpenAI para interactuar con la API de Whisper.python-dotenv
: Una biblioteca para cargar variables de entorno desde un archivo.env
.
Paso 2: Configurar la Estructura del Proyecto
Crea la siguiente estructura de carpetas para tu proyecto:
/whisper_transcriber
│
├── app.py
├── .env
└── templates/
└── index.html
/whisper_transcriber
: El directorio raíz de tu proyecto.app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar tu clave API de OpenAI.templates/
: Un directorio para almacenar tus plantillas HTML.templates/index.html
: La plantilla HTML para la página principal de tu aplicación.
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
en el directorio raíz de tu proyecto (/whisper_transcriber
). Añade el siguiente código a app.py
:
from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcribe(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file and displays the transcription.
"""
transcript = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", transcript=transcript, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación:
from flask import Flask, request, render_template, jsonify, make_response
: Importa los módulos necesarios de Flask.import openai
: Importa la biblioteca Python de OpenAI.import os
: Importa el móduloos
para interactuar con el sistema operativo (por ejemplo, para rutas de archivos, variables de entorno).from dotenv import load_dotenv
: Importa la funciónload_dotenv
para cargar variables de entorno desde un archivo.env
.import logging
: Importa el módulo de registro.from typing import Optional
: Importa Optional para sugerencias de tipo
- Variables de Entorno:
load_dotenv()
: Carga la clave API de OpenAI desde el archivo.env
.openai.api_key = os.getenv("OPENAI_API_KEY")
: Obtiene la clave API de OpenAI del entorno y la configura para la biblioteca OpenAI.
- Aplicación Flask:
app = Flask(__name__)
: Crea una instancia de la aplicación Flask.
- Configuración de Registro:
logging.basicConfig(level=logging.INFO)
: Configura el módulo de registro para registrar eventos en el nivel INFO.logger = logging.getLogger(__name__)
: Crea un objeto de registro.
- Función
allowed_file
:def allowed_file(filename: str) -> bool:
: Verifica si la extensión del archivo está permitida.- Devuelve verdadero si el nombre del archivo tiene una extensión de audio válida
- Función
transcribe_audio
:def transcribe_audio(file_path: str) -> Optional[str]:
: Define una función para transcribir un archivo de audio usando la API de OpenAI.Args
:file_path
(str
): La ruta al archivo de audio.
Returns
:Optional[str]
: El texto transcrito si tiene éxito,None
en caso contrario.
- La función abre el archivo de audio en modo binario (
"rb"
) y lo pasa aopenai.Audio.transcribe()
. - Registra la ruta del archivo antes de la transcripción y la longitud del texto transcrito después de una transcripción exitosa.
- Incluye manejo de errores usando un bloque
try...except
para capturar posibles excepcionesopenai.error.OpenAIError
(específicas de OpenAI) yException
general para otros errores. Si ocurre un error, registra el error y devuelveNone
.
- Ruta
index
:@app.route("/", methods=["GET", "POST"])
: Este decorador define la ruta para la página principal de la aplicación ("/"). La funciónindex()
maneja tanto peticiones GET como POST.def index():
: Esta función maneja las peticiones a la URL raíz ("/").transcript = None
: Inicializa una variable para almacenar el texto de la transcripción.error_message = None
: Inicializa una variable para almacenar cualquier mensaje de error.if request.method == "POST":
: Este bloque se ejecuta cuando el usuario envía el formulario (es decir, sube un archivo de audio).- Manejo de Archivos:
if 'audio_file' not in request.files: ...
: Verifica si elaudio_file
está presente en la petición.file = request.files['audio_file']
: Obtiene el archivo subido de la petición.if file.filename == '': ...
: Verifica si el usuario seleccionó un archivo.
if file and allowed_file(file.filename):
: Verifica si se subió un archivo y si tiene una extensión permitida.temp_file_path = ...
: Genera una ruta temporal para guardar el archivo de audio subido. Utiliza la extensión del nombre de archivo original para asegurar que el archivo se guarde con el formato correcto.file.save(temp_file_path)
: Guarda el archivo de audio subido en la ruta temporal.transcript = transcribe_audio(temp_file_path)
: Llama a la funcióntranscribe_audio()
para transcribir el archivo de audio.if not transcript: ...
: Verifica si la transcripción fue exitosa. Si no lo fue, establece un mensaje de error.os.remove(temp_file_path)
: Elimina el archivo de audio temporal después de procesarlo.
else:
: Si el tipo de archivo no está permitido, establece un mensaje de error.- La función luego renderiza la plantilla
index.html
, pasando eltranscript
yerror_message
.
- Manejo de Archivos:
- La función también renderiza la plantilla
index.html
para peticiones GET.
@app.errorhandler(500)
: Maneja errores 500.- Registra el error.
- Renderiza una página de error.
if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el directorio raíz de tu proyecto. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whisper Voice Note Transcriber</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb; /* Tailwind's gray-50 */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151; /* Tailwind's gray-700 */
}
.container {
max-width: 800px; /* Increased max-width */
width: 95%; /* Take up most of the viewport */
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem; /* Tailwind's rounded-lg */
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
text-align: center;
}
h2 {
font-size: 2.25rem; /* Tailwind's text-3xl */
font-weight: 600; /* Tailwind's font-semibold */
margin-bottom: 1.5rem; /* Tailwind's mb-6 */
color: #1e293b; /* Tailwind's gray-900 */
}
p{
color: #6b7280; /* Tailwind's gray-500 */
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem; /* Tailwind's mt-4 */
display: flex;
flex-direction: column;
align-items: center; /* Center form elements */
gap: 0.5rem; /* Tailwind's gap-2 */
}
label {
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
color: #4b5563; /* Tailwind's gray-600 */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
display: block; /* Ensure label takes full width */
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px; /* Added max-width for file input */
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
font-size: 1rem; /* Tailwind's text-base */
margin-bottom: 0.25rem; /* Tailwind's mb-1 */
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
color: #fff;
font-size: 1rem; /* Tailwind's text-base */
font-weight: 600; /* Tailwind's font-semibold */
cursor: pointer;
transition: background-color 0.3s ease; /* Smooth transition */
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca; /* Tailwind's bg-indigo-700 on hover */
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
}
textarea {
width: 100%;
max-width: 600px; /* Increased max-width for textarea */
height: 200px;
padding: 0.75rem; /* Tailwind's p-3 */
border-radius: 0.5rem; /* Tailwind's rounded-md */
border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
margin-top: 1rem; /* Tailwind's mt-4 */
font-size: 1rem; /* Tailwind's text-base */
line-height: 1.5rem; /* Tailwind's leading-relaxed */
resize: vertical; /* Allow vertical resizing */
margin-left: auto;
margin-right: auto;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
}
textarea:focus {
outline: none;
border-color: #3b82f6; /* Tailwind's border-blue-500 */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
}
/* --- Error Styles --- */
.error-message {
color: #dc2626; /* Tailwind's text-red-600 */
margin-top: 1rem; /* Tailwind's mt-4 */
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"],
textarea {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Voice Note Transcriber</h2>
<p> Upload an audio file to transcribe. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Transcribe">
</form>
{% if transcript %}
<h3>📝 Transcription:</h3>
<textarea readonly>{{ transcript }}</textarea>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y establece la configuración del viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluyendo un formulario para subir archivos de audio y una sección para mostrar la transcripción.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS está actualizado con un diseño moderno.
- Diseño responsivo: El diseño se adapta mejor, especialmente en pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo del formulario y de los campos de entrada para mayor usabilidad.
- Visualización clara de errores: Los mensajes de error están estilizados para ser claramente visibles.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para manejar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga solo a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización de la transcripción:
- Se utiliza un
<textarea readonly>
para mostrar el texto transcrito. El atributoreadonly
evita que el usuario edite la transcripción.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar cualquier mensaje de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo,
recording.mp3
). - Visualiza la transcripción mostrada en la página.
5.3.4 Notas sobre Formatos de Audio y Seguridad
Whisper es compatible con una amplia gama de formatos de audio, cada uno con ventajas únicas y casos de uso específicos. Exploremos cada formato en detalle:
.mp3
- El formato estándar de la industria para audio comprimido que ofrece un excelente equilibrio entre calidad de audio y tamaño de archivo. Perfecto para la mayoría de grabaciones de voz y audio de uso general, típicamente alcanzando relaciones de compresión de 10:1 mientras mantiene una buena fidelidad de audio..mp4
- Un formato contenedor versátil utilizado principalmente para video pero igualmente capaz de manejar pistas de audio de alta calidad. Admite múltiples códecs de audio y es particularmente útil cuando se trabaja con contenido multimedia que incluye tanto elementos de video como de audio..m4a
- Un formato contenedor de audio especializado que típicamente utiliza codificación AAC. Ofrece mejor calidad de sonido que MP3 a tasas de bits similares y es particularmente adecuado para grabaciones de voz debido a su eficiente compresión de patrones de habla..wav
- El estándar de oro para la calidad de audio, proporcionando audio sin comprimir y sin pérdidas. Si bien los tamaños de archivo son significativamente más grandes, es ideal para aplicaciones profesionales donde la fidelidad del audio es crucial, como servicios de transcripción profesional o análisis de audio..webm
- Un formato moderno de código abierto diseñado específicamente para aplicaciones web. Ofrece compresión eficiente y capacidades de transmisión rápida, haciéndolo ideal para grabación y reproducción de voz basada en web.
Al implementar tu aplicación en un entorno de producción, es crucial implementar medidas de seguridad robustas. Aquí hay consideraciones detalladas de seguridad:
- Agregar validación de tamaño de archivo - Implementa límites estrictos de tamaño de archivo (recomendado: 25MB) para mantener la estabilidad del servidor. Esto previene potenciales ataques de denegación de servicio y asegura una asignación eficiente de recursos. Considera implementar indicadores de carga progresiva y carga por fragmentos para archivos más grandes.
- Automáticamente eliminar archivos temporales después de la transcripción - Implementa un sistema seguro de limpieza de archivos que elimine los archivos procesados inmediatamente después de la transcripción. Esto no solo conserva el almacenamiento del servidor sino que también garantiza la privacidad del usuario al prevenir el acceso no autorizado a los archivos de audio subidos.
- Implementar límite de frecuencia o autenticación para cargas de usuario - Implementa algoritmos sofisticados de limitación de frecuencia basados en direcciones IP o cuentas de usuario. Considera implementar autenticación OAuth2 y control de acceso basado en roles (RBAC) para gestionar efectivamente los permisos de usuario.
Esta robusta aplicación de transcripción de voz aprovecha varias tecnologías poderosas:
- Flask para la interfaz de usuario y manejo de cargas - Proporciona un marco de trabajo ligero pero potente para manejar cargas de archivos y servir la interfaz web
- Whisper para reconocimiento de voz de alta calidad - Utiliza modelos de aprendizaje automático de última generación para lograr transcripciones precisas en múltiples idiomas y acentos
- La API de OpenAI para integración perfecta - Permite fácil acceso a capacidades avanzadas de IA con rendimiento confiable y actualizaciones regulares
Esta versátil herramienta de voz a texto sirve como base para numerosas aplicaciones prácticas, incluyendo:
- Un chatbot sofisticado con capacidades de entrada por voz
- Un asistente de toma de notas inteligente que puede transcribir y organizar contenido hablado
- Un resumidor de reuniones integral que puede procesar y analizar discusiones grabadas
- Una herramienta de podcasting con IA avanzada para transcripción automática y análisis de contenido