AI Restaurant Menu Optimization System Development

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI Restaurant Menu Optimization System Development
Medium
~1-2 weeks
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822

AI Restaurant Menu Optimization System

Menu engineering with AI is not just "remove underperforming dishes." The system analyzes profitability, popularity, seasonality, prep time, kitchen impact, and forecasts demand for procurement. McDonald's and Starbucks use ML for quarterly menu reviews.

Menu Analysis: Stars/Puzzles/Plowhorses/Dogs Matrix

import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from anthropic import Anthropic
import json

class MenuEngineeringAnalyzer:
    """Classic menu engineering matrix + ML extensions"""

    def classify_menu_items(self, sales_data: pd.DataFrame) -> pd.DataFrame:
        """
        Boston Consulting Group matrix for menu:
        - Stars: high margin + high popularity → keep, promote
        - Puzzles: high margin + low popularity → rename/reposition
        - Plowhorses: low margin + high popularity → reduce costs
        - Dogs: low margin + low popularity → remove
        """
        df = sales_data.copy()

        # Normalized metrics
        median_popularity = df['orders_count'].median()
        median_margin = df['contribution_margin_pct'].median()

        df['high_popularity'] = df['orders_count'] > median_popularity
        df['high_margin'] = df['contribution_margin_pct'] > median_margin

        def classify(row):
            if row['high_popularity'] and row['high_margin']:
                return 'star'
            elif not row['high_popularity'] and row['high_margin']:
                return 'puzzle'
            elif row['high_popularity'] and not row['high_margin']:
                return 'plowhorse'
            else:
                return 'dog'

        df['category'] = df.apply(classify, axis=1)

        # Additional metrics
        df['revenue_share'] = df['total_revenue'] / df['total_revenue'].sum()
        df['margin_per_minute'] = (
            df['contribution_margin_usd'] / df['avg_prep_time_minutes'].clip(1)
        )

        return df.sort_values(['category', 'contribution_margin_usd'], ascending=[True, False])

    def compute_menu_mix_impact(self, items: pd.DataFrame) -> dict:
        """What happens to revenue when menu changes"""
        stars = items[items['category'] == 'star']
        dogs = items[items['category'] == 'dog']
        puzzles = items[items['category'] == 'puzzle']

        return {
            'stars_revenue_share': stars['revenue_share'].sum(),
            'dogs_revenue_share': dogs['revenue_share'].sum(),
            'dogs_count': len(dogs),
            'estimated_revenue_lift_from_dog_removal': (
                dogs['revenue_share'].sum() * 0.6  # 60% orders shift to stars
            ),
            'puzzles_reposition_opportunity': len(puzzles)
        }


class DemandForecastForMenu:
    """Demand forecasting for menu items for procurement"""

    def __init__(self):
        self.models = {}

    def train_item_model(self, item_id: str, sales_history: pd.DataFrame):
        """Forecast model for specific dish"""
        if len(sales_history) < 60:
            return

        features = self._build_features(sales_history)
        y = sales_history['orders_count']

        self.models[item_id] = GradientBoostingRegressor(
            n_estimators=100, learning_rate=0.1, random_state=42
        )
        self.models[item_id].fit(features, y)

    def _build_features(self, df: pd.DataFrame) -> pd.DataFrame:
        return pd.DataFrame({
            'weekday': df['date'].dt.weekday,
            'month': df['date'].dt.month,
            'is_weekend': (df['date'].dt.weekday >= 5).astype(int),
            'is_holiday': df.get('is_holiday', 0),
            'temperature': df.get('temperature_c', 15),
            'is_raining': df.get('is_raining', 0),
            'lag_7d': df['orders_count'].shift(7).fillna(0),
            'lag_14d': df['orders_count'].shift(14).fillna(0),
            'rolling_mean_7d': df['orders_count'].rolling(7).mean().fillna(0),
            'special_event': df.get('special_event', 0),
        }).fillna(0)

    def forecast_week(self, item_id: str,
                       next_7_days: pd.DataFrame) -> dict:
        """Forecast orders for week for inventory management"""
        if item_id not in self.models:
            return {'error': 'No model trained'}

        features = self._build_features(next_7_days)
        daily_forecast = self.models[item_id].predict(features).clip(0)

        return {
            'item_id': item_id,
            'daily_forecast': daily_forecast.round().astype(int).tolist(),
            'total_week': int(daily_forecast.sum()),
            'peak_day': next_7_days['date'].iloc[daily_forecast.argmax()].strftime('%A'),
            'confidence': 'high' if item_id in self.models else 'low'
        }


class MenuAIAdvisor:
    """LLM consultant for menu optimization"""

    def __init__(self):
        self.llm = Anthropic()

    def generate_optimization_report(self, menu_analysis: pd.DataFrame,
                                      restaurant_concept: str,
                                      season: str) -> str:
        """Report with menu optimization recommendations"""
        stars = menu_analysis[menu_analysis['category'] == 'star'][['item_name', 'revenue_share']].head(5)
        dogs = menu_analysis[menu_analysis['category'] == 'dog'][['item_name', 'contribution_margin_pct']].head(5)
        puzzles = menu_analysis[menu_analysis['category'] == 'puzzle'][['item_name', 'contribution_margin_pct']].head(3)

        response = self.llm.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=500,
            messages=[{
                "role": "user",
                "content": f"""You're a restaurant consultant. Provide menu optimization recommendations.

Restaurant concept: {restaurant_concept}
Season: {season}

Stars (keep & promote): {stars.to_dict('records')}
Dogs (consider removing): {dogs.to_dict('records')}
Puzzles (reposition/rename): {puzzles.to_dict('records')}

Provide specific recommendations:
1. Which dogs to remove and why
2. How to reposition puzzle items (name changes, placement, description)
3. How to leverage stars better
4. 2-3 seasonal items to consider adding
5. Pricing adjustments for plowhorses

Be specific. 3-4 paragraphs."""
            }]
        )
        return response.content[0].text

    def suggest_new_items(self, current_menu: list[str],
                           trending_ingredients: list[str],
                           cuisine_type: str) -> list[dict]:
        """Suggestions for new dishes based on trends"""
        response = self.llm.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=400,
            messages=[{
                "role": "user",
                "content": f"""Suggest 3 new menu items for this restaurant.

Cuisine: {cuisine_type}
Current menu (sample): {current_menu[:10]}
Trending ingredients: {trending_ingredients[:8]}

For each item return JSON:
{{"name": "...", "description": "...", "main_ingredients": [...], "estimated_food_cost_pct": 25-35, "positioning": "starter|main|dessert"}}

Return JSON array. Suggest items that complement the current menu."""
            }]
        )
        try:
            return json.loads(response.content[0].text)
        except Exception:
            return []

Regular AI menu analysis (quarterly) increases contribution margin by 3-6 percentage points. Removing bottom-10% "dog" category items rarely reduces revenue by more than 2%—guests switch to alternatives. Demand forecasting reduces food waste by 15-25%.