Compare commits
2 Commits
26414094d4
...
7953a56501
| Author | SHA1 | Date | |
|---|---|---|---|
| 7953a56501 | |||
| bc77082c20 |
49
.env.reod
49
.env.reod
@@ -1,49 +0,0 @@
|
||||
# Configuración de la aplicación
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_URL=https://reod-dragon.ddns.net
|
||||
|
||||
# Configuración de la base de datos
|
||||
DB_HOST=10.10.4.17
|
||||
DB_PORT=3390
|
||||
DB_NAME=bot
|
||||
DB_USER=nickpons666
|
||||
DB_PASS=MiPo6425@@
|
||||
DB_DIALECT=mysql
|
||||
|
||||
# Configuración de JWT
|
||||
JWT_SECRET=19c5020fa8207d2c3b9e82f430784667e001f1eb733848922f7bcb9be98f93c2
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_EXPIRATION=3600
|
||||
|
||||
# Configuración de Discord
|
||||
DISCORD_GUILD_ID=1338327171013541999
|
||||
DISCORD_CLIENT_ID=1385790344594985061
|
||||
DISCORD_CLIENT_SECRET=hK9SNiYdenHQVxakt8Mx3RoMkZ5oOJvk
|
||||
DISCORD_BOT_TOKEN=MTM4NTc5MDM0NDU5NDk4NTA2MQ.GvobiS.TRQM9dX7vDjmuGVa3Ckp6YRtGEWxdW0gBDbvCI
|
||||
|
||||
# Configuración de Telegram
|
||||
TELEGRAM_BOT_TOKEN=8469229183:AAEVIV5e7rjDXKNgFTX0dnCW6JWB88X4p2I
|
||||
TELEGRAM_WEBHOOK_TOKEN=webhook_secure_token_12345
|
||||
TEST_ENV_LOAD=caos_cargado
|
||||
|
||||
LIBRETRANSLATE_URL=http://10.10.4.17:5000
|
||||
|
||||
N8N_URL=https://n8n-dragon.ddns.net
|
||||
N8N_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4MWY4YjU3YS0wMTg2LTQ1NTctOWZlMC1jYWUxNjZlYzZlMTkiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzU1OTMwODM5fQ.2tLbddyhMTKplp9n-qVNiAgQCUj2YEvVASwLnNjgCt0
|
||||
|
||||
# -----------------------------------------
|
||||
# --- Configuración para la migración a n8n ---
|
||||
# -----------------------------------------
|
||||
# URL base de esta aplicación, para que n8n pueda llamarla.
|
||||
APP_BASE_URL=https://reod-dragon.ddns.net
|
||||
|
||||
# Clave secreta para la comunicación segura entre n8n y api_handler.php.
|
||||
# DEBE SER UNA CADENA LARGA Y ALEATORIA. Genera una con: openssl rand -hex 32
|
||||
INTERNAL_API_KEY="b5dda33b8eb062e06e100c98a8947c0248b6e38973dfd689e81f725af238d23c"
|
||||
|
||||
# URL completa del webhook de n8n que procesa la cola de mensajes (process_queue_workflow).
|
||||
# La obtienes del nodo Webhook en tu flujo de n8n.
|
||||
N8N_PROCESS_QUEUE_WEBHOOK_URL="https://n8n-dragon.ddns.net/webhook/telegram-unified"
|
||||
N8N_IA_WEBHOOK_URL="https://n8n-dragon.ddns.net/webhook/ia"
|
||||
N8N_IA_WEBHOOK_URL_DISCORD="https://n8n-dragon.ddns.net/webhook/42e803ae-8aee-4b1c-858a-6c6d3fbb6230"
|
||||
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
@@ -33,7 +33,7 @@ try {
|
||||
throw new Exception("La variable de entorno LIBRETRANSLATE_URL no está configurada en tu archivo .env");
|
||||
}
|
||||
|
||||
$translator = new Translate();
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$libreLanguages = $translator->getSupportedLanguages();
|
||||
|
||||
if ($libreLanguages === null) {
|
||||
|
||||
158
analisis_archivos_comunes.txt
Normal file
158
analisis_archivos_comunes.txt
Normal file
@@ -0,0 +1,158 @@
|
||||
ANÁLISIS DE ARCHIVOS COMUNES - BOT DE DISCORD Y TELEGRAM
|
||||
========================================================
|
||||
|
||||
Fecha de análisis: 8 de febrero de 2026
|
||||
|
||||
## 1. ARCHIVOS UTILIZADOS POR AMBOS BOTS (DISCORD Y TELEGRAM)
|
||||
|
||||
### Configuración y Base de Datos:
|
||||
├── config/config.php - Configuración central (tokens, DB, URLs)
|
||||
├── includes/db.php - Conexión a base de datos compartida
|
||||
├── includes/logger.php - Sistema de logging personalizado
|
||||
├── includes/session_check.php - Validación de sesiones y CSRF
|
||||
├── includes/activity_logger.php - Registro de actividad de usuarios
|
||||
└── includes/auth.php - Funciones de autenticación
|
||||
|
||||
### Sistema de Traducción:
|
||||
├── includes/Translate.php - Clase de LibreTranslate
|
||||
├── src/Translate.php - Clase principal de traducción
|
||||
├── translate_message.php - Endpoint de procesamiento de traducciones
|
||||
├── process_translation_queue.php - Worker de traducción en background
|
||||
├── src/TranslationWorker.php - Worker individual de traducción
|
||||
├── src/TranslationCache.php - Sistema de caché de traducciones
|
||||
└── src/TranslationWorkerPool.php - Pool de workers de traducción
|
||||
|
||||
### Helpers y Utilidades Compartidas:
|
||||
├── common/helpers/schedule_helpers.php - Funciones de programación recurrente
|
||||
├── common/helpers/sender_factory.php - Factory para crear senders específicos
|
||||
├── common/helpers/converter_factory.php - Factory para conversores HTML
|
||||
├── common/helpers/url_helper.php - Utilidades de URLs y seguridad
|
||||
├── common/helpers/emojis.php - Manejo de emojis
|
||||
├── includes/schedule_helpers.php - Helper alternativo de programación
|
||||
├── includes/translation_helper.php - Helper de traducción frontend
|
||||
├── includes/message_handler.php - Manejador central de mensajes
|
||||
├── includes/error_handler.php - Manejo centralizado de errores
|
||||
└── includes/tren_handler.php - Handler específico de trenes
|
||||
|
||||
### Templates y Componentes UI:
|
||||
├── templates/header.php - Cabecera HTML común
|
||||
├── templates/footer.php - Footer HTML común
|
||||
├── templates/admin/ - Templates de administración compartidos
|
||||
|
||||
### Procesamiento y Colas:
|
||||
├── process_queue.php - Procesador principal de colas de mensajes
|
||||
├── includes/message_handler.php - Manejo de creación/actualización de mensajes
|
||||
└── includes/scheduled_messages_table_body.php - Componente de tabla compartido
|
||||
|
||||
## 2. ARCHIVOS COMUNES PARA ENVÍO DE MENSAJES DESDE create_message.php
|
||||
|
||||
### Flujo Principal de Envío:
|
||||
1. create_message.php (formulario) →
|
||||
2. includes/message_handler.php (procesamiento) →
|
||||
3. process_queue.php (ejecución) →
|
||||
4. [DiscordSender|TelegramSender] (envío específico)
|
||||
|
||||
### Archivos Involucrados en el Envío:
|
||||
|
||||
#### create_message.php:
|
||||
├── Incluye: session_check.php, db.php
|
||||
├── Template: templates/header.php, footer.php
|
||||
├── Acción: POST a includes/message_handler.php
|
||||
└── JavaScript: Manejo de Summernote, validación, selección de destinatarios
|
||||
|
||||
#### includes/message_handler.php:
|
||||
├── Incluye: session_check.php, db.php, activity_logger.php, schedule_helpers.php
|
||||
├── Procesa: Creación/actualización de mensajes en DB
|
||||
├── Programa: Envíos inmediatos, diferidos, recurrentes
|
||||
├── Dispara: process_queue.php para envíos inmediatos
|
||||
└── Registra: Actividad en activity_log
|
||||
|
||||
#### process_queue.php:
|
||||
├── Incluye: db.php, SenderFactory, ConverterFactory
|
||||
├── Consulta: Mensajes pendientes en schedules
|
||||
├── Crea: Sender apropiado via SenderFactory
|
||||
├── Convierte: HTML via ConverterFactory
|
||||
└── Ejecuta: Envío through platform-specific sender
|
||||
|
||||
#### Senders Específicos:
|
||||
├── discord/DiscordSender.php - Envío a Discord API
|
||||
├── src/DiscordSender.php - Versión alternativa Discord
|
||||
├── src/TelegramSender.php - Envío a Telegram Bot API
|
||||
└── telegram/TelegramSender.php - Versión alternativa Telegram
|
||||
|
||||
#### Conversores de Contenido:
|
||||
├── discord/converters/HtmlToDiscordMarkdownConverter.php
|
||||
├── src/HtmlToDiscordMarkdownConverter.php
|
||||
└── src/HtmlToTelegramHtmlConverter.php
|
||||
|
||||
#### Tablas de Base de Datos Compartidas:
|
||||
├── recipients - Destinatarios (con campo 'platform' para distinguir)
|
||||
├── messages - Contenido de mensajes (compartido)
|
||||
├── schedules - Programación de envíos (compartido)
|
||||
├── sent_messages - Registro de mensajes enviados
|
||||
├── translation_queue - Cola de traducciones
|
||||
├── recurrent_messages - Plantillas de mensajes recurrentes
|
||||
└── supported_languages - Configuración de idiomas
|
||||
|
||||
## 3. ARQUITECTURA DE COMPONENTES COMPARTIDOS
|
||||
|
||||
### Patrón Factory:
|
||||
```php
|
||||
// Creación de sender específico
|
||||
$sender = SenderFactory::create($platform, $pdo);
|
||||
$converter = ConverterFactory::create($platform);
|
||||
```
|
||||
|
||||
### Flujo de Datos Compartido:
|
||||
1. Usuario selecciona plataforma en create_message.php
|
||||
2. message_handler.php guarda en DB con plataforma indicada
|
||||
3. process_queue.php lee plataforma de DB
|
||||
4. SenderFactory crea sender apropiado
|
||||
5. ConverterFactory crea conversor apropiado
|
||||
6. Se envía mensaje a plataforma específica
|
||||
|
||||
### Configuración Compartida:
|
||||
├── Database: Misma conexión para ambas plataformas
|
||||
├── Translation: Mismo servicio de traducción
|
||||
├── Templates: Mismo sistema de plantillas recurrentes
|
||||
├── Gallery: Misma galería de imágenes
|
||||
├── Scheduling: Mismo sistema de programación
|
||||
└── Activity: Mismo sistema de registro de actividad
|
||||
|
||||
## 4. DIFERENCIACIÓN POR PLATAFORMA
|
||||
|
||||
### En Base de Datos:
|
||||
├── Campo 'platform' en tabla recipients ('discord' | 'telegram')
|
||||
├── Platform-specific tokens en config.php
|
||||
├── IDs de plataforma en platform_id
|
||||
└── Chat modes específicos por plataforma
|
||||
|
||||
### En Código:
|
||||
├── Directorios separados: /discord/ y /telegram/
|
||||
├── Senders específicos por plataforma
|
||||
├── Conversores específicos por formato
|
||||
├── Webhooks específicos por plataforma
|
||||
└── Commands específicos por plataforma
|
||||
|
||||
## 5. BENEFICIOS DE ESTA ARQUITECTURA
|
||||
|
||||
✅ Reutilización máxima de código entre plataformas
|
||||
✅ Mantenimiento centralizado de lógica común
|
||||
✅ Base de datos unificada para reporting
|
||||
✅ Sistema de traducción compartido
|
||||
✅ Interfaz web unificada para administración
|
||||
✅ Sistema de programación compartido
|
||||
✅ Logging centralizado
|
||||
✅ Sistema de plantillas compartido
|
||||
|
||||
## 6. PATRONES DE DISEÑO IMPLEMENTADOS
|
||||
|
||||
🏗️ Factory Pattern - Para senders y converters
|
||||
🏗️ Strategy Pattern - Para manejo de plataformas
|
||||
🏗️ Singleton Pattern - Para conexión DB
|
||||
🏗️ Observer Pattern - Para logging
|
||||
🏗️ Template Method - Para flujo de envío
|
||||
|
||||
Esta arquitectura permite añadir nuevas plataformas fácilmente mediante la creación
|
||||
de nuevos senders y converters, mientras se mantiene toda la lógica de negocio
|
||||
compartida entre ambas plataformas actuales.
|
||||
0
attachments
Normal file
0
attachments
Normal file
0
clear_opcache.php
Normal file → Executable file
0
clear_opcache.php
Normal file → Executable file
@@ -7,45 +7,37 @@ require_once __DIR__ . '/../vendor/autoload.php';
|
||||
// Verificar si estamos en un contenedor Docker
|
||||
$is_docker = (getenv('DOCKER_CONTAINER') === '1') || ($_SERVER['DOCKER_CONTAINER'] ?? null) === '1';
|
||||
|
||||
if ($is_docker) {
|
||||
// Docker: cargar archivo .env creado por el entrypoint
|
||||
$dotenv = null;
|
||||
if (file_exists(dirname(__DIR__) . '/.env')) {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
|
||||
try {
|
||||
$dotenv->load();
|
||||
} catch (Exception $e) {
|
||||
die('Error al cargar el archivo de entorno en Docker: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Entorno local: cargar archivo .env según APP_ENVIRONMENT
|
||||
$env = getenv('APP_ENVIRONMENT') ?: ($_SERVER['APP_ENVIRONMENT'] ?? 'pruebas');
|
||||
// Entorno: cargar archivo .env según APP_ENVIRONMENT
|
||||
$env = getenv('APP_ENVIRONMENT') ?: ($_SERVER['APP_ENVIRONMENT'] ?? 'pruebas');
|
||||
|
||||
if ($env === 'reod') {
|
||||
$envFile = '.env';
|
||||
if ($env) {
|
||||
$envFile = '.env.' . $env;
|
||||
}
|
||||
|
||||
$dotenv = null;
|
||||
if (file_exists(dirname(__DIR__) . '/' . $envFile)) {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__), $envFile);
|
||||
} elseif (file_exists(dirname(__DIR__) . '/.env')) {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
|
||||
}
|
||||
|
||||
if ($dotenv) {
|
||||
try {
|
||||
$dotenv->load();
|
||||
} catch (Exception $e) {
|
||||
die('Error al cargar el archivo de entorno: ' . $e->getMessage());
|
||||
}
|
||||
$dotenv->required([
|
||||
'DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS',
|
||||
'JWT_SECRET', 'APP_URL'
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$envFile = '.env.' . $env;
|
||||
}
|
||||
|
||||
$dotenv = null;
|
||||
if (file_exists(dirname(__DIR__) . '/' . $envFile)) {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__), $envFile);
|
||||
} elseif (file_exists(dirname(__DIR__) . '/.env')) {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
|
||||
}
|
||||
|
||||
if ($dotenv) {
|
||||
try {
|
||||
$dotenv->load();
|
||||
} catch (Exception $e) {
|
||||
die('Error al cargar el archivo de entorno: ' . $e->getMessage());
|
||||
}
|
||||
// ... el resto de la configuración ...
|
||||
// Aquí es donde definimos las variables obligatorias
|
||||
$dotenv->required([
|
||||
'DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS',
|
||||
'JWT_SECRET', 'APP_URL'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Environment Configuration
|
||||
define('ENVIRONMENT', $_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? 'production');
|
||||
|
||||
@@ -54,7 +46,9 @@ $is_cli = (php_sapi_name() === 'cli' || defined('STDIN'));
|
||||
|
||||
// Helper function to get env vars
|
||||
function getEnvVar($name, $default = null) {
|
||||
return $_ENV[$name] ?? $_SERVER[$name] ?? getenv($name) ?? $default;
|
||||
// Priorizamos getenv() para las variables cargadas por Dotenv,
|
||||
// ya que sabemos que funciona y $_ENV puede estar corrupto o contener Array en algunos entornos Docker.
|
||||
return getenv($name) ?: ($_ENV[$name] ?? $_SERVER[$name] ?? $default);
|
||||
}
|
||||
|
||||
// Configurar la URL base y el protocolo
|
||||
|
||||
0
direct_check.php
Normal file → Executable file
0
direct_check.php
Normal file → Executable file
224
discord_bot.php
224
discord_bot.php
@@ -38,6 +38,10 @@ if (!defined('DISCORD_BOT_TOKEN') || empty(DISCORD_BOT_TOKEN)) {
|
||||
try {
|
||||
$discord = new Discord([
|
||||
'token' => DISCORD_BOT_TOKEN,
|
||||
<<<<<<< HEAD
|
||||
'intents' => Intents::GUILDS | Intents::GUILD_MESSAGES | Intents::DIRECT_MESSAGES | Intents::GUILD_MEMBERS | Intents::GUILD_MESSAGE_REACTIONS | Intents::MESSAGE_CONTENT,
|
||||
'logger' => $logger
|
||||
=======
|
||||
'intents' => Intents::GUILDS | Intents::GUILD_MESSAGES | Intents::DIRECT_MESSAGES | Intents::GUILD_MEMBERS | Intents::GUILD_MESSAGE_REACTIONS,
|
||||
'logger' => $logger,
|
||||
'loop' => \React\EventLoop\Loop::get(),
|
||||
@@ -45,6 +49,7 @@ try {
|
||||
'heartbeat_interval' => 30, // Enviar heartbeat cada 30 segundos
|
||||
'reconnect_timeout' => 60, // Timeout para reconexión
|
||||
]
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
]);
|
||||
|
||||
// Manejar eventos de conexión y desconexión
|
||||
@@ -104,6 +109,39 @@ try {
|
||||
$originalMessage = $interaction->message;
|
||||
$channel = $interaction->channel;
|
||||
|
||||
<<<<<<< HEAD
|
||||
// Responder de inmediato para evitar timeout de interacción
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent('⌛ Procesando traducción...'), true);
|
||||
|
||||
// Extraer contenido del mensaje: primero content plano, luego embeds como fallback
|
||||
$originalContent = trim((string) ($originalMessage->content ?? ''));
|
||||
if ($originalContent === '' && count($originalMessage->embeds) > 0) {
|
||||
foreach ($originalMessage->embeds as $embed) {
|
||||
$originalContent .= trim((string) ($embed->description ?? '')) . "\n";
|
||||
}
|
||||
$originalContent = trim($originalContent);
|
||||
}
|
||||
|
||||
if (!empty($originalContent)) {
|
||||
try {
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$sourceLang = $translator->detectLanguage($originalContent) ?? 'es';
|
||||
if ($sourceLang === $targetLang) {
|
||||
// Fallback: muchas plantillas están en ES; intenta forzar ES como origen
|
||||
$fallbackSrc = 'es';
|
||||
if ($fallbackSrc !== $targetLang) {
|
||||
$translatedText = $translator->translateText($originalContent, $fallbackSrc, $targetLang);
|
||||
$sourceLang = $fallbackSrc;
|
||||
} else {
|
||||
$translatedText = null;
|
||||
}
|
||||
} else {
|
||||
$translatedText = $translator->translateText($originalContent, $sourceLang, $targetLang);
|
||||
}
|
||||
|
||||
// Obtener bandera desde supported_languages
|
||||
$flag = '';
|
||||
=======
|
||||
try {
|
||||
// Buscar el mensaje original que se está traduciendo
|
||||
// Para interacciones, el mensaje original está en el mensaje de la interacción
|
||||
@@ -114,6 +152,7 @@ try {
|
||||
if ($messageReference && $messageReference->message_id) {
|
||||
$referencedMessageId = $messageReference->message_id;
|
||||
$channel->messages->fetch($referencedMessageId)->done(function (Message $referencedMessage) use ($interaction, $targetLang, $logger, $discord, $userId, $pdo) {
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
try {
|
||||
$originalContent = trim((string) ($referencedMessage->content ?? ''));
|
||||
|
||||
@@ -224,6 +263,111 @@ try {
|
||||
return; // Salir después de manejar la interacción
|
||||
}
|
||||
|
||||
// MANEJAR TRADUCCIÓN A IDIOMA ESPECÍFICO (desde botones de idiomas)
|
||||
if (strpos($customId, 'translate_to_lang:') === 0) {
|
||||
// Extraer el ID del mensaje original y el idioma destino del custom_id
|
||||
$parts = explode(':', $customId);
|
||||
if (count($parts) < 3) {
|
||||
$interaction->respondWithMessage(MessageBuilder::new()->setContent("❌ Error: Formato de botón de traducción inválido."), true);
|
||||
return;
|
||||
}
|
||||
$originalMessageId = $parts[1];
|
||||
$targetLang = $parts[2];
|
||||
|
||||
// 1. Deferir la respuesta de forma efímera para que el usuario sepa que se está procesando
|
||||
$interaction->acknowledge(true)->done(function() use ($originalMessageId, $targetLang, $interaction, $discord, $pdo, $logger, $userId) {
|
||||
// 2. Obtener el mensaje original usando su ID
|
||||
$interaction->channel->messages->fetch($originalMessageId)->done(function ($originalMessage) use ($originalMessageId, $interaction, $discord, $pdo, $logger, $userId, $targetLang) {
|
||||
$originalContent = (string) ($originalMessage->content ?? '');
|
||||
|
||||
$emojiMap = [];
|
||||
preg_match_all('/<a?:(\w+):(\d+)>/', $originalContent, $matches, PREG_OFFSET_CAPTURE);
|
||||
foreach ($matches[0] as $match) {
|
||||
$emojiMap[$match[1]] = $match[0];
|
||||
}
|
||||
$contentForTranslation = preg_replace('/<a?:(\w+):(\d+)>/', '', $originalContent);
|
||||
$contentForTranslation = trim($contentForTranslation);
|
||||
|
||||
if (empty($contentForTranslation)) {
|
||||
$interaction->editOriginalResponse(MessageBuilder::new()->setContent("⚠️ El mensaje no contiene texto traducible."));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$detectionResultForSource = $translator->detectLanguage($contentForTranslation);
|
||||
$sourceLang = $detectionResultForSource[0]['language'] ?? 'es';
|
||||
|
||||
if ($sourceLang === $targetLang) {
|
||||
$interaction->editOriginalResponse(MessageBuilder::new()->setContent("⚠️ El mensaje ya está en el idioma seleccionado ({$targetLang})."));
|
||||
return;
|
||||
}
|
||||
|
||||
$translatedText = $translator->translateText($contentForTranslation, $sourceLang, $targetLang);
|
||||
|
||||
if (!empty($translatedText)) {
|
||||
foreach ($emojiMap as $emojiTag) {
|
||||
$translatedText .= ' ' . $emojiTag;
|
||||
}
|
||||
$translatedText = trim($translatedText);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT flag_emoji, language_name FROM supported_languages WHERE language_code = ? AND is_active = 1");
|
||||
$stmt->execute([$targetLang]);
|
||||
$langInfo = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$flag = $langInfo['flag_emoji'] ?? '🏳️';
|
||||
$langName = $langInfo['language_name'] ?? strtoupper($targetLang);
|
||||
|
||||
$embed = new Embed($discord);
|
||||
$embed->setTitle("{$flag} Traducción a {$langName}");
|
||||
$embed->setDescription($translatedText);
|
||||
$embed->setColor("#5865F2");
|
||||
$embed->setFooter("Traducido de {$sourceLang} • Solo tú puedes ver esto");
|
||||
|
||||
$imageUrl = null;
|
||||
if ($originalMessage->attachments !== null && count($originalMessage->attachments) > 0) {
|
||||
$firstAttachment = $originalMessage->attachments->first();
|
||||
if ($firstAttachment && isset($firstAttachment->url)) {
|
||||
$contentType = $firstAttachment->content_type ?? '';
|
||||
if (strpos($contentType, 'image/') === 0 || strpos($contentType, 'video/') === 0) {
|
||||
$imageUrl = $firstAttachment->url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$imageUrl && $originalMessage->stickers !== null && count($originalMessage->stickers) > 0) {
|
||||
$firstSticker = $originalMessage->stickers->first();
|
||||
if ($firstSticker && isset($firstSticker->image_url)) {
|
||||
$imageUrl = $firstSticker->image_url;
|
||||
}
|
||||
}
|
||||
|
||||
if ($imageUrl) {
|
||||
$embed->setImage($imageUrl);
|
||||
}
|
||||
|
||||
// 3. Editar la respuesta original con el resultado
|
||||
$builder = MessageBuilder::new()->addEmbed($embed);
|
||||
$interaction->sendFollowUpMessage($builder, true);
|
||||
|
||||
$logger->info("[TRANSLATION_BUTTON] Usuario {$userId} tradujo mensaje #{$originalMessageId} de {$sourceLang} a {$targetLang}");
|
||||
} else {
|
||||
$interaction->editOriginalResponse(MessageBuilder::new()->setContent("⚠️ No se pudo traducir el mensaje."));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$logger->error("[TRANSLATION_BUTTON] Error al traducir", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
|
||||
$interaction->editOriginalResponse(MessageBuilder::new()->setContent("❌ Error al traducir: " . $e->getMessage()));
|
||||
}
|
||||
}, function ($error) use ($interaction, $logger) {
|
||||
$logger->error("[TRANSLATION_BUTTON] Error al obtener mensaje original", ['error' => $error->getMessage()]);
|
||||
$interaction->editOriginalResponse(MessageBuilder::new()->setContent("❌ No se pudo obtener el mensaje original."));
|
||||
});
|
||||
}, function ($error) use ($logger, $interaction) {
|
||||
$logger->error("[TRANSLATION_BUTTON] Error al reconocer (defer) la interacción.", ['error' => $error->getMessage()]);
|
||||
// If even deferring fails, we can't edit the response.
|
||||
});
|
||||
return; // Finalizar para no procesar otros ifs
|
||||
}
|
||||
|
||||
// Traducción de plantillas completas (comandos #)
|
||||
if (strpos($customId, 'translate_template:') === 0) {
|
||||
$payload = substr($customId, strlen('translate_template:'));
|
||||
@@ -597,6 +741,27 @@ function handleDiscordCommand(Message $message, PDO $pdo, Logger $logger)
|
||||
function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
||||
{
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
$translator = new Translate(LIBRETRANSLATE_URL); // Instanciar al inicio
|
||||
|
||||
$messageContentOriginal = trim($message->content);
|
||||
|
||||
// Determine if there is translatable text content based on LibreTranslate confidence
|
||||
$hasTranslatableText = false;
|
||||
$contentForDetection = ''; // Initialize outside if block for broader scope
|
||||
|
||||
if (!empty($messageContentOriginal)) { // Only try to detect if message has any content
|
||||
// Prepare content for language detection: remove custom Discord emojis
|
||||
$contentForDetection = preg_replace('/<a?:(\w+):(\d+)>/u', '', $messageContentOriginal);
|
||||
// Removed: $contentForDetection = strip_tags($contentForDetection); // This was the culprit
|
||||
$contentForDetection = trim($contentForDetection);
|
||||
|
||||
if (!empty($contentForDetection)) { // Only if there's something left to detect
|
||||
$detectionResult = $translator->detectLanguage($contentForDetection);
|
||||
$confidence = $detectionResult[0]['confidence'] ?? 0.0;
|
||||
if ($confidence > 0.0) {
|
||||
$hasTranslatableText = true;
|
||||
=======
|
||||
$text = $message->content;
|
||||
$attachments = $message->attachments;
|
||||
|
||||
@@ -613,10 +778,28 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
||||
}
|
||||
if (!empty($attachment->caption)) {
|
||||
$attachmentText .= $attachment->caption . ' ';
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
// If no translatable text is found, do not send buttons.
|
||||
if (!$hasTranslatableText) {
|
||||
$logger->info("[TRANSLATION_BUTTONS] Mensaje de Discord #{$message->id} sin contenido de texto traducible, no se envían botones de traducción.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Detectar idioma original (using the content prepared for detection, which we know has text)
|
||||
$finalDetectionResult = $translator->detectLanguage($contentForDetection); // This will be the full array or null
|
||||
$detectedLang = $finalDetectionResult[0]['language'] ?? 'es'; // Correctly extract language
|
||||
|
||||
// 2. Obtener todos los idiomas activos con información completa
|
||||
$langStmt = $pdo->query("SELECT language_code, language_name, flag_emoji FROM supported_languages WHERE is_active = 1 ORDER BY language_name ASC");
|
||||
$activeLangs = $langStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 3. Filtrar los idiomas de destino (todos los activos menos el original)
|
||||
=======
|
||||
// Combinar texto principal con texto de attachments
|
||||
$fullText = trim($text . ' ' . $attachmentText);
|
||||
$hasAnyText = !empty($fullText);
|
||||
@@ -637,21 +820,42 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
||||
$activeLangs = $langStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Filtrar idiomas diferentes al detectado
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
$targetLangs = array_filter($activeLangs, function($lang) use ($detectedLang) {
|
||||
return $lang['language_code'] !== $detectedLang;
|
||||
});
|
||||
|
||||
<<<<<<< HEAD
|
||||
// 4. Si no hay idiomas a los que traducir, no hacer nada
|
||||
if (empty($targetLangs)) {
|
||||
$logger->info("[TRANSLATION_BUTTONS] No se requieren botones de traducción para el mensaje de Discord #{$message->id} desde '$detectedLang'.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Crear botones de traducción para cada idioma destino
|
||||
=======
|
||||
if (empty($targetLangs)) {
|
||||
$logger->info("[TRADUCCIÓN] No hay idiomas disponibles para traducir desde '$detectedLang'");
|
||||
return;
|
||||
}
|
||||
|
||||
// Crear botones con banderas
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
$components = [];
|
||||
$actionRow = ActionRow::new();
|
||||
$buttonCount = 0;
|
||||
|
||||
foreach ($targetLangs as $lang) {
|
||||
<<<<<<< HEAD
|
||||
$button = Button::new(Button::STYLE_SECONDARY, 'translate_to_lang:' . $message->id . ':' . $lang['language_code'])
|
||||
->setLabel($lang['language_name']);
|
||||
if (!empty($lang['flag_emoji'])) {
|
||||
$button->setEmoji($lang['flag_emoji']);
|
||||
}
|
||||
$actionRow->addComponent($button);
|
||||
$buttonCount++;
|
||||
|
||||
=======
|
||||
$button = Button::new(Button::STYLE_SECONDARY, 'translate_manual:' . $lang['language_code'])
|
||||
->setLabel($lang['language_name']);
|
||||
|
||||
@@ -663,16 +867,35 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
||||
$buttonCount++;
|
||||
|
||||
// Discord permite máximo 5 botones por ActionRow
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
if ($buttonCount % 5 === 0) {
|
||||
$components[] = $actionRow;
|
||||
$actionRow = ActionRow::new();
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
if ($buttonCount % 5 !== 0) {
|
||||
$components[] = $actionRow;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
// 6. Enviar mensaje del bot con botones como respuesta al mensaje original
|
||||
$builder = MessageBuilder::new()
|
||||
->setContent('🌐 Select a language to translate to:')
|
||||
->setComponents($components);
|
||||
|
||||
$message->reply($builder)->done(function () use ($logger, $message, $detectedLang) {
|
||||
$logger->info("[TRANSLATION_BUTTONS] Botones de traducción enviados para mensaje #{$message->id} (idioma detectado: $detectedLang)");
|
||||
}, function ($error) use ($logger, $message) {
|
||||
$logger->error("[TRANSLATION_BUTTONS] Error al enviar botones para mensaje #{$message->id}", ['error' => $error->getMessage()]);
|
||||
});
|
||||
|
||||
} catch (Throwable $e) {
|
||||
$logger->error("[TRANSLATION_BUTTONS] Error al procesar mensaje para botones de traducción", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
|
||||
=======
|
||||
// Enviar mensaje con botones efímeros
|
||||
$builder = MessageBuilder::new()
|
||||
// ->setContent("🌍 **Selecciona idioma para traducir:**")
|
||||
@@ -684,6 +907,7 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
||||
|
||||
} catch (Throwable $e) {
|
||||
$logger->error("[Error Traducción Discord]", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
|
||||
>>>>>>> 26414094d4262e5ab092028955a4f0de57092f43
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
86
docker/bot-lastwar.yaml
Executable file
86
docker/bot-lastwar.yaml
Executable file
@@ -0,0 +1,86 @@
|
||||
name: bot-lastwar
|
||||
services:
|
||||
bot-lastwar:
|
||||
image: 10.10.4.3:5000/bot-lastwar:v3
|
||||
container_name: bot_lastwar_funcionando
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- target: 80
|
||||
published: "8086"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /media/ZimaOS-HD/AppData/bot_lastwar/logs
|
||||
target: /var/www/html/bot/logs
|
||||
environment:
|
||||
# --- App Configuration ---
|
||||
- APP_ENV=production
|
||||
- APP_ENVIRONMENT=reod
|
||||
- APP_URL=https://reod-dragon.ddns.net
|
||||
- INTERNAL_API_KEY=b5dda33b8eb062e06e100c98a8947c0248b6e38973dfd689e81f725af238d23c
|
||||
- TEST_ENV_LOAD=caos_cargado
|
||||
- TZ=America/Mexico_City
|
||||
- USE_LOCALHOST=false
|
||||
|
||||
# --- Database Configuration ---
|
||||
- DB_DIALECT=mysql
|
||||
- DB_HOST=10.10.4.17
|
||||
- DB_NAME=bot
|
||||
- DB_PASS='MiPo6425@@'
|
||||
- DB_PORT=3390
|
||||
- DB_USER=nickpons666
|
||||
|
||||
# --- Discord Configuration ---
|
||||
- DISCORD_BOT_TOKEN=MTM4NTc5MDM0NDU5NDk4NTA2MQ.GvobiS.TRQM9dX7vDjmuGVa3Ckp6YRtGEWxdW0gBDbvCI
|
||||
- DISCORD_CLIENT_ID=1385790344594985061
|
||||
- DISCORD_CLIENT_SECRET=hK9SNiYdenHQVxakt8Mx3RoMkZ5oOJvk
|
||||
- DISCORD_GUILD_ID=1338327171013541999
|
||||
|
||||
# --- JWT Configuration ---
|
||||
- JWT_ALGORITHM=HS256
|
||||
- JWT_EXPIRATION=3600
|
||||
- JWT_SECRET=19c5020fa8207d2c3b9e82f430784667e001f1eb733848922f7bcb9be98f93c2
|
||||
|
||||
# --- Services Configuration ---
|
||||
- LIBRETRANSLATE_URL=http://10.10.4.17:5000
|
||||
- N8N_IA_WEBHOOK_URL=https://n8n-dragon.ddns.net/webhook/ia
|
||||
- N8N_IA_WEBHOOK_URL_DISCORD=https://n8n-dragon.ddns.net/webhook/42e803ae-8aee-4b1c-858a-6c6d3fbb6230
|
||||
- N8N_PROCESS_QUEUE_WEBHOOK_URL=https://n8n-dragon.ddns.net/webhook/telegram-unified
|
||||
- N8N_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4MWY4YjU3YS0wMTg2LTQ1NTctOWZlMC1jYWUxNjZlYzZlMTkiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzU1OTMwODM5fQ.2tLbddyhMTKplp9n-qVNiAgQCUj2YEvVASwLnNjgCt0
|
||||
- N8N_URL=https://n8n-dragon.ddns.net
|
||||
|
||||
# --- Telegram Configuration ---
|
||||
- TELEGRAM_BOT_TOKEN=8469229183:AAEVIV5e7rjDXKNgFTX0dnCW6JWB88X4p2I
|
||||
- TELEGRAM_WEBHOOK_TOKEN=webhook_secure_token_12345
|
||||
|
||||
# --- Docker Specific Settings ---
|
||||
command:
|
||||
- /entrypoint.sh
|
||||
user: 0:0
|
||||
network_mode: bridge
|
||||
privileged: false
|
||||
cpu_shares: 90
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 16663138304
|
||||
reservations:
|
||||
devices: []
|
||||
cap_add: []
|
||||
devices: []
|
||||
labels:
|
||||
icon: https://www.ruthlessreviews.com/wp-content/uploads/2025/12/last-war-image.jpg
|
||||
|
||||
x-casaos:
|
||||
author: self
|
||||
category: self
|
||||
hostname: ""
|
||||
icon: https://www.ruthlessreviews.com/wp-content/uploads/2025/12/last-war-image.jpg
|
||||
index: /
|
||||
is_uncontrolled: false
|
||||
port_map: "8086"
|
||||
scheme: http
|
||||
store_app_id: bot-lastwar
|
||||
title:
|
||||
custom: ""
|
||||
en_us: bot-lastwar
|
||||
@@ -13,7 +13,7 @@ echo "Generando archivo .env desde variables de entorno..."
|
||||
# Eliminar todos los archivos .env existentes para evitar conflictos
|
||||
rm -f /var/www/html/bot/.env* 2>/dev/null || true
|
||||
|
||||
env | grep -E "^(DB_|JWT_|DISCORD_|TELEGRAM_|LIBRETRANSLATE_|N8N_|APP_|INTERNAL_API_KEY|TEST_ENV_LOAD)" > /tmp/env_vars.txt
|
||||
env > /tmp/env_vars.txt
|
||||
|
||||
# Determinar el nombre del archivo .env según el entorno
|
||||
if [ "$ENVIRONMENT" = "reod" ]; then
|
||||
@@ -39,7 +39,10 @@ fi
|
||||
|
||||
rm -f /tmp/env_vars.txt
|
||||
|
||||
echo "Archivo .env generado"
|
||||
echo "Archivo .env generado en ${ENV_FILE}"
|
||||
# Corregir permisos para que el servidor web (www-data) pueda leerlo
|
||||
chown www-data:www-data "$ENV_FILE"
|
||||
chmod 644 "$ENV_FILE"
|
||||
|
||||
if [ -f /var/www/html/bot/composer.json ]; then
|
||||
echo "Instalando dependencias de Composer..."
|
||||
@@ -55,12 +58,12 @@ touch /var/log/apache2/access.log 2>/dev/null || true
|
||||
chmod 666 /var/log/apache2/*.log 2>/dev/null || true
|
||||
chown -R www-data:www-data /var/www/html/bot/logs /var/log/apache2 2>/dev/null || true
|
||||
|
||||
echo "Configurando sitio Apache..."
|
||||
echo "Configurando sitio Apache y limpiando caché de Opcache..."
|
||||
if [ "$ENVIRONMENT" = "reod" ]; then
|
||||
a2ensite reod-dragon.ddns.net.conf 2>/dev/null || true
|
||||
else
|
||||
a2dissite reod-dragon.ddns.net.conf 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "Iniciando Supervisor..."
|
||||
echo "Iniciando Supervisor (que gestionará Apache y los workers)..."
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
@@ -14,11 +14,11 @@ class DatabaseConnection {
|
||||
|
||||
private function __construct() {
|
||||
$this->config = [
|
||||
'host' => $_ENV['DB_HOST'] ?? 'localhost',
|
||||
'port' => $_ENV['DB_PORT'] ?? '3306',
|
||||
'name' => $_ENV['DB_NAME'] ?? 'bot',
|
||||
'user' => $_ENV['DB_USER'] ?? 'nickpons666',
|
||||
'pass' => $_ENV['DB_PASS'] ?? 'MiPo6425@@',
|
||||
'host' => DB_HOST,
|
||||
'port' => DB_PORT,
|
||||
'name' => DB_NAME,
|
||||
'user' => DB_USER,
|
||||
'pass' => DB_PASS,
|
||||
'charset' => 'utf8mb4',
|
||||
'timeout' => 30, // Tiempo de espera de conexión en segundos
|
||||
'reconnect_attempts' => 3, // Número de intentos de reconexión
|
||||
|
||||
31
plan_diagnostico_docker.md
Executable file
31
plan_diagnostico_docker.md
Executable file
@@ -0,0 +1,31 @@
|
||||
### **Plan de Diagnóstico: Problemas en el Entorno Docker**
|
||||
|
||||
**Objetivo:** Identificar por qué la aplicación se comporta de manera diferente dentro de Docker, específicamente en la traducción de mensajes, el envío de imágenes y la funcionalidad de los botones.
|
||||
|
||||
**Fase 1: Verificación de Configuración y Entorno**
|
||||
* [x] **1. Revisar la configuración de Docker:**
|
||||
* **Acción:** Analizar los archivos `docker/Dockerfile`, `docker/docker-compose.local.yml`, `docker/entrypoint.sh`.
|
||||
* **Resultado:** Se confirmó que el `entrypoint.sh` genera un nuevo archivo `.env` basado en las variables de entorno pasadas al contenedor. El `docker-compose.local.yml` actual pasa muy pocas variables.
|
||||
|
||||
* [x] **2. Confirmar la lógica de carga en `config.php`:**
|
||||
* **Acción:** Volver a examinar `config.php`.
|
||||
* **Resultado:** La lógica es correcta, pero el archivo `.env` que carga está incompleto en el contenedor.
|
||||
|
||||
* [x] **3. Comparar variables de entorno (Local vs. Docker):**
|
||||
* **Acción:** Listar las variables del `.env.pruebas` local y compararlas con las proporcionadas en `docker-compose.local.yml`.
|
||||
* **Resultado:** Se confirmó que variables críticas (`APP_URL`, `DB_*`, `LIBRETRANSLATE_URL`, etc.) NO se están pasando al contenedor. **Esta es la causa raíz del problema.**
|
||||
|
||||
**Fase 2: Análisis de Rutas, URLs y Conectividad**
|
||||
* [x] **4, 5, 6. Análisis detallado de síntomas:**
|
||||
* **Nota:** Se omite el análisis detallado de cada síntoma individual, ya que todos (fallo de traducción, imágenes y botones) son una consecuencia directa de la falta de variables de entorno identificada en la Fase 1.
|
||||
|
||||
**Fase 3: Propuesta de Soluciones y Verificación**
|
||||
* [x] **7. Proponer e implementar las correcciones:**
|
||||
* **Propuesta Original:** Modificar `docker-compose.local.yml` para utilizar la directiva `env_file` y apuntar al archivo `.env.pruebas`.
|
||||
* **Actualización 1:** La causa principal está en el `entrypoint.sh` y su manejo de las variables en producción. Se ha modificado `docker/entrypoint.sh` para que capture *todas* las variables de entorno proporcionadas en el `yaml` de despliegue, en lugar de usar un filtro `grep` restrictivo.
|
||||
* **Actualización 2:** Se identificó que `DB_PASS` en el YAML no estaba correctamente entrecomillado, lo que causaba corrupción. Se corrigió el `docker/bot-lastwar.yaml` para añadir comillas a `DB_PASS` y mejorar la organización de las variables.
|
||||
* **Actualización 3:** Se identificó un error en `includes/db.php` donde el código dependía de `$_ENV`, el cual puede no estar poblado, causando un error de conexión a la base de datos `No such file or directory`. Se modificó `includes/db.php` para usar `getenv()` en lugar de `$_ENV` para una lectura más robusta de las variables de entorno de la base de datos.
|
||||
|
||||
* [ ] **8. Verificación final:**
|
||||
* **Acción:** Construir la nueva imagen de Docker, desplegarla usando `bot-lastwar.yaml` y probar los escenarios que antes fallaban (traducciones, comandos con imágenes, botones).
|
||||
* **Meta:** Confirmar que la aplicación funciona correctamente en el contenedor.
|
||||
515
plan_separacion_plataformas.md
Normal file
515
plan_separacion_plataformas.md
Normal file
@@ -0,0 +1,515 @@
|
||||
PLAN DE MIGRACIÓN COMPLETO - SEPARACIÓN DE PLATAFORMAS DISCORD/TELEGRAM
|
||||
============================================================================
|
||||
|
||||
OPCIÓN 1: SEPARACIÓN GRADUAL CON MANTENIMIENTO DE COMPATIBILIDAD
|
||||
============================================================================
|
||||
|
||||
Fecha: 8 de febrero de 2026
|
||||
Duración estimada: 15-20 días laborales
|
||||
Riesgo: Alto (Mitigado con backups y pruebas)
|
||||
Impacto: Muy alto (Requiere planificación cuidadosa)
|
||||
|
||||
==========================================
|
||||
VISIÓN GENERAL Y ESTRATEGIA
|
||||
==========================================
|
||||
|
||||
Objetivo: Crear dos instancias completamente independientes del sistema de bots,
|
||||
manteniendo funcionalidad existente y evitando downtime crítico.
|
||||
|
||||
Estrategia:
|
||||
1. Crear estructura paralela sin afectar sistema actual
|
||||
2. Migrar datos de forma segura
|
||||
3. Implementar routing específico por plataforma
|
||||
4. Validar extensivamente antes de corte
|
||||
5. Realizar cambio mínimo de DNS/configuración final
|
||||
|
||||
==========================================
|
||||
ESTRUCTURA OBJETIVO FINAL
|
||||
==========================================
|
||||
|
||||
/bot/
|
||||
├── shared/ # Mínimo compartido (solo config general)
|
||||
│ ├── config_basic.php # Configuración no sensible
|
||||
│ └── constants.php # Constantes globales
|
||||
├── discord/
|
||||
│ ├── bot.php # Bot de Discord independiente
|
||||
│ ├── web/
|
||||
│ │ ├── create_message.php # Interfaz específica Discord
|
||||
│ │ ├── admin/ # Admin específico Discord
|
||||
│ │ └── templates/ # Templates específicos
|
||||
│ ├── includes/
|
||||
│ │ ├── db.php # Conexión específica Discord
|
||||
│ │ ├── DiscordSender.php # Sender específico
|
||||
│ │ ├── message_handler.php # Handler específico
|
||||
│ │ └── [todos los includes específicos]
|
||||
│ ├── database/
|
||||
│ │ └── estructura_discord.sql # Tablas específicas Discord
|
||||
│ └── logs/
|
||||
│ └── discord_*.log # Logs específicos
|
||||
├── telegram/
|
||||
│ ├── bot.php # Bot de Telegram independiente
|
||||
│ ├── web/
|
||||
│ │ ├── create_message.php # Interfaz específica Telegram
|
||||
│ │ ├── admin/ # Admin específico Telegram
|
||||
│ │ └── templates/ # Templates específicos
|
||||
│ ├── includes/
|
||||
│ │ ├── db.php # Conexión específica Telegram
|
||||
│ │ ├── TelegramSender.php # Sender específico
|
||||
│ │ ├── message_handler.php # Handler específico
|
||||
│ │ └── [todos los includes específicos]
|
||||
│ ├── database/
|
||||
│ │ └── estructura_telegram.sql # Tablas específicas Telegram
|
||||
│ └── logs/
|
||||
│ └── telegram_*.log # Logs específicos
|
||||
└── legacy/ # Backup del sistema actual
|
||||
└── [todo el código actual]
|
||||
|
||||
==========================================
|
||||
FASE 1: PREPARACIÓN Y ANÁLISIS (Días 1-2)
|
||||
==========================================
|
||||
|
||||
Objetivo: Análisis detallado y preparación del entorno
|
||||
|
||||
**DÍA 1: Análisis de Dependencias**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Mapear todas las dependencias entre archivos
|
||||
│ ├── Identificar archivos críticos compartidos
|
||||
│ ├── Documentar flujo completo de datos
|
||||
│ └── Crear diagrama de arquitectura actual
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Análisis de base de datos actual
|
||||
│ ├── Identificar tablas compartidas vs específicas
|
||||
│ ├── Documentar relaciones y constraints
|
||||
│ └── Estimar volumen de datos a migrar
|
||||
|
||||
**DÍA 2: Planificación y Preparación**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Crear repositorio de backup completo
|
||||
│ ├── Setup de entorno de pruebas paralelo
|
||||
│ ├── Definir estrategia de rollback
|
||||
│ └── Preparar scripts de validación
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Crear estructura de directorios destino
|
||||
│ ├── Setup de base de datos de pruebas
|
||||
│ ├── Preparar scripts de migración de datos
|
||||
│ └── Documentar puntos críticos de validación
|
||||
|
||||
**DELIVERABLES FASE 1:**
|
||||
✅ Diagrama de dependencias completo
|
||||
✅ Estructura de directorios creada
|
||||
✅ Entorno de pruebas funcionando
|
||||
✅ Scripts de backup y rollback listos
|
||||
✅ Documentación de puntos críticos
|
||||
|
||||
==========================================
|
||||
FASE 2: DUPLICACIÓN DE ESTRUCTURA (Días 3-5)
|
||||
==========================================
|
||||
|
||||
Objetivo: Crear estructura base duplicada sin modificar sistema actual
|
||||
|
||||
**DÍA 3: Estructura de Directorios y Configuración**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Copiar estructura completa a /discord/ y /telegram/
|
||||
│ ├── Crear archivos de configuración específicos
|
||||
│ ├── Setup de variables de entorno separadas
|
||||
│ └── Configurar paths relativos específicos
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Adaptar includes de cada plataforma
|
||||
│ ├── Configurar logging específico por plataforma
|
||||
│ ├── Ajustar rutas de templates y assets
|
||||
│ └── Validar estructura básica
|
||||
|
||||
**DÍA 4: Base de Datos Específica**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Exportar estructura completa de DB actual
|
||||
│ ├── Crear databases discord_bot y telegram_bot
|
||||
│ ├── Importar estructura a ambas BDs
|
||||
│ └── Configurar usuarios y permisos específicos
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Crear scripts de conexión específicos
|
||||
│ ├── Adaptar archivos de configuración de DB
|
||||
│ ├── Probar conexiones a ambas BDs
|
||||
│ └── Validar que no haya cruces
|
||||
|
||||
**DÍA 5: Adaptación Básica de Código**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Adaptar paths de includes en cada plataforma
|
||||
│ ├── Modificar require_once para paths relativos
|
||||
│ ├── Actualizar rutas de templates
|
||||
│ └── Ajustar configuración de logging
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Probar carga básica de archivos PHP
|
||||
│ ├── Validar que no haya errores de sintaxis
|
||||
│ ├── Verificar conexión a DB específica
|
||||
│ └── Documentar cambios realizados
|
||||
|
||||
**DELIVERABLES FASE 2:**
|
||||
✅ Estructura duplicada completa
|
||||
✅ Bases de datos separadas funcionando
|
||||
✅ Configuración específica por plataforma
|
||||
✅ Validación básica de estructura
|
||||
|
||||
==========================================
|
||||
FASE 3: MIGRACIÓN DE DATOS (Días 6-9)
|
||||
==========================================
|
||||
|
||||
Objetivo: Migrar datos de forma segura manteniendo integridad
|
||||
|
||||
**DÍA 6: Scripts de Migración**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Crear scripts de exportación por plataforma
|
||||
│ ├── Implementar filtros por platform='discord'/'telegram'
|
||||
│ ├── Setup de validación de integridad referencial
|
||||
│ └── Preparar scripts de rollback de datos
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Test de scripts con subset de datos
|
||||
│ ├── Validar integridad de datos migrados
|
||||
│ ├── Verificar counts y relaciones
|
||||
│ └── Optimizar rendimiento de migración
|
||||
|
||||
**DÍA 7: Migración de Datos Principales**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Backup completo de producción
|
||||
│ ├── Migrar tabla recipients (filtrada por plataforma)
|
||||
│ ├── Migrar tabla messages
|
||||
│ └── Migrar tabla schedules
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Migrar tabla sent_messages
|
||||
│ ├── Migrar tabla recurrent_messages
|
||||
│ ├── Migrar tabla supported_languages
|
||||
│ └── Validar integridad de relaciones
|
||||
|
||||
**DÍA 8: Migración de Datos de Configuración**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Migrar tabla activity_log (con prefijo)
|
||||
│ ├── Migrar tabla translation_queue
|
||||
│ ├── Migrar tabla telegram_interactions (solo Telegram)
|
||||
│ └── Migrar configuraciones específicas
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Validar consistencia de datos migrados
|
||||
│ ├── Verificar counts vs original
|
||||
│ ├── Test de queries complejas
|
||||
│ └── Documentar datos migrados
|
||||
|
||||
**DÍA 9: Validación y Ajustes de Datos**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Ejecutar scripts de validación completa
|
||||
│ ├── Verificar integridad referencial
|
||||
│ ├── Test de operaciones CRUD
|
||||
│ └── Validar timestamps y secuencias
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Corregir anomalías encontradas
|
||||
│ ├── Optimizar índices específicos
|
||||
│ ├── Validar performance de queries
|
||||
│ └── Preparar reporte de migración
|
||||
|
||||
**DELIVERABLES FASE 3:**
|
||||
✅ Datos completamente migrados a ambas BDs
|
||||
✅ Validación de integridad completada
|
||||
✅ Scripts de rollback de datos probados
|
||||
✅ Documentación de migración
|
||||
|
||||
==========================================
|
||||
FASE 4: ADAPTACIÓN DE LÓGICA DE NEGOCIO (Días 10-13)
|
||||
==========================================
|
||||
|
||||
Objetivo: Adaptar toda la lógica para operación independiente
|
||||
|
||||
**DÍA 10: Adaptación de Bot Files**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Adaptar discord_bot.php para BD específica
|
||||
│ ├── Adaptar telegram_bot_webhook.php para BD específica
|
||||
│ ├── Ajustar conexiones y paths
|
||||
│ └── Configurar logging específico
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Adaptar includes específicos de cada bot
|
||||
│ ├── Modificar handlers de mensajes
|
||||
│ ├── Ajustar sistemas de traducción
|
||||
│ └── Validar funcionamiento básico
|
||||
|
||||
**DÍA 11: Adaptación de Web Interface - Discord**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Adaptar discord/web/create_message.php
|
||||
│ ├── Modificar para usar BD específica
|
||||
│ ├── Ajustar recipient selection
|
||||
│ └── Configurar paths específicos
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Adaptar discord/web/admin/
|
||||
│ ├── Modificar todos los archivos de admin
|
||||
│ ├── Ajustar templates específicos
|
||||
│ └── Validar interfaz completa
|
||||
|
||||
**DÍA 12: Adaptación de Web Interface - Telegram**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Adaptar telegram/web/create_message.php
|
||||
│ ├── Modificar para usar BD específica
|
||||
│ ├── Ajustar recipient selection
|
||||
│ └── Configurar paths específicos
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Adaptar telegram/web/admin/
|
||||
│ ├── Modificar todos los archivos de admin
|
||||
│ ├── Ajustar templates específicos
|
||||
│ └── Validar interfaz completa
|
||||
|
||||
**DÍA 13: Adaptación de Procesos en Background**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Adaptar discord/process_queue.php
|
||||
│ ├── Adaptar telegram/process_queue.php
|
||||
│ ├── Ajustar sistemas de traducción específicos
|
||||
│ └── Configurar logging independiente
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Adaptar scripts de workers
|
||||
│ ├── Modificar sistemas de scheduling
|
||||
│ ├── Ajustar procesos de traducción
|
||||
│ └── Validar procesos background
|
||||
|
||||
**DELIVERABLES FASE 4:**
|
||||
✅ Bots funcionando con BDs específicas
|
||||
✅ Interfaces web adaptadas y funcionando
|
||||
✅ Procesos background adaptados
|
||||
✅ Logging específico funcionando
|
||||
|
||||
==========================================
|
||||
FASE 5: TESTING Y VALIDACIÓN (Días 14-16)
|
||||
==========================================
|
||||
|
||||
Objetivo: Validación exhaustiva antes de producción
|
||||
|
||||
**DÍA 14: Testing Funcional**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Test completo de bot de Discord
|
||||
│ ├── Validar todos los comandos
|
||||
│ ├── Probar envío de mensajes
|
||||
│ └── Test de sistema de traducción
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Test completo de bot de Telegram
|
||||
│ ├── Validar todos los comandos
|
||||
│ ├── Probar envío de mensajes
|
||||
│ └── Test de sistema de traducción
|
||||
|
||||
**DÍA 15: Testing de Web Interface**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Test completo de web Discord
|
||||
│ ├── Probar creación de mensajes
|
||||
│ ├── Test de administración
|
||||
│ └── Validar programación
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Test completo de web Telegram
|
||||
│ ├── Probar creación de mensajes
|
||||
│ ├── Test de administración
|
||||
│ └── Validar programación
|
||||
|
||||
**DÍA 16: Testing de Integración y Stress**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Test de ambas plataformas simultáneamente
|
||||
│ ├── Validar que no haya interferencia
|
||||
│ ├── Test de carga concurrente
|
||||
│ └── Medición de rendimiento
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Test de procesos background
|
||||
│ ├── Validar sistema de traducción bajo carga
|
||||
│ ├── Test de recuperación de errores
|
||||
│ └── Documentar resultados
|
||||
|
||||
**DELIVERABLES FASE 5:**
|
||||
✅ Validación funcional completa
|
||||
✅ Testing de integración exitoso
|
||||
✅ Métricas de性能 documentadas
|
||||
✅ Checklist de validación completado
|
||||
|
||||
==========================================
|
||||
FASE 6: DEPLOY Y MIGRACIÓN FINAL (Días 17-18)
|
||||
==========================================
|
||||
|
||||
Objetivo: Migración final con mínimo impacto
|
||||
|
||||
**DÍA 17: Preparación para Producción**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Backup final de sistema actual
|
||||
│ ├── Preparar entorno de producción
|
||||
│ ├── Configurar DNS y rutas
|
||||
│ └── Documentar plan de corte
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Configurar variables de entorno producción
|
||||
│ ├── Validar conexiones a BDs finales
|
||||
│ ├── Test de endpoints expuestos
|
||||
│ └── Preparar monitoreo
|
||||
|
||||
**DÍA 18: Migración Final**
|
||||
├── **MAÑANA (2 horas) - WINDOW DE MIGRACIÓN:**
|
||||
│ ├── Poner sistema actual en modo mantenimiento
|
||||
│ ├── Migrar última data diferencial
|
||||
│ ├── Apuntar rutas a nuevos sistemas
|
||||
│ └── Iniciar nuevos servicios
|
||||
├── **MAÑANA (2 horas) - VALIDACIÓN INMEDIATA:**
|
||||
│ ├── Verificar bots conectados
|
||||
│ ├── Test básico de funcionalidad
|
||||
│ ├── Validar logs corriendo
|
||||
│ └── Confirmar no hay errores críticos
|
||||
├── **TARDE (4 horas) - MONITOREO INTENSIVO:**
|
||||
│ ├── Monitorear rendimiento
|
||||
│ ├── Validar todas las funcionalidades
|
||||
│ ├── Revisar logs en tiempo real
|
||||
│ └── Estar listo para rollback si es necesario
|
||||
|
||||
**DELIVERABLES FASE 6:**
|
||||
✅ Sistema completamente migrado
|
||||
✅ Ambas plataformas funcionando independientemente
|
||||
✅ Monitoreo activo implementado
|
||||
✅ Plan de rollback validado
|
||||
|
||||
==========================================
|
||||
FASE 7: POST-MIGRACIÓN Y OPTIMIZACIÓN (Días 19-20)
|
||||
==========================================
|
||||
|
||||
Objetivo: Optimizar y documentar nueva arquitectura
|
||||
|
||||
**DÍA 19: Optimización y Ajustes**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Analizar performance post-migración
|
||||
│ ├── Optimizar queries específicos
|
||||
│ ├── Ajustar configuración de cache
|
||||
│ └── Optimizar índices de BD
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Configurar monitoreo específico
|
||||
│ ├── Setup de alertas personalizadas
|
||||
│ ├── Optimizar procesos background
|
||||
│ └── Ajustar configuración de logs
|
||||
|
||||
**DÍA 20: Documentación y Handover**
|
||||
├── **MAÑANA (4 horas):**
|
||||
│ ├── Documentar nueva arquitectura
|
||||
│ ├── Crear guías de operación
|
||||
│ ├── Documentar procedimientos de backup
|
||||
│ └── Preparar documentación técnica
|
||||
├── **TARDE (4 horas):**
|
||||
│ ├── Capacitar al equipo en nueva estructura
|
||||
│ ├── Crear runbooks de operación
|
||||
│ ├── Documentar puntos críticos
|
||||
│ └── Cerrar proyecto exitosamente
|
||||
|
||||
**DELIVERABLES FASE 7:**
|
||||
✅ Sistema optimizado funcionando
|
||||
✅ Documentación completa
|
||||
✅ Equipo capacitado
|
||||
✅ Proyecto cerrado exitosamente
|
||||
|
||||
==========================================
|
||||
RIESGOS CRÍTICOS Y MITIGACIÓN
|
||||
==========================================
|
||||
|
||||
**RIESGO 1: Pérdida de Datos During Migración**
|
||||
├── Impacto: Crítico
|
||||
├── Mitigación:
|
||||
│ ├── Múltiples backups (antes, durante, después)
|
||||
│ ├── Scripts de validación de integridad
|
||||
│ ├── Test con datos de prueba primero
|
||||
│ └── Rollback planificado y testado
|
||||
|
||||
**RIESGO 2: Downtime Prolongado**
|
||||
├── Impacto: Alto
|
||||
├── Mitigación:
|
||||
│ ├── Ventana de migración planificada
|
||||
│ ├── Estructura paralela pre-creada
|
||||
│ ├── Scripts automatizados para velocidad
|
||||
│ └── Team listo para rollback inmediato
|
||||
|
||||
**RIESGO 3: Regresiones Funcionales**
|
||||
├── Impacto: Alto
|
||||
├── Mitigación:
|
||||
│ ├── Testing extensivo en ambiente aislado
|
||||
│ ├── Checklist de validación detallado
|
||||
│ ├── Monitoreo intensivo post-migración
|
||||
│ └── Equipo de soporte listo
|
||||
|
||||
**RIESGO 4: Problemas de Performance**
|
||||
├── Impacto: Medio
|
||||
├── Mitigación:
|
||||
│ ├── Medición de baseline actual
|
||||
│ ├── Optimización específica por plataforma
|
||||
│ ├── Monitoreo continuo de métricas
|
||||
│ └── Plan de optimización post-migración
|
||||
|
||||
==========================================
|
||||
REQUERIMIENTOS DE RECURSOS
|
||||
==========================================
|
||||
|
||||
**Personal:**
|
||||
├── 1 Desarrollador Senior (Líder del proyecto)
|
||||
├── 1 Desarrollador Mid (Soporte técnico)
|
||||
├── 1 DBA (Para migración de datos)
|
||||
└── 1 DevOps/Infraestructura (Para deploy)
|
||||
|
||||
**Infraestructura:**
|
||||
├── Servidor adicional para staging/paralelo
|
||||
├── 2 bases de datos adicionales
|
||||
├── Storage extra para backups
|
||||
└── Herramientas de monitoreo
|
||||
|
||||
**Software/Herramientas:**
|
||||
├── Herramientas de comparación de BD
|
||||
├── Scripts de migración automatizados
|
||||
├── Sistema de control de versiones
|
||||
└── Herramientas de testing automatizado
|
||||
|
||||
==========================================
|
||||
MÉTRICAS DE ÉXITO
|
||||
==========================================
|
||||
|
||||
**Técnicas:**
|
||||
✅ 0% de pérdida de datos durante migración
|
||||
✅ <30 minutos de downtime total
|
||||
✅ 100% de funcionalidades validadas
|
||||
✅ Performance igual o superior al sistema actual
|
||||
|
||||
**Operativas:**
|
||||
✅ 100% de independencia entre plataformas
|
||||
✅ Capacidad de actualizar una plataforma sin afectar la otra
|
||||
✅ Logs y monitoreo específico por plataforma
|
||||
✅ Documentación completa y accesible
|
||||
|
||||
==========================================
|
||||
CHECKLIST FINAL DE VALIDACIÓN
|
||||
==========================================
|
||||
|
||||
**Pre-Migración:**
|
||||
☐ Backup completo realizado y validado
|
||||
☐ Scripts de migración testeados extensivamente
|
||||
☐ Equipo completo notificado y listo
|
||||
☐ Ventana de mantenimiento comunicada a usuarios
|
||||
☐ Plan de rollback testado y validado
|
||||
|
||||
**Post-Migración:**
|
||||
☐ Ambos bots conectados y funcionando
|
||||
☐ Interfaces web accesibles y funcionales
|
||||
☐ Datos migrados correctamente (counts validados)
|
||||
☐ Logs generándose correctamente
|
||||
☐ Procesos background corriendo
|
||||
☐ Monitoreo detectando anomalías
|
||||
☐ Backup post-migración realizado
|
||||
|
||||
**Week Post-Migración:**
|
||||
☐ Performance estable
|
||||
☐ Usuarios reportando normalidad
|
||||
☐ Logs sin errores críticos
|
||||
☐ Sistemas de traducción funcionando
|
||||
☐ Programación de mensajes funcionando
|
||||
☐ Documentación completada
|
||||
☐ Equipo capacitado
|
||||
|
||||
==========================================
|
||||
CONCLUSIÓN
|
||||
==========================================
|
||||
|
||||
Este plan proporciona una ruta clara y estructurada para lograr la separación completa
|
||||
de las plataformas Discord y Telegram con mínimo riesgo y máximo beneficio.
|
||||
|
||||
La separación permitirá:
|
||||
- Desarrollo independiente
|
||||
- Despliegues seguros y aislados
|
||||
- Especialización por plataforma
|
||||
- Mayor estabilidad operativa
|
||||
- Escalabilidad independiente
|
||||
|
||||
El tiempo estimado (15-20 días) considera todas las validaciones necesarias
|
||||
para garantizar una migración exitosa sin impacto crítico en el negocio.
|
||||
@@ -20,7 +20,7 @@ require_once __DIR__ . '/src/DiscordSender.php';
|
||||
use Discord\Parts\Embed\Embed;
|
||||
|
||||
// Instanciar las clases necesarias
|
||||
$translator = new Translate();
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
|
||||
$running = true;
|
||||
|
||||
@@ -74,7 +74,7 @@ while ($running) {
|
||||
custom_log("[JOB #{$job['id']}] Procesando trabajo para Discord con múltiples idiomas.");
|
||||
$targetLangs = explode(',', $job['target_lang']);
|
||||
|
||||
$discordSender = new DiscordSender($_ENV['DISCORD_BOT_TOKEN']);
|
||||
$discordSender = new DiscordSender(DISCORD_BOT_TOKEN);
|
||||
|
||||
// Pre-procesar el texto para proteger las menciones de Discord
|
||||
$originalText = $job['text_to_translate'];
|
||||
@@ -128,7 +128,7 @@ while ($running) {
|
||||
// --- LÓGICA MEJORADA PARA TELEGRAM USANDO UN SOLO MENSAJE HTML ---
|
||||
custom_log("[JOB #{$job['id']}] Procesando trabajo para Telegram con múltiples idiomas.");
|
||||
$targetLangs = explode(',', $job['target_lang']);
|
||||
$telegram = new TelegramSender($_ENV['TELEGRAM_BOT_TOKEN'], $pdo);
|
||||
$telegram = new TelegramSender(TELEGRAM_BOT_TOKEN, $pdo, BOT_BASE_URL);
|
||||
|
||||
$htmlOutput = "<b>Traducciones:</b>\n\n";
|
||||
$translationCount = 0;
|
||||
@@ -137,7 +137,7 @@ while ($running) {
|
||||
if (empty($langCode)) continue;
|
||||
|
||||
$translatedText = $translator->translateHtml($job['text_to_translate'], $job['source_lang'], $langCode);
|
||||
|
||||
|
||||
if ($translatedText && trim(strtolower($translatedText)) !== trim(strtolower($job['text_to_translate']))) {
|
||||
// Obtener nombre del idioma y bandera
|
||||
$langInfoStmt = $pdo->prepare("SELECT language_name, flag_emoji FROM supported_languages WHERE language_code = ?");
|
||||
@@ -190,7 +190,6 @@ while ($running) {
|
||||
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
|
||||
custom_log("--- PROCESADOR DE COLA DETENIDO ---");
|
||||
|
||||
/**
|
||||
|
||||
@@ -68,7 +68,7 @@ try {
|
||||
$originalHtml = $stmt->fetchColumn();
|
||||
|
||||
if ($originalHtml) {
|
||||
$translator = new Translate();
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$textContent = strip_tags(html_entity_decode($originalHtml));
|
||||
$sourceLang = $translator->detectLanguage($textContent);
|
||||
|
||||
@@ -78,8 +78,7 @@ try {
|
||||
|
||||
if ($translatedHtml && $translatedHtml !== $originalHtml) {
|
||||
$sender = new DiscordSender(DISCORD_BOT_TOKEN);
|
||||
$mention = "<@{"
|
||||
. $userId . "}>;
|
||||
$mention = "<@" . $userId . ">";
|
||||
$finalContent = $mention . " *Traducción a {" . $targetLang . "}:*\n" . $translatedHtml;
|
||||
$sender->sendMessage($channelId, $finalContent);
|
||||
direct_log("[MANUAL_TRANSLATE_WORKER] Traducción enviada con éxito.");
|
||||
|
||||
@@ -4,21 +4,22 @@ class Translate
|
||||
{
|
||||
private $apiUrl;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(string $apiUrl)
|
||||
{
|
||||
$this->apiUrl = rtrim($_ENV['LIBRETRANSLATE_URL'], '/');
|
||||
$this->apiUrl = rtrim($apiUrl, '/');
|
||||
}
|
||||
|
||||
public function detectLanguage($text)
|
||||
{
|
||||
if (empty(trim($text))) {
|
||||
return null;
|
||||
return null; // Or return an empty array indicating no detection
|
||||
}
|
||||
|
||||
$response = $this->request('/detect', ['q' => $text]);
|
||||
|
||||
// Return the full response array if detection was successful
|
||||
if (isset($response[0]['language'])) {
|
||||
return $response[0]['language'];
|
||||
return $response; // Return the array, e.g., [{"confidence":90.0,"language":"es"}]
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -10,7 +10,7 @@ class TranslationWorker {
|
||||
public function __construct($workerId, $pdo) {
|
||||
$this->workerId = "worker_" . $workerId . "_" . getmypid();
|
||||
$this->pdo = $pdo;
|
||||
$this->translator = new Translate();
|
||||
$this->translator = new Translate(LIBRETRANSLATE_URL);
|
||||
|
||||
// Configurar sleep time desde environment
|
||||
if (isset($_ENV['TRANSLATION_WORKER_SLEEP'])) {
|
||||
|
||||
@@ -8,11 +8,13 @@ class TelegramSender
|
||||
private $botToken;
|
||||
private $apiUrl = 'https://api.telegram.org/bot';
|
||||
private $pdo;
|
||||
private $baseUrl; // Nueva propiedad para almacenar BOT_BASE_URL
|
||||
|
||||
public function __construct($botToken, $pdo)
|
||||
public function __construct($botToken, $pdo, string $baseUrl)
|
||||
{
|
||||
$this->botToken = $botToken;
|
||||
$this->pdo = $pdo;
|
||||
$this->baseUrl = rtrim($baseUrl, '/'); // Asegurarse de que no tenga una barra al final
|
||||
}
|
||||
|
||||
public function sendMessage($chatId, $content, $options = [], $addTranslateButton = false, $messageLanguage = 'es', $originalFullContent = null)
|
||||
@@ -302,7 +304,7 @@ class TelegramSender
|
||||
|
||||
// Convertir rutas relativas a absolutas si es necesario
|
||||
if (!preg_match('/^https?:\/\//', $image_url)) {
|
||||
$base_url = rtrim($_ENV['APP_URL'], '/');
|
||||
$base_url = $this->baseUrl;
|
||||
$image_url = $base_url . '/' . ltrim($image_url, '/');
|
||||
custom_log("[DEBUG] URL de imagen convertida: " . $image_url);
|
||||
|
||||
@@ -605,7 +607,7 @@ class TelegramSender
|
||||
|
||||
// Si la URL es relativa, intentar convertirla a absoluta
|
||||
if (!preg_match('/^https?:\/\//i', $url)) {
|
||||
$baseUrl = rtrim($_ENV['APP_URL'], '/');
|
||||
$baseUrl = $this->baseUrl;
|
||||
$absoluteUrl = $baseUrl . '/' . ltrim($url, '/');
|
||||
custom_log("${logPrefix} URL relativa detectada, convirtiendo a absoluta: $absoluteUrl");
|
||||
$url = $absoluteUrl;
|
||||
@@ -712,7 +714,7 @@ class TelegramSender
|
||||
}
|
||||
|
||||
if (!preg_match('/^https?:\/\//', $url)) {
|
||||
$baseUrl = rtrim($_ENV['APP_URL'], '/');
|
||||
$baseUrl = $this->baseUrl;
|
||||
$url = $baseUrl . '/' . ltrim($url, '/');
|
||||
custom_log("[DEBUG] isValidImageUrl: URL convertida a absoluta: " . $url);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ ini_set('log_errors', 1);
|
||||
|
||||
// Verificación de autenticación
|
||||
$authToken = $_GET['auth_token'] ?? '';
|
||||
$expectedToken = $_ENV['TELEGRAM_WEBHOOK_TOKEN'] ?? '';
|
||||
$expectedToken = TELEGRAM_WEBHOOK_TOKEN;
|
||||
if (!empty($expectedToken) && $authToken !== $expectedToken) {
|
||||
http_response_code(403);
|
||||
custom_log("Acceso no autorizado: token inválido.");
|
||||
@@ -30,7 +30,7 @@ if (!empty($expectedToken) && $authToken !== $expectedToken) {
|
||||
}
|
||||
|
||||
// Verificar token del bot
|
||||
$botToken = $_ENV['TELEGRAM_BOT_TOKEN'] ?? '';
|
||||
$botToken = TELEGRAM_BOT_TOKEN;
|
||||
if (empty($botToken)) {
|
||||
http_response_code(500);
|
||||
custom_log("Token de bot no configurado.");
|
||||
@@ -49,8 +49,8 @@ if (!$update) {
|
||||
custom_log("Update recibido: " . json_encode($update, JSON_PRETTY_PRINT));
|
||||
|
||||
try {
|
||||
$telegram = new TelegramSender($botToken, $pdo);
|
||||
$translator = new Translate();
|
||||
$telegram = new TelegramSender(TELEGRAM_BOT_TOKEN, $pdo, BOT_BASE_URL);
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$commandLocker = new CommandLocker($pdo);
|
||||
|
||||
$message = $update['message'] ?? $update['channel_post'] ?? null;
|
||||
@@ -248,7 +248,8 @@ try {
|
||||
|
||||
if (!empty($originalText)) {
|
||||
try {
|
||||
$sourceLang = $translator->detectLanguage($originalText);
|
||||
$detectionResult = $translator->detectLanguage($originalText);
|
||||
$sourceLang = $detectionResult[0]['language'] ?? null;
|
||||
if ($sourceLang && $sourceLang !== $targetLang) {
|
||||
$translatedText = $translator->translateHtml($originalText, $sourceLang, $targetLang);
|
||||
$telegram->answerCallbackQuery($callbackId, ['text' => $translatedText, 'show_alert' => true]);
|
||||
@@ -279,7 +280,8 @@ try {
|
||||
if ($originalContent) {
|
||||
// Detectar idioma real del contenido y aplicar fallback si coincide con el destino
|
||||
$plain = strip_tags(html_entity_decode($originalContent, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
|
||||
$sourceLang = $translator->detectLanguage($plain) ?? 'es';
|
||||
$detectionResult = $translator->detectLanguage($plain);
|
||||
$sourceLang = $detectionResult[0]['language'] ?? 'es';
|
||||
if ($sourceLang === $targetLang) {
|
||||
$fallbackSrc = 'es';
|
||||
if ($fallbackSrc !== $targetLang) {
|
||||
@@ -351,7 +353,8 @@ try {
|
||||
|
||||
function handleCommand($pdo, $telegram, $commandLocker, $translator, $text, $from, $chatId, $messageId) {
|
||||
$userId = $from['id'];
|
||||
$detectedLang = $translator->detectLanguage($text) ?? 'es';
|
||||
$detectionResult = $translator->detectLanguage($text);
|
||||
$detectedLang = $detectionResult[0]['language'] ?? 'es';
|
||||
|
||||
if (strpos($text, '/setlang') === 0 || strpos($text, '/setlanguage') === 0) {
|
||||
$parts = explode(' ', $text, 2);
|
||||
@@ -459,7 +462,8 @@ function handleCommand($pdo, $telegram, $commandLocker, $translator, $text, $fro
|
||||
$converter = new HtmlToTelegramHtmlConverter();
|
||||
$content = $converter->convert($content);
|
||||
|
||||
$detectedLang = $translator->detectLanguage(strip_tags($content)) ?? 'es';
|
||||
$detectionResult = $translator->detectLanguage(strip_tags($content));
|
||||
$detectedLang = $detectionResult[0]['language'] ?? 'es';
|
||||
if ($detectedLang !== 'es') {
|
||||
$translatedContent = $translator->translateHtml($content, $detectedLang, 'es');
|
||||
if ($translatedContent) $content = $translatedContent;
|
||||
@@ -520,7 +524,8 @@ function handleRegularMessage($pdo, $telegram, $commandLocker, $translator, $tex
|
||||
|
||||
try {
|
||||
// 1. Detectar el idioma del mensaje entrante
|
||||
$detectedLang = $translator->detectLanguage(strip_tags($text)) ?? 'es';
|
||||
$detectionResult = $translator->detectLanguage(strip_tags($text));
|
||||
$detectedLang = $detectionResult[0]['language'] ?? 'es';
|
||||
|
||||
// 2. Guardar la interacción original en la base de datos
|
||||
try {
|
||||
|
||||
@@ -39,7 +39,7 @@ try {
|
||||
exit;
|
||||
}
|
||||
|
||||
$translator = new Translate();
|
||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||
$translatedText = $translator->translateHtml($originalText, $sourceLang, $targetLang);
|
||||
|
||||
if ($translatedText) {
|
||||
|
||||
@@ -21,18 +21,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
|
||||
// Cargar las variables de entorno
|
||||
try {
|
||||
// Determinar el entorno desde la variable de entorno del servidor
|
||||
$environment = $_SERVER['APP_ENVIRONMENT'] ?? 'pruebas'; // Usar 'pruebas' como fallback
|
||||
$envFile = '.env.' . $environment;
|
||||
// Determinar el entorno
|
||||
$environment = getenv('APP_ENVIRONMENT') ?: 'pruebas';
|
||||
|
||||
// Verificar si el archivo de entorno existe
|
||||
if (!file_exists(__DIR__ . '/' . $envFile)) {
|
||||
throw new \Dotenv\Exception\InvalidPathException("El archivo de entorno '{$envFile}' no se encuentra.");
|
||||
// Construir el nombre del archivo de entorno correcto
|
||||
if ($environment === 'reod') {
|
||||
$envFile = '.env';
|
||||
} else {
|
||||
$envFile = '.env.' . $environment;
|
||||
}
|
||||
|
||||
// Cargar el archivo de entorno correspondiente
|
||||
// Cargar el archivo de entorno
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__, $envFile);
|
||||
$dotenv->load();
|
||||
|
||||
} catch (\Dotenv\Exception\InvalidPathException $e) {
|
||||
http_response_code(500);
|
||||
$errorMessage = "Error al cargar la configuración del entorno: " . $e->getMessage();
|
||||
|
||||
Reference in New Issue
Block a user