little update

This commit is contained in:
David Vargas 2024-11-11 07:40:48 +00:00
parent 9ffcf83889
commit 16980a8c17
11 changed files with 329 additions and 60 deletions

3
.gitignore vendored
View File

@ -4,4 +4,5 @@ bot.log
.wwebjs_cache
node_modules
temp
config.json
config.json
database/ubications.json

60
commands/guide_command.js Normal file
View File

@ -0,0 +1,60 @@
const fs = require('fs');
const path = require('path');
// Cargar ubicaciones guardadas desde el archivo JSON
const locationsFilePath = path.join(__dirname, '../database/ubications.json');
let destinationLocation = null; // Variable para guardar la ubicación deseada temporalmente
function handleGuideCommand(client, message) {
const commandParts = message.body.trim().split(' ');
if (commandParts.length < 2) {
message.reply('❌ Por favor, especifica la ubicación deseada. Ejemplo: !guiaciudad casa');
return;
}
const locationName = commandParts[1];
let locations;
try {
locations = JSON.parse(fs.readFileSync(locationsFilePath, 'utf8'));
} catch (error) {
message.reply('❌ No se pudo leer el archivo de ubicaciones. Asegúrate de que exista y esté en formato JSON.');
console.error('Error leyendo ubicaciones:', error);
return;
}
if (!locations[locationName]) {
message.reply(`❌ Ubicación "${locationName}" no encontrada en tu base de datos.`);
return;
}
// Guardar la ubicación deseada temporalmente
destinationLocation = locations[locationName];
message.reply(`📍 Ubicación "${locationName}" encontrada. Por favor, envía tu ubicación actual para planificar la ruta.`);
}
function handleLocationMessage(client, message) {
if (destinationLocation) {
const currentLatitude = message.location.latitude;
const currentLongitude = message.location.longitude;
const destinationLatitude = destinationLocation.latitude;
const destinationLongitude = destinationLocation.longitude;
// Generar el enlace de Google Maps para la ruta
const mapsUrl = `https://www.google.com/maps/dir/?api=1&origin=${currentLatitude},${currentLongitude}&destination=${destinationLatitude},${destinationLongitude}`;
// Responder con el enlace de Google Maps
message.reply(`🗺️ Aquí tienes la ruta a la ubicación deseada: ${mapsUrl}`);
// Limpiar la ubicación de destino para la próxima vez
destinationLocation = null;
} else {
message.reply('❌ No has especificado una ubicación de destino. Usa el comando !guiaciudad {ubicacion_deseada} primero.');
}
}
module.exports = {
handleGuideCommand,
handleLocationMessage
};

View File

@ -0,0 +1,21 @@
const { getStoicQuote } = require('../tasks/stoicism_reminder');
/**
* Maneja el comando `!estoico` para enviar una cita de estoicismo en español.
* @param {Object} client - Instancia del cliente de WhatsApp.
* @param {Object} message - Mensaje recibido de WhatsApp.
*/
const handleStoicismCommand = async (client, message) => {
try {
const quoteMessage = await getStoicQuote();
await client.sendMessage(message.from, quoteMessage);
console.log(`📤 Cita de estoicismo enviada en respuesta a ${message.from}`);
} catch (error) {
console.error('❌ Error al enviar la cita de estoicismo:', error);
await client.sendMessage(message.from, '❌ Hubo un problema al obtener la cita de estoicismo. Intenta más tarde.');
}
};
module.exports = {
handleStoicismCommand
};

0
database/.gitkeep Normal file
View File

View File

