菜单 Feed

定义

FoodMenuFeed 的定义

message FoodMenuFeed {
  repeated MenuComponent data = 1;
}

 
message MenuComponent {
  oneof type {
    food.menu.v1.Menu menu = 1;
    food.menu.v1.MenuSection section = 2;
    food.menu.v1.MenuItem item = 3;
    food.menu.v1.MenuItemOption option = 4;

  }
}

 
 
// Top-level catalog of food items offered by a Food establishment. Menu
// contains a list of merchant ids and the menu that apply to those merchants.
// A Menu can be used to represent single merchant with the menu, or multiple
// merchants (typically chain restaurants) with the menus.
message Menu {
  // An opaque string from a partner which uniquely identifies the Menu within
  // the partner feed.
  // Required.
  string menu_id = 1;

  // The merchants to whom the menu apply.
  // Note: This field is repeated so chain restaurants can share the same menu
  // across multiple locations, each of which is a separate merchant.
  // Required.
  repeated string merchant_ids = 2;

  // The name that can identify the Menu when a user is browsing the menu.
  // Optional.
  TextField display_name = 3;

  // The default language code associated with the text labels contained in the
  // menu. Expects BCP-47 language code, such as "en-US" or "sr-Latn".
  //
  // For more information, see
  // http://www.unicode.org/reports/tr35/#Unicode_locale_identifier.
  // Optional.
  string language = 4;

  // Disclaimer to be shown to the user for the menu. For example, nutritional
  // information disclosure and allergen disclosure.
  // Optional.
  Disclaimer disclaimer = 5;

  // IDs of items contained within this menu. Expects first-level menu items
  // only.
  // Optional.
  repeated string menu_item_ids = 6;

  // IDs of sections contained within this menu. Expects first-level menu
  // sections only.
  // Optional.
  repeated string menu_section_ids = 7;

  // Timestamp when this Menu or any of its contents was last updated by the
  // restaurant; i.e. a date to be associated with the phrase “accurate as of
  // date”.
  // Optional.
  google.protobuf.Timestamp last_merchant_update_time = 8;

}

 
 
// A menu section is a grouping of items on a menu. Separate MenuSections are
// usually created for each logical grouping of items on a menu. For example,
// meal course type (Appetizer, Main, Dessert) and food categories (Burgers,
// Drinks) are typical sections.
message MenuSection {
  // An opaque string from a partner that uniquely identifies the MenuSection
  // within the partner feed.
  // Required.
  string menu_section_id = 1;

  // The name that can identify the MenuSection when a user is browsing the
  // menu.
  // Required.
  TextField display_name = 2;

  // A description of the menu section.
  // Optional.
  TextField description = 3;

  // Image(s) of the menu section.
  // Optional.
  repeated Image images = 4;


  // IDs of MenuItem entities that correspond to this MenuSection entity. A
  // section is expected to have at least 1 item if it does not contain any
  // sub-sections.
  // Optional.
  repeated string menu_item_ids = 6;

  // Child MenuSections (sub-sections) that correspond to this MenuSection
  // entity.
  // Optional.
  repeated string menu_section_ids = 7;






}

 
 
