Add recipes, images, AI photo ID, barcode scanning & ingredient matching

- Fuzzy ingredient matching for bar inventory against recipes
- AI photo identification API for bottles/labels (drink + bar context)
- Barcode scanner with photo toggle for My Bar
- Barcode scan + photo ID buttons on Add Drink form
- Auto-pull product images from Open Food Facts barcode lookup
- Recipes section on drink detail pages with bar availability
- Dedicated Recipes page in sidebar navigation
- Bar item image support (schema, upload, display)
- Drink detail image upload component
- MinIO image proxy through Next.js rewrites (fixes broken image links)
- Improved category mapping (energy drinks → Mixers, not Spirits)
- Re-process saved recipe ingredients against current bar inventory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
JP Scott
2026-03-04 22:26:17 -07:00
parent 2ac2c4b2d4
commit dc1ad4d0c0
36 changed files with 1892 additions and 144 deletions

View File

@@ -183,7 +183,14 @@ Create a recipe for the requested cocktail. Return a valid JSON object:
- "glassware" (string, optional): Recommended glass
- "notes" (string, optional): Tips, variations, or history
Mark ingredients available:true only if matching item exists in bar inventory. Do not include text before or after the JSON.`
Mark ingredients available:true if a matching item exists in bar inventory.
When checking availability, match flexibly:
- Ignore brand names — "Angostura Aromatic Bitters" matches "Angostura bitters" or just "bitters"
- Match the core ingredient identity — "simple syrup" matches "Simple Syrup", "bourbon" matches "Maker's Mark Bourbon"
- If the bar inventory lists a specific brand/product that IS the ingredient type, mark it available
- Be generous — if the user clearly has something that serves the same purpose, mark it available
Do not include text before or after the JSON.`
export const WHAT_CAN_I_MAKE_PROMPT = `You are an expert bartender. Based on the user's bar inventory, suggest cocktails they can make.
@@ -201,7 +208,14 @@ Return a valid JSON array of objects:
- "glassware" (string, optional)
- "missingCount" (number): How many ingredients missing (0 = can make now)
Sort by missingCount ascending. Return up to 10. Do not include text before or after the JSON.`
Sort by missingCount ascending. Return up to 10.
When checking availability, match flexibly:
- Ignore brand names — "Angostura Aromatic Bitters" matches "Angostura bitters" or just "bitters"
- Match the core ingredient identity — "simple syrup" matches "Simple Syrup", "bourbon" matches "Maker's Mark Bourbon"
- If the bar inventory lists a specific brand/product that IS the ingredient type, mark it available
- Be generous — if the user clearly has something that serves the same purpose, mark it available
Do not include text before or after the JSON.`
export function buildBarInventoryString(items: { name: string; category: string; quantity: string }[]): string {
const byCategory: Record<string, string[]> = {}