Разработка AI-системы оптимизации меню ресторана

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка AI-системы оптимизации меню ресторана
Средний
~1-2 недели
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1286
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

AI-система оптимизации меню ресторана

Меню-инжиниринг с AI — это не просто «уберём плохо продающиеся блюда». Система анализирует маржинальность, популярность, сезонность, время приготовления, влияние на кухонные операции и предсказывает спрос для закупок. McDonald's и Starbucks используют ML для ежеквартального пересмотра меню.

Анализ меню: матрица Stars/Puzzles/Plowhorses/Dogs

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

class MenuEngineeringAnalyzer:
    """Классическая матрица меню-инжиниринга + ML расширения"""

    def classify_menu_items(self, sales_data: pd.DataFrame) -> pd.DataFrame:
        """
        Матрица Boston Consulting Group для меню:
        - Stars: высокая маржа + высокая популярность → сохраняем, продвигаем
        - Puzzles: высокая маржа + низкая популярность → переименовать/переместить
        - Plowhorses: низкая маржа + высокая популярность → снизить себестоимость
        - Dogs: низкая маржа + низкая популярность → убираем
        """
        df = sales_data.copy()

        # Нормализованные метрики
        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)

        # Дополнительные метрики
        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:
        """Что случится с выручкой при изменении меню"""
        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% заказов перейдёт на звёзды
            ),
            'puzzles_reposition_opportunity': len(puzzles)
        }


class DemandForecastForMenu:
    """Прогноз спроса на блюда для закупок"""

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

    def train_item_model(self, item_id: str, sales_history: pd.DataFrame):
        """Модель прогноза для конкретного блюда"""
        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:
        """Прогноз заказов на неделю для управления запасами"""
        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-консультант по оптимизации меню"""

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

    def generate_optimization_report(self, menu_analysis: pd.DataFrame,
                                      restaurant_concept: str,
                                      season: str) -> str:
        """Отчёт с рекомендациями по меню"""
        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 in Russian:
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]:
        """Предложения новых блюд на основе трендов"""
        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 []

Регулярный AI-анализ меню (ежеквартально) повышает contribution margin на 3-6 процентных пунктов. Удаление bottom-10% items по категории «dog» редко снижает выручку более чем на 2% — гости переключаются на альтернативы. Прогнозирование спроса снижает food waste на 15-25%.