Tutorial 13: Creando el Método para Obtener la URL de la API
¡Hola y bienvenido de nuevo!
En esta lección vamos a crear un método que nos permita obtener las URLs correctas de la API de OpenAI según el tipo de operación que necesitemos realizar: transcripción o traducción. ¡Vamos a ello!
📋 Contenido del Tutorial
Entendiendo los endpoints de OpenAI
Agregando la propiedad dataType
Creando el método getApiUrl
Método para manejar errores
Documentación de la API
Código completo
Explicación detallada
Próximos pasos
🔗 1. Entendiendo los endpoints de OpenAI
¿Qué es un endpoint?
Un endpoint es una URL específica donde una API acepta solicitudes. Es como la dirección a la que enviamos nuestros datos para que sean procesados.
Los endpoints de Whisper
OpenAI proporciona dos endpoints principales para trabajar con audio:
| Endpoint | URL | Función |
|---|---|---|
| Transcripciones | https://api.openai.com/v1/audio/transcriptions | Convierte audio a texto en el mismo idioma |
| Traducciones | https://api.openai.com/v1/audio/translations | Convierte audio a texto en inglés |
¿Por qué necesitamos dos endpoints?
Documentación oficial
Puedes encontrar la documentación completa en:
https://platform.openai.com/docs/guides/speech-to-text
Pasos para acceder:
Ve a platform.openai.com
Haz clic en "Documentation"
Selecciona "Speech to text" en el menú
📊 2. Agregando la propiedad dataType
¿Qué es dataType?
dataType es una propiedad que vamos a usar para indicar qué tipo de operación queremos realizar:
public $dataType;
Valores posibles
| Valor | Significado | Uso |
|---|---|---|
"ASR" | Automatic Speech Recognition | Transcribir audio a texto |
"TRANSLATE" | Traducción | Traducir el texto a otros idiomas |
¿Cómo se usa?
// Para transcribir $whisperObj->dataType = "ASR"; // Para traducir $whisperObj->dataType = "TRANSLATE";
Agregando la propiedad a la clase
class Whisper { public $error; public $dataType; // ← Nueva propiedad private $DB; // ... resto de la clase }
🔧 3. Creando el método getApiUrl
Estructura del método
public function getApiUrl() { if ($this->dataType === "ASR") { return "https://api.openai.com/v1/audio/transcriptions"; } else { return "https://api.openai.com/v1/chat/completions"; } }
¿Qué hace este método?
Verifica el valor de
dataTypeSi es "ASR": Devuelve la URL para transcripciones
Si es otro valor: Devuelve la URL para traducciones
Endpoints correctos
| Tipo | URL correcta |
|---|---|
| ASR | https://api.openai.com/v1/audio/transcriptions |
| Traducción | https://api.openai.com/v1/chat/completions |
Nota: Para traducciones de texto, usamos el endpoint de chat completions, que nos permite usar modelos como GPT para traducir.
❌ 4. Método para manejar errores
Agregando el método errors()
public function errors() { return $this->error; }
¿Para qué sirve?
Este método nos permite obtener el mensaje de error almacenado en la propiedad $error de forma segura.
Uso del método
// En index.php if ($file) { // Procesamiento exitoso } else { // Mostrar el error $error = $whisperObj->errors(); echo "Error: " . $error; }
Beneficios
| Beneficio | Explicación |
|---|---|
| Encapsulamiento | Acceso controlado a la propiedad |
| Consistencia | Siempre devuelve el error actual |
| Flexibilidad | Podemos modificar la lógica sin cambiar el código cliente |
📚 5. Documentación de la API
Endpoint de Transcripciones
POST https://api.openai.com/v1/audio/transcriptions
Headers:
Authorization: Bearer TU_API_KEY Content-Type: multipart/form-data
Parámetros:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
file | File | Sí | Archivo de audio/video |
model | String | Sí | whisper-1 |
language | String | No | Código del idioma (ej: es) |
response_format | String | No | json, text, srt, vtt |
Endpoint de Traducción de Texto
POST https://api.openai.com/v1/chat/completions
Headers:
Authorization: Bearer TU_API_KEY Content-Type: application/json
Parámetros:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
model | String | Sí | gpt-3.5-turbo o gpt-4 |
messages | Array | Sí | Mensajes para el chat |
temperature | Number | No | Creatividad (0-1) |
💻 6. Código completo
Archivo: backend/classes/Whisper.php
<?php /** * Clase Whisper * * Maneja la subida, transcripción y traducción de archivos * utilizando la API de OpenAI */ class Whisper { /** * @var string Mensajes de error */ public $error; /** * @var string Tipo de operación (ASR o TRANSLATE) */ public $dataType; /** * @var PDO Conexión a la base de datos */ private $DB; /** * Constructor - Establece conexión a la base de datos */ public function __construct() { $db = new DB(); $this->DB = $db->connect(); } /** * Obtiene el mensaje de error actual * * @return string El mensaje de error */ public function errors() { return $this->error; } /** * Obtiene la URL de la API según el tipo de operación * * @return string URL del endpoint de la API */ public function getApiUrl() { // Si es ASR (Automatic Speech Recognition) if ($this->dataType === "ASR") { return "https://api.openai.com/v1/audio/transcriptions"; } else { // Para traducciones y otros usos return "https://api.openai.com/v1/chat/completions"; } } /** * Sube un archivo al servidor * * @param array $file Arreglo $_FILES * @return string|false Ruta del archivo o false en caso de error */ public function upload($file) { // 1. Extraer información del archivo $fileTmp = $file['tmp_name']; $filename = basename($file['name']); $fileSize = $file['size']; $errors = $file['error']; $mime = $file['type']; // 2. Obtener la extensión del archivo $ext = pathinfo($filename, PATHINFO_EXTENSION); $ext = strtolower($ext); // 3. Obtener el directorio raíz del proyecto $parentDirectory = dirname(dirname(dirname(__FILE__))); // 4. Definir los tipos de archivo permitidos $allowedMedia = [ 'video/mp4', 'video/mpeg', 'audio/mpeg', 'audio/mpeg3', 'audio/wav' ]; // 5. Validar el tipo de archivo if (!in_array($mime, $allowedMedia)) { $this->error = "Formato de archivo inválido"; return false; } // 6. Validar el tamaño del archivo (máximo 20 MB) if ($fileSize > 20000000) { $this->error = "El archivo es demasiado grande (máximo 20 MB)"; return false; } // 7. Crear nombre único y subir el archivo $folder = 'files/'; $uniqueName = md5(time() . mt_rand()); $file = $folder . $uniqueName . '.' . $ext; // 8. Mover el archivo if (move_uploaded_file($fileTmp, $parentDirectory . '/' . $file)) { return $file; } else { $this->error = "Error al mover el archivo"; return false; } } /** * Prepara la solicitud para la API de OpenAI * * @param string $filePath Ruta del archivo * @return array Datos para la solicitud */ public function prepareApiRequest($filePath) { // Verificar que la API Key esté configurada if (!defined('OPENAI_API_KEY') || OPENAI_API_KEY === '') { $this->error = "API Key no configurada"; return false; } // Verificar que el archivo existe if (!file_exists($filePath)) { $this->error = "El archivo no existe"; return false; } // Obtener la URL según el tipo de operación $url = $this->getApiUrl(); // Preparar los datos según el tipo if ($this->dataType === "ASR") { // Datos para transcripción $postFields = [ 'file' => curl_file_create($filePath), 'model' => 'whisper-1', 'language' => 'es', 'response_format' => 'json' ]; } else { // Datos para traducción $postFields = json_encode([ 'model' => 'gpt-3.5-turbo', 'messages' => [ [ 'role' => 'system', 'content' => 'Traduce el siguiente texto al español' ], [ 'role' => 'user', 'content' => file_get_contents($filePath) ] ], 'temperature' => 0.7 ]); } return [ 'url' => $url, 'postFields' => $postFields ]; } /** * Envía la solicitud a la API de OpenAI * * @param array $requestData Datos preparados * @return string|false Resultado de la API o false en caso de error */ public function sendApiRequest($requestData) { $ch = curl_init(); // Configurar cURL curl_setopt($ch, CURLOPT_URL, $requestData['url']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_TIMEOUT, 60); // Configurar headers $headers = [ 'Authorization: Bearer ' . OPENAI_API_KEY ]; if ($this->dataType === "ASR") { $headers[] = 'Content-Type: multipart/form-data'; curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData['postFields']); } else { $headers[] = 'Content-Type: application/json'; curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData['postFields']); } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Ejecutar la solicitud $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); // Verificar errores if ($error) { $this->error = "Error cURL: " . $error; return false; } if ($httpCode !== 200) { $this->error = "Error HTTP: " . $httpCode . " - " . $response; return false; } return $response; } } ?>
Archivo: backend/init.php (actualizado)
<?php /** * Archivo de inicialización de la aplicación */ // ============================================= // 1. CONFIGURACIÓN DE LA API KEY // ============================================= // Cargar variables de entorno desde .env function loadEnv($path = __DIR__ . '/../.env') { if (!file_exists($path)) { return false; } $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($lines as $line) { if (strpos($line, '#') === 0 || strpos($line, '=') === false) { continue; } list($key, $value) = explode('=', $line, 2); $key = trim($key); $value = trim($value, '"\''); putenv("$key=$value"); $_ENV[$key] = $value; } return true; } // Cargar .env loadEnv(); // Definir API Key define('OPENAI_API_KEY', getenv('OPENAI_API_KEY') ?: ''); // ============================================= // 2. CARGAR CLASES // ============================================= require 'classes/DB.php'; require 'classes/Whisper.php'; // ============================================= // 3. CREAR INSTANCIAS // ============================================= $whisperObj = new Whisper(); // Configurar el tipo de operación (por defecto: ASR) $whisperObj->dataType = "ASR"; // ============================================= // 4. VERIFICACIONES // ============================================= // Verificar API Key if (OPENAI_API_KEY === '') { die('⚠️ Error: La API Key de OpenAI no está configurada'); } // Verificar conexión a la base de datos if (!$whisperObj->DB) { die('⚠️ Error: No se pudo conectar a la base de datos'); } ?>
Archivo: index.php (sección PHP actualizada)
<?php // Cargar la configuración inicial include 'backend/init.php'; // Variables para mensajes $error = null; $success = null; // Verificar si la solicitud es POST if ($_SERVER['REQUEST_METHOD'] === "POST") { // Verificar si el archivo está presente if (isset($_FILES['file'])) { // Verificar que no esté vacío if (!empty($_FILES['file']['name'])) { // Procesar el archivo $file = $whisperObj->upload($_FILES['file']); if ($file) { // Determinar el tipo de archivo $mime = $_FILES['file']['type']; $type = strpos($mime, 'video/') === 0 ? 'video' : 'audio'; // Guardar en la base de datos $id = $whisperObj->saveFileInfo($file, $type); if ($id) { $success = "¡Archivo subido correctamente! ID: " . $id; // Aquí llamaremos a la API para transcribir // $result = $whisperObj->transcribe($file); } else { $error = $whisperObj->errors(); } } else { $error = $whisperObj->errors(); } } else { $error = "Por favor selecciona un archivo para convertir a texto"; } } else { $error = "Por favor selecciona un archivo para convertir a texto"; } } ?>
📖 7. Explicación detallada
El método getApiUrl
public function getApiUrl() { if ($this->dataType === "ASR") { return "https://api.openai.com/v1/audio/transcriptions"; } else { return "https://api.openai.com/v1/chat/completions"; } }
Flujo de decisión:
¿dataType es "ASR"?
↓
├── Sí → Usar endpoint de transcripciones
│ https://api.openai.com/v1/audio/transcriptions
│
└── No → Usar endpoint de chat/completions
https://api.openai.com/v1/chat/completions¿Por qué dos endpoints diferentes?
| Endpoint | Cuándo usar | Ejemplo |
|---|---|---|
| Transcripciones | Para convertir audio a texto | Un video en español → texto en español |
| Chat Completions | Para traducir texto | Texto en español → texto en inglés |
El método errors()
public function errors() { return $this->error; }
Ventajas de usar un método en lugar de acceder directamente:
// ❌ Acceso directo (menos seguro) echo $whisperObj->error; // ✅ Usando el método (más seguro) echo $whisperObj->errors();
🧪 8. Probando la funcionalidad
Prueba 1: Verificar la URL para ASR
$whisperObj->dataType = "ASR"; $url = $whisperObj->getApiUrl(); echo $url; // Resultado esperado: https://api.openai.com/v1/audio/transcriptions
Prueba 2: Verificar la URL para traducción
$whisperObj->dataType = "TRANSLATE"; $url = $whisperObj->getApiUrl(); echo $url; // Resultado esperado: https://api.openai.com/v1/chat/completions
Prueba 3: Verificar el método errors()
$whisperObj->error = "Error de prueba"; echo $whisperObj->errors(); // Resultado esperado: Error de prueba
📊 9. Resumen de la clase Whisper hasta ahora
Propiedades
| Propiedad | Tipo | Descripción |
|---|---|---|
$error | string | Almacena mensajes de error |
$dataType | string | Tipo de operación (ASR/TRANSLATE) |
$DB | PDO | Conexión a la base de datos |
Métodos
| Método | Parámetros | Retorno | Descripción |
|---|---|---|---|
__construct() | - | void | Constructor, conecta a BD |
errors() | - | string | Devuelve el error actual |
getApiUrl() | - | string | Devuelve la URL de la API |
upload() | $file | string/false | Sube un archivo |
prepareApiRequest() | $filePath | array/false | Prepara la solicitud API |
sendApiRequest() | $requestData | string/false | Envía solicitud a API |
Diagrama de flujo
┌─────────────────────────────────────────────┐ │ APLICACIÓN WHISPER │ ├─────────────────────────────────────────────┤ │ │ │ 1. Usuario sube archivo │ │ ↓ │ │ 2. upload() valida y guarda archivo │ │ ↓ │ │ 3. Se establece dataType │ │ ↓ │ │ 4. getApiUrl() selecciona endpoint │ │ ↓ │ │ 5. prepareApiRequest() prepara datos │ │ ↓ │ │ 6. sendApiRequest() envía a OpenAI │ │ ↓ │ │ 7. Se recibe y procesa respuesta │ │ ↓ │ │ 8. Se guarda en la base de datos │ │ │ └─────────────────────────────────────────────┘
🎯 10. Próximos pasos
Lo que hemos logrado
✅ Propiedad dataType añadida
✅ Método getApiUrl() implementado
✅ Método errors() para manejo de errores
✅ Preparación para usar la API de OpenAI
Lo que viene en la próxima lección
En la siguiente lección vamos a:
Implementar la comunicación con la API de OpenAI
Enviar archivos para transcripción
Recibir y procesar la respuesta
Guardar la transcripción en la base de datos
Avance del código de la próxima lección
// Nuevo método en Whisper.php public function transcribe($filePath) { // 1. Preparar la solicitud $request = $this->prepareApiRequest($filePath); // 2. Enviar a la API $response = $this->sendApiRequest($request); // 3. Procesar respuesta if ($response) { $data = json_decode($response, true); return $data['text'] ?? false; } return false; }
❓ Preguntas frecuentes
¿Qué significa ASR?
Automatic Speech Recognition (Reconocimiento Automático del Habla)
Es el proceso de convertir audio en texto
¿Por qué usar el endpoint de chat para traducciones?
Porque usamos modelos de lenguaje (GPT) para traducir texto
Ofrece mejores resultados que modelos específicos de traducción
¿Puedo usar el endpoint de traducciones de audio?
Sí, OpenAI también tiene
/v1/audio/translationsTraduce audio directamente a texto en inglés
¿Qué pasa si dataType no está configurado?
Por defecto, usará el endpoint de chat/completions
Es mejor configurarlo explícitamente
¿Cómo sé qué endpoint usar?
Si quieres transcribir audio →
ASRSi quieres traducir texto →
TRANSLATEu otro
¿Los endpoints son gratuitos?
No, ambos endpoints tienen costo
Los precios varían según el modelo usado
🎓 Ejercicio práctico
Ejercicio 1: Probar ambos endpoints
// Probar ASR $whisperObj->dataType = "ASR"; echo $whisperObj->getApiUrl(); // Probar TRADUCCIÓN $whisperObj->dataType = "TRANSLATE"; echo $whisperObj->getApiUrl();
Ejercicio 2: Agregar más tipos
Amplía el método getApiUrl() para soportar más operaciones:
public function getApiUrl() { switch ($this->dataType) { case "ASR": return "https://api.openai.com/v1/audio/transcriptions"; case "TRANSLATE_AUDIO": return "https://api.openai.com/v1/audio/translations"; case "TRANSLATE_TEXT": return "https://api.openai.com/v1/chat/completions"; default: return "https://api.openai.com/v1/audio/transcriptions"; } }
Ejercicio 3: Agregar validación
Agrega validación para dataType:
public function setDataType($type) { $allowedTypes = ['ASR', 'TRANSLATE_AUDIO', 'TRANSLATE_TEXT']; if (in_array($type, $allowedTypes)) { $this->dataType = $type; return true; } $this->error = "Tipo de operación no válido"; return false; }
¡Excelente trabajo! Ahora tenemos la capacidad de seleccionar dinámicamente el endpoint correcto de la API según la operación que necesitemos realizar. En la próxima lección, implementaremos la comunicación real con la API.
Comentarios
Publicar un comentario