@ -7,6 +7,8 @@ const logger = require('./utils/logger');
const { handleRecipeCommand } = require('./commands/recipes_command');
const { handleWeatherCommand } = require('./commands/weather_command');
const { initializeCronJobs } = require('./services/cron_service');
const { handleGuideCommand, handleLocationMessage } = require('./commands/guide_command');
const { handleStoicismCommand } = require('./commands/stoicism_command');
dotenv.config();
@ -57,10 +59,11 @@ class WhatsAppBot {
this.myNumber = this.myId.split('@')[0];
logger.info(`🔑 Tu ID de WhatsApp es: ${this.myId}`);
logger.info(`📱 Tu número de teléfono es: ${this.myNumber}`);
const initCron = await initializeCronJobs(this.client);
if (initCron) logger.info('⏰ Tareas programadas inicializadas correctamente');
initializeCronJobs(this.client);
const chat = await this.client.getChatById(this.myId);
logger.info(`💭 Chat propio encontrado: ${JSON.stringify(chat, null, 2)}`);
//logger.info(`💭 Chat propio encontrado: ${JSON.stringify(chat, null, 2)}`);
} catch (error) {
logger.error(`❌ Error al obtener información: ${error}`);
}
@ -74,7 +77,12 @@ class WhatsAppBot {
async handleMessage(message) {
if (!this.myId || !this.isChatAllowed(message.from)) return;
if (message.type === 'location') {
handleLocationMessage(this.client, message);
return;
}
console.log('📨 Mensaje creado:', {
from: message.from,
fromMe: message.fromMe,
@ -82,21 +90,27 @@ class WhatsAppBot {
type: message.type,
timestamp: message.timestamp
});
const command = message.body.trim().toLowerCase();
if (command === '!ping') {
await this.handlePingCommand(message);
} else if (command.startsWith('!clima')) {
await handleWeatherCommand(this.client, message);
} else if (command.startsWith('!receta')) {
await handleRecipeCommand(this.client, message);
const commands = {
'!ping': () => this.handlePingCommand(message),
'!clima': () => handleWeatherCommand(this.client, message),
'!receta': () => handleRecipeCommand(this.client, message),
'!guiaciudad': () => handleGuideCommand(this.client, message),
'!calm': () => handleStoicismCommand(this.client, message)
};
const commandHandler = Object.entries(commands).find(([key]) => command.startsWith(key));
if (commandHandler) {
await commandHandler[1]();
}
}
}
async handlePingCommand(message) {
try {
await this.client.sendMessage(message.from, 'pong');
await this.client.sendMessage(message.from, 'pong madafaka');
console.log(`📤 Respondido 'pong' al número autorizado ${message.from}`);
} catch (error) {
console.error('❌ Error al enviar respuesta:', error);

48
plugins/brainstormer.js Normal file
View File

@ -0,0 +1,48 @@
const axios = require('axios');
const dotenv = require('dotenv');
dotenv.config();
const apiKey = process.env.GOOGLE_GEMINI_API_KEY;
/**
* Genera una lista de ideas creativas para un tema dado.
* @param {String} topic - Tema para el cual generar ideas.
* @returns {Promise<String>} - Lista de ideas creativas.
*/
const brainstormIdeas = async (topic) => {
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`;
// Define el prompt para pedir ideas creativas sobre el tema
const prompt = `
Por favor, genera una lista de ideas creativas sobre el siguiente tema.
Las ideas deben ser únicas y variadas, apropiadas para el contexto y el tema proporcionado.
Tema:
${topic}
`;
try {
const response = await axios.post(
url,
{
contents: [{ parts: [{ text: prompt }] }]
},
{
headers: { 'Content-Type': 'application/json' }
}
);
// Extrae las ideas generadas de la respuesta
const ideas = response.data.candidates[0].content.parts[0].text;
return ideas;
} catch (error) {
console.error('Error al generar ideas:', JSON.stringify(error.response?.data, null, 2));
return 'Hubo un problema al generar ideas creativas.';
}
};
module.exports = {
brainstormIdeas
};

49
plugins/email_draft.js Normal file
View File

@ -0,0 +1,49 @@
const axios = require('axios');
const dotenv = require('dotenv');
dotenv.config();
const apiKey = process.env.GOOGLE_GEMINI_API_KEY;
/**
* Genera un borrador de correo electrónico en base a una descripción y un tono.
* @param {String} description - Descripción del contenido del correo.
* @param {String} tone - Tono del correo, 'formal' o 'informal'.
* @returns {Promise<String>} - Borrador de correo electrónico.
*/
const draftEmail = async (description, tone = 'formal') => {
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`;
// Define el prompt para pedir un correo con el tono adecuado
const prompt = `
Por favor, redacta un correo electrónico en tono ${tone} basado en la siguiente descripción.
Asegúrate de que sea claro y apropiado para el contexto.
Descripción del correo:
${description}
`;
try {
const response = await axios.post(
url,
{
contents: [{ parts: [{ text: prompt }] }]
},
{
headers: { 'Content-Type': 'application/json' }
}
);
// Extrae el borrador de correo de la respuesta
const emailDraft = response.data.candidates[0].content.parts[0].text;
return emailDraft;
} catch (error) {
console.error('Error al generar el borrador de correo:', JSON.stringify(error.response?.data, null, 2));
return 'Hubo un problema al generar el borrador de correo electrónico.';
}
};
module.exports = {
draftEmail
};

49
plugins/formatter.js Normal file
View File

@ -0,0 +1,49 @@
const axios = require('axios');
const dotenv = require('dotenv');
dotenv.config();
const apiKey = process.env.GOOGLE_GEMINI_API_KEY;
/**
* Formatea y organiza un texto con buena indentación y explicaciones.
* @param {String} text - Texto a formatear y organizar.
* @returns {Promise<String>} - Texto formateado y organizado.
*/
const formatText = async (text) => {
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`;
// Definimos un prompt específico para pedir una reformateación y organización del texto
const prompt = `
Por favor, organiza y formatea el siguiente texto con buena indentación y estructura,
proporciona explicaciones claras y usa subtítulos si es necesario.
No modifiques el contenido, pero haz que sea fácil de leer y entender.
Texto a organizar:
${text}
`;
try {
const response = await axios.post(
url,
{
contents: [{ parts: [{ text: prompt }] }]
},
{
headers: { 'Content-Type': 'application/json' }
}
);
// Extrae el texto organizado de la respuesta
const formattedText = response.data.candidates[0].content.parts[0].text;
return formattedText;
} catch (error) {
console.error('Error al formatear el texto:', JSON.stringify(error.response?.data, null, 2));
return text; // Devuelve el texto original en caso de error
}
};
module.exports = {
formatText
};

View File

@ -13,9 +13,10 @@ const apiKey = process.env.GOOGLE_GEMINI_API_KEY;
*/
const translateText = async (text, targetLang = 'es') => {
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`;
console.log('Texto crudo sin traduccion ' + text);
// Añadimos el preprompt para que especifique la traducción al español
const prompt = `Por favor, traduce el siguiente texto al español:\n\n${text}`;
const prompt = `Eres un experto en idiomas, tu tarea es traducir el siguiente texto al español:\n\n${text}`;
try {
const response = await axios.post(
@ -30,6 +31,9 @@ const translateText = async (text, targetLang = 'es') => {
// Extrae el texto traducido de la respuesta
const translatedText = response.data.candidates[0].content.parts[0].text;
console.log('Texto traducido: ' + translatedText);
return translatedText;
} catch (error) {
console.error('Error al traducir el texto:', JSON.stringify(error.response?.data, null, 2));

View File

@ -1,56 +1,29 @@
const cron = require('node-cron');
const { sendReminder } = require('../tasks/send_reminder');
const config = require('../config.json');
const { sendStoicReminder } = require('../tasks/stoicism_reminder');
/**
* Convierte el intervalo en horas o minutos a minutos.
* @param {String} intervalo - Intervalo en el formato "2 horas" o "45 minutos".
* @returns {Number} - Intervalo en minutos.
*/
const getIntervalInMinutes = (intervalo) => {
const [amount, unit] = intervalo.split(' ');
return unit.includes('hora') ? parseInt(amount) * 60 : parseInt(amount);
};
/**
* Programa las tareas de recordatorio basadas en el horario y el intervalo.
* Inicializa las tareas de recordatorio programadas para citas de estoicismo.
* @param {Object} client - Instancia del cliente de WhatsApp.
*/
const initializeCronJobs = (client) => {
const dailyRoutines = config.rutinas.diarias;
dailyRoutines.forEach((routine) => {
const { actividad, detalles } = routine;
const { intervalo, horario, que, hora } = detalles;
if (intervalo && horario) {
const intervalInMinutes = getIntervalInMinutes(intervalo);
const [startHour, startMinute] = horario.inicio.split(':').map(Number);
const [endHour, endMinute] = horario.fin.split(':').map(Number);
cron.schedule(`*/${intervalInMinutes} * * * *`, () => {
const now = new Date();
const isWithinTimeFrame =
now.getHours() >= startHour &&
now.getHours() <= endHour &&
(now.getHours() < endHour || now.getMinutes() <= endMinute);
if (isWithinTimeFrame) {
sendReminder(client, actividad, que);
}
});
}
else if (hora) {
const [hour, minute] = hora.split(':');
cron.schedule(`${minute} ${hour} * * *`, () => {
sendReminder(client, actividad, que);
});
}
// Enviar recordatorio al despertar (7:00 AM)
cron.schedule('0 7 * * *', () => {
sendStoicReminder(client);
});
console.log('⏰ Recordatorios programados según configuración en config.json');
// Enviar recordatorio al mediodía (12:00 PM)
cron.schedule('0 12 * * *', () => {
sendStoicReminder(client);
});
// Enviar recordatorio antes de dormir (9:00 PM)
cron.schedule('0 21 * * *', () => {
sendStoicReminder(client);
});
console.log('⏰ Recordatorios de citas de estoicismo programados para las 7:00 AM, 12:00 PM y 9:00 PM.');
};
module.exports = {
initializeCronJobs
};
};

View File

@ -0,0 +1,50 @@
const axios = require('axios');
const { translateText } = require('../plugins/translator');
const dotenv = require('dotenv');
dotenv.config();
const AUTHORIZED_NUMBER = process.env.AUTHORIZED_NUMBER;
/**
* Obtiene una cita de estoicismo de la API y la traduce al español.
* @returns {Promise<String>} - Cita traducida al español.
*/
const getStoicQuote = async () => {
try {
const response = await axios.get('https://stoic.tekloon.net/stoic-quote');
const { author, quote } = response.data.data;
// Traducir la cita al español
const translatedQuote = await translateText(quote, 'es');
// Formato mejorado para WhatsApp
return `━━━━━━━━━━━━━━━\n` +
`🧘‍♂️ *REMINDER* 🧘‍♀️\n\n` +
`\n${translatedQuote}\n\n` +
`*- ${author}*\n` +
`━━━━━━━━━━━━━━━`;
} catch (error) {
console.error('Error al obtener la cita de estoicismo:', error);
return '❌ Hubo un problema al obtener la cita de estoicismo.';
}
};
/**
* Envía una cita de estoicismo traducida al español al número autorizado.
* @param {Object} client - Instancia del cliente de WhatsApp.
*/
const sendStoicReminder = async (client) => {
const quoteMessage = await getStoicQuote();
try {
await client.sendMessage(AUTHORIZED_NUMBER, quoteMessage);
console.log(`📤 Cita de estoicismo enviada a ${AUTHORIZED_NUMBER}`);
} catch (error) {
console.error('❌ Error al enviar la cita de estoicismo:', error);
}
};
module.exports = {
sendStoicReminder,
getStoicQuote
};