118 lines
4.2 KiB
JavaScript
118 lines
4.2 KiB
JavaScript
|
// MacroPlanner.js
|
||
|
// Node.js script skeleton for meal planning + nutritional analysis pipeline using USDA FoodData Central
|
||
|
|
||
|
const fs = require('fs');
|
||
|
const xlsx = require('xlsx');
|
||
|
const axios = require('axios');
|
||
|
require('dotenv').config();
|
||
|
|
||
|
// === CONFIG ===
|
||
|
const EXCEL_FILE = 'plantilla_plan_comidas.xlsx';
|
||
|
const SHEET_NAME = 'Semana 1';
|
||
|
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
||
|
const USDA_API_KEY = process.env.USDA_API_KEY;
|
||
|
|
||
|
// === STEP 1: Load Excel and parse meals ===
|
||
|
function parseMealsFromExcel(filePath, sheetName) {
|
||
|
const workbook = xlsx.readFile(filePath);
|
||
|
const sheet = workbook.Sheets[sheetName];
|
||
|
const json = xlsx.utils.sheet_to_json(sheet, { defval: '' });
|
||
|
return json.map(row => ({
|
||
|
dia: row['Día'],
|
||
|
desayuno: row['Desayuno'],
|
||
|
comida: row['Comida'],
|
||
|
cena: row['Cena']
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
// === STEP 2: Call ChatGPT to extract ingredients ===
|
||
|
async function getIngredientsFromMeal(description) {
|
||
|
const prompt = `Extrae los ingredientes clave con cantidades aproximadas de esta comida: "${description}". Devuélvelo como lista en JSON con nombre y cantidad.`;
|
||
|
|
||
|
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
|
||
|
model: 'gpt-4',
|
||
|
messages: [{ role: 'user', content: prompt }],
|
||
|
temperature: 0.2
|
||
|
}, {
|
||
|
headers: { 'Authorization': `Bearer ${OPENAI_API_KEY}` }
|
||
|
});
|
||
|
|
||
|
const text = response.data.choices[0].message.content;
|
||
|
return JSON.parse(text);
|
||
|
}
|
||
|
|
||
|
// === STEP 3: Use USDA API to get nutrient info ===
|
||
|
async function getNutritionFromIngredients(ingredients) {
|
||
|
let totals = { protein: 0, carbs: 0, fat: 0 };
|
||
|
|
||
|
for (const item of ingredients) {
|
||
|
try {
|
||
|
const searchRes = await axios.get(`https://api.nal.usda.gov/fdc/v1/foods/search`, {
|
||
|
params: {
|
||
|
api_key: USDA_API_KEY,
|
||
|
query: item.nombre,
|
||
|
pageSize: 1
|
||
|
}
|
||
|
});
|
||
|
|
||
|
const food = searchRes.data.foods[0];
|
||
|
if (!food || !food.fdcId) continue;
|
||
|
|
||
|
const foodRes = await axios.get(`https://api.nal.usda.gov/fdc/v1/food/${food.fdcId}`, {
|
||
|
params: { api_key: USDA_API_KEY }
|
||
|
});
|
||
|
|
||
|
for (const nutrient of foodRes.data.foodNutrients) {
|
||
|
if (nutrient.nutrientName === 'Protein') totals.protein += nutrient.value;
|
||
|
if (nutrient.nutrientName === 'Carbohydrate, by difference') totals.carbs += nutrient.value;
|
||
|
if (nutrient.nutrientName === 'Total lipid (fat)') totals.fat += nutrient.value;
|
||
|
}
|
||
|
} catch (error) {
|
||
|
console.warn(`Error retrieving data for ingredient: ${item.nombre}`, error.message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return totals;
|
||
|
}
|
||
|
|
||
|
// === STEP 4: Combine and write back to Excel ===
|
||
|
async function processAndWriteBack() {
|
||
|
const meals = parseMealsFromExcel(EXCEL_FILE, SHEET_NAME);
|
||
|
const updatedMeals = [];
|
||
|
|
||
|
for (const entry of meals) {
|
||
|
const daySummary = { ...entry, protein: 0, carbs: 0, fat: 0 };
|
||
|
|
||
|
for (const meal of ['desayuno', 'comida', 'cena']) {
|
||
|
if (!entry[meal]) continue;
|
||
|
try {
|
||
|
const ingredients = await getIngredientsFromMeal(entry[meal]);
|
||
|
const macros = await getNutritionFromIngredients(ingredients);
|
||
|
daySummary.protein += macros.protein;
|
||
|
daySummary.carbs += macros.carbs;
|
||
|
daySummary.fat += macros.fat;
|
||
|
} catch (err) {
|
||
|
console.error(`Error processing ${entry.dia} - ${meal}:`, err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
updatedMeals.push({
|
||
|
'Día': daySummary.dia,
|
||
|
'Desayuno': entry.desayuno,
|
||
|
'Comida': entry.comida,
|
||
|
'Cena': entry.cena,
|
||
|
'Proteínas (g)': daySummary.protein.toFixed(1),
|
||
|
'Carbohidratos (g)': daySummary.carbs.toFixed(1),
|
||
|
'Grasas (g)': daySummary.fat.toFixed(1)
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const newSheet = xlsx.utils.json_to_sheet(updatedMeals);
|
||
|
const newBook = xlsx.utils.book_new();
|
||
|
xlsx.utils.book_append_sheet(newBook, newSheet, SHEET_NAME);
|
||
|
xlsx.writeFile(newBook, 'resultado_macros.xlsx');
|
||
|
console.log('Macros calculados y archivo actualizado: resultado_macros.xlsx');
|
||
|
}
|
||
|
|
||
|
processAndWriteBack();
|