diff --git a/commands/recipes_command.js b/commands/recipes_command.js index 44542fb..386a973 100644 --- a/commands/recipes_command.js +++ b/commands/recipes_command.js @@ -1,6 +1,49 @@ +const axios = require('axios'); +const { MessageMedia } = require('whatsapp-web.js'); const recipesService = require('../services/recipes_service'); const recipeUtils = require('../utils/recipe_utils'); +/** + * Selecciona una receta aleatoria de una lista. + * @param {Array} recipes - Lista de recetas. + * @returns {Object} - Una receta aleatoria de la lista. + */ +const getRandomRecipe = (recipes) => { + return recipes[Math.floor(Math.random() * recipes.length)]; +}; + +/** + * Realiza una búsqueda flexible utilizando varias estrategias. + * @param {String} query - La consulta de búsqueda introducida por el usuario. + * @returns {Object|null} - Objeto de receta encontrado o null si no hay coincidencias. + */ +const flexibleSearch = async (query) => { + const words = query.split(' '); + let recipes; + + // 1. Intentar búsqueda exacta + recipes = await recipesService.searchMealByName(query); + if (recipes && recipes.length > 0) return getRandomRecipe(recipes); + + // 2. Intentar con palabras clave parciales + for (let i = words.length; i > 0; i--) { + const partialQuery = words.slice(0, i).join(' '); + recipes = await recipesService.searchMealByName(partialQuery); + if (recipes && recipes.length > 0) return getRandomRecipe(recipes); + } + + // 3. Intentar con cada palabra como filtro de ingrediente + for (const word of words) { + recipes = await recipesService.filterByIngredient(word); + if (recipes && recipes.length > 0) { + const randomRecipe = await recipesService.lookupMealById(getRandomRecipe(recipes).idMeal); + if (randomRecipe) return randomRecipe; + } + } + + return null; +}; + /** * Maneja el comando de recetas. * @param {Object} client - Instancia del cliente de WhatsApp. @@ -15,19 +58,30 @@ const handleRecipeCommand = async (client, message) => { let recipe; if (subCommand === '!receta') { - if (query) { - // Buscar receta por nombre - recipe = await recipesService.searchMealByName(query); + if (query === 'saludable') { + recipe = await recipesService.getRandomHealthyMeal(); + } else if (query) { + recipe = await flexibleSearch(query); } else { - // Obtener receta aleatoria recipe = await recipesService.getRandomMeal(); } + if (!recipe) { + throw new Error('No se encontraron recetas para tu búsqueda.'); + } + const recipeInfo = recipeUtils.formatRecipeInfo(recipe); - await client.sendMessage(message.from, recipeInfo); + + // Descargar la imagen de la receta + const imageUrl = recipe.strMealThumb; + const response = await axios.get(imageUrl, { responseType: 'arraybuffer' }); + const imageBase64 = Buffer.from(response.data, 'binary').toString('base64'); + const media = new MessageMedia('image/jpeg', imageBase64, 'receta.jpg'); + + // Enviar la imagen con la información de la receta como leyenda + await client.sendMessage(message.from, media, { caption: 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) { diff --git a/services/recipes_service.js b/services/recipes_service.js index f12658f..7c10c05 100644 --- a/services/recipes_service.js +++ b/services/recipes_service.js @@ -1,24 +1,22 @@ const axios = require('axios'); /** - * Busca una receta por nombre utilizando la API de TheMealDB. + * Busca recetas 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. + * @returns {Array} - Lista de recetas encontradas. + * @throws {Error} - Si no se encuentran recetas 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 - } + 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 + return response.data.meals; // Devuelve todas las recetas encontradas } catch (error) { throw new Error(`Error al buscar la receta: ${error.message}`); } @@ -65,8 +63,59 @@ const filterByIngredient = async (ingredient) => { } }; +/* +* Categorías saludables para filtrar recetas. +*/ +const healthyCategories = ['Salad', 'Chicken', 'Eggs', 'Fish', 'Seafood', 'Pasta', 'Rice', 'Beef', 'Pork', 'Lamb']; + +/** + * Obtiene una receta aleatoria de categorías saludables. + * @returns {Object} - Objeto de receta aleatoria saludable. + * @throws {Error} - Si no se encuentra una receta o hay un error en la solicitud. + */ +const getRandomHealthyMeal = async () => { + try { + // Escoge una categoría saludable al azar + const randomCategory = healthyCategories[Math.floor(Math.random() * healthyCategories.length)]; + + // Filtra las recetas por la categoría saludable seleccionada + const response = await axios.get('https://www.themealdb.com/api/json/v1/1/filter.php', { + params: { c: randomCategory } + }); + + if (!response.data.meals || response.data.meals.length === 0) { + throw new Error('No se encontraron recetas saludables.'); + } + + // Escoge una receta aleatoria dentro de las recetas saludables + const randomMeal = response.data.meals[Math.floor(Math.random() * response.data.meals.length)]; + return await lookupMealById(randomMeal.idMeal); + } catch (error) { + throw new Error(`Error al obtener una receta saludable: ${error.message}`); + } +}; + +/** + * Busca los detalles completos de una receta por ID. + * @param {String} id - ID de la receta. + * @returns {Object} - Objeto de receta con detalles completos. + */ +const lookupMealById = async (id) => { + try { + const response = await axios.get(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${id}`); + if (!response.data.meals) { + throw new Error('No se encontraron detalles para la receta.'); + } + return response.data.meals[0]; + } catch (error) { + throw new Error(`Error al obtener detalles de la receta: ${error.message}`); + } +}; + module.exports = { searchMealByName, getRandomMeal, - filterByIngredient -}; + filterByIngredient, + getRandomHealthyMeal, + lookupMealById +}; \ No newline at end of file