# Multi-Column Menu Extraction Instructions

## Overview
This document provides specific instructions for extracting menu data from multi-column restaurant menus (typically 2-4 columns) with complex layouts, pipe-separated ingredients, and multiple price formats.

## Menu Structure Characteristics

### 1. Layout Pattern
- **Multi-column layout**: Menus are organized in 2-4 vertical columns
- **Category headers**: Bold, uppercase section titles (e.g., "АНТИПАСТИ", "САЛАТИ", "МЕСО", "РИБА")
- **Reading order**: Top-to-bottom within each column, then left-to-right across columns
- **Column independence**: Each column may contain complete or partial categories

### 2. Item Format Structure

Standard item format:
```
[ITEM NAME] [SERVING_SIZE] | [PRICE_BGN] лв. | [PRICE_EUR] €
[Description with ingredients separated by | or commas]
```

Example:
```
Микс от Свежи Салати
Авокадо | Чери Домати | Годжи Бери | Смокинов
дресинг | Зехтин Екстра Върджин
280 г | 14.99 лв. | 7.66 €
```

### 3. Item Components

#### Item Name (Line 1)
- **Format**: Bold/prominent text, often title case
- **Position**: First line of menu item
- **Extraction**: Exact name as displayed, preserve capitalization
- **Translation**: Translate to target language while preserving proper nouns

#### Description/Ingredients (Lines 2-N)
- **Format**: Regular text with multiple separators
- **Separators**:
  - Pipe character (`|`) - primary separator between ingredients
  - Comma (`,`) - alternative separator or within ingredient phrases
  - Line breaks - continuation of description
- **Extraction**:
  - Combine all lines between item name and price/serving line
  - Preserve ingredient order
  - Keep separator structure (convert to single separator if needed)
- **Translation**: Translate each ingredient/component individually

#### Serving Size and Prices (Last Line)
- **Format**: `[WEIGHT] г | [PRICE1] лв. | [PRICE2] €`
- **Patterns**:
  - Weight in grams: `300 г`, `250 г`, `1000 г`
  - Primary price in BGN: `14.99 лв.`, `28.99 лв.`
  - Secondary price in EUR: `7.66 €`, `14.82 €`
- **Extraction Rules**:
  - **serving_size**: Extract with unit (e.g., "300 г")
  - **measure**: Set to `0` (grams) when weight is in grams
  - **price**: Extract ONLY the first price value (BGN) without currency symbol
    - Example: `14.99 лв. | 7.66 €` → extract `"14.99"`
    - Always format with 2 decimal places: `"15.00"` not `"15"`

### 4. Category Organization

#### Category Headers
- **Appearance**: Bold, uppercase, often with background color or border
- **Position**: At the top of sections, may span multiple items
- **Examples**:
  - `АНТИПАСТИ` (Antipasti)
  - `САЛАТИ` (Salads)
  - `МЕСО` (Meat)
  - `РИБА` (Fish)
  - `ПРЯСНА ПАСТА` (Fresh Pasta)
  - `PIZZA ITALIANA`
  - `БУРГЕР` (Burger)
  - `ДЕСЕРТИ` (Desserts)

#### Category Identification Rules
1. **Explicit headers**: Look for bold, uppercase text that doesn't have prices
2. **Visual separation**: Categories are often separated by lines, spacing, or background colors
3. **Context clues**: Text styling, font size, positioning
4. **Multi-column handling**: A category may continue across columns or multiple pages

#### Category Descriptions (Optional)
- Some categories have descriptive text below the header
- Example: `КЛАСИЧЕСКИ ИТАЛИАНСКИ ПИЦИ НА ПЕЩ, РЪЧНО ПРАВЕНИ ОТ ИТАЛИАНСКИ БРАШНА И ЛИМЕЦ 350 Г`
- Extract as `category.description` field

### 5. Special Cases and Variations

#### Item Variations
Some items have multiple variations listed consecutively:

```
Традиционна Салата 'Цезар'
Пъдпъдъче Яйце | Пудра от Панчета
300 г | 17.99 лв. | 9.20 €

с гриловано пиле 300 г | 19.99 лв. | 10.22 €
със скариди 3 бр. 300 г | 21.99 лв. | 11.24 €
```

**Extraction approach**:
- **Option A** (Recommended): Create separate items for each variation
  - Item 1: "Традиционна Салата 'Цезар'"
  - Item 2: "Традиционна Салата 'Цезар' с гриловано пиле"
  - Item 3: "Традиционна Салата 'Цезар' със скариди"
- **Option B**: Create one item with variations in notes field
- **Decision**: Use Option A for better menu management

#### Allergen Information
- **Indicator**: Underlined product names indicate allergens
- **Extraction**: Note in `notes` field when allergen information is present
- **Bottom section**: Menu may have allergen legend - extract as separate note if needed

#### Special Notes
Some items have additional information:
- Preparation methods: "на грил", "пържени", "запечено"
- Dietary markers: "ВЕГАН", "БЕЗ ГЛУТЕН"
- Spice levels: "ПИКАНТЕН"
- Special qualifiers: "от деня", "сезонен"

Extract these in the `notes` field.

### 6. Measure Type Detection

Based on `serving_size` content, set `measure` field:

```
measure = 0  # Weight units (g, gr, gram, гр, грам, kg, кг)
measure = 1  # Volume units (ml, мл, l, л, liter, литър)
measure = 2  # Count/pieces (pc, pcs, бр, брой, парче, pieces)
measure = 3  # Length units (cm, см, centimeter)
measure = null  # Cannot determine or no serving_size
```

Examples:
- `"300 г"` → measure = 0
- `"250 ml"` → measure = 1
- `"3 бр."` → measure = 2
- `"25 см"` → measure = 3

### 7. Multi-Column Reading Strategy

#### Column Detection
1. Analyze page layout to identify column boundaries
2. Detect vertical separators or spacing between columns
3. Identify column width patterns (typically equal width)

#### Reading Order
1. **Primary order**: Top-to-bottom within each column
2. **Secondary order**: Left-to-right across columns
3. **Category continuity**: Track if category continues in next column

#### Example Layout
```
┌─────────────────┬─────────────────┬─────────────────┐
│ CATEGORY A      │ CATEGORY B      │ CATEGORY C      │
│ - Item 1        │ - Item 6        │ - Item 10       │
│ - Item 2        │ - Item 7        │ - Item 11       │
│ - Item 3        │ - Item 8        │ - Item 12       │
│                 │                 │                 │
│ CATEGORY A cont │ CATEGORY B cont │ CATEGORY D      │
│ - Item 4        │ - Item 9        │ - Item 13       │
│ - Item 5        │                 │ - Item 14       │
└─────────────────┴─────────────────┴─────────────────┘
```

### 8. Price Extraction Rules

#### Multiple Price Format
When menu displays prices in multiple currencies:
- **Format**: `[WEIGHT] | [PRICE_BGN] лв. | [PRICE_EUR] €`
- **Extraction**: Extract the EUR (€) price value (SECOND price in the format)
- **Currency removal**: Remove ALL currency symbols and abbreviations

#### Examples
| Menu Text | Extract |
|-----------|---------|
| `300 г \| 19.99 лв. \| 10.22 €` | `"10.22"` |
| `250 г \| 24.99 лв. \| 12.78 €` | `"12.78"` |
| `400 г \| 28.99 лв. \| 14.82 €` | `"14.82"` |

#### Decimal Formatting
- Always use 2 decimal places
- Examples: `"15.00"` not `"15"`, `"12.50"` not `"12.5"`

### 9. Language Handling

#### Source Language (Bulgarian - Cyrillic)
- Handle Cyrillic characters correctly
- Preserve original spelling and capitalization
- Common patterns:
  - `лв.` = Bulgarian Lev (BGN)
  - `г` = grams
  - `бр.` = pieces
  - `с` = with
  - `от` = from/of

#### Translation Requirements
- Translate ALL textual content to target language
- Preserve proper nouns (restaurant names, brand names, specific dish names)
- Keep numeric values unchanged
- Maintain structure and organization

### 10. Edge Cases and Handling

#### Missing Information
- **No price**: Set `price` to `null`
- **No serving size**: Set `serving_size` to `null` and `measure` to `null`
- **No description**: Set `description` to `null`
- **No category**: Place in "Uncategorized" or "Други" category

#### Handwritten Prices
- Extract handwritten price modifications
- If both printed and handwritten prices exist, prefer handwritten (more recent)
- Note in `notes` if uncertainty exists

#### Complex Descriptions
Some descriptions are very long with many ingredients:
```
Калмари | Тигрови Скариди | Филе от Лаврак | Миди |
Свежи Салати с Авокадо | Чери Домати | Мисо Лимон Дресинг
```

**Handling**:
- Combine all lines into single description
- Keep pipe separators or convert to commas
- Ensure readability in target language

#### Nested Categories
Some menus have sub-categories or groupings:
- Main: `PIZZA ITALIANA`
- Sub: `КЛАСИЧЕСКИ` (Classic pizzas)

**Handling**:
- Create separate categories for sub-sections, OR
- Include sub-category name in description, OR
- Use hierarchical category names: "Pizza Italiana - Класически"

### 11. Validation Rules

Before finalizing extraction, validate:

1. **All items have names**: No empty `name` fields
2. **Price format**: All prices are numeric strings without symbols
3. **Measure consistency**: `measure` values are only 0, 1, 2, 3, or null
4. **Category assignment**: Every item belongs to a category
5. **No duplicates**: Check for duplicate items within categories
6. **Translation completeness**: All required fields are translated

### 12. Example Extraction

#### Source Menu Text
```
Микс от Свежи Салати
Авокадо | Чери Домати | Годжи Бери | Смокинов
дресинг | Зехтин Екстра Върджин
280 г | 14.99 лв. | 7.66 €
```

#### Extracted JSON (Target: English)
```json
{
  "name": "Fresh Salad Mix",
  "description": "Avocado | Cherry Tomatoes | Goji Berries | Fig Dressing | Extra Virgin Olive Oil",
  "price": "14.99",
  "serving_size": "280 g",
  "measure": 0,
  "notes": null
}
```

### 13. Implementation Checklist

When implementing menu extraction for this format:

- [ ] Detect multi-column layout structure
- [ ] Identify all category headers and boundaries
- [ ] Extract items in correct reading order (top-to-bottom, left-to-right)
- [ ] Parse pipe-separated ingredient lists
- [ ] Extract serving size and prices from combined line
- [ ] Extract ONLY first price when multiple currencies present
- [ ] Set correct measure type based on serving_size units
- [ ] Handle item variations (create separate items)
- [ ] Capture allergen information in notes
- [ ] Preserve category organization across columns
- [ ] Translate all text fields to target language
- [ ] Validate all extracted data meets schema requirements

### 14. Common Mistakes to Avoid

1. **❌ Wrong**: Extracting BGN (лв) price instead of EUR price
   - **✅ Correct**: Always extract EUR (€) price when both currencies are present

2. **❌ Wrong**: Including currency symbols in price: `"14.99 лв."`
   - **✅ Correct**: Numeric only: `"14.99"`

3. **❌ Wrong**: Missing decimal places: `"15"`
   - **✅ Correct**: Always 2 decimals: `"15.00"`

4. **❌ Wrong**: Losing ingredient separators: "Avocado Cherry Tomatoes Goji Berries"
   - **✅ Correct**: Keep structure: "Avocado | Cherry Tomatoes | Goji Berries"

5. **❌ Wrong**: Reading left-to-right across columns for all items
   - **✅ Correct**: Read top-to-bottom within each column first

6. **❌ Wrong**: Splitting item variations into description field
   - **✅ Correct**: Create separate items for each variation

7. **❌ Wrong**: Setting measure as string: `"grams"`
   - **✅ Correct**: Integer value: `0`

8. **❌ Wrong**: Ignoring category headers in multi-column layouts
   - **✅ Correct**: Detect and assign categories properly

## Summary

This menu format requires careful attention to:
- **Multi-column layout detection and reading order**
- **Pipe-separated ingredient parsing**
- **Multiple currency price extraction (first price only)**
- **Item variation handling (create separate items)**
- **Proper measure type detection**
- **Category organization across columns**
- **Complete translation while preserving structure**

Following these instructions will ensure accurate extraction of all menu items with complete metadata suitable for restaurant menu management systems.
