Add translation functionality for recipe instructions and enhance recipe search logic
This commit is contained in:
parent
7237ffb567
commit
71dbf28481
@ -2,6 +2,7 @@ const axios = require('axios');
|
|||||||
const { MessageMedia } = require('whatsapp-web.js');
|
const { MessageMedia } = require('whatsapp-web.js');
|
||||||
const recipesService = require('../services/recipes_service');
|
const recipesService = require('../services/recipes_service');
|
||||||
const recipeUtils = require('../utils/recipe_utils');
|
const recipeUtils = require('../utils/recipe_utils');
|
||||||
|
const { translateText } = require('../plugins/translator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selecciona una receta aleatoria de una lista.
|
* Selecciona una receta aleatoria de una lista.
|
||||||
@ -70,7 +71,12 @@ const handleRecipeCommand = async (client, message) => {
|
|||||||
throw new Error('No se encontraron recetas para tu búsqueda.');
|
throw new Error('No se encontraron recetas para tu búsqueda.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipeInfo = recipeUtils.formatRecipeInfo(recipe);
|
// Traducir instrucciones al español antes de formatear la información
|
||||||
|
const instructions = recipe.strInstructions
|
||||||
|
? await translateText(recipe.strInstructions, 'es')
|
||||||
|
: 'No hay instrucciones disponibles.';
|
||||||
|
|
||||||
|
const recipeInfo = await recipeUtils.formatRecipeInfo({ ...recipe, strInstructions: instructions });
|
||||||
|
|
||||||
// Descargar la imagen de la receta
|
// Descargar la imagen de la receta
|
||||||
const imageUrl = recipe.strMealThumb;
|
const imageUrl = recipe.strMealThumb;
|
||||||
@ -92,4 +98,4 @@ const handleRecipeCommand = async (client, message) => {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
handleRecipeCommand
|
handleRecipeCommand
|
||||||
};
|
};
|
||||||
|
13
index.js
13
index.js
@ -5,6 +5,7 @@ const qrcode = require('qrcode-terminal');
|
|||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv');
|
||||||
const weatherUtils = require('./utils/weather_utils');
|
const weatherUtils = require('./utils/weather_utils');
|
||||||
const weatherService = require('./services/weather_service');
|
const weatherService = require('./services/weather_service');
|
||||||
|
const logger = require('./utils/logger');
|
||||||
const { handleRecipeCommand } = require('./commands/recipes_command'); // Importar el comando de recetas
|
const { handleRecipeCommand } = require('./commands/recipes_command'); // Importar el comando de recetas
|
||||||
const { handleWeatherCommand } = require('./commands/weather_command'); // Importar el comando de clima
|
const { handleWeatherCommand } = require('./commands/weather_command'); // Importar el comando de clima
|
||||||
|
|
||||||
@ -49,20 +50,20 @@ class WhatsAppBot {
|
|||||||
|
|
||||||
handleQR(qr) {
|
handleQR(qr) {
|
||||||
qrcode.generate(qr, { small: true });
|
qrcode.generate(qr, { small: true });
|
||||||
console.log('🔍 Escanea el QR code con tu WhatsApp.');
|
logger.info('🔍 Escanea el QR code con tu WhatsApp.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleReady() {
|
async handleReady() {
|
||||||
console.log('✅ Cliente de WhatsApp está listo!');
|
logger.info('✅ Cliente de WhatsApp está listo!');
|
||||||
try {
|
try {
|
||||||
this.myId = this.client.info.wid._serialized;
|
this.myId = this.client.info.wid._serialized;
|
||||||
this.myNumber = this.myId.split('@')[0];
|
this.myNumber = this.myId.split('@')[0];
|
||||||
console.log(`🔑 Tu ID de WhatsApp es: ${this.myId}`);
|
logger.info(`🔑 Tu ID de WhatsApp es: ${this.myId}`);
|
||||||
console.log(`📱 Tu número de teléfono es: ${this.myNumber}`);
|
logger.info(`📱 Tu número de teléfono es: ${this.myNumber}`);
|
||||||
const chat = await this.client.getChatById(this.myId);
|
const chat = await this.client.getChatById(this.myId);
|
||||||
console.log('💭 Chat propio encontrado:', chat);
|
logger.info(`💭 Chat propio encontrado: ${JSON.stringify(chat, null, 2)}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Error al obtener información: ${error}`);
|
logger.error(`❌ Error al obtener información: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
plugins/translator.js
Normal file
45
plugins/translator.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const dotenv = require('dotenv');
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const apiKey = process.env.GOOGLE_GEMINI_API_KEY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traduce un texto utilizando la API de Google Gemini.
|
||||||
|
* @param {String} text - Texto a traducir.
|
||||||
|
* @param {String} targetLang - Idioma de destino, 'es' para español.
|
||||||
|
* @returns {Promise<String>} - Texto traducido.
|
||||||
|
*/
|
||||||
|
const translateText = async (text, targetLang = 'es') => {
|
||||||
|
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`;
|
||||||
|
|
||||||
|
// 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}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
contents: [{ parts: [{ text: prompt }] }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Respuesta de la API de traducción:', response.data);
|
||||||
|
console.log('Texto original:', text);
|
||||||
|
|
||||||
|
// Extrae el texto traducido de la respuesta
|
||||||
|
const translatedText = response.data.candidates[0].content.parts[0].text;
|
||||||
|
return translatedText;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error al traducir el texto:', JSON.stringify(error.response?.data, null, 2));
|
||||||
|
return text; // Devuelve el texto original en caso de error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
translateText
|
||||||
|
};
|
@ -1,25 +1,59 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Busca recetas por nombre utilizando la API de TheMealDB.
|
* Realiza una búsqueda de recetas usando combinaciones de palabras.
|
||||||
* @param {String} name - Nombre de la receta a buscar.
|
* @param {String} name - Nombre de la receta a buscar.
|
||||||
* @returns {Array} - Lista de recetas encontradas.
|
* @returns {Array} - Lista de recetas encontradas.
|
||||||
* @throws {Error} - Si no se encuentran recetas o hay un error en la solicitud.
|
* @throws {Error} - Si no se encuentran recetas o hay un error en la solicitud.
|
||||||
*/
|
*/
|
||||||
const searchMealByName = async (name) => {
|
const searchMealByName = async (name) => {
|
||||||
|
const words = name.split(' ');
|
||||||
|
let recipes = [];
|
||||||
|
|
||||||
|
// Intenta la búsqueda completa primero
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/search.php', {
|
recipes = await performSearch(name);
|
||||||
params: { s: name }
|
if (recipes.length > 0) return recipes;
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.data.meals) {
|
|
||||||
throw new Error('No se encontraron recetas para tu búsqueda.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.data.meals; // Devuelve todas las recetas encontradas
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Error al buscar la receta: ${error.message}`);
|
console.log(`No se encontraron recetas para "${name}", probando combinaciones...`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si no encuentra con el nombre completo, intenta con combinaciones
|
||||||
|
for (let i = 0; i < words.length; i++) {
|
||||||
|
const partialName = words.slice(i).join(' ');
|
||||||
|
try {
|
||||||
|
recipes = await performSearch(partialName);
|
||||||
|
if (recipes.length > 0) return recipes;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`No se encontraron recetas para "${partialName}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no encuentra nada, intenta con cada palabra individualmente
|
||||||
|
for (const word of words) {
|
||||||
|
try {
|
||||||
|
recipes = await performSearch(word);
|
||||||
|
if (recipes.length > 0) return recipes;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`No se encontraron recetas para "${word}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no se encontraron resultados, lanza un error
|
||||||
|
throw new Error('No se encontraron recetas para tu búsqueda.');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realiza la búsqueda en la API de TheMealDB.
|
||||||
|
* @param {String} query - Consulta de búsqueda.
|
||||||
|
* @returns {Array} - Lista de recetas encontradas.
|
||||||
|
*/
|
||||||
|
const performSearch = async (query) => {
|
||||||
|
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/search.php', { params: { s: query } });
|
||||||
|
// console.log('Request URL:', response.config.url);
|
||||||
|
// console.log('Response:', response.data);
|
||||||
|
|
||||||
|
return response.data.meals || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +64,7 @@ const searchMealByName = async (name) => {
|
|||||||
const getRandomMeal = async () => {
|
const getRandomMeal = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/random.php');
|
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/random.php');
|
||||||
|
|
||||||
if (!response.data.meals) {
|
if (!response.data.meals) {
|
||||||
throw new Error('No se pudo obtener una receta aleatoria.');
|
throw new Error('No se pudo obtener una receta aleatoria.');
|
||||||
}
|
}
|
||||||
@ -48,15 +83,11 @@ const getRandomMeal = async () => {
|
|||||||
const filterByIngredient = async (ingredient) => {
|
const filterByIngredient = async (ingredient) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/filter.php', {
|
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/filter.php', {
|
||||||
params: {
|
params: { i: ingredient }
|
||||||
i: ingredient
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.data.meals) {
|
if (!response.data.meals) {
|
||||||
throw new Error('No se encontraron recetas con ese ingrediente.');
|
throw new Error('No se encontraron recetas con ese ingrediente.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.data.meals;
|
return response.data.meals;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Error al filtrar por ingrediente: ${error.message}`);
|
throw new Error(`Error al filtrar por ingrediente: ${error.message}`);
|
||||||
@ -75,10 +106,7 @@ const healthyCategories = ['Salad', 'Chicken', 'Eggs', 'Fish', 'Seafood', 'Pasta
|
|||||||
*/
|
*/
|
||||||
const getRandomHealthyMeal = async () => {
|
const getRandomHealthyMeal = async () => {
|
||||||
try {
|
try {
|
||||||
// Escoge una categoría saludable al azar
|
|
||||||
const randomCategory = healthyCategories[Math.floor(Math.random() * healthyCategories.length)];
|
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', {
|
const response = await axios.get('https://www.themealdb.com/api/json/v1/1/filter.php', {
|
||||||
params: { c: randomCategory }
|
params: { c: randomCategory }
|
||||||
});
|
});
|
||||||
@ -87,7 +115,6 @@ const getRandomHealthyMeal = async () => {
|
|||||||
throw new Error('No se encontraron recetas saludables.');
|
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)];
|
const randomMeal = response.data.meals[Math.floor(Math.random() * response.data.meals.length)];
|
||||||
return await lookupMealById(randomMeal.idMeal);
|
return await lookupMealById(randomMeal.idMeal);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -118,4 +145,4 @@ module.exports = {
|
|||||||
filterByIngredient,
|
filterByIngredient,
|
||||||
getRandomHealthyMeal,
|
getRandomHealthyMeal,
|
||||||
lookupMealById
|
lookupMealById
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
|
const { translateText } = require('../plugins/translator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formatea la información de una receta para enviarla como mensaje.
|
* Formatea la información de una receta para enviarla como mensaje.
|
||||||
* @param {Object} recipe - Objeto de receta obtenido de TheMealDB.
|
* @param {Object} recipe - Objeto de receta obtenido de TheMealDB.
|
||||||
* @returns {String} - Mensaje formateado con la información de la receta.
|
* @returns {String} - Mensaje formateado con la información de la receta.
|
||||||
*/
|
*/
|
||||||
const formatRecipeInfo = (recipe) => {
|
const formatRecipeInfo = async (recipe) => {
|
||||||
|
// Traducir instrucciones de la receta
|
||||||
|
const instructions = recipe.strInstructions
|
||||||
|
? await translateText(recipe.strInstructions, 'es')
|
||||||
|
: 'No hay instrucciones disponibles.';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
🍽️ *${recipe.strMeal}*
|
🍽️ *${recipe.strMeal}*
|
||||||
|
|
||||||
@ -11,7 +18,7 @@ const formatRecipeInfo = (recipe) => {
|
|||||||
🌍 *Área:* ${recipe.strArea || 'No disponible'}
|
🌍 *Área:* ${recipe.strArea || 'No disponible'}
|
||||||
|
|
||||||
📝 *Instrucciones:*
|
📝 *Instrucciones:*
|
||||||
${recipe.strInstructions || 'No hay instrucciones disponibles.'}
|
${instructions}
|
||||||
|
|
||||||
🔗 *Fuente:*
|
🔗 *Fuente:*
|
||||||
${recipe.strSource || 'No disponible'}
|
${recipe.strSource || 'No disponible'}
|
||||||
@ -46,4 +53,4 @@ const getIngredientsList = (recipe) => {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
formatRecipeInfo
|
formatRecipeInfo
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user