diff --git a/discord_bot.php b/discord_bot.php index 8183a86..36aabe3 100755 --- a/discord_bot.php +++ b/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) { - echo "Interacción recibida" . PHP_EOL; - try { handleButtonInteraction($interaction, $discord); - } catch (Exception $e) { echo "Error en interacción: " . $e->getMessage() . PHP_EOL; } @@ -190,13 +187,27 @@ function handleSlashCommand(PDO $pdo, Message $message, string $content): void switch ($cmd) { case 'comandos': + require_once __DIR__ . '/discord/DiscordSender.php'; + $msg = "📋 **Comandos disponibles:**\n\n"; - $msg .= "`#comando` - Enviar plantilla\n"; $msg .= "`/comandos` - Ver comandos\n"; $msg .= "`/setlang [código]` - Establecer idioma\n"; $msg .= "`/bienvenida` - Mensaje de bienvenida\n"; - $msg .= "`/agente` - Cambiar a modo IA"; - $message->channel->sendMessage($msg); + $msg .= "`/agente` - Cambiar a modo IA\n"; + + $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; case 'setlang': @@ -382,62 +393,7 @@ function handleButtonInteraction($interaction, Discord $discord): void $customId = $data->custom_id ?? ''; if (str_starts_with($customId, 'translate_')) { - try { - 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 - } + handleTranslateInteraction($interaction, $customId); } elseif (str_starts_with($customId, 'chat_mode_')) { try { 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(); diff --git a/src/Translate.php b/src/Translate.php index e6a6410..d5b2cc9 100755 --- a/src/Translate.php +++ b/src/Translate.php @@ -34,6 +34,15 @@ class Translate } 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); $translatedLines = []; @@ -53,7 +62,12 @@ class Translate $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) { error_log("Translation error: " . $e->getMessage()); return null; @@ -131,4 +145,60 @@ class Translate 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()); + } + } }