// Represents a single food or drink item offered by a Food establishment.
message MenuItem {
  // An opaque string from a partner that uniquely identifies the MenuItem
  // within the partner feed.
  // Required.
  string menu_item_id = 1;

  // The name that can identify the MenuItem when a user is browsing the menu.
  // Required.
  TextField display_name = 2;

  // A description of the menu item.
  // Optional.
  TextField description = 3;

  // Image(s) of the menu item.
  // Optional.
  repeated Image images = 4;

  // Container that specifies a list of options available on an item.
  message MenuItemOptionSet {
    // IDs of menu item options that are applicable to this menu item.
    // Required.
    repeated string menu_item_option_ids = 1;
  }

  // The menu item must either have a price, or a set of menu item options.
  // Required.
  oneof pricing {
    option (validator.one_of) = {

    // Available offers to purchase this food item.
    OfferSet offer_set = 6;

    // Available options for this menu item.
    MenuItemOptionSet menu_item_option_set = 7;
  }

  // Attributes about this menu item.
  // Optional.
  MenuItemAttributes item_attributes = 8;


}

 
 
// Describes choices that a user would be required to make when selecting a
// dish / combo. The user must select an option, otherwise the order is
// considered invalid (e.g. the user must choose small, medium, or large for a
// pizza).
message MenuItemOption {
  // An opaque string from a partner that uniquely identifies the
  // MenuItemOption within the partner feed.
  // Required.
  string menu_item_option_id = 9;

  // Option property and value e.g. Size: Small.
  // Required.
  MenuItemOptionProperty value = 2;



  // Available offers to purchase this menu item option.
  // Required.
  OfferSet offer_set = 4;

  // Attributes about this menu item option.
  // Optional.
  MenuItemAttributes item_attributes = 5;


}

 
// Describes attributes about a particular menu item or option.
message MenuItemAttributes {
  // Number of servings available in a given menu item.
  // Optional.
  int32 number_of_servings = 1;

  // Describes all the nutritional information of the item, e.g. calories, fat
  // content.
  // Optional.
  NutritionInformation nutrition_information = 2;

  // The dietary restrictions that this menu item complies with.
  // Optional.
  repeated DietaryRestriction suitable_diets = 3;

  // Additives of this menu item.
  // Optional.
  repeated Additive additive = 4;

  // Allergens of this menu item.
  // Optional.
  repeated Allergen allergen = 5;

  // Packaging and recycling information of this menu item.
  // Optional.
  DepositInfo packaging_deposit_info = 6;
}

 

OfferSet 的定义

 
// Container for a list of offers available on a menu item / option.
// Only one offer should be applicable/valid at one particular time.
// For example, a drink can have 2 offers where one is applicable in the morning
// while the other is applicable in the evening during happy hours.
message OfferSet {
  // List of possible offers.
  // Required.
  repeated Offer offers = 1;
}

 

优惠的定义

 
// Represents pricing and availability information for MenuItems and
// MenuItemOptions.
message Offer {
  // Monetary value of the menu item/option on sale. Can be 0 to represent free.
  // Required.
  google.type.Money price = 1;






}

 

免责声明定义

// Partner provided disclaimer shown to the user. Contains a text disclaimer
// along with an optional URL for more information.
// Some example include: associated medical risks/warnings, any additional
// fees/gratutity, etc.
message Disclaimer {
  // Body of the disclaimer text to be shown to the user.
  // Required.
  TextField text = 1;

  // URL containing more information about the disclaimer.
  // Optional.
  string uri = 2;
}

 

TextField 定义

// A text payload that contains one or more localized values.
message TextField {
  // Per-locale text values.
  //
  // If there is only one desired locale support, then the language_code within
  // each text is not required to be set and the language will be inferred from
  // the default language of the menu.
  //
  // If there are multiple texts across different locales, then the
  // language_code must be set for each text. The first text in the list is
  // considered the preferred representation.
  // Required.
  repeated google.type.LocalizedText text = 1;
}

 

图片定义

// Represents an image associated with a menu entity.
message Image {
  // URL containing the raw pixels of the image.
  // Required.
  string uri = 1;
}

 
// Describes the property of a menu item option and its value.
message MenuItemOptionProperty {
  // Types of property that the option is for.
  enum PropertyType {
    // Do not use. The property type is not explicitly specified.
    UNKNOWN_PROPERTY_TYPE = 0;

    // A generic menu item option property, which is not one of the more
    // specific types below. Use this if the property is not of type
    // SIZE or PIZZA_SIDE.
    OPTION = 1;

    // Denotes the menu item option property of size (e.g. small, medium, or
    // large).
    SIZE = 2;

    // Property specific to pizzas. For example: this MenuItemOption is only
    // valid for a portion/whole pizza, such as mushroom toppings on the left
    // side, right side, or whole pizza).
    PIZZA_SIDE = 3;
  }

  // Well-defined values for the option property.
  enum PropertyValue {
    // Do not use. The property value is not explicitly specified.
    UNKNOWN_PROPERTY_VALUE = 0;

    // The MenuItemOption applies only to the left side of a pizza.
    PIZZA_SIDE_LEFT = 1;

    // The MenuItemOption applies only to the right side of a pizza.
    PIZZA_SIDE_RIGHT = 2;

    // The MenuItemOption applies to the entire pizza.
    PIZZA_SIDE_WHOLE = 3;
  }

  // The type of this option property.
  // Required.
  PropertyType property_type =;

  // Required.
  oneof value {
    // A well-defined value for the option property. Currently only expected
    // if the property_type is PIZZA_SIDE.
    PropertyValue property_val = 2;

    // A free-form text for the value of the property. Expected for
    // property_type OPTION and SIZE.
    TextField text_val = 3;
  }
}

 

NutritionInformation 定义

 
// Describes all the nutritional measurements of a MenuItem or add-on.
message NutritionInformation {
  // Describes a single nutritional measurement of the serving of food.
  message NutritionValue {
    // Describes a closed range for the nutrition value. E.g. "100-150 cal"
    message Range {
      // The minimum amount of nutrition value.
      // Required.
      double min =
          1;

      // The maximum amount of nutrition value.
      // Required.
      double max =
          2;
    }

    // Required oneof.
    oneof value {
      option (validator.one_of) = {

      // A single number representing the amount of nutritional value.
      double amount = 1;

      // A range representing the amount of nutritional value.
      Range range = 3;
    }

    // The unit associated with the amount as specified from the partner. We
    // will validate the feed so that the unit for each type of nutrition value
    // is expected for that type of value. For example, only ENERGY_CALORIES
    // and ENERGY_KILOJOULES are expected on energy property of
    // NutritionalInformation.
    // Required.
    NutritionValueUnit unit =
        2;
  }

  // The amount of nutritional energy of the serving of food. Can be defined
  // in Calories or kilojoules.
  // Optional.
  NutritionValue energy = 1;

  // The amount of sodium content, measured in grams or milligrams.
  // Optional.
  NutritionValue sodium_content = 2;

  // The number of servings the nutrition value applies to.
  // Optional.
  int32 serving_size = 3;

  // Nutrition information in free text. For example "Contains preservatives".
  // Optional.
  TextField description = 4;
}

 

DietaryRestriction 的定义

 
// Indicates a dietary restriction or guideline adhered to during
// food preparation.
enum DietaryRestriction {
  // Do not use. The dietary restriction is not explicitly specified.
  DIET_UNSPECIFIED = 0;
  DIET_DIABETIC = 1;
  DIET_GLUTEN_FREE = 2;
  DIET_HALAL = 3;
  DIET_HINDU = 4;
  DIET_KOSHER = 5;
  DIET_LOW_CALORIE = 6;
  DIET_LOW_FAT = 7;
  DIET_LOW_LACTOSE = 8;
  DIET_LOW_SALT = 9;
  DIET_VEGAN = 10;
  DIET_VEGETARIAN = 11;
}

 

加法定义

// Additive shown to the user on the MenuItem. An additive preserves or enhances
// the quality of the food.
message Additive {
  // Descriptive text of the additive, e.g. "preservatives".
  // Required.
  TextField name = 1;

  // Whether the MenuItem contains, may contain, or is free from this additive.
  // Defaults to contains.
  // Optional.
  ContainmentLevelCode containment_level_code = 2;
}

 

过敏原的定义

// Allergen shown to the user on the MenuItem. An allergen relates to qualities
// of food that causes allergic reactions.
message Allergen {
  // Type of allergen.
  // Required.
  AllergenTypeCode allergen_type_code =
      1;

  // Whether the MenuItem contains, may contain, or is free from this allergen.
  // Defaults to contains.
  // Optional.
  ContainmentLevelCode containment_level_code = 2;
}

 

AllergenTypeCode 定义

 
// Allergen type derived from GS1: http://gs1.org/voc/AllergenTypeCode
enum AllergenTypeCode {
  // Do not use. The allergen type code is not explicitly specified.
  ALLERGEN_TYPE_CODE_UNSPECIFIED = 0;
  ALLERGEN_TYPE_CODE_ALMONDS = 1;
  ALLERGEN_TYPE_CODE_ALPHA_ISOMETHYL_IONONE = 2;
  ALLERGEN_TYPE_CODE_ALCOHOL = 3;
  ALLERGEN_TYPE_CODE_AMYL_CINNAMAL = 4;
  ALLERGEN_TYPE_CODE_ANISE_ALCOHOL = 5;
  ALLERGEN_TYPE_CODE_BARLEY = 6;
  ALLERGEN_TYPE_CODE_BENZYL_ALCOHOL = 7;
  ALLERGEN_TYPE_CODE_BENZYL_BENZOATE = 8;
  ALLERGEN_TYPE_CODE_BENZYL_CINNAMATE = 9;
  ALLERGEN_TYPE_CODE_BENZYL_SALICYLATE = 10;
  ALLERGEN_TYPE_CODE_BRAZIL_NUTS = 11;
  ALLERGEN_TYPE_CODE_BUTYLPHENYL_METHYLPROPIONATE = 12;
  ALLERGEN_TYPE_CODE_CARROTS = 13;
  ALLERGEN_TYPE_CODE_CASHEW_NUTS = 14;
  ALLERGEN_TYPE_CODE_CELERY = 15;
  ALLERGEN_TYPE_CODE_CEREALS_CONTAINING_GLUTEN = 16;
  ALLERGEN_TYPE_CODE_CINNAMAL = 17;
  ALLERGEN_TYPE_CODE_CINNAMYL_ALCOHOL = 18;
  ALLERGEN_TYPE_CODE_CITRAL = 19;
  ALLERGEN_TYPE_CODE_CITRONELLOL = 20;
  ALLERGEN_TYPE_CODE_COCOA = 21;
  ALLERGEN_TYPE_CODE_CORIANDER = 22;
  ALLERGEN_TYPE_CODE_CORN = 23;
  ALLERGEN_TYPE_CODE_COUMARIN = 24;
  ALLERGEN_TYPE_CODE_CRUSTACEANS = 25;
  ALLERGEN_TYPE_CODE_EGGS = 26;
  ALLERGEN_TYPE_CODE_EUGENOL = 27;
  ALLERGEN_TYPE_CODE_EVERNIA_FURFURACEA = 28;
  ALLERGEN_TYPE_CODE_EVERNIA_PRUNASTRI = 29;
  ALLERGEN_TYPE_CODE_FARNESOL = 30;
  ALLERGEN_TYPE_CODE_FISH = 31;
  ALLERGEN_TYPE_CODE_GERANIOL = 32;
  ALLERGEN_TYPE_CODE_GLUTEN = 33;
  ALLERGEN_TYPE_CODE_HAZELNUTS = 34;
  ALLERGEN_TYPE_CODE_HEXYL_CINNAMAL = 35;
  ALLERGEN_TYPE_CODE_HYDROXYCITRONELLAL = 36;
  ALLERGEN_TYPE_CODE_HYDROXYISOHEXYL_3_CYCLOHEXENE_CARBOXALDEHYDE_ISOEUGENOL_LIMONENE_LINAL =
      37;
  ALLERGEN_TYPE_CODE_KAMUT = 38;
  ALLERGEN_TYPE_CODE_LACTOSE = 39;
  ALLERGEN_TYPE_CODE_LUPINE = 40;
  ALLERGEN_TYPE_CODE_MACADAMIA_NUTS = 41;
  ALLERGEN_TYPE_CODE_METHYL_2_OCTYNOATE = 42;
  ALLERGEN_TYPE_CODE_MILK = 43;
  ALLERGEN_TYPE_CODE_MOLLUSCS = 44;
  ALLERGEN_TYPE_CODE_MUSTARD = 45;
  ALLERGEN_TYPE_CODE_NO_DECLARED_ALLERGENS = 46;
  ALLERGEN_TYPE_CODE_OAT = 47;
  ALLERGEN_TYPE_CODE_PEANUTS = 48;
  ALLERGEN_TYPE_CODE_PEAS = 49;
  ALLERGEN_TYPE_CODE_PECAN_NUTS = 50;
  ALLERGEN_TYPE_CODE_PISTACHIOS = 51;
  ALLERGEN_TYPE_CODE_POD_FRUITS = 52;
  ALLERGEN_TYPE_CODE_QUEENSLAND_NUTS = 53;
  ALLERGEN_TYPE_CODE_RYE = 54;
  ALLERGEN_TYPE_CODE_SESAME_SEEDS = 55;
  ALLERGEN_TYPE_CODE_SOYBEANS = 56;
  ALLERGEN_TYPE_CODE_SPELT = 57;
  ALLERGEN_TYPE_CODE_SULPHUR_DIOXIDE = 58;
  ALLERGEN_TYPE_CODE_TREE_NUTS = 59;
  ALLERGEN_TYPE_CODE_TREE_NUT_TRACES = 60;
  ALLERGEN_TYPE_CODE_WALNUTS = 61;
  ALLERGEN_TYPE_CODE_WHEAT = 62;
}

 

ContainmentLevelCode 的定义

 
// Indicates the level of containment a food item has of a certain attribute,
// such as allergens or additives.
enum ContainmentLevelCode {
  // Do not use. The containment level code is not explicitly specified.
  CONTAINMENT_LEVEL_CODE_UNSPECIFIED = 0;
  CONTAINMENT_LEVEL_CODE_CONTAINS = 1;
  CONTAINMENT_LEVEL_CODE_DOES_NOT_CONTAIN = 2;
  CONTAINMENT_LEVEL_CODE_MAY_CONTAIN = 3;
}

 

DepositInfo 定义

 
// Partner provided deposit info to instruct the user how to deposit a food item
// or bottle and the value of such deposit.
message DepositInfo {
  // The deposit strategy to employ, e.g. "reusable".
  // Optional.
  DepositCode deposit_code = 1;

  // Value refunded for depositing the item properly.
  // Optional.
  google.type.Money deposit_value = 2;
}

 

菜单 Feed 示例

{
  "data": [
    {
      "menu": {
        "menu_id": "menu1",
        "merchant_ids": [
          "dining-1"
        ],
        "display_name": {
          "text": [
            {
              "text": "Menu",
              "language_code": "en-US"
            }
          ]
        },
        "language": "en-US",
        "menu_section_ids": [
          "appetizers",
          "dinner"
        ],
        "last_merchant_update_time": {
          "seconds": 1692825444
        }
      }
    },
    {
      "section": {
        "menu_section_id": "appetizers",
        "display_name": {
          "text": [
            {
              "text": "Lunch Appetizers",
              "language_code": "en-US"
            }
          ]
        },
        "menu_item_ids": [
          "breadsticks-sauce"
        ]
      }
    },
    {
      "section": {
        "menu_section_id": "dinner",
        "display_name": {
          "text": [
            {
              "text": "Dinner",
              "language_code": "en-US"
            }
          ]
        },
        "menu_item_ids": [
          "meatballs"
        ]
      }
    },
    {
      "item": {
        "menu_item_id": "breadsticks-sauce",
        "display_name": {
          "text": [
            {
              "text": "Bread Sticks & Sauce",
              "language_code": "en-US"
            }
          ]
        },
        "description": {
          "text": [
            {
              "text": "Breakfast basket w/ side of tomato sauce (size 6 or 12)",
              "language_code": "en-US"
            }
          ]
        },
        "images": [
          {
            "uri": "http://www.example.com/photos/breadsticks.jpg"
          },
          {
            "uri": "http://www.example.com/photos/sauce.jpg"
          }
        ],
        "menu_item_option_set": {
          "menu_item_option_ids": [
            "breadstick-sm",
            "breadstick-lg"
          ]
        }
      }
    },
    {
      "item": {
        "menu_item_id": "meatballs",
        "display_name": {
          "text": [
            {
              "text": "Grandma Grace's Meatballs",
              "language_code": "en-US"
            }
          ]
        },
        "description": {
          "text": [
            {
              "text": "Two 40x beef with pork tomato sauce, coarse grated cheese",
              "language_code": "en-US"
            }
          ]
        },
        "images": [
          {
            "uri": "http://www.example.com/photos/meatballs.jpg"
          },
          {
            "uri": "http://www.example.com/photos/meatballs2.jpg"
          }
        ],
        "offer_set": {
          "offers": [
            {
              "price": {
                "currency_code": "USD",
                "units": 1,
                "nanos": 750000000
              }
            }
          ]
        }
      }
    },
    {
      "option": {
        "menu_item_option_id": "breadstick-sm",
        "value": {
          "property_type": "SIZE",
          "text_val": {
            "text": [
              {
                "text": "Small",
                "language_code": "en-US"
              }
            ]
          }
        },
        "offer_set": {
          "offers": [
            {
              "price": {
                "currency_code": "USD",
                "units": 8,
                "nanos": 0
              }
            }
          ]
        }
      }
    },
    {
      "option": {
        "menu_item_option_id": "breadstick-lg",
        "value": {
          "property_type": "SIZE",
          "text_val": {
            "text": [
              {
                "text": "Large",
                "language_code": "en-US"
              }
            ]
          }
        },
        "offer_set": {
          "offers": [
            {
              "price": {
                "currency_code": "USD",
                "units": 11,
                "nanos": 0
              }
            }
          ]
        }
      }
    }
  ]
}

此 Feed 包含菜单数据 Feed 中非 ASCII 字符的示例。第一个菜单项 非 ASCII 字符。第二个菜单项具有以 十六进制 UTF-8 表示法。这两种方法都是在菜单 Feed 中添加非 ASCII 字符的有效选项。建议按原样添加非 ASCII 字符。

{
  "data": [
    {
      "menu": {
        "menu_id": "menu2",
        "merchant_ids": [
          "dining-2"
        ],
        "display_name": {
          "text": [
            {
              "text": "Menu",
              "language_code": "en-FR"
            }
          ]
        },
        "language": "en-FR",
        "menu_section_ids": [
          "salad"
        ],
        "last_merchant_update_time": {
          "seconds": 1692902166
        }
      }
    },
    {
      "section": {
        "menu_section_id": "salad",
        "display_name": {
          "text": [
            {
              "text": "Salade",
              "language_code": "en-FR"
            }
          ]
        },
        "menu_item_ids": [
          "cesar",
          "nicoise"
        ]
      }
    },
    {
      "item": {
        "menu_item_id": "cesar",
        "display_name": {
          "text": [
            {
              "text": "Salade César",
              "language_code": "en-FR"
            }
          ]
        },
        "description": {
          "text": [
            {
                "text": "Classique délicieux, croustillant grâce à ses croûtons et gourmande grâce à sa tendre volaille.",
                "language_code": "en-FR"
            }
          ]
        },
        "offer_set": {
          "offers": [
            {
              "price": {
                "currency_code": "EUR",
                "units": 9,
                "nanos": 450000000
              }
            }
          ]
        }
      }
    },
    {
      "item": {
        "menu_item_id": "nicoise",
        "display_name": {
          "text": [
            {
              "text": "Salade Ni\u00e7oise",
              "language_code": "en-FR"
            }
          ]
        },
        "description": {
          "text": [
            {
              "text": "Salade fran\u00e7aise d\u00e9licieuse et nourrissante",
              "language_code": "en-FR"
            }
          ]
        },
        "offer_set": {
          "offers": [
            {
              "price": {
                "currency_code": "EUR",
                "units": 10,
                "nanos": 800000000
              }
            }
          ]
        }
      }
    }
  ]
}

描述符文件

{
  "generation_timestamp": 1692998244,
  "name": "google.food_menu",
  "data_file": [
    "menu1_1692825444.json",
    "menu2_1692902166.json"
  ]
}