avocavo 1.1.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +2 -2
- package/bin/avocavo.js +85 -0
- package/lib/api.js +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the Avocavo CLI will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.1] - 2026-03-31
|
|
6
|
+
|
|
7
|
+
### ✨ Conversational Text Analysis
|
|
8
|
+
- **NEW**: Added `avocavo analyze <text>` command to seamlessly parse free-form, conversational meal text.
|
|
9
|
+
- **ENHANCED**: Implemented GPT-backed context inference to automatically resolve missing quantities (e.g., "butter" -> "1 pat butter") instead of reverting to 100g defaults.
|
|
10
|
+
- **IMPROVED**: Standardized JSON output structure to match the `/batch` endpoint schema for unified downstream processing.
|
|
11
|
+
|
|
5
12
|
## [1.1.1] - 2025-08-21
|
|
6
13
|
|
|
7
14
|
### ✨ UPC/Barcode Search Support
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ avocavo --help
|
|
|
27
27
|
- 🥗 **USDA Database** - Access to comprehensive nutrition data
|
|
28
28
|
- 🧮 **Batch Analysis** - Analyze multiple ingredients at once
|
|
29
29
|
- 📊 **Rich Output** - Beautiful tables and JSON formats
|
|
30
|
-
- 🔒 **SSL Security** - All connections use
|
|
30
|
+
- 🔒 **SSL Security** - All connections use secured HTTPS
|
|
31
31
|
|
|
32
32
|
## 📦 Installation
|
|
33
33
|
|
|
@@ -97,7 +97,7 @@ Remove stored credentials.
|
|
|
97
97
|
|
|
98
98
|
## 🔒 Security
|
|
99
99
|
|
|
100
|
-
- **SSL Verification**: All API calls use
|
|
100
|
+
- **SSL Verification**: All API calls use secured HTTPS connections
|
|
101
101
|
- **Secure Storage**: Credentials stored in system keychain (not plaintext)
|
|
102
102
|
- **OAuth Flow**: Secure browser-based authentication
|
|
103
103
|
- **No Hardcoded Secrets**: All sensitive data handled securely
|
package/bin/avocavo.js
CHANGED
|
@@ -663,6 +663,91 @@ program
|
|
|
663
663
|
}
|
|
664
664
|
});
|
|
665
665
|
|
|
666
|
+
// Free-text analyze command
|
|
667
|
+
program
|
|
668
|
+
.command('analyze <text>')
|
|
669
|
+
.description('Analyze free-form meal text — AI extracts and looks up each ingredient automatically')
|
|
670
|
+
.option('--verbose', 'Show detailed USDA info for each ingredient')
|
|
671
|
+
.action(async (text, options) => {
|
|
672
|
+
try {
|
|
673
|
+
const api = await getApiClient();
|
|
674
|
+
const globalOpts = program.opts();
|
|
675
|
+
const verbose = options.verbose || globalOpts.verbose;
|
|
676
|
+
|
|
677
|
+
console.log(chalk.cyan(`🤖 Analyzing: "${text}"...`));
|
|
678
|
+
|
|
679
|
+
const result = await api.analyzeText(text, verbose);
|
|
680
|
+
|
|
681
|
+
if (program.opts().json) {
|
|
682
|
+
console.log(JSON.stringify(result, null, 2));
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (result.success) {
|
|
687
|
+
// Show what the AI extracted
|
|
688
|
+
const extracted = result.extracted_ingredients || [];
|
|
689
|
+
if (extracted.length > 0) {
|
|
690
|
+
console.log('');
|
|
691
|
+
console.log(chalk.bold('🔍 Detected ingredients:'));
|
|
692
|
+
extracted.forEach(ing => console.log(chalk.gray(` • ${ing}`)));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
console.log('');
|
|
696
|
+
console.log(chalk.green(`✅ Analysis complete — ${result.summary.successful}/${result.batch_size || extracted.length} items matched`));
|
|
697
|
+
console.log('');
|
|
698
|
+
|
|
699
|
+
// Results table (same style as batch)
|
|
700
|
+
const tableData = (result.results || []).map(item => [
|
|
701
|
+
item.success ? '✅' : '❌',
|
|
702
|
+
item.ingredient,
|
|
703
|
+
item.success ? `${item.nutrition.calories}` : 'N/A',
|
|
704
|
+
item.success ? `${item.nutrition.protein}g` : 'N/A',
|
|
705
|
+
item.success ? `${item.nutrition.total_fat}g` : 'N/A',
|
|
706
|
+
item.success ? `${item.nutrition.carbohydrates}g` : 'N/A',
|
|
707
|
+
item.success ? `${item.nutrition.fiber}g` : 'N/A',
|
|
708
|
+
item.success ? `${item.nutrition.sodium}mg` : 'N/A'
|
|
709
|
+
]);
|
|
710
|
+
|
|
711
|
+
if (tableData.length > 0) {
|
|
712
|
+
console.log(formatTable([
|
|
713
|
+
['Status', 'Ingredient', 'Calories', 'Protein', 'Fat', 'Carbs', 'Fiber', 'Sodium'],
|
|
714
|
+
...tableData
|
|
715
|
+
]));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Total calories summary
|
|
719
|
+
const totalCal = (result.results || [])
|
|
720
|
+
.filter(i => i.success)
|
|
721
|
+
.reduce((sum, i) => sum + (i.nutrition?.calories || 0), 0);
|
|
722
|
+
if (totalCal > 0) {
|
|
723
|
+
console.log('');
|
|
724
|
+
console.log(chalk.bold(`🔥 Total Calories: ${chalk.yellow(totalCal.toFixed(1))} kcal`));
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// USDA sources (with --verbose)
|
|
728
|
+
if (verbose) {
|
|
729
|
+
const withUSDA = (result.results || []).filter(i => i.success && i.metadata?.usda_match);
|
|
730
|
+
if (withUSDA.length > 0) {
|
|
731
|
+
console.log('');
|
|
732
|
+
console.log(chalk.bold('🔗 USDA Sources:'));
|
|
733
|
+
withUSDA.forEach(item => {
|
|
734
|
+
const usda = item.metadata.usda_match;
|
|
735
|
+
console.log(chalk.gray(` ${item.ingredient} → ${usda.description} (FDC: ${usda.fdc_id})`));
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
} else {
|
|
741
|
+
console.log(chalk.red(`❌ ${result.error || 'Analysis failed'}`));
|
|
742
|
+
console.log(chalk.cyan('💡 Try rephrasing or use: avocavo batch --ingredients "item1" "item2"'));
|
|
743
|
+
process.exit(1);
|
|
744
|
+
}
|
|
745
|
+
} catch (error) {
|
|
746
|
+
console.error(chalk.red(`❌ Analyze error: ${error.message}`));
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
|
|
666
751
|
// UPC/Barcode search command
|
|
667
752
|
program
|
|
668
753
|
.command('upc <upc>')
|
package/lib/api.js
CHANGED
|
@@ -41,6 +41,17 @@ class NutritionAPI {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
async analyzeText(text, verbose = false) {
|
|
45
|
+
try {
|
|
46
|
+
const response = await this.client.post(`${this.baseUrl}/api/v2/nutrition/analyze`, {
|
|
47
|
+
text: text
|
|
48
|
+
});
|
|
49
|
+
return response.data;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw this.handleError(error);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
async analyzeRecipe(ingredients, servings = 1, verbose = false) {
|
|
45
56
|
try {
|
|
46
57
|
const response = await this.client.post(`${this.baseUrl}/api/v2/nutrition/recipe`, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "avocavo",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|