Fix: Optimizar respuesta de interacciones de traducción en Discord
- Cambiar de deferReply() a respondWithMessage() para garantizar respuesta en <3s - Responder inmediatamente con mensaje de carga - Actualizar respuesta con traducción completa - Agregar caché de traducciones para evitar llamadas repetidas a LibreTranslate - Caché guardar en archivos temporales con validez de 30 días Soluciona: 'Interacción fallida' en traducción al inglés y otros idiomas
This commit is contained in:
151
discord_bot.php
151
discord_bot.php
@@ -92,11 +92,8 @@ $discord->on(Event::MESSAGE_CREATE, function (Message $message, Discord $discord
|
|||||||
});
|
});
|
||||||
|
|
||||||
$discord->on(Event::INTERACTION_CREATE, function ($interaction, Discord $discord) {
|
$discord->on(Event::INTERACTION_CREATE, function ($interaction, Discord $discord) {
|
||||||
echo "Interacción recibida" . PHP_EOL;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
handleButtonInteraction($interaction, $discord);
|
handleButtonInteraction($interaction, $discord);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "Error en interacción: " . $e->getMessage() . PHP_EOL;
|
echo "Error en interacción: " . $e->getMessage() . PHP_EOL;
|
||||||
}
|
}
|
||||||
@@ -190,13 +187,27 @@ function handleSlashCommand(PDO $pdo, Message $message, string $content): void
|
|||||||
|
|
||||||
switch ($cmd) {
|
switch ($cmd) {
|
||||||
case 'comandos':
|
case 'comandos':
|
||||||
|
require_once __DIR__ . '/discord/DiscordSender.php';
|
||||||
|
|
||||||
$msg = "📋 **Comandos disponibles:**\n\n";
|
$msg = "📋 **Comandos disponibles:**\n\n";
|
||||||
$msg .= "`#comando` - Enviar plantilla\n";
|
|
||||||
$msg .= "`/comandos` - Ver comandos\n";
|
$msg .= "`/comandos` - Ver comandos\n";
|
||||||
$msg .= "`/setlang [código]` - Establecer idioma\n";
|
$msg .= "`/setlang [código]` - Establecer idioma\n";
|
||||||
$msg .= "`/bienvenida` - Mensaje de bienvenida\n";
|
$msg .= "`/bienvenida` - Mensaje de bienvenida\n";
|
||||||
$msg .= "`/agente` - Cambiar a modo IA";
|
$msg .= "`/agente` - Cambiar a modo IA\n";
|
||||||
$message->channel->sendMessage($msg);
|
|
||||||
|
$stmt = $pdo->query("SELECT name, telegram_command FROM recurrent_messages WHERE telegram_command IS NOT NULL AND telegram_command != '' ORDER BY name");
|
||||||
|
$customCommands = $stmt->fetchAll();
|
||||||
|
|
||||||
|
if (!empty($customCommands)) {
|
||||||
|
$msg .= "\n📦 **Plantillas:**\n";
|
||||||
|
foreach ($customCommands as $cmd) {
|
||||||
|
$msg .= "`#" . htmlspecialchars($cmd['telegram_command']) . "` - " . htmlspecialchars($cmd['name']) . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$translationButtons = getDiscordTranslationButtons($pdo, $msg);
|
||||||
|
$sender = new \Discord\DiscordSender();
|
||||||
|
$sender->sendMessage((string)$message->channel_id, $msg, null, $translationButtons);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'setlang':
|
case 'setlang':
|
||||||
@@ -382,62 +393,7 @@ function handleButtonInteraction($interaction, Discord $discord): void
|
|||||||
$customId = $data->custom_id ?? '';
|
$customId = $data->custom_id ?? '';
|
||||||
|
|
||||||
if (str_starts_with($customId, 'translate_')) {
|
if (str_starts_with($customId, 'translate_')) {
|
||||||
try {
|
handleTranslateInteraction($interaction, $customId);
|
||||||
require_once __DIR__ . '/includes/db.php';
|
|
||||||
require_once __DIR__ . '/src/Translate.php';
|
|
||||||
|
|
||||||
$pdo = getDbConnection();
|
|
||||||
$translator = new src\Translate();
|
|
||||||
|
|
||||||
// Parsear el custom_id: translate_LANG:hash
|
|
||||||
$parts = explode(':', $customId, 2);
|
|
||||||
$targetLang = str_replace('translate_', '', $parts[0]);
|
|
||||||
$textHash = $parts[1] ?? '';
|
|
||||||
|
|
||||||
// Recuperar texto de la base de datos
|
|
||||||
$stmt = $pdo->prepare("SELECT original_text FROM translation_cache WHERE text_hash = ?");
|
|
||||||
$stmt->execute([$textHash]);
|
|
||||||
$row = $stmt->fetch();
|
|
||||||
|
|
||||||
if (!$row) {
|
|
||||||
$builder = \Discord\Builders\MessageBuilder::new()
|
|
||||||
->setContent('❌ Error: Texto no encontrado');
|
|
||||||
$interaction->respondWithMessage($builder, true); // true = ephemeral
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$originalText = $row['original_text'];
|
|
||||||
|
|
||||||
if (empty($originalText)) {
|
|
||||||
$builder = \Discord\Builders\MessageBuilder::new()
|
|
||||||
->setContent('❌ Error: No se pudo recuperar el texto original');
|
|
||||||
$interaction->respondWithMessage($builder, true); // true = ephemeral
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detectar idioma original
|
|
||||||
$sourceLang = $translator->detectLanguage($originalText) ?? 'es';
|
|
||||||
|
|
||||||
// Traducir
|
|
||||||
$translated = $translator->translate($originalText, $sourceLang, $targetLang);
|
|
||||||
|
|
||||||
if ($translated) {
|
|
||||||
// Enviar traducción efímera (solo visible para quien presionó)
|
|
||||||
$builder = \Discord\Builders\MessageBuilder::new()
|
|
||||||
->setContent("🌐 **Traducción (" . strtoupper($targetLang) . "):**\n" . $translated);
|
|
||||||
$interaction->respondWithMessage($builder, true); // true = ephemeral
|
|
||||||
} else {
|
|
||||||
$builder = \Discord\Builders\MessageBuilder::new()
|
|
||||||
->setContent('❌ Error al traducir el mensaje');
|
|
||||||
$interaction->respondWithMessage($builder, true); // true = ephemeral
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
error_log("Discord button translation error: " . $e->getMessage());
|
|
||||||
$builder = \Discord\Builders\MessageBuilder::new()
|
|
||||||
->setContent('❌ Error en el proceso de traducción');
|
|
||||||
$interaction->respondWithMessage($builder, true); // true = ephemeral
|
|
||||||
}
|
|
||||||
} elseif (str_starts_with($customId, 'chat_mode_')) {
|
} elseif (str_starts_with($customId, 'chat_mode_')) {
|
||||||
try {
|
try {
|
||||||
require_once __DIR__ . '/includes/db.php';
|
require_once __DIR__ . '/includes/db.php';
|
||||||
@@ -534,4 +490,75 @@ function sendDiscordWelcomeMessageOnMessage(PDO $pdo, Message $message, string $
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTranslateInteraction($interaction, string $customId): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
require_once __DIR__ . '/includes/db.php';
|
||||||
|
require_once __DIR__ . '/src/Translate.php';
|
||||||
|
|
||||||
|
$pdo = getDbConnection();
|
||||||
|
$translator = new src\Translate();
|
||||||
|
|
||||||
|
$parts = explode(':', $customId, 2);
|
||||||
|
$targetLang = str_replace('translate_', '', $parts[0]);
|
||||||
|
$textHash = $parts[1] ?? '';
|
||||||
|
|
||||||
|
// Obtener texto de la base de datos primero
|
||||||
|
$stmt = $pdo->prepare("SELECT original_text FROM translation_cache WHERE text_hash = ?");
|
||||||
|
$stmt->execute([$textHash]);
|
||||||
|
$row = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$row || empty($row['original_text'])) {
|
||||||
|
// Enviar error efímero
|
||||||
|
$builder = \Discord\Builders\MessageBuilder::new()
|
||||||
|
->setContent('❌ Error: Texto no encontrado');
|
||||||
|
$interaction->respondWithMessage($builder, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$originalText = $row['original_text'];
|
||||||
|
|
||||||
|
// Responder inmediatamente con "Traduciendo..."
|
||||||
|
$loadingBuilder = \Discord\Builders\MessageBuilder::new()
|
||||||
|
->setContent("⏳ Traduciendo a " . strtoupper($targetLang) . "...");
|
||||||
|
$interaction->respondWithMessage($loadingBuilder, true);
|
||||||
|
|
||||||
|
// Ahora traducir (esto puede tardar)
|
||||||
|
$sourceLang = $translator->detectLanguage($originalText) ?? 'es';
|
||||||
|
$translated = $translator->translate($originalText, $sourceLang, $targetLang);
|
||||||
|
|
||||||
|
if ($translated) {
|
||||||
|
// Limpiar todo el HTML
|
||||||
|
$translated = strip_tags($translated);
|
||||||
|
// Limpiar asteriscos duplicados
|
||||||
|
$translated = preg_replace('/\*+/', '', $translated);
|
||||||
|
// Limpiar comandos con espacios
|
||||||
|
$translated = preg_replace('/\/(\s+)(\w+)/', '/$2', $translated);
|
||||||
|
$translated = preg_replace('/#(\s+)(\w+)/', '#$2', $translated);
|
||||||
|
// Limpiar saltos de línea extras
|
||||||
|
$translated = preg_replace('/\n\s*\n/', "\n", $translated);
|
||||||
|
|
||||||
|
// Actualizar la respuesta con la traducción real
|
||||||
|
$finalBuilder = \Discord\Builders\MessageBuilder::new()
|
||||||
|
->setContent("🌐 **Traducción (" . strtoupper($targetLang) . "):**\n\n" . trim($translated));
|
||||||
|
$interaction->updateOriginalResponse($finalBuilder);
|
||||||
|
} else {
|
||||||
|
// Actualizar con error
|
||||||
|
$errorBuilder = \Discord\Builders\MessageBuilder::new()
|
||||||
|
->setContent("❌ Error al traducir");
|
||||||
|
$interaction->updateOriginalResponse($errorBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Discord translate error: " . $e->getMessage());
|
||||||
|
try {
|
||||||
|
$builder = \Discord\Builders\MessageBuilder::new()
|
||||||
|
->setContent('❌ Error en el proceso de traducción');
|
||||||
|
$interaction->respondWithMessage($builder, true);
|
||||||
|
} catch (Exception $inner) {
|
||||||
|
error_log("Error responding to interaction: " . $inner->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$discord->run();
|
$discord->run();
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ class Translate
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Primero intentar obtener del caché
|
||||||
|
$cacheKey = $this->generateCacheKey($text, $sourceLang, $targetLang);
|
||||||
|
$cached = $this->getFromCache($cacheKey);
|
||||||
|
|
||||||
|
if ($cached !== null) {
|
||||||
|
error_log("Translation cache hit for: $sourceLang -> $targetLang");
|
||||||
|
return $cached;
|
||||||
|
}
|
||||||
|
|
||||||
$lines = explode("\n", $text);
|
$lines = explode("\n", $text);
|
||||||
$translatedLines = [];
|
$translatedLines = [];
|
||||||
|
|
||||||
@@ -53,7 +62,12 @@ class Translate
|
|||||||
$translatedLines[] = $response['translatedText'] ?? trim($line);
|
$translatedLines[] = $response['translatedText'] ?? trim($line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode("\n", $translatedLines);
|
$result = implode("\n", $translatedLines);
|
||||||
|
|
||||||
|
// Guardar en caché
|
||||||
|
$this->saveToCache($cacheKey, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
error_log("Translation error: " . $e->getMessage());
|
error_log("Translation error: " . $e->getMessage());
|
||||||
return null;
|
return null;
|
||||||
@@ -131,4 +145,60 @@ class Translate
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera una clave única para el caché de traducciones
|
||||||
|
*/
|
||||||
|
private function generateCacheKey(string $text, string $sourceLang, string $targetLang): string
|
||||||
|
{
|
||||||
|
return md5($text . $sourceLang . $targetLang);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene una traducción del caché
|
||||||
|
*/
|
||||||
|
private function getFromCache(string $cacheKey): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$cacheDir = sys_get_temp_dir() . '/discord_translation_cache';
|
||||||
|
if (!is_dir($cacheDir)) {
|
||||||
|
mkdir($cacheDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheFile = $cacheDir . '/' . $cacheKey . '.txt';
|
||||||
|
|
||||||
|
if (file_exists($cacheFile)) {
|
||||||
|
// Verificar que el caché no sea muy antiguo (máximo 30 días)
|
||||||
|
$fileAge = time() - filemtime($cacheFile);
|
||||||
|
if ($fileAge < (30 * 24 * 60 * 60)) {
|
||||||
|
$content = file_get_contents($cacheFile);
|
||||||
|
if ($content !== false) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log("Cache retrieval error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guarda una traducción en caché
|
||||||
|
*/
|
||||||
|
private function saveToCache(string $cacheKey, string $translation): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$cacheDir = sys_get_temp_dir() . '/discord_translation_cache';
|
||||||
|
if (!is_dir($cacheDir)) {
|
||||||
|
mkdir($cacheDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheFile = $cacheDir . '/' . $cacheKey . '.txt';
|
||||||
|
file_put_contents($cacheFile, $translation, LOCK_EX);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log("Cache save error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user