avocavo
Version:
Avocavo CLI - Structured nutrition data API with USDA-based calculations where applicable. Consistent nutrition estimates for apps and workflows. For informational use only. Not affiliated with or endorsed by USDA.
256 lines (222 loc) โข 8.95 kB
JavaScript
const chalk = require('chalk');
const { table } = require('table');
function formatNutrition(nutrition) {
if (!nutrition) return chalk.gray('No nutrition data available');
const lines = [];
// Helper function to format a value
const formatValue = (value, unit = '', decimals = 1) => {
if (value === null || value === undefined) {
return chalk.gray('null');
}
return chalk.bold(`${Number(value).toFixed(decimals)}${unit}`);
};
// Main macros - use _total format (API standard) with fallback to simple format
const calories = nutrition.calories_total ?? nutrition.calories;
const protein = nutrition.protein_total ?? nutrition.protein;
const fat = nutrition.total_fat_total ?? nutrition.total_fat;
const carbs = nutrition.carbohydrates_total ?? nutrition.carbohydrates;
const fiber = nutrition.fiber_total ?? nutrition.fiber;
const sugar = nutrition.sugar_total ?? nutrition.sugar;
// Primary nutrients
lines.push(` ๐ฅ Calories: ${formatValue(calories, '', 0)}`);
lines.push(` ๐ฅฉ Protein: ${formatValue(protein, 'g')}`);
lines.push(` ๐ง Total Fat: ${formatValue(fat, 'g')}`);
lines.push(` ๐พ Carbohydrates: ${formatValue(carbs, 'g')}`);
lines.push(` ๐ฟ Fiber: ${formatValue(fiber, 'g')}`);
lines.push(` ๐ฏ Sugar: ${formatValue(sugar, 'g')}`);
// Fat breakdown
lines.push(` ๐ Saturated Fat: ${formatValue(nutrition.saturated_fat, 'g')}`);
lines.push(` ๐ Monounsaturated Fat: ${formatValue(nutrition.monounsaturated_fat, 'g')}`);
lines.push(` ๐ Polyunsaturated Fat: ${formatValue(nutrition.polyunsaturated_fat, 'g')}`);
lines.push(` ๐ Trans Fat: ${formatValue(nutrition.trans_fat, 'g')}`);
lines.push(` ๐ Cholesterol: ${formatValue(nutrition.cholesterol, 'mg')}`);
// Minerals
lines.push(` ๐ง Sodium: ${formatValue(nutrition.sodium, 'mg')}`);
lines.push(` ๐ฆด Calcium: ${formatValue(nutrition.calcium, 'mg')}`);
lines.push(` ๐ฉธ Iron: ${formatValue(nutrition.iron, 'mg')}`);
lines.push(` ๐งฒ Magnesium: ${formatValue(nutrition.magnesium, 'mg')}`);
lines.push(` ๐ฆด Phosphorus: ${formatValue(nutrition.phosphorus, 'mg')}`);
lines.push(` ๐ Potassium: ${formatValue(nutrition.potassium, 'mg')}`);
lines.push(` ๐งฌ Zinc: ${formatValue(nutrition.zinc, 'mg')}`);
lines.push(` ๐งฌ Selenium: ${formatValue(nutrition.selenium, 'ยตg')}`);
// Vitamins
lines.push(` ๐ฅ Vitamin A: ${formatValue(nutrition.vitamin_a, 'ยตg')}`);
lines.push(` ๐ Vitamin C: ${formatValue(nutrition.vitamin_c, 'mg')}`);
lines.push(` โ๏ธ Vitamin D: ${formatValue(nutrition.vitamin_d_iu, 'IU')}`);
lines.push(` ๐ฟ Vitamin E: ${formatValue(nutrition.vitamin_e, 'mg')}`);
lines.push(` ๐ฅฌ Vitamin K: ${formatValue(nutrition.vitamin_k, 'ยตg')}`);
lines.push(` ๐ง Thiamin (B1): ${formatValue(nutrition.thiamin, 'mg')}`);
lines.push(` ๐ง Riboflavin (B2): ${formatValue(nutrition.riboflavin, 'mg')}`);
lines.push(` ๐ง Niacin (B3): ${formatValue(nutrition.niacin, 'mg')}`);
lines.push(` ๐ง Vitamin B6: ${formatValue(nutrition.vitamin_b6, 'mg')}`);
lines.push(` ๐ง Vitamin B12: ${formatValue(nutrition.vitamin_b12, 'ยตg')}`);
lines.push(` ๐งฌ Folate: ${formatValue(nutrition.folate, 'ยตg')}`);
return lines.length > 0 ? lines.join('\n') : chalk.gray('No nutrition data available');
}
function formatPerformanceMetrics(result) {
if (!result) return '';
const lines = [];
// Cache information (remove cache_type from user display)
if (result.metadata?.cached !== undefined || result.from_cache !== undefined) {
const cached = result.metadata?.cached ?? result.from_cache;
const cacheIcon = cached ? 'โก' : '๐';
const cacheText = cached ? 'Cached' : 'Fresh';
lines.push(` ${cacheIcon} Cache: ${chalk.cyan(cacheText)}`);
}
// Processing time
const processingTime = result.metadata?.processing_time_ms ?? result.processing_time_ms;
if (processingTime !== undefined) {
lines.push(` โฑ๏ธ Time: ${formatResponseTime(processingTime)}`);
}
// Method used
if (result.metadata?.method_used) {
const methodIcons = {
'sql_exact': '๐ฏ',
'fuzzy_match': '๐',
'llm_driven_search': '๐ค',
'usda_api_fallback': '๐',
'core_mapping_reuse': '๐พ',
'portion_adjusted': '๐',
'modifier_adjusted_conversion': '๐ง',
'small_measurement_fallback': '๐ค',
'small_measurement': '๐ค'
};
const methodDescriptions = {
'sql_exact': 'Direct USDA match',
'fuzzy_match': 'USDA fuzzy search',
'llm_driven_search': 'Smart USDA matching',
'usda_api_fallback': 'USDA API search',
'core_mapping_reuse': 'Cached USDA match',
'portion_adjusted': 'Size-adjusted USDA match',
'modifier_adjusted_conversion': 'Modified USDA match',
'small_measurement_fallback': 'Small portion USDA match',
'small_measurement': 'Micro portion USDA match'
};
const icon = methodIcons[result.metadata.method_used] || '๐ง';
lines.push(` ${icon} Method: ${chalk.blue(result.metadata.method_used)}`);
}
// Parsing tier information
if (result.metadata?.portion_source) {
const tierIcons = {
'tier_1_exact': '1๏ธโฃ',
'tier_2_fuzzy': '2๏ธโฃ',
'tier_3_adjusted': '3๏ธโฃ',
'tier_4_with_modifier': '4๏ธโฃ',
'tier_5_generic': '5๏ธโฃ',
'tier_6_small_measurement': '6๏ธโฃ',
'tier_7_semantic_match': '7๏ธโฃ'
};
const tierIcon = tierIcons[result.metadata.portion_source] || '๐ข';
lines.push(` ${tierIcon} Tier: ${chalk.green(result.metadata.portion_source)}`);
}
// Parsing details
if (result.parsing?.estimated_grams || result.estimated_grams) {
const grams = result.parsing?.estimated_grams ?? result.estimated_grams;
lines.push(` โ๏ธ Weight: ${chalk.magenta(grams + 'g')}`);
}
return lines.length > 0 ? '\n' + chalk.gray('Performance:') + '\n' + lines.join('\n') : '';
}
function formatUSDAMatch(usda, verificationUrl) {
if (!usda) return '';
const lines = [];
lines.push(` ๐ Description: ${chalk.cyan(usda.description)}`);
lines.push(` ๐ข FDC ID: ${chalk.yellow(usda.fdc_id)}`);
lines.push(` ๐ Data Type: ${chalk.blue(usda.data_type)}`);
if (verificationUrl) {
lines.push(` ๐ Verify: ${chalk.underline(verificationUrl)}`);
}
return '\n' + chalk.gray('USDA Source:') + '\n' + lines.join('\n');
}
function formatTable(data, options = {}) {
const config = {
border: {
topBody: 'โ',
topJoin: 'โฌ',
topLeft: 'โ',
topRight: 'โ',
bottomBody: 'โ',
bottomJoin: 'โด',
bottomLeft: 'โ',
bottomRight: 'โ',
bodyLeft: 'โ',
bodyRight: 'โ',
bodyJoin: 'โ',
joinBody: 'โ',
joinLeft: 'โ',
joinRight: 'โค',
joinJoin: 'โผ'
},
drawHorizontalLine: (index, size) => {
return index === 0 || index === 1 || index === size;
},
...options
};
return table(data, config);
}
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function formatDuration(ms) {
if (ms < 1000) {
return `${ms.toFixed(1)}ms`;
} else if (ms < 60000) {
return `${(ms / 1000).toFixed(1)}s`;
} else {
const minutes = Math.floor(ms / 60000);
const seconds = ((ms % 60000) / 1000).toFixed(1);
return `${minutes}m ${seconds}s`;
}
}
function formatPercentage(value, total) {
if (!total || total === 0) return '0%';
return `${((value / total) * 100).toFixed(1)}%`;
}
function formatUsage(current, limit) {
if (!limit) return `${current.toLocaleString()}`;
const percentage = (current / limit) * 100;
const color = percentage > 90 ? chalk.red : percentage > 75 ? chalk.yellow : chalk.green;
return `${color(current.toLocaleString())}/${limit.toLocaleString()} (${percentage.toFixed(1)}%)`;
}
function formatResponseTime(ms) {
if (ms < 100) {
return chalk.green(`${ms.toFixed(1)}ms`);
} else if (ms < 300) {
return chalk.yellow(`${ms.toFixed(1)}ms`);
} else {
return chalk.red(`${ms.toFixed(1)}ms`);
}
}
function formatStatus(status) {
switch (status.toLowerCase()) {
case 'ok':
case 'available':
case 'active':
case 'success':
return chalk.green(status);
case 'degraded':
case 'warning':
return chalk.yellow(status);
case 'error':
case 'failed':
case 'unavailable':
return chalk.red(status);
default:
return chalk.gray(status);
}
}
module.exports = {
formatNutrition,
formatPerformanceMetrics,
formatUSDAMatch,
formatTable,
formatBytes,
formatDuration,
formatPercentage,
formatUsage,
formatResponseTime,
formatStatus
};