Add recipe and weather command handling for WhatsApp bot

This commit is contained in:
David Vargas 2024-11-05 21:58:06 -06:00
parent bd26a59081
commit 4c9455f644
5 changed files with 219 additions and 32 deletions

View File

@ -0,0 +1,41 @@
const recipesService = require('../services/recipes_service');
const recipeUtils = require('../utils/recipe_utils');
/**
* Maneja el comando de recetas.
* @param {Object} client - Instancia del cliente de WhatsApp.
* @param {Object} message - Mensaje recibido.
*/
const handleRecipeCommand = async (client, message) => {
const parts = message.body.trim().split(' ');
const subCommand = parts[0].toLowerCase();
const query = parts.slice(1).join(' ');
try {
let recipe;
if (subCommand === '!receta') {
if (query) {
// Buscar receta por nombre
recipe = await recipesService.searchMealByName(query);
} else {
// Obtener receta aleatoria
recipe = await recipesService.getRandomMeal();
}
const recipeInfo = recipeUtils.formatRecipeInfo(recipe);
await client.sendMessage(message.from, recipeInfo);
console.log(`📤 Información de la receta enviada a ${message.from}`);
} else {
// Manejar otros subcomandos si es necesario
await client.sendMessage(message.from, '❌ Comando no reconocido.');
}
} catch (error) {
console.error('❌ Error al manejar el comando de recetas:', error);
await client.sendMessage(message.from, `❌ Error al obtener la receta: ${error.message}`);
}
};
module.exports = {
handleRecipeCommand
};

View File

@ -0,0 +1,48 @@
const weatherService = require('../services/weather_service');
const weatherUtils = require('../utils/weather_utils');
/**
* Maneja el comando de clima.
* @param {Client} client - Instancia del cliente de WhatsApp.
* @param {Object} message - Mensaje recibido.
*/
const handleWeatherCommand = async (client, message) => {
const parts = message.body.trim().split(' ');
const command = parts[0].toLowerCase();
const city = parts.length > 1 ? parts.slice(1).join(' ') : 'Guatemala';
try {
const { latitude, longitude } = await weatherUtils.getCoordinates(city);
const weather = await weatherService.getWeather(latitude, longitude);
const weatherDescription = weatherUtils.translateWeatherCode(weather.weathercode);
const weatherInfo = formatWeatherInfo(city, weather, weatherDescription);
await client.sendMessage(message.from, weatherInfo);
console.log(`📤 Información del clima de ${city} enviada a ${message.from}`);
} catch (error) {
console.error('❌ Error al obtener el clima:', error);
await client.sendMessage(message.from, `❌ Error al obtener el clima: ${error.message}`);
}
};
/**
* Formatea la información del clima para enviarla como mensaje.
* @param {String} city - Nombre de la ciudad.
* @param {Object} weather - Datos del clima obtenidos del servicio.
* @param {String} weatherDescription - Descripción traducida del código de clima.
* @returns {String} - Mensaje formateado con la información del clima.
*/
const formatWeatherInfo = (city, weather, weatherDescription) => {
return `
🌤 *Clima Actual en ${city}*:
- 🌡 Temperatura: ${weather.temperature}°C
- 💨 Viento: ${weather.windspeed} km/h
- 🧭 Dirección del viento: ${weather.winddirection}°
- Condición: ${weatherDescription}
- Hora: ${new Date(weather.time).toLocaleTimeString('es-ES')}
`.trim();
};
module.exports = {
handleWeatherCommand
};

View File

@ -1,8 +1,12 @@
// index.js
const { Client, LocalAuth } = require('whatsapp-web.js');
const qrcode = require('qrcode-terminal');
const dotenv = require('dotenv');
const weatherUtils = require('./utils/weather_utils');
const weatherService = require('./services/weather_service');
const { handleRecipeCommand } = require('./commands/recipes_command'); // Importar el comando de recetas
const { handleWeatherCommand } = require('./commands/weather_command'); // Importar el comando de clima
// Configuración inicial
dotenv.config();
@ -84,7 +88,9 @@ class WhatsAppBot {
if (command === '!ping') {
await this.handlePingCommand(message);
} else if (command.startsWith('!clima')) {
await this.handleWeatherCommand(message);
await handleWeatherCommand(this.client, message);
} else if (command.startsWith('!receta')) {
await handleRecipeCommand(this.client, message);
}
}
@ -97,35 +103,6 @@ class WhatsAppBot {
}
}
async handleWeatherCommand(message) {
const parts = message.body.split(' ');
const city = parts.length > 1 ? parts.slice(1).join(' ') : 'Guatemala';
try {
const { latitude, longitude } = await weatherUtils.getCoordinates(city);
const weather = await weatherService.getWeather(latitude, longitude);
const weatherDescription = weatherUtils.translateWeatherCode(weather.weathercode);
const weatherInfo = this.formatWeatherInfo(city, weather, weatherDescription);
await this.client.sendMessage(message.from, weatherInfo);
console.log(`📤 Información del clima de ${city} enviada a ${message.from}`);
} catch (error) {
console.error('❌ Error al obtener el clima:', error);
await this.client.sendMessage(message.from, `❌ Error al obtener el clima: ${error.message}`);
}
}
formatWeatherInfo(city, weather, weatherDescription) {
return `
🌤 *Clima Actual en ${city}*:
- 🌡 Temperatura: ${weather.temperature}°C
- 💨 Viento: ${weather.windspeed} km/h
- 🧭 Dirección del viento: ${weather.winddirection}°
- Condición: ${weatherDescription}
- Hora: ${new Date(weather.time).toLocaleTimeString('es-ES')}
`.trim();
}
logMessage(message) {
console.log('📩 Mensaje recibido:', {
from: message.from,

View File

@ -0,0 +1,72 @@
const axios = require('axios');
/**
* Busca una receta por nombre utilizando la API de TheMealDB.
* @param {String} name - Nombre de la receta a buscar.
* @returns {Object} - Objeto de receta encontrado.
* @throws {Error} - Si no se encuentra la receta o hay un error en la solicitud.
*/
const searchMealByName = async (name) => {
try {
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/search.php', {
params: {
s: name
}
});
if (!response.data.meals) {
throw new Error('No se encontraron recetas para tu búsqueda.');
}
return response.data.meals[0]; // Retorna la primera receta encontrada
} catch (error) {
throw new Error(`Error al buscar la receta: ${error.message}`);
}
};
/**
* Obtiene una receta aleatoria utilizando la API de TheMealDB.
* @returns {Object} - Objeto de receta aleatoria.
* @throws {Error} - Si hay un error en la solicitud.
*/
const getRandomMeal = async () => {
try {
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/random.php');
if (!response.data.meals) {
throw new Error('No se pudo obtener una receta aleatoria.');
}
return response.data.meals[0];
} catch (error) {
throw new Error(`Error al obtener una receta aleatoria: ${error.message}`);
}
};
/**
* Filtra recetas por ingrediente principal utilizando la API de TheMealDB.
* @param {String} ingredient - Ingrediente principal para filtrar recetas.
* @returns {Array} - Lista de recetas que contienen el ingrediente especificado.
* @throws {Error} - Si no se encuentran recetas o hay un error en la solicitud.
*/
const filterByIngredient = async (ingredient) => {
try {
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/filter.php', {
params: {
i: ingredient
}
});
if (!response.data.meals) {
throw new Error('No se encontraron recetas con ese ingrediente.');
}
return response.data.meals;
} catch (error) {
throw new Error(`Error al filtrar por ingrediente: ${error.message}`);
}
};
module.exports = {
searchMealByName,
getRandomMeal,
filterByIngredient
};

49
utils/recipe_utils.js Normal file
View File

@ -0,0 +1,49 @@
/**
* Formatea la información de una receta para enviarla como mensaje.
* @param {Object} recipe - Objeto de receta obtenido de TheMealDB.
* @returns {String} - Mensaje formateado con la información de la receta.
*/
const formatRecipeInfo = (recipe) => {
return `
🍽 *${recipe.strMeal}*
📄 *Categoría:* ${recipe.strCategory || 'No disponible'}
🌍 *Área:* ${recipe.strArea || 'No disponible'}
📝 *Instrucciones:*
${recipe.strInstructions || 'No hay instrucciones disponibles.'}
🔗 *Fuente:*
${recipe.strSource || 'No disponible'}
🌐 *Video:*
${recipe.strYoutube || 'No disponible'}
🌐 *Imagen:*
${recipe.strMealThumb}
🛒 *Ingredientes:*
${getIngredientsList(recipe)}
`.trim();
};
/**
* Genera una lista de ingredientes y sus medidas.
* @param {Object} recipe - Objeto de receta obtenido de TheMealDB.
* @returns {String} - Lista formateada de ingredientes.
*/
const getIngredientsList = (recipe) => {
let ingredients = '';
for (let i = 1; i <= 20; i++) {
const ingredient = recipe[`strIngredient${i}`];
const measure = recipe[`strMeasure${i}`];
if (ingredient && ingredient.trim() !== '') {
ingredients += `- ${ingredient} - ${measure}\n`;
}
}
return ingredients || 'No hay ingredientes disponibles.';
};
module.exports = {
formatRecipeInfo
};