Free-text meal parsing
Product decision
Free text is a core low-friction logging method. A user should be able to type or speak “2 roti, one bowl dal and a little aloo gobi” and receive an editable draft.
The parser does not calculate calories from language. It identifies foods, quantities, units, and uncertainty. Versioned nutrition records, household recipes, serving conversions, cooking yield, and retention rules perform the calculation.
This separation prevents an LLM from inventing authoritative nutrition values and allows the AI provider to be removed or replaced without changing the Flutter flow or confirmed-log model.
Stable boundary
The Node recipe/meal service owns a provider-neutral MealTextParser contract:
parse(input, locale, structuredContext) -> ParsedMealDraft
structuredContext contains only what parsing needs:
- User locale and preferred units.
- Saved household item identifiers and names.
- Recent item identifiers, names, and usual servings.
- Catalog candidates retrieved by the service.
It never contains raw chat history. Provider responses are untrusted external input and must pass schema validation before becoming a draft.
Parsing pipeline
- Validate input: enforce length, Unicode normalization, supported locale, and rate limits.
- Normalize language: preserve the original text while producing normalized tokens and transliterations.
- Extract structure: food phrases, numeric quantities, number words, units, meal slot, and modifiers such as “half,” “little,” or “large.”
- Retrieve trusted candidates: household presets first, user history second, regional/common dishes third, canonical catalog fourth.
- Rank matches: exact alias, prior confirmed match, locale, market, source quality, and fuzzy similarity.
- Represent ambiguity: unresolved phrases and colloquial portions become alternatives or visible ranges.
- Create a draft: no confirmed log is written.
- Calculate nutrition: deterministic service/database code scales versioned nutrient values and ranges.
- User review: the user can replace matches, change quantities, remove items, and confirm.
- Learn safely: store the confirmed structured correction, not an assumption that an unconfirmed model answer was correct.
Parser implementations
Standard parser — included
The standard parser is deterministic and remains available if all AI providers are disabled:
- Quantity and unit grammar.
- Number-word dictionaries.
- Regional aliases and transliterations.
- Fuzzy catalog search.
- Household-preset and history matching.
- Common phrase ranges such as “little” or “one bowl.”
It handles common descriptions cheaply and predictably.
Enhanced parser — paid candidate
The enhanced parser may use an LLM for complex mixed-language descriptions, implicit grouping, and unfamiliar regional phrasing. It returns the same ParsedMealDraft schema as the standard parser.
Routing policy:
- Always run retrieval and deterministic parsing first.
- Invoke AI only when the user is entitled and complexity/confidence thresholds justify it.
- Give AI retrieved candidate identifiers; do not ask it to invent a nutrition record.
- Validate output against allowed candidates, units, ranges, and schema.
- Fall back to the standard draft when the provider times out, fails, exceeds budget, or is disabled.
The client never depends on a provider name. A server-side feature flag and entitlement router can replace an AI adapter, disable enhanced parsing, or move it between subscription tiers.
Draft contract
Each proposed item contains:
- Original recognized phrase.
- Candidate nutrition item/version identifier, when matched.
- Display name and match source.
- Quantity and unit.
- Gram minimum, expected value, and maximum.
- Match confidence and reason.
- Alternatives when confidence is low.
- Whether explicit user review is required.
The draft also records parser strategy (standard or enhanced), parser/model version, latency, and expiration. Raw provider responses are retained only in protected short-lived diagnostics when necessary.
Entitlements and feature flags
Server-managed entitlements determine access; Flutter display state is not authorization.
Suggested capabilities:
text_parse_standardtext_parse_enhancedvoice_transcriptionphoto_estimation
Required flags:
- Global enhanced-parser kill switch.
- Provider-specific kill switch.
- Per-user daily/monthly budget.
- Locale rollout allowlist.
- Shadow/evaluation mode that never affects user drafts.
Disabling enhanced parsing must leave text logging functional through the standard parser.
Goal-free use
A nutrition target is optional. Users can choose “Just track for now” during onboarding and use all core logging methods without a calorie goal.
In observe mode:
- Today shows consumed nutrition without “remaining” language.
- Dashboards distinguish missing days from zero intake.
- Insights describe evidence: averages, timing, source confidence, and variation.
- The product does not infer weight-loss, bulking, or medical intent.
- After sufficient confirmed history, it may ask whether the user wants to explore a target.
- Suggestions always include “Keep observing” and can be dismissed.
This helps users who follow a diet without understanding its pattern while avoiding diagnosis or unsolicited prescriptive advice.
Dashboard layers
Home dashboard
- Today’s confirmed energy and macros.
- Estimate/range indicator.
- Meals and fast logging.
- No-goal state or active target, depending on user choice.
Detailed tracker dashboard
- Logged-day coverage and missing-day treatment.
- Energy and macro trends.
- Protein, fiber, and selected nutrient averages.
- Household-food proportion.
- Estimated-versus-verified nutrition proportion.
- Nutrition-confidence explanation and uncertain dishes to review.
- Evidence-backed behavioral signals.
Dashboards are computed from confirmed structured logs. They do not require an LLM.
Privacy and safety
- Treat meal text and transcripts as sensitive.
- Do not use raw meal descriptions for unrelated provider training.
- Send the minimum structured context to a provider.
- Redact meal text from routine logs and error trackers.
- Provide draft deletion and enforce expiration.
- Never auto-confirm a parsed meal.
- Never present generated text as medical advice.
- Do not hard-code provider keys or expose them to Flutter.
Test matrix
Standard parser
- Integers, decimals, fractions, number words, and ranges.
- Grams, millilitres, cups, tablespoons, pieces, bowls, katori, and roti counts.
- Missing quantity, unknown unit, and contradictory quantity.
- English, Hindi, mixed language, transliteration, punctuation, and spelling errors.
- Household preset precedence.
- History versus generic-catalog ranking.
- Unknown food and multiple plausible matches.
- Empty, whitespace-only, oversized, malformed Unicode, and adversarial input.
Enhanced adapter
- Schema-invalid provider output.
- Invented candidate identifiers.
- Prompt-injection-like food text.
- Timeout, rate limit, partial output, provider outage, and budget exhaustion.
- Standard-parser fallback equivalence.
- Entitlement denial and kill switch.
- Locale-specific accuracy and correction rates.
Nutrition and confirmation
- Exact versus ranged portions.
- Recipe yield and retention scaling.
- Immutable catalog-version snapshot on confirmation.
- User correction before confirmation.
- Retry idempotency and duplicate prevention.
- Draft expiration and deletion.
- No goal versus active target dashboards.
Release evaluation measures item-match accuracy, quantity accuracy, correction rate, confirmation rate, latency, cost, and error rate by locale. A low correction rate is meaningful only when users actually confirm the draft.