little update
This commit is contained in:
parent
9ffcf83889
commit
16980a8c17
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ bot.log
|
||||
node_modules
|
||||
temp
|
||||
config.json
|
||||
database/ubications.json
|
60
commands/guide_command.js
Normal file
60
commands/guide_command.js
Normal 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
|
||||
};
|
21
commands/stoicism_command.js
Normal file
21
commands/stoicism_command.js
Normal 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
0
database/.gitkeep
Normal file
34
index.js
34
index.js
@ -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}`);
|
||||
}
|
||||
@ -75,6 +78,11 @@ 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,
|
||||
@ -85,18 +93,24 @@ class WhatsAppBot {
|
||||
|
||||
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
48
plugins/brainstormer.js
Normal 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
49
plugins/email_draft.js
Normal 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
49
plugins/formatter.js
Normal 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
|
||||
};
|
@ -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));
|
||||
|
@ -1,54 +1,27 @@
|
||||
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 = {
|
||||
|
50
tasks/stoicism_reminder.js
Normal file
50
tasks/stoicism_reminder.js
Normal 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
|
||||
};
|
Loading…
Reference in New Issue
Block a user