20: Creando el Método para Actualizar la Traducción en la Base de Datos
20: Creando el Método para Actualizar la Traducción en la Base de Datos
¡Hola y bienvenido de nuevo!
En esta lección vamos a crear un método para actualizar la base de datos con la traducción del texto. Cuando el usuario seleccione un idioma y haga clic en "Translate", guardaremos la traducción en la base de datos para mostrarla posteriormente. ¡Vamos a ello!
📋 Contenido del Tutorial
Entendiendo la actualización de datos
Creando el método update
La consulta UPDATE en SQL
Vinculando parámetros para UPDATE
Seguridad en las actualizaciones
Código completo
Explicación detallada
Próximos pasos
💾 1. Entendiendo la actualización de datos
¿Qué es una actualización en SQL?
Una actualización (UPDATE) modifica datos existentes en una tabla de la base de datos. A diferencia de INSERT (que agrega nuevos registros), UPDATE cambia los valores de registros ya existentes.
Estructura de UPDATE
UPDATE nombre_tabla SET columna1 = valor1, columna2 = valor2 WHERE columna_condicion = valor_condicion;
Nuestro caso de uso
Cuando un usuario traduce el texto:
1. Texto original: "Hello world" 2. Idioma seleccionado: "Spanish" 3. Traducción: "Hola mundo" 4. Actualizar en la base de datos: - translated = "Hola mundo" - lang = "Spanish" - Donde ID = 1
Columnas a actualizar
| Columna | Valor | Descripción |
|---|---|---|
translated | Texto traducido | Contenido en el idioma destino |
lang | Idioma destino | Ej: "Spanish", "French" |
🔧 2. Creando el método update
Estructura del método
public function update($fileID, $content, $lang) { // 1. Preparar la consulta UPDATE $stmt = $this->DB->prepare( "UPDATE `files` SET `translated` = :content, `lang` = :lang WHERE `ID` = :fileID" ); // 2. Vincular los parámetros $stmt->bindParam(":content", $content, PDO::PARAM_STR); $stmt->bindParam(":lang", $lang, PDO::PARAM_STR); $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT); // 3. Ejecutar la consulta $stmt->execute(); }
Parámetros del método
| Parámetro | Tipo | Descripción | Ejemplo |
|---|---|---|---|
$fileID | int | ID del archivo a actualizar | 1 |
$content | string | Texto traducido | "Hola mundo" |
$lang | string | Idioma de la traducción | "Spanish" |
📝 3. La consulta UPDATE en SQL
Consulta completa
UPDATE `files` SET `translated` = :content, `lang` = :lang WHERE `ID` = :fileID
Desglose de la consulta
| Parte | Significado | Ejemplo |
|---|---|---|
UPDATE files | Tabla a actualizar | files |
SET translated = :content | Columna a modificar | translated = "Hola mundo" |
SET lang = :lang | Columna a modificar | lang = "Spanish" |
WHERE ID = :fileID | Condición de búsqueda | ID = 1 |
¿Qué hace cada parte?
UPDATE files ← Tabla: files SET ← Comienza la asignación translated = :content ← Columna: translated lang = :lang ← Columna: lang WHERE ID = :fileID ← Solo el registro con este ID
Ejemplo de ejecución
-- Antes de UPDATE ID | content | translated | lang 1 | "Hello world" | NULL | NULL -- Ejecutar UPDATE UPDATE files SET translated = "Hola mundo", lang = "Spanish" WHERE ID = 1 -- Después de UPDATE ID | content | translated | lang 1 | "Hello world" | "Hola mundo" | "Spanish"
🔗 4. Vinculando parámetros para UPDATE
¿Por qué vincular parámetros?
| Razón | Explicación |
|---|---|
| Seguridad | Previene inyección SQL |
| Rendimiento | La consulta se compila una vez |
| Mantenimiento | Código más limpio |
Código de vinculación
// Vincular el contenido (texto) $stmt->bindParam(":content", $content, PDO::PARAM_STR); // Vincular el idioma (texto) $stmt->bindParam(":lang", $lang, PDO::PARAM_STR); // Vincular el ID (entero) $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT);
Tipos de parámetros PDO
| Constante | Tipo | Uso |
|---|---|---|
PDO::PARAM_STR | String | Texto, nombres, descripciones |
PDO::PARAM_INT | Integer | IDs, contadores, números |
PDO::PARAM_BOOL | Boolean | True/False |
PDO::PARAM_NULL | NULL | Valores nulos |
🛡️ 5. Seguridad en las actualizaciones
Buenas prácticas
public function update($fileID, $content, $lang) { try { // 1. Validar que el ID existe if (!$this->fileExists($fileID)) { $this->error = "El archivo no existe"; return false; } // 2. Validar que el contenido no esté vacío if (empty($content)) { $this->error = "El contenido no puede estar vacío"; return false; } // 3. Validar que el idioma sea válido $allowedLanguages = ['English', 'Spanish', 'French', 'German']; if (!in_array($lang, $allowedLanguages)) { $this->error = "Idioma no válido"; return false; } // 4. Ejecutar la actualización $stmt = $this->DB->prepare( "UPDATE `files` SET `translated` = :content, `lang` = :lang WHERE `ID` = :fileID" ); $stmt->bindParam(":content", $content, PDO::PARAM_STR); $stmt->bindParam(":lang", $lang, PDO::PARAM_STR); $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT); return $stmt->execute(); } catch (PDOException $e) { $this->error = "Error al actualizar: " . $e->getMessage(); return false; } }
Verificaciones adicionales
| Verificación | Código | Propósito |
|---|---|---|
| Existencia | $this->fileExists($fileID) | Verificar que el archivo existe |
| Contenido | !empty($content) | No guardar traducciones vacías |
| Idioma | in_array($lang, $allowed) | Solo idiomas permitidos |
| Excepción | try-catch | Capturar errores de base de datos |
💻 6. Código completo
Archivo: backend/classes/Whisper.php (método update agregado)
<?php class Whisper{ public $error; public $dataType; public $file; public $lang; public $content; private $DB; public function __construct(){ $db = new DB; $this->DB = $db->connect(); } public function errors(){ return $this->error; } public function getApiUrl(){ if($this->dataType === "ASR"){ return "https://api.openai.com/v1/audio/transcriptions"; }else{ return "https://api.openai.com/v1/chat/completions"; } } public function getHeader(){ if($this->dataType === "ASR"){ return [ 'Authorization: Bearer ' . API_TOKEN, 'Content-Type: multipart/form-data' ]; }else{ return [ 'Authorization: Bearer ' . API_TOKEN, 'Content-Type: application/json' ]; } } public function getData(){ if($this->dataType === "ASR"){ return [ 'file' => $this->file, 'model' => 'whisper-1' ]; }else{ return json_encode([ 'model' => 'gpt-3.5-turbo', 'messages' => [ [ 'role' => 'system', 'content' => 'You will be provided with a text, and your task is to translate it into ' . $this->lang ], [ 'role' => 'user', 'content' => $this->content ] ] ]); } } public function getFile(){ if($this->dataType === 'ASR'){ $this->file = curl_file_create($this->file); } } public function covert(){ $apiUrl = $this->getApiUrl(); $ch = curl_init($apiUrl); curl_setopt($ch, CURLOPT_POST, true); $this->getFile(); curl_setopt($ch, CURLOPT_POSTFIELDS, $this->getData()); curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeader()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); if($response){ return json_decode($response, true); }else{ $this->error = "API REQUEST FAILED"; } } public function upload($file){ $fileTmp = $file['tmp_name']; $filename = basename($file['name']); $fileSize = $file['size']; $errors = $file['error']; $mime = $file['type']; //get file extension $ext = pathinfo($filename, PATHINFO_EXTENSION); $ext = strtolower($ext); $parentDirectoy = dirname(dirname(dirname(__FILE__))); $allowedMedia = ['video/mp4','video/mpeg', 'audio/mpeg','audio/mpeg3','audio/wav']; if(in_array($mime, $allowedMedia)){ if($fileSize <= 20000000){ $folder = 'files/'; $file = $folder. md5(time() . mt_rand()) . '.'.$ext; move_uploaded_file($fileTmp, $parentDirectoy . '/'.$file); return $file; }else{ $this->error = "File is large!"; } }else{ $this->error = "invalid file format!"; } } public function save($file, $content, $type){ $stmt = $this->DB->prepare("INSERT INTO `files` (`fileUrl`, `content`, `type`) VALUES (:fileUrl, :content, :type)"); $stmt->bindParam(":fileUrl", $file, PDO::PARAM_STR); $stmt->bindParam(":content", $content, PDO::PARAM_STR); $stmt->bindParam(":type", $type, PDO::PARAM_STR); $stmt->execute(); return $this->DB->lastInsertId(); } public function getRecentList(){ $stmt = $this->DB->prepare("SELECT * FROM `files` ORDER BY `ID` DESC"); $stmt->execute(); $files = $stmt->fetchAll(PDO::FETCH_OBJ); foreach($files as $file){ echo '<a href="view.php?file='.$file->ID.'"> <li class="rounded flex my-5 cursor-pointer hover:bg-gray-100 items-center"> <div class="w-14"> '.(($file->type === 'audio') ? '<img src="frontend/images/audio-img.png"/>' : '<img src="frontend/images/video-img.png"/>' ) .' </div> <div class=" overflow-hidden w-60 font-normal h-auto font-bold p-2 "> <div> <p class="truncate">'.htmlspecialchars($file->content).'</p> </div> </div> </li> </a>'; } } public function getFileById($fileID){ $stmt = $this->DB->prepare("SELECT * FROM `files` WHERE `ID` = :fileID"); $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetch(PDO::FETCH_OBJ); } /** * Actualiza la traducción de un archivo en la base de datos * * @param int $fileID ID del archivo a actualizar * @param string $content Texto traducido * @param string $lang Idioma de la traducción * @return bool True si se actualizó correctamente, false en caso de error */ public function update($fileID, $content, $lang){ try { // 1. Verificar que el archivo existe $file = $this->getFileById($fileID); if (!$file) { $this->error = "El archivo no existe"; return false; } // 2. Verificar que el contenido no esté vacío if (empty($content)) { $this->error = "El contenido no puede estar vacío"; return false; } // 3. Verificar que el idioma sea válido $allowedLanguages = ['English', 'Spanish', 'French', 'German']; if (!in_array($lang, $allowedLanguages)) { $this->error = "Idioma no válido"; return false; } // 4. Preparar la consulta UPDATE $stmt = $this->DB->prepare( "UPDATE `files` SET `translated` = :content, `lang` = :lang WHERE `ID` = :fileID" ); // 5. Vincular los parámetros $stmt->bindParam(":content", $content, PDO::PARAM_STR); $stmt->bindParam(":lang", $lang, PDO::PARAM_STR); $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT); // 6. Ejecutar la consulta $result = $stmt->execute(); if ($result) { return true; } else { $this->error = "Error al ejecutar la actualización"; return false; } } catch (PDOException $e) { $this->error = "Error en la base de datos: " . $e->getMessage(); return false; } } } ?>
Archivo: translate.php (nuevo archivo)
<?php /** * Archivo para manejar las solicitudes de traducción * Recibe el contenido, idioma y ID del archivo, y guarda la traducción */ // Incluir la configuración include 'backend/init.php'; // Configurar la respuesta como JSON header('Content-Type: application/json'); // Verificar que sea una solicitud POST if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode([ 'success' => false, 'error' => 'Método no permitido' ]); exit; } // Obtener los datos del formulario $content = $_POST['content'] ?? ''; $lang = $_POST['lang'] ?? ''; $fileId = isset($_POST['file_id']) ? (int)$_POST['file_id'] : 0; // Validar los datos if (empty($content)) { echo json_encode([ 'success' => false, 'error' => 'No hay contenido para traducir' ]); exit; } if (empty($lang)) { echo json_encode([ 'success' => false, 'error' => 'No se seleccionó un idioma' ]); exit; } if ($fileId <= 0) { echo json_encode([ 'success' => false, 'error' => 'ID de archivo inválido' ]); exit; } // Configurar Whisper para traducción $whisperObj->dataType = 'TRANSLATE'; $whisperObj->content = $content; $whisperObj->lang = $lang; // Enviar a la API $result = $whisperObj->convert(); // Verificar el resultado if ($result && isset($result['choices'][0]['message']['content'])) { $translated = $result['choices'][0]['message']['content']; // Guardar en la base de datos $updated = $whisperObj->update($fileId, $translated, $lang); if ($updated) { echo json_encode([ 'success' => true, 'translated' => $translated, 'lang' => $lang, 'message' => 'Traducción guardada correctamente' ]); } else { echo json_encode([ 'success' => false, 'error' => $whisperObj->errors() ]); } } else { echo json_encode([ 'success' => false, 'error' => $whisperObj->errors() ?: 'Error al traducir el texto' ]); } ?>
Archivo: view.php (actualizado con JavaScript para traducción)
<!-- JS CODE HERE --> <script> $(document).ready(function() { // Evento del botón de traducción $('#translateBtn').click(function(e) { e.preventDefault(); // Mostrar loader $('#loader').removeClass('hidden'); // Obtener datos var lang = $('#lang').val(); var content = $('div#scroll h3:first').next('div').text().trim(); var fileId = <?php echo $file ? $file->ID : 0; ?>; // Validar que haya contenido if (!content || content === 'No hay contenido para mostrar') { $('#loader').addClass('hidden'); alert('No hay contenido para traducir'); return; } // Validar que haya un archivo seleccionado if (fileId === 0) { $('#loader').addClass('hidden'); alert('No hay archivo seleccionado'); return; } // Enviar solicitud AJAX $.ajax({ url: 'translate.php', method: 'POST', data: { content: content, lang: lang, file_id: fileId }, dataType: 'json', success: function(response) { $('#loader').addClass('hidden'); if (response.success) { // Mostrar mensaje de éxito alert('¡Traducción completada!'); // Recargar la página para mostrar la traducción location.reload(); } else { // Mostrar error alert('Error: ' + (response.error || 'Error desconocido')); } }, error: function(xhr, status, error) { $('#loader').addClass('hidden'); console.error('Error AJAX:', error); alert('Error al conectar con el servidor'); } }); }); }); </script>
📖 7. Explicación detallada
El método update paso a paso
public function update($fileID, $content, $lang) { try { // 1. Verificar que el archivo existe $file = $this->getFileById($fileID); if (!$file) { $this->error = "El archivo no existe"; return false; } // 2. Validar contenido if (empty($content)) { $this->error = "El contenido no puede estar vacío"; return false; } // 3. Validar idioma $allowedLanguages = ['English', 'Spanish', 'French', 'German']; if (!in_array($lang, $allowedLanguages)) { $this->error = "Idioma no válido"; return false; } // 4. Ejecutar UPDATE $stmt = $this->DB->prepare( "UPDATE `files` SET `translated` = :content, `lang` = :lang WHERE `ID` = :fileID" ); $stmt->bindParam(":content", $content, PDO::PARAM_STR); $stmt->bindParam(":lang", $lang, PDO::PARAM_STR); $stmt->bindParam(":fileID", $fileID, PDO::PARAM_INT); return $stmt->execute(); } catch (PDOException $e) { $this->error = "Error en la base de datos: " . $e->getMessage(); return false; } }
¿Qué hace la consulta UPDATE?
Antes de UPDATE:
ID | fileUrl | content | translated | lang 1 | files/ | "Hello world" | NULL | NULL
Después de UPDATE:
ID | fileUrl | content | translated | lang 1 | files/ | "Hello world" | "Hola mundo" | "Spanish"
Validaciones implementadas
| Validación | Código | Propósito |
|---|---|---|
| Existencia | $this->getFileById($fileID) | Verificar que el ID existe |
| Contenido | !empty($content) | No guardar texto vacío |
| Idioma | in_array($lang, $allowed) | Solo idiomas permitidos |
🧪 8. Probando la traducción
Paso 1: Subir un archivo
Ve a
http://localhost/whisper/Selecciona un archivo de audio o video
Espera la transcripción
Paso 2: Traducir el texto
En
view.php, selecciona un idioma (ej: "Spanish")Haz clic en "Translate"
Espera el procesamiento
Paso 3: Verificar la traducción
La página se recarga automáticamente
La traducción aparece en la sección "Translated Content"
El idioma se muestra en el título
Paso 4: Verificar en la base de datos
-- Verificar la traducción guardada SELECT ID, content, translated, lang FROM files WHERE ID = [TU_ID];
📊 9. Resumen del flujo de traducción
Diagrama de secuencia
Usuario → view.php
↓
Selecciona idioma
↓
Clic en "Translate"
↓
JavaScript (AJAX) → translate.php
↓
translate.php → Whisper->convert()
↓
Whisper → API de OpenAI
↓
API devuelve traducción
↓
translate.php → Whisper->update()
↓
update → Base de datos
↓
Respuesta JSON → JavaScript
↓
Recargar página → Mostrar traducciónDatos guardados
| Columna | Origen | Ejemplo |
|---|---|---|
translated | API de OpenAI | "Hola mundo" |
lang | Select del usuario | "Spanish" |
❓ Preguntas frecuentes
¿Qué hace UPDATE en SQL?
Modifica registros existentes en una tabla
Permite cambiar valores de columnas específicas
¿Por qué necesito WHERE en UPDATE?
Para especificar qué registros actualizar
Sin
WHERE, se actualizarían TODOS los registros
¿Qué pasa si el ID no existe?
getFileById()retornafalseEl método
update()retornafalsecon un error
¿Puedo traducir varias veces?
Sí, cada traducción sobrescribe la anterior
El idioma y el texto se actualizan
¿Por qué usar PDO::PARAM_INT para el ID?
Especifica que el valor es un número entero
Mejora la seguridad y el rendimiento
¿Qué son las excepciones PDO?
Son errores que lanza PDO cuando algo falla
Se capturan con
try-catchpara manejarlos
🎯 Próximos pasos
Lo que hemos logrado
✅ Método update() implementado
✅ Validación de datos antes de actualizar
✅ Consulta UPDATE con parámetros vinculados
✅ Manejo de errores con try-catch
✅ Integración con traducción
Lo que viene en la próxima lección
En la siguiente lección vamos a:
Completar el ciclo de traducción
Mejorar la interfaz de usuario
Agregar más idiomas de traducción
Optimizar el rendimiento
Resumen del proyecto completo
📁 Proyecto Whisper ├── 📄 index.php → Subir archivos ├── 📄 view.php → Ver archivos y traducciones ├── 📄 translate.php → Procesar traducciones ├── 📁 backend/ │ ├── 📄 init.php → Configuración │ └── 📁 classes/ │ ├── 📄 DB.php → Conexión a BD │ └── 📄 Whisper.php → Lógica principal ├── 📁 files/ → Archivos subidos └── 📁 frontend/ → Estilos e imágenes
¡Excelente trabajo! Ahora tenemos un sistema completo de traducción que guarda los resultados en la base de datos. La aplicación está lista para ser usada y expandida.
Comentarios
Publicar un comentario