o
    êÍŽjz` ã                   @   s  U d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dlm	Z	m
Z
mZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlZd d	lmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% d d
l&m'Z'm(Z( eƒ  e )d¡Z*e )d¡Z+e ,dej-¡Z.de/de/fdd„Z0de/de/fdd„Z1dgde
de2de/fdd„Z3				dhde/dee/ de/fdd„Z4de/de/fdd„Z5d e
e	 de	e/e/f fd!d"„Z6d#e/d$e	e/e/f dee/ fd%d&„Z7d'e	d$e	e/e/f de	fd(d)„Z8d*d+d,d-œZ9e	e/e2f e:d.< h d/£Z;d0e	d1e/de<fd2d3„Z=	did4e
e	 d5e2d1e/d6ee> de
e	 f
d7d8„Z?g d9¢g d:¢g d;¢d<d=gg d>¢d?œZ@e	e/e
e/ f e:d@< g dA¢g dB¢g dB¢dCœZAe	e/e
e/ f e:dD< dEdFdGdHdId?œZBd,dJdJdKdLd?œZCe	e/e2f e:dM< d4e
e	 dNe/de
e	 fdOdP„ZDdQe
e	 dRe
e	 d1e/dSe	e/e2f dTe>dee	e/e
e	 f e>f fdUdV„ZEdWe	e/e
e	 f d1e/de/fdXdY„ZFdQe
e	 dRe
e	 dee/e	e/e/f f fdZd[„ZGdQe
e	 dRe
e	 d1e/dee/e	e/e/f f fd\d]„ZHdjd e
e	 de2de/fd_d`„ZIG dadb„ dbƒZJG dcdd„ ddƒZKG dedf„ dfƒZLdS )ké    N)Údatetime)ÚDictÚListÚOptionalÚTuple)ÚHTTPException)Ú
ChatOpenAI)ÚChatPromptTemplate)ÚOpenAI)Úload_dotenv)ÚMealÚMealPlanResponseÚSwapMealResponseÚFoodScanResponseÚHarmfulIngredientÚSafeIngredientÚNeutralIngredientÚ
IngredientÚMacronutrientsÚDailyNutritionResponseÚSwapMealRequestÚFoodTypeInfoÚfood_types_for_scan)ÚMealGenVectorStoreÚScannerVectorStoreéô  éd   u»   \b(grilled|roasted|baked|fried|steamed|fresh|smoked|saut[eÃ©]ed|pan[-\s]seared|boiled|raw|cooked|diced|sliced|chopped|minced|shredded|whole|dried|canned|frozen|organic|lean|light|dark)\s+Ú
blood_typeÚreturnc                 C   s<   | sdS |   ¡  ¡  d¡d  d¡d   ¡ }|dv r|S dS )NÚOú+r   ú-)r   ÚAÚBÚAB)ÚstripÚupperÚsplit)r   Úcleaned© r)   úT/home/esfera/Desktop/Rishu/fitness/Fitness-lenito-AI-main/fitness_app/ai_services.pyÚ_normalize_blood_type+   s   $r+   Ú	diet_typec                 C   s.   | sdS dddddddœ}|  |  ¡  ¡ d¡S )NÚstandardÚveganÚpescatarianÚ
vegetarianÚ	carnivore)Úclassicr-   r.   r/   r0   r1   )Úgetr%   Úlower)r,   Úmappingr)   r)   r*   Ú_normalize_diet_type2   s   ýr6   éP   ÚitemsÚ	max_itemsc                 C   sj   | sdS g }| d|… D ]}t |tƒr | d¡p| d¡pd}nt|ƒ}|r+| |¡ q|r3d |¡S dS )zBFormat food names from str list or dict list for prompt injection.úNone providedNÚ	food_nameÚnameÚ ú, )Ú
isinstanceÚdictr3   ÚstrÚappendÚjoin)r8   r9   ÚnamesÚitemr<   r)   r)   r*   Ú_food_names=   s   

€rF   Úclient_rulesc                 C   sX   |rt |ƒ ¡ rt |ƒ ¡ S d| › dt|pg ƒ› dt|pg ƒ› dt|p$g ƒ› d| › d�S )zÐ
    Build blood-group diet rules for LLM prompts.
    If the client already sent blood_group_rules (FormData / query), use that.
    Otherwise build from vector-store beneficial / neutral / avoid lists.
    zBlood Type zQ diet rules (ground truth from our food database):
- Beneficial (prefer / safe): z
- Neutral (allowed): z'
- Avoid (do not recommend / harmful): zN
Prefer beneficial foods, allow neutral, never use avoid foods for blood type Ú.)rA   r%   rF   ©r   Ú
beneficialÚneutralÚavoidrG   r)   r)   r*   Úformat_blood_group_rulesL   s   
ÿ
þ
ýüÿrM   r<   c                 C   s   t  d| ¡ ¡ S )u-   'grilled Chicken Breast' â†’ 'Chicken Breast'r=   )Ú_COOKING_ADJÚsubr%   ©r<   r)   r)   r*   Ú_strip_cooking_adjectivesg   s   rQ   Ú
food_dictsc                 C   s.   i }| D ]}|  dd¡}|r||| ¡ < q|S )z�
    Build {lowercase_name: exact_db_name} from a list of food dicts.
    Used for post-generation normalisation of LLM ingredient output.
    r;   r=   ©r3   r4   )rR   ÚlookupÚfr<   r)   r)   r*   Ú_build_name_lookupl   s   €rV   Ú
ingredientrT   c                 C   sh   t | ƒ ¡  ¡ }||v r|| S | ¡ D ]\}}||v r |  S q| ¡ D ]\}}||v r1|  S q%dS )zù
    Try to map an LLM-output ingredient string to the exact DB name.
    1. Strip cooking adjectives, exact match.
    2. Substring match (DB name inside ingredient, or ingredient inside DB name).
    Returns exact DB name if found, else None.
    N)rQ   r4   r%   r8   )rW   rT   r(   r4   Úoriginalr)   r)   r*   Ú_match_to_db_namey   s   ÿÿrY   Ú	meal_dictc              	   C   sb   g }|   dg ¡D ]"}|  dd¡}t||ƒ}| |r|n||  dd¡|  dd¡dœ¡ q|| d< | S )z’
    Walk through a meal's ingredient list and replace each name with the
    exact DB name where possible.  Quantity and icon are preserved.
    Úingredientsr<   r=   ÚquantityÚiconõ   ðŸ�½ï¸�©r<   r\   r]   )r3   rY   rB   )rZ   rT   Únew_ingredientsÚingÚraw_nameÚdb_namer)   r)   r*   Ú_normalise_meal_ingredients“   s   




ýrd   éF   é   é
   )ÚHighÚMediumÚLowÚPRIORITY_WEIGHTS¾   rj   rh   ri   ÚfoodÚ	meal_timec                 C   s   |   | ¡ d¡dv S )Nri   ¾   rh   ri   rS   )rm   rn   r)   r)   r*   Ú_is_eligible_for_meal¯   s   rp   ÚfoodsÚnÚ
used_namesc                    s�  ˆd u rt ƒ ‰‡ ‡fdd„| D ƒ}t|ƒ|k r!‡ ‡fdd„| D ƒ}t|ƒ|k r0‡ fdd„| D ƒ}dd„ |D ƒ}dd„ |D ƒ}g }t|ƒ|kr}t|ƒ}dd„ |D ƒ}	|r|t|ƒ|k r|tjtt|ƒƒ|	dd	�d
 }
| | |
¡¡ |	 |
¡ |r|t|ƒ|k sYnE| |¡ |t|ƒ }|rÂ|d
krÂt|ƒ}t	d gt|ƒ }	tt
|t|ƒƒƒD ]}tjtt|ƒƒ|	dd	�d
 }
| | |
¡¡ |	 |
¡ q¤|d |… S )Nc                    s.   g | ]}t |ˆ ƒr| d d¡ ¡ ˆvr|‘qS ©r;   r=   )rp   r3   r4   ©Ú.0rU   ©rn   rs   r)   r*   Ú
<listcomp>¾   s    þþz/_weighted_sample_no_replace.<locals>.<listcomp>c                    s8   g | ]}|  ˆ  ¡ d ¡dv r|  dd¡ ¡ ˆvr|‘qS )ri   rl   r;   r=   rS   ru   rw   r)   r*   rx   Æ   s    þc                    s$   g | ]}|  ˆ  ¡ d ¡dv r|‘qS )ri   rl   rS   ru   )rn   r)   r*   rx   Î   s
    ÿc                 S   s    g | ]}|  d d¡dv r|‘qS )Úpriorityri   ro   ©r3   ru   r)   r)   r*   rx   Ô   ó     c                 S   s    g | ]}|  d d¡dkr|‘qS )ry   ri   rj   rz   ru   r)   r)   r*   rx   Õ   r{   c                 S   s   g | ]
}t  |d  d¡‘qS )ry   rf   )rk   r3   ru   r)   r)   r*   rx   Ü   ó    é   )ÚweightsÚkr   rj   )ÚsetÚlenÚlistÚrandomÚchoicesÚrangerB   ÚpopÚextendrk   Úmin)rq   rr   rn   rs   ÚeligibleÚhigh_medÚlowÚresultÚpoolr~   ÚidxÚ	remainingÚ_r)   rw   r*   Ú_weighted_sample_no_replace´   sF   ÿÿ
ÿ
ý€
r‘   )ÚProteinÚSeafoodzDairy / ProteinúCarb / ProteinzLegume / ProteinÚDairy)ÚCarbzCarb / Legumez
Carb / NutzLegume / CarbúCarb / VegetableúVegetable / Carbr”   )Ú	Vegetabler˜   r—   zVegetable / cornÚFruitzFruit / Seasoning)z	Fat / Nutz
Fat / SeedzFat / Spreadz	Fat / OilzFat / Dairy)r’   ÚCarbsÚ
VegetablesÚFruitsÚFatsÚ_CATEGORY_ALIASES)r’   r›   r�   rž   ©r’   r›   rœ   rž   ©Ú	breakfastÚlunchÚdinnerÚ_MEAL_CATEGORIESé   é   é   é   é   é   é   é   Ú_SWAP_POOL_SIZESÚlogicalc                    s$   t t ||g¡ƒ‰ ‡ fdd„| D ƒS )zJReturn foods whose DB category matches any alias for the logical category.c                    s    g | ]}|  d d¡ˆ v r|‘qS )Úcategoryr=   rz   ru   ©Úaliasesr)   r*   rx     r{   z/_filter_by_logical_category.<locals>.<listcomp>)r€   rŸ   r3   )rq   r¯   r)   r±   r*   Ú_filter_by_logical_category  s   r³   rJ   rK   Ú
pool_sizesÚused_globallyc                 C   s  t  | ¡ g d¢¡}i }t|ƒ}dd„ | D ƒ}|D ]o}	| |	d¡}
tdt|
d ƒƒ}td|
| ƒ}t| |	ƒ}t||	ƒ}t|ƒ|k rM||t|ƒ 7 }t|ƒ}t||||ƒ}t||||ƒ}|| }|D ]}| dd¡ ¡ |v rod	nd
|d< qa|||	< |D ]}| 	| dd¡ ¡ ¡ qzq||fS )z»
    For each required category, draw foods using priority-weighted sampling.
    Returns (selected_by_category, updated_used_names).
    70% drawn from beneficial, 30% from neutral.
    r    c                 S   s   h | ]
}|  d d¡ ¡ ’qS rt   rS   ru   r)   r)   r*   Ú	<setcomp>,  r|   z(_select_pool_for_meal.<locals>.<setcomp>é   r}   çffffffæ?r;   r=   Ú
BeneficialÚNeutralÚ_compat)
r¥   r3   r4   r€   ÚmaxÚroundr³   r�   r‘   Úadd)rJ   rK   rn   r´   rµ   Ú
categoriesÚselectedÚused_this_mealÚ	ben_namesÚcatÚtotal_nÚn_benÚn_neuÚben_catÚneu_catÚsel_benÚsel_neuÚcombinedrU   r)   r)   r*   Ú_select_pool_for_meal  s.   

"ÿrÌ   rÀ   c              
   C   sÈ   d|  ¡ › d�dddddg}|  ¡ D ]L\}}|sq| d|  ¡ › d	�¡ |D ]2}| d
d¡}| dd¡}| dd¡}|dkr@dnd}	|dkrHdnd}
| d|	› d|
› d|› �¡ q&| d¡ qd |¡S )z˜
    Format the pre-selected pool into a compact, unambiguous prompt block.
    Lists EXACT food names from the DB. LLM must use these exact names.
    z=== PRE-SELECTED FOOD POOL FOR z ===zJRULE: Use ONLY the EXACT food names listed below in your ingredient lists.uV         â˜…â˜… = High priority (use as primary ingredient, ~70% of calorie contribution)u<         â˜…  = Medium priority (supporting/variety role, ~30%)z4      [B] = Beneficial for blood type  [N] = Neutralr=   z  [ú]r;   ry   ri   r»   rº   rh   u   â˜…â˜…u   â˜… r¹   r#   ÚNz    z [z] Ú
)r&   r8   rB   r3   rC   )rÀ   rn   ÚlinesrÃ   rq   rU   r<   ry   ÚcompatÚtagÚctr)   r)   r*   Ú_format_pool_for_promptI  s(   	ú
rÔ   c              	   C   s–   g }t ƒ }dD ]4}t| ||t|ƒ\}}| t||ƒ¡ | ¡ D ]\}}|D ]}	|	 d¡dkr9| |	 dd¡ ¡ ¡ q%qq| | }
t	|
ƒ}d 
|¡|fS )z‘
    Build the food database string for the full 27-meal plan prompt.
    Also returns a name lookup dict for post-generation normalisation.
    r¡   ry   rh   r;   r=   z

)r€   rÌ   Ú_POOL_SIZESrB   rÔ   r8   r3   r¾   r4   rV   rC   )rJ   rK   Úsectionsrµ   rn   rÀ   Ú
used_afterrÃ   rq   rU   Ú	all_foodsÚname_lookupr)   r)   r*   Ú_build_full_plan_databaseh  s"   
ÿ€þÿrÚ   c                 C   s4   t | ||ttƒ ƒ\}}| | }t|ƒ}t||ƒ|fS )zx
    Build the food database for a swap-meal prompt (single meal time).
    Returns (database_string, name_lookup).
    )rÌ   r®   r€   rV   rÔ   )rJ   rK   rn   rÀ   r�   rØ   rÙ   r)   r)   r*   Ú_build_swap_databaseƒ  s   	ÿrÛ   é2   c                 C   s$   | sdS d  dd„ | d |… D ƒ¡S )NÚNonerÏ   c                 s   sB   � | ]}t |tƒrd |d › d| dd¡› d�nd |› �V  qdS )u   â€¢ r;   z (r°   r=   ú)N)r?   r@   r3   ru   r)   r)   r*   Ú	<genexpr>š  s   € ÿ ÿ
þz,_format_food_list_bullets.<locals>.<genexpr>©rC   )rR   r9   r)   r)   r*   Ú_format_food_list_bullets—  s
   

ýrá   c                   @   s6   e Zd Zdd„ Zddd„Zdd„ Zdd	„ Zd
d„ ZdS )ÚMealImageGeneratorc                 C   s   t t d¡d�| _d S )NÚOPENAI_API_KEY)Úapi_key)r
   ÚosÚgetenvÚclient©Úselfr)   r)   r*   Ú__init__¥  ó   zMealImageGenerator.__init__r=   c              
   C   st   d  dd„ |D ƒ¡}d|› d|› d|› d�}z|  |¡W S  ty9 } ztd|› d	|› �ƒ W Y d }~d S d }~ww )
Nr>   c                 s   s.   � | ]}|  d d¡› d|  dd¡› �V  qdS )r\   Úsomeú r<   r=   Nrz   ©rv   Úir)   r)   r*   rß   ©  s   € 
ÿz9MealImageGenerator.generate_meal_image.<locals>.<genexpr>z"Professional food photography of: z. Description: z. Ingredients: zg. Style: High-quality restaurant presentation, natural lighting, appetizing. No text, labels, or logos.zImage gen failed for ú: )rC   Ú_generate_imageÚ	ExceptionÚprint)ré   Ú	meal_nameÚdescriptionr[   Úsub_categoryÚingredient_listÚpromptÚer)   r)   r*   Úgenerate_meal_image¨  s    
ÿÿÿÿ€þz&MealImageGenerator.generate_meal_imagec                 C   s"   | j jjd|ddd�}|jd jS )Núgpt-image-1.5Ú	1024x1024r‹   ©Úmodelrø   ÚsizeÚqualityr   )rç   ÚimagesÚgenerateÚdataÚb64_json)ré   rø   Úrr)   r)   r*   rñ   ¸  s   ÿz"MealImageGenerator._generate_imagec              
   C   s€   z|› d|› d�}| j jjd|d d… ddd�}|jd jW S  ty? } ztd	|› d
|› �ƒ |  |¡W  Y d }~S d }~ww )Nz Category: zV. Style: Professional food photography, clean presentation. No text, labels, or logos.rû   iè  rü   r‹   rý   r   zCategory image failed for rð   )rç   r  r  r  r  rò   ró   Ú generate_fallback_category_image)ré   r°   rø   Ú
meals_dictÚenhancedr  rù   r)   r)   r*   Úgenerate_category_image¾  s   ÿþ€þz*MealImageGenerator.generate_category_imagec              
   C   sv   ddddœ}|  | ¡ d¡}z| jjjd|ddd	�}|jd
 jW S  ty: } ztd|› �ƒ W Y d }~d S d }~ww )NzQBeautiful breakfast spread, clean white background, professional food photographyzIAppetizing lunch plate, clean presentation, professional food photographyzGDelicious dinner, elegant plating, professional restaurant presentationr¡   z0Professional food photography of a balanced mealrû   rü   r‹   rý   r   zFallback image failed: )	r3   r4   rç   r  r  r  r  rò   ró   )ré   r°   Úpromptsrø   r  rù   r)   r)   r*   r  Î  s   ýÿ€þz3MealImageGenerator.generate_fallback_category_imageN©r=   )Ú__name__Ú
__module__Ú__qualname__rê   rú   rñ   r	  r  r)   r)   r)   r*   râ   ¤  s    
râ   c                	   @   s*  e Zd Zd*dee fdd„Zededefdd„ƒZed	edefd
d„ƒZ	ede
fdd„ƒZededefdd„ƒZdd„ Zdd„ Zdd„ Zdedefdd„Z		d+dedee dedefdd„Z	d,dededefd d!„Zd*d"d#„Zd$eeee f deeee f fd%d&„Zd'ee dee fd(d)„ZdS )-ÚEnhancedMealPlanGeneratorNÚvector_storec                 C   s^   t ddt d¡d�| _|ptƒ | _tƒ | _t 	d¡| _
t 	d¡| _t 	d¡| _t 	d¡| _d S )	Núgpt-4or¸   rã   ©rþ   Útemperaturerä   a  
        You are an expert food photographer. Create a single image prompt representing {category} meals.
        MEAL SUMMARY: {meal_options_summary}
        USER: Blood Type {blood_type}, Diet {diet_type}, Country {country}
        Return ONLY the image prompt text.
        u3  
        You are an expert nutritionist specialising in blood type diets. Calculate the optimal daily calorie intake, macronutrient distribution, and meal calorie distribution.

        USER PROFILE:
        - Blood Type: {blood_type}
        - Diet Type: {diet_type}
        - Country: {country}
        - Age: {age} years
        - Current Weight: {weight} kg
        - Desired Weight: {desired_weight} kg
        - Height: {height} cm
        - Main Goal: {main_goal}

        CALORIE DISTRIBUTION GUIDELINES:
        Breakfast 25%, Lunch 40%, Dinner 35%

        BLOOD TYPE MACRONUTRIENT GUIDELINES:
        - O:  Protein 30-40%, Fat 30-35%, Carbs 25-35%
        - A:  Protein 15-25%, Fat 25-30%, Carbs 45-60%
        - B:  Balanced (Carbs 30-40%, Protein 20-30%, Fat 30-35%)
        - AB: Similar to A but slightly more protein (20-30%)

        DIET ADJUSTMENTS:
        - Vegan: plant-based protein sources
        - Carnivore: Protein 50-60%, Fat 40-50%, minimal carbs
        - Pescatarian: moderate protein from fish, balanced macros
        - Vegetarian: plant-based protein with dairy/eggs

        If desired_weight is provided, adjust calories for 0.5-1 kg/week loss or 0.25-0.5 kg/week gain.

        Respond ONLY with valid JSON:
        {{
            "total_daily_calories": number,
            "total_daily_macronutrients": {{"carbohydrates": number, "protein": number, "fat": number}},
            "meal_calorie_distribution": {{"breakfast": number, "lunch": number, "dinner": number}}
        }}
        carbs*4 + protein*4 + fat*9 â‰ˆ total_daily_calories.
        us?  
        You are an expert nutritionist specialising in blood type diets.
        Generate a personalised daily meal plan with 3 subâ€‘categories per meal Ã— 3 options = 27 meals total.

        USER PROFILE:
        - Blood Type: {blood_type}  |  Diet: {diet_type}  |  Country: {country}
        - Age: {age}  |  Weight: {weight} kg  |  Height: {height} cm
        - Dislikes: {food_dislikes}  |  Allergies: {allergies}
        - Target Daily Calories: {target_calories}  |  Macros: {total_daily_macronutrients}
        - Goal: {main_goal}

        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        BLOOD GROUP RULES (must follow)
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        {blood_group_rules}
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�

        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        BACKEND PREâ€‘SELECTED FOOD POOL
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        {food_database}
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        ABSOLUTE RULES (must be followed for every single meal)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�

        1. INGREDIENT RULES
        a. Use ONLY the EXACT food names from the pool above. Copy them characterâ€‘forâ€‘case.
        b. DO NOT add any ingredient not in the pool â€“ no salt, pepper, oil, water, spices,
            herbs, sauces, stock, etc., unless it is explicitly listed in the pool.
        c. List EVERY ingredient you use in the `ingredients` array.
        d. The 3 meals within a subâ€‘category must use a different primary protein/carb source.
            Do not repeat the exact same ingredient combination.

        2. PRIORITY RULES
        â˜…â˜… High priority â†’ primary ingredient (~70 % of the meal's calories).
        â˜…  Medium priority â†’ supporting role (~30 % of calories).
        You may repeat a highâ€‘priority protein across different meals if it naturally fits;
        aim for variety in carb sources, vegetables, cooking styles and meal names.

        3. CALORIE RANGES (VARY NATURALLY)
        Breakfast meals: each between {breakfast_cal_min} and {breakfast_cal_max} kcal(use any number which is within the range and look natural).
        Lunch meals:     each between {lunch_cal_min} and {lunch_cal_max} kcal(use any number which is within the range and look natural).
        Dinner meals:    each between {dinner_cal_min} and {dinner_cal_max} kcal(use any number which is within the range and look natural).
        âš  Do NOT make all meals in a mealâ€‘time identical in calories. Vary them naturally
            across the 9 options, keeping each within its range. The numbers needs to vary across the 3 subâ€‘categories and 3 options and needs to use variety of different calorie values within each one range, not the same repeated.
                                                                 
        4. CALORIE MATHS
        total_calories = (carbohydrates Ã— 4) + (protein Ã— 4) + (fat Ã— 9)
        Must equal the stated calorie value.
        Every ingredient must have a quantity in grams (g) or millilitres (ml).
        The macronutrient totals must be the sum of the listed ingredients.

        5. PORTION ADJUSTMENT ORDER (when tuning to hit target)
        Adjust in this strict order: â‘  carbs â†’ â‘¡ protein â†’ â‘¢ fats/oils/seeds.
        Never add an ingredient that is not already present just to hit numbers.

        6. COUNTRY CONTEXT
        {country_guidance}

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BANNED MEAL TYPES (NEVER generate these)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Do NOT generate any of the following meal types under any circumstances:
        - Wraps, Burritos, Tacos
        - Rice Bowls, Quinoa Bowls, Comfort Bowls, Power Bowls, Protein Bowls, Noodle Bowls
        - Any meal named or structured as a "Bowl" of any kind
        The goal is realistic plated meals, not trendy bowl/wrap formats.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        MEAL NAMING RULES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Meal names must describe the actual food being served.
        âœ“ GOOD names: "Grilled Salmon with Rice & Broccoli", "Steak with Sweet Potato & Asparagus",
                      "Shrimp Stir Fry", "Blueberry Oatmeal", "Scrambled Eggs with Spinach"
        âœ— BAD names:  "Comfort Bowl", "Power Bowl", "Protein Packed Bowl", "Energy Bowl",
                      "Light & Fresh Bowl", "Nourish Bowl", "Wellness Plate"
        The name must reflect the protein, cooking method, and key ingredients.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BREAKFAST TEMPLATES â€“ CHOOSE ONE STYLE PER MEAL
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Every breakfast meal must belong to exactly ONE of the four templates below.
        NEVER mix ingredients from different templates in the same meal.

        Target breakfast distribution across the 9 breakfast meals:
        ~30% Oatmeal (â‰ˆ3 meals) | ~30% Yogurt Bowls (â‰ˆ3 meals) | ~30% Egg-Based (â‰ˆ3 meals) | ~10% Other Approved

        â–  OATMEAL BREAKFAST
        Must contain: oats + at least 1 fruit + at least 1 approved topping.
        Approved toppings (only if in pool): Honey, Cinnamon, Walnuts, Almonds, Chia Seeds,
            Pumpkin Seeds, Flax Seeds.
        FORBIDDEN: fish, meat, eggs, rice, noodles, savoury proteins, random oils.
        Example: Oats + Blueberries + Walnuts + Honey â†’ "Blueberry Walnut Oatmeal"

        â–  YOGURT BOWL BREAKFAST
        Must contain: yogurt + at least 1 fruit + at least 1 approved topping.
        Approved toppings (only if in pool): Honey, Walnuts, Almonds, Chia Seeds,
            Pumpkin Seeds, Flax Seeds, Granola.
        FORBIDDEN: fish, meat, eggs, rice, noodles, savoury proteins.
        Example: Greek Yogurt + Strawberries + Chia Seeds + Honey â†’ "Strawberry Yogurt Bowl"

        â–  EGG BREAKFAST
        Allowed: eggs + vegetables + optional approved carb (e.g. potato, bread if in pool)
                + optional approved fat/oil.
        FORBIDDEN: fruit, berries, yogurt, kefir, honey, oats.
        Example: scrambled eggs + spinach + wholeâ€‘grain toast + olive oil.

        â–  SAVOURY BREAKFAST
        Allowed: eggs, fish/tofu (ONLY if breakfast priority is Medium or High),
                rice/potato/vegetables (ONLY if breakfast priority Medium or High).
        FORBIDDEN: oats, berries, fruit, yogurt, kefir, honey, sweet ingredients.
        Example: smoked salmon + scrambled eggs + sautÃ©ed vegetables.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        LUNCH & DINNER MEAL TYPES & DISTRIBUTION
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Across the 9 lunch meals and 9 dinner meals, use this distribution:
        â€¢ 70% Standard Plated Meals  (â‰ˆ6 meals per meal time)
        â€¢ 20% Stir Fries             (â‰ˆ2 meals per meal time)
        â€¢ 10% Salads                 (â‰ˆ1 meal per meal time)

        â–  STANDARD PLATED MEAL (most common)
        Structure: Protein + Carbohydrate + Vegetable
        Every meal must contain:
        â€¢ a clear main protein (100â€‘180 g cooked)
        â€¢ a carb (rice/pasta/noodles 60â€‘90 g dry; potatoes 150â€‘250 g)
        â€¢ vegetables (50â€‘150 g)
        â€¢ optional fats (5â€‘15 g)
        All quantities in grams or millilitres; no cups or tablespoons.
        Examples: "Grilled Salmon with Rice & Broccoli", "Steak with Sweet Potato & Asparagus",
                  "Turkey with Potatoes & Kale", "Cod with Rice & Green Beans"

        â–  STIR FRY
        Structure: Protein + Vegetables + Optional Carbohydrate
        Must contain a clear protein source and at least 2 vegetables.
        Carbohydrate is optional (e.g. rice noodles or rice on the side).
        Examples: "Chicken & Vegetable Stir Fry", "Shrimp Stir Fry with Broccoli & Peppers"

        â–  SALAD
        Structure: Protein + Salad Vegetables + Optional Carb or Fat
        Must contain a clear protein source; not just leaves.
        Examples: "Grilled Chicken Salad", "Tuna Salad with Mixed Greens"

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        SEASONING & FLAVOUR RULES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Meals must not be plain. Add suitable seasonings from the pool where available.
        If the following are in the pool, apply them to matching proteins:
        â€¢ Fish dishes   â†’ Lemon, Garlic, Dill, Parsley
        â€¢ Beef dishes   â†’ Garlic, Rosemary, Black Pepper
        â€¢ Turkey dishes â†’ Garlic, Rosemary, Thyme
        â€¢ Vegetables    â†’ Herbs, Garlic, Black Pepper

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        PROTEIN ROTATION & VARIETY RULES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        â€¢ Do NOT use the same primary protein in consecutive meals within a meal time.
        â€¢ Rotate proteins across all 9 meals in each meal time â€“ avoid repeating the same
          protein more than twice across lunch options or more than twice across dinner options.
        â€¢ Rotate fruits, vegetables, carbohydrates, and breakfast toppings for variety.
        â€¢ The same meal must not appear more than once across the 27 generated meals.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BANNED PAIRINGS (never appear together in ANY meal)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        - fish + berries / fruit / oats / yogurt / kefir
        - meat + berries / fruit
        - rice + yogurt / kefir
        - noodles for breakfast
        - oil as a main ingredient
        - random fruit in savoury lunch/dinner meals
        - sweet ingredients (fruit, berries, yogurt, kefir, honey) in any lunch/dinner

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        MEAL COMPLEXITY DISTRIBUTION
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Target: 80% Simple Meals | 20% Complex/Specialty Meals
        Simple = Protein + Vegetable + Carbohydrate (easy to prepare)
        Complex = Stir Fries or specialty preparations
        Keep most meals straightforward and realistic to cook.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        SUBâ€‘CATEGORY DEFINITIONS (3 per meal time)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�

        1. PROTEINâ€‘PACKED
        - Feels highâ€‘protein, filling, gym/performance focused.
        - Protein clearly dominates the meal (>30 g).
        - Larger approved protein portions, moderate carbs, balanced fats.
        - Avoid: fruitâ€‘heavy, lowâ€‘protein, snackâ€‘style meals.
        - Calorie feel: substantial, higher than other subâ€‘categories.

        2. LIGHT & FRESH
        - Feels lighter, refreshing, cleaner, easier to digest.
        - Lighter approved protein portions, more fruit/vegetables, simpler combinations.
        - Avoid: heavy oily meals, dense carbs, oversized portions, greasy meals.
        - Calorie feel: lighter, lower than Proteinâ€‘Packed.

        3. HEALTHY & COMFORTING
        - Feels warm, balanced, comforting, realistic, healthy but satisfying.
        - Balanced protein/carb/fat, softer comforting foods, everyday combinations.
        - Avoid: random ingredient combos, ultraâ€‘light or extremely heavy meals.
        - Calorie feel: balanced, moderate.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        MEAL QUALITY TEST
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Before finalising each meal, ask: "Would a normal person realistically cook, order, or eat this?"
        If NO â†’ reject and regenerate.
        Requirements: clear protein, realistic ingredient combinations, descriptive meal name,
        proper cooking method in description.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        OUTPUT FORMAT (valid JSON only, no extra text)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        {{
        "breakfast_options": {{
            "protein_packed":      [ meal_obj, meal_obj, meal_obj ],
            "light_fresh":         [ meal_obj, meal_obj, meal_obj ],
            "healthy_comforting":  [ meal_obj, meal_obj, meal_obj ]
        }},
        "lunch_options": {{ ... }},
        "dinner_options": {{ ... }}
        }}

        Where each meal_obj is:
        {{
        "meal_name": "string",
        "category": "Breakfast|Lunch|Dinner",
        "sub_category": "Protein-Packed|Light & Fresh|Healthy & Comforting",
        "total_calories": number,
        "macronutrients": {{"carbohydrates": number, "protein": number, "fat": number}},
        "description": "string",
        "ingredients": [{{"name": "EXACT_POOL_NAME", "quantity": "Xg or Xml", "icon": "emoji"}}],
        "number_of_servings": 1
        }}
        u,  
        You are an expert nutritionist. Generate 3 COMPLETELY DISTINCT alternative {category} meals for the {sub_category} subâ€‘category.

        USER: Blood Type {blood_type} | Diet {diet_type} | Country {country}
        Target: {target_calories} kcal Â± 5 | Allergies: {allergies} | Dislikes: {food_dislikes}

        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        BACKEND PREâ€‘SELECTED FOOD POOL FOR {category_upper}
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�
        {food_database}
        â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        ABSOLUTE RULES (must be followed for every single meal)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�

        1. INGREDIENT RULES
        a. Use ONLY the EXACT food names from the pool above. Copy them characterâ€‘forâ€‘case.
        b. DO NOT add any ingredient not in the pool â€“ no salt, pepper, oil, water, spices,
            herbs, sauces, stock, etc., unless it is explicitly listed in the pool.
        c. List EVERY ingredient you use in the `ingredients` array.
        d. The 3 meals within a subâ€‘category must use a different primary protein/carb source.
            Do not repeat the exact same ingredient combination.

        2. PRIORITY RULES
        â˜…â˜… High priority â†’ primary ingredient (~70 % of the meal's calories).
        â˜…  Medium priority â†’ supporting role (~30 % of calories).
        You may repeat a highâ€‘priority protein across different meals if it naturally fits;
        aim for variety in carb sources, vegetables, cooking styles and meal names.

        3. CALORIE MATHS
        total_calories = (carbsÃ—4)+(proteinÃ—4)+(fatÃ—9). Must match {target_calories} Â±5 kcal.
        Every ingredient must have a quantity in g or ml.
        Adjust in order: carbs â†’ protein â†’ fats.

        4. PORTION ADJUSTMENT ORDER (when tuning to hit target)
        Adjust in this strict order: â‘  carbs â†’ â‘¡ protein â†’ â‘¢ fats/oils/seeds.
        Never add an ingredient that is not already present just to hit numbers.

        5. COUNTRY CONTEXT
        {country_guidance}

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BANNED MEAL TYPES (NEVER generate these)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Do NOT generate any of the following meal types:
        - Wraps, Burritos, Tacos
        - Rice Bowls, Quinoa Bowls, Comfort Bowls, Power Bowls, Protein Bowls, Noodle Bowls
        - Any meal named or structured as a "Bowl" of any kind
        The goal is realistic plated meals, not trendy bowl/wrap formats.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        MEAL NAMING RULES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Meal names must describe the actual food.
        âœ“ GOOD: "Grilled Salmon with Rice & Broccoli", "Shrimp Stir Fry", "Blueberry Oatmeal"
        âœ— BAD:  "Comfort Bowl", "Power Bowl", "Protein Packed Bowl", "Energy Bowl", "Nourish Bowl"
        The name must reflect the protein, cooking method, and key ingredients.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BREAKFAST TEMPLATES â€“ CHOOSE ONE STYLE PER MEAL
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Every breakfast meal must belong to exactly ONE of the four templates below.
        NEVER mix ingredients from different templates in the same meal.

        â–  OATMEAL BREAKFAST
        Must contain: oats + at least 1 fruit + at least 1 approved topping.
        Approved toppings (only if in pool): Honey, Cinnamon, Walnuts, Almonds, Chia Seeds,
            Pumpkin Seeds, Flax Seeds.
        FORBIDDEN: fish, meat, eggs, rice, noodles, savoury proteins, random oils.

        â–  YOGURT BOWL BREAKFAST
        Must contain: yogurt + at least 1 fruit + at least 1 approved topping.
        Approved toppings (only if in pool): Honey, Walnuts, Almonds, Chia Seeds,
            Pumpkin Seeds, Flax Seeds, Granola.
        FORBIDDEN: fish, meat, eggs, rice, noodles, savoury proteins.

        â–  EGG BREAKFAST
        Allowed: eggs + vegetables + optional approved carb (e.g. potato, bread if in pool)
                + optional approved fat/oil.
        FORBIDDEN: fruit, berries, yogurt, kefir, honey, oats.
        Example: scrambled eggs + spinach + wholeâ€‘grain toast + olive oil.

        â–  SAVOURY BREAKFAST
        Allowed: eggs, fish/tofu (ONLY if breakfast priority is Medium or High),
                rice/potato/vegetables (ONLY if breakfast priority Medium or High).
        FORBIDDEN: oats, berries, fruit, yogurt, kefir, honey, sweet ingredients.
        Example: smoked salmon + scrambled eggs + sautÃ©ed vegetables.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        LUNCH & DINNER MEAL TYPES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        â–  STANDARD PLATED MEAL: Protein + Carbohydrate + Vegetable
          â€¢ protein (100â€‘180 g cooked), carb (60â€‘90 g dry), vegetables (50â€‘150 g), optional fats (5â€‘15 g)
          â€¢ All quantities in grams or millilitres; no cups or tablespoons.
          â€¢ Examples: "Grilled Salmon with Rice & Broccoli", "Steak with Sweet Potato & Asparagus"

        â–  STIR FRY: Protein + Vegetables + Optional Carbohydrate
          â€¢ Must contain a clear protein source and at least 2 vegetables.
          â€¢ Examples: "Chicken & Vegetable Stir Fry", "Shrimp Stir Fry with Broccoli & Peppers"

        â–  SALAD: Protein + Salad Vegetables + Optional Carb or Fat
          â€¢ Must contain a clear protein source; not just leaves.
          â€¢ Examples: "Grilled Chicken Salad", "Tuna Salad with Mixed Greens"

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        SEASONING & FLAVOUR RULES
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Meals must not be plain. Add suitable seasonings from the pool where available.
        â€¢ Fish dishes   â†’ Lemon, Garlic, Dill, Parsley
        â€¢ Beef dishes   â†’ Garlic, Rosemary, Black Pepper
        â€¢ Turkey dishes â†’ Garlic, Rosemary, Thyme
        â€¢ Vegetables    â†’ Herbs, Garlic, Black Pepper

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        BANNED PAIRINGS (never appear together in ANY meal)
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        - fish + berries / fruit / oats / yogurt / kefir
        - meat + berries / fruit
        - rice + yogurt / kefir
        - noodles for breakfast
        - oil as a main ingredient
        - random fruit in savoury lunch/dinner meals
        - sweet ingredients (fruit, berries, yogurt, kefir, honey) in any lunch/dinner

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        SUBâ€‘CATEGORY DEFINITIONS
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�

        1. PROTEINâ€‘PACKED
        - Feels highâ€‘protein, filling, gym/performance focused.
        - Protein clearly dominates the meal (>30 g).
        - Larger approved protein portions, moderate carbs, balanced fats.
        - Avoid: fruitâ€‘heavy, lowâ€‘protein, snackâ€‘style meals.
        - Calorie feel: substantial, higher than other subâ€‘categories.

        2. LIGHT & FRESH
        - Feels lighter, refreshing, cleaner, easier to digest.
        - Lighter approved protein portions, more fruit/vegetables, simpler combinations.
        - Avoid: heavy oily meals, dense carbs, oversized portions, greasy meals.
        - Calorie feel: lighter, lower than Proteinâ€‘Packed.

        3. HEALTHY & COMFORTING
        - Feels warm, balanced, comforting, realistic, healthy but satisfying.
        - Balanced protein/carb/fat, softer comforting foods, everyday combinations.
        - Avoid: random ingredient combos, ultraâ€‘light or extremely heavy meals.
        - Calorie feel: balanced, moderate.

        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        MEAL QUALITY TEST
        â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
        Before finalising each meal, ask: "Would a normal person realistically cook, order, or eat this?"
        If NO â†’ reject and regenerate.
        Requirements: clear protein, realistic combinations, descriptive meal name, proper cooking method.

        VARIETY: the 3 meals must differ in protein, carb, vegetable, cooking style, and cultural flavour.

        Return ONLY valid JSON:
        {{
        "alternatives": [
            {{
            "meal_name": "string",
            "category": "{category}",
            "sub_category": "{sub_category}",
            "total_calories": number,
            "macronutrients": {{"carbohydrates": number, "protein": number, "fat": number}},
            "description": "string",
            "ingredients": [{{"name": "EXACT_POOL_NAME", "quantity": "Xg or Xml", "icon": "emoji"}}],
            "number_of_servings": 1
            }},
            {{...}}, {{...}}
        ]
        }}
        )r   rå   ræ   Úllmr   r  râ   Úmeal_image_generatorr	   Úfrom_templateÚcategory_image_promptÚdaily_nutrition_promptÚmeal_plan_promptÚswap_meal_prompt©ré   r  r)   r)   r*   rê   ä  s   þ( sz"EnhancedMealPlanGenerator.__init__Úcountryr   c                 C   óJ   dddœ}| s	dS |   ¡  ¡ }|dv r|d S |dv r|d S d	| › d
�S )Nz_Traditional Chinese cooking: steaming, stir-frying, braising. Ginger, garlic, tofu, vegetables.zUKorean traditions: fermented foods, gochujang, sesame oil, kimchi, varied vegetables.©ÚchinaÚsouth_koreaz<Create balanced meals using generally available ingredients.©r  Úchineser  ©zsouth koreazsouth koreanÚkoreaÚkoreanr   z7Create balanced meals incorporating local cuisine from z when appropriate.©r%   r4   ©r  Úgr   r)   r)   r*   Úget_country_guidanceÀ  s   þz.EnhancedMealPlanGenerator.get_country_guidancer°   c                 C   s   |   ¡ dkrdS | › d�S )Nr¢   z>Light protein + carb or fruit + optional fats. No heavy meats.zW: protein 100-180g cooked + carb 60-90g dry + vegetables 50-150g + optional fats 5-15g.)r4   )r°   r)   r)   r*   Ú_meal_structure_textÍ  s   
z.EnhancedMealPlanGenerator._meal_structure_textc                 C   sD   | r |r |r d| d|  d|   d }t dtdt|d ƒƒƒS dS )Nrg   g      @r·   iÜ  i   gÍÌÌÌÌÌø?éÐ  )r¼   rˆ   Úint)ÚageÚweightÚheightÚbmrr)   r)   r*   Úcalculate_target_caloriesÓ  s   z3EnhancedMealPlanGenerator.calculate_target_caloriesÚbtfc                 C   sX   g }|   ¡ D ] \}}|r&dd„ |D ƒ}| | dd¡ ¡ › dd |¡› �¡ qd |¡S )Nc                 S   s"   g | ]}t |tƒr|d  n|‘qS )r;   )r?   r@   ru   r)   r)   r*   rx   ß  s   " zFEnhancedMealPlanGenerator._format_blood_type_foods.<locals>.<listcomp>r�   rí   rð   r>   rÏ   )r8   rB   ÚreplaceÚtitlerC   )r2  rÐ   rÃ   rq   rD   r)   r)   r*   Ú_format_blood_type_foodsÚ  s   &€
z2EnhancedMealPlanGenerator._format_blood_type_foodsc                 Ã   s€  �zŸg }|rD|  ¡ D ]9\}}t|d d… ƒD ],\}}d dd„ |jd d… D ƒ¡}	| | dd¡ ¡ › d|d › d	|j› d
|	› �¡ qq
d |¡pM|› d�}
| j| j	B }t
4 I d H š% | ||
| dd¡| dd¡| dd¡dœ¡I d H }W d   ƒI d H  n1 I d H s…w   Y  |j ¡ }| d¡rž| d¡d  ¡ W S |W S  ty¿ } ztd|› �ƒ d|› d�W  Y d }~S d }~ww )Né   r>   c                 s   s   � | ]}|j V  qd S ©NrP   ©rv   ra   r)   r)   r*   rß   ë  s   € zKEnhancedMealPlanGenerator.generate_category_image_prompt.<locals>.<genexpr>é   r�   rí   r}   rð   u    â€” rÏ   z4 protein-packed, light & fresh, healthy & comfortingr   r=   r,   r-   r  )r°   Úmeal_options_summaryr   r,   r  z```zCategory image prompt error: z!Professional food photography of z. meals, balanced, appetising, clean background)r8   Ú	enumeraterC   r[   rB   r3  r4  rô   r  r  ÚIMAGE_SEMAPHOREÚainvoker3   Úcontentr%   Ú
startswithr'   rò   ró   )ré   r°   r  Ú	user_dataÚ	summariesrO   Úmealsrï   ÚmÚkeysÚsummaryÚchainr  Úprù   r)   r)   r*   Úgenerate_category_image_promptå  s4   €4þ


ü(ÿ
$€þz8EnhancedMealPlanGenerator.generate_category_image_promptc              
   Ã   s†   �z$|   |||¡I d H }| j |||¡}|r#|tt ¡ ƒd d… fW S dW S  tyB } ztd|› d|› �ƒ W Y d }~dS d }~ww )Nr«   ©NNzCategory image error rð   )rH  r  r	  rA   ÚuuidÚuuid4rò   ró   )ré   r°   r  r@  rø   Úb64rù   r)   r)   r*   Úgenerate_single_category_imageü  s   €$€þz8EnhancedMealPlanGenerator.generate_single_category_imagec                 Ã   sN   �|j |j|jdœ}i }| ¡ D ]\}}|r |  |||¡I d H nd||< q|S )Nr¡   rI  )Úbreakfast_optionsÚlunch_optionsÚdinner_optionsr8   rM  )ré   Ú	meal_planr@  ÚcatsÚoutr<   Úmdr)   r)   r*   Úgenerate_category_images  s   €þ"z2EnhancedMealPlanGenerator.generate_category_imagesr@  c                 Ã   s¦  �t | dd¡ƒ}t| dd¡ƒ}| dd¡}| j| jB }t4 I d H š2 | |||p+d| dd¡| d	d¡| d
d¡| dd¡| dd¡dœ¡I d H }W d   ƒI d H  n1 I d H s[w   Y  t dd|j	 
¡ ¡}t dd|¡ 
¡ }zt |¡}W n tjy� }	 ztdd|	› �ƒ‚d }	~	ww | dd¡}
| di ¡}| d¡p²t|
d ƒt|
d ƒt|
d ƒdœ}t|
t| dd¡| dd¡| dd¡d �| d!d"¡t ¡ |d#�S )$Nr   r   r,   r-   r  r=   úNot specifiedr-  r.  Údesired_weightr/  Ú	main_goalúStay Fit)r   r,   r  r-  r.  rW  r/  rX  ú^```json\s*ú\s*```$r   z$Failed to parse nutrition response: Útotal_daily_caloriesr+  Útotal_daily_macronutrientsÚmeal_calorie_distributionç333333Ó?çš™™™™™Ù?r¡   Úcarbohydrateséú   Úproteinr   ÚfatéC   ©ra  rc  rd  Úuser_idÚunknown)r\  r]  rg  Úcalculation_timestampr^  )r+   r3   r6   r  r  ÚLLM_SEMAPHOREr=  ÚrerO   r>  r%   ÚjsonÚloadsÚJSONDecodeErrorr   r,  r   r   r   Únow)ré   r@  r   r,   r  rF  r  r>  r  rù   ÚtotalÚmacrosÚ	meal_distr)   r)   r*   Úcalculate_daily_nutrition  sT   €




ù(ÿ€ÿ



ý


ý
÷z3EnhancedMealPlanGenerator.calculate_daily_nutritionFÚdaily_nutritionÚgenerate_imagesc           #   
   ƒ   s”  �t | dd¡ƒ}t| dd¡ƒ}| dd¡}| jj||dd�I d H }| jj||d	d�I d H }td
t|ƒ› dt|ƒ› �ƒ t|||g | d¡d�}	t	||ƒ\}
‰ |r^|j
}|j}|jp\i }n|  | d¡| d¡| d¡¡}d }i }| dt|d ƒ¡}| dt|d ƒ¡}| dt|d ƒ¡}|d }|d }|d }|d }|d }|d }|r¶t |j|j|jdœ¡nd}| j| jB }t4 I d H šm | i d|“d|“d|pÒd“d| dd¡“d| dd¡“d| dd¡“d| dd¡“d| dd¡“d|“d|“d| dd ¡“d!t |¡“d"|“d#|“d$|“d%|“d&|“||
|	|  |¡d'œ¥¡I d H }W d   ƒI d H  n1 I d H �s8w   Y  t d(d|j ¡ ¡}t d)d|¡ ¡ }zt |¡}W n( tj�y } ztd*|› d+|d d,… › �ƒ |  ||¡W  Y d }~S d }~ww g d-¢}g d.¢}|D ]2}||v�r™|  ||¡  S |D ]} | || v�s¯t|| |  ƒd/k�r¹|  ||¡    S �q›�qŠ|D ]}|D ]} ‡ fd0d1„|| |  D ƒ|| | < �qÃ�q¿t |  !|d2 ¡|  !|d3 ¡|  !|d4 ¡| d5d6¡||| d!¡d7�}!|�r|j
|!_
|j|!_|�rH|  "|!|¡I d H }"|" dd8¡d9 |!_#|" dd8¡d: |!_$|" dd8¡d9 |!_%|" dd8¡d: |!_&|" dd8¡d9 |!_'|" dd8¡d: |!_(|!S );Nr   r   r,   r-   r  r=   r   ©ÚlimitéÈ   u!   [MealPlan] Pools â€” beneficial: ú, neutral: Úblood_group_rulesrI   r-  r.  r/  r¢   g      Ð?r£   r`  r¤   gffffffÖ?r·   rf  rV  Úfood_dislikesrÝ   Ú	allergiesÚtarget_caloriesr]  rX  rY  r^  Úbreakfast_cal_minÚbreakfast_cal_maxÚlunch_cal_minÚlunch_cal_maxÚdinner_cal_min)Údinner_cal_maxÚfood_databaserz  Úcountry_guidancerZ  r[  zJSON error: rÏ   i�  )rN  rO  rP  ©Úprotein_packedÚlight_freshÚhealthy_comfortingr9  c                    ó   g | ]}t |ˆ ƒ‘qS r)   ©rd   )rv   Úmeal©rÙ   r)   r*   rx   ¡  ó    ÿÿz@EnhancedMealPlanGenerator.generate_meal_plan.<locals>.<listcomp>rN  rO  rP  rg  rh  ©rN  rO  rP  rg  r   r,   r^  rI  r   r}   ))r+   r3   r6   r  Úget_beneficial_foodsÚget_neutral_foodsró   r�   rM   rÚ   r\  r]  r^  r1  r,  rl  Údumpsra  rc  rd  r  r  rj  r=  r)  rk  rO   r>  r%   rm  rn  Ú_create_fallback_meal_planr   Ú_convert_subcatsrU  Úbreakfast_imageÚbreakfast_image_idÚlunch_imageÚlunch_image_idÚdinner_imageÚdinner_image_id)#ré   r@  rt  ru  r   r,   r  ÚbenÚneurz  r„  Útargetrq  ÚdistÚb_calÚl_calÚd_calÚbreakfast_minÚbreakfast_maxÚ	lunch_minÚ	lunch_maxÚ
dinner_minÚ
dinner_maxÚ	macro_strrF  r  r>  r  rù   Úreq_catsÚreq_subsrÃ   rO   rQ  Úimgsr)   r�  r*   Úgenerate_meal_plan;  s  €û	ÿüýüÿÿþýüûúùø	÷
ö
õôóòñðì*ÿ€þ
$ÿÿ

þÿ
ù	z,EnhancedMealPlanGenerator.generate_meal_planÚswap_requestc                 ƒ   s2  �t |jpdƒ}t|jpdƒ}|jpd}|jpd}| ¡ }| jj||dd�I d H }| jj	||dd�I d H }	t
dt|ƒ› d	t|	ƒ› �ƒ t||	|ƒ\}
‰ | j| jB }t4 I d H š6 | || ¡ |jpbd
|||pgd|jpkd|jpod|jpsd|
|  |¡|  |¡dœ¡I d H }W d   ƒI d H  n1 I d H s“w   Y  t dd|j ¡ ¡}t dd|¡ ¡ }zt |¡}W n tjyÇ } ztdd|› �ƒ‚d }~ww d|vsÔt|d ƒdkrÙtddƒ‚‡ fdd„|d D ƒ|d< |   |d ¡}|�r	|D ]}| j!j"|j#|j$dd„ |j%D ƒ|jd�|_&qòt'|||j�pd
|j�pdd�S )Nr   r-   r=   ÚLunchi,  rv  é–   u!   [SwapMeal] Pools â€” beneficial: ry  ÚGeneralrV  iX  rÝ   )r°   Úcategory_upperrö   r   r,   r  r}  r|  r{  r„  Úmeal_structurer…  rZ  r[  r   z$Failed to parse swap meal response: Úalternativesr9  z$Expected exactly 3 alternative mealsc                    rŠ  r)   r‹  )rv   rC  r�  r)   r*   rx   í  rŽ  zAEnhancedMealPlanGenerator.generate_swap_meals.<locals>.<listcomp>c                 S   s   g | ]	}|j |jd œ‘qS )©r<   r\   r´  rî   r)   r)   r*   rx   ÷  ó    )rô   rõ   r[   rö   )r³  Úoriginal_categoryÚoriginal_sub_categoryr}  )(r+   r   r6   r,   r  r°   r4   r  r�  r‘  ró   r�   rÛ   r  r  rj  r=  r&   rö   Úcurrent_caloriesr|  r{  r*  r)  rk  rO   r>  r%   rl  rm  rn  r   Ú_convert_meal_listr  rú   rô   rõ   r[   Úimager   )ré   r­  ru  r   r,   r  r°   Úmeal_keyr›  rœ  r„  rF  r  r>  r  rù   rB  rC  r)   r�  r*   Úgenerate_swap_mealsÁ  sj   €

õ(ÿ€ÿ


þ
ý

üz-EnhancedMealPlanGenerator.generate_swap_mealsc           
      C   sè   t dƒ |r	|jn|  | d¡| d¡| d¡¡}|r |jpi ni }| dt|d ƒ¡}| dt|d ƒ¡}| d	t|d ƒ¡}d
d„ }t|d|ƒ|d|ƒ|d|ƒ| dd¡| dd¡| dd¡|||dœd�}	|rr|j|	_|j|	_|	S )NzUsing fallback meal planr-  r.  r/  r¢   r_  r£   r`  r¤   c                    s   g d¢}‡ ‡fdd„|D ƒS )Nr†  c                    s(   i | ]‰ ˆ ‡‡‡ fd d„t dƒD ƒ“qS )c                    s®   g | ]S}t ˆ› d ˆ dd ¡ ¡ › d |d › �ˆˆ dd ¡ ¡ ˆ tˆ d d ˆ d d ˆ d d d�d	ˆ dd ¡› d ˆ ¡ › d
�tdddd�tdddd�tdddd�gd�‘qS )rí   r�   r}   g      à?r­   r_  gš™™™™™É?é	   rf  zA balanced rH   zMixed vegetablesÚ100gu   ðŸ¥—r_   zProtein sourceÚ150gu   ðŸ�—zWhole grainsÚ80gu   ðŸŒ¾©rô   r°   rö   Útotal_caloriesÚmacronutrientsrõ   r[   )r   r3  r4  r   r4   r   rî   )Úcalr°   Úscr)   r*   rx     s     ô"ÿýùÿz`EnhancedMealPlanGenerator._create_fallback_meal_plan.<locals>._fb.<locals>.<dictcomp>.<listcomp>r9  )r…   )rv   ©rÄ  r°   )rÅ  r*   Ú
<dictcomp>  s    òóÿzUEnhancedMealPlanGenerator._create_fallback_meal_plan.<locals>._fb.<locals>.<dictcomp>r)   )r°   rÄ  Úsubsr)   rÆ  r*   Ú_fb  s   ñzAEnhancedMealPlanGenerator._create_fallback_meal_plan.<locals>._fbÚ	Breakfastr®  ÚDinnerrg  rh  r   r   r,   r-   r¡   r�  )ró   r\  r1  r3   r^  r,  r   r]  )
ré   r@  rt  r�  rž  rŸ  r   r¡  rÉ  Úmpr)   r)   r*   r“    s4   
ÿÿ€ 



ù	z4EnhancedMealPlanGenerator._create_fallback_meal_planr  c                    s   ‡ fdd„|  ¡ D ƒS )Nc                    s   i | ]
\}}|ˆ   |¡“qS r)   )r¹  )rv   rO   rB  rè   r)   r*   rÇ  1  r|   z>EnhancedMealPlanGenerator._convert_subcats.<locals>.<dictcomp>)r8   )ré   r  r)   rè   r*   r”  0  rë   z*EnhancedMealPlanGenerator._convert_subcatsÚ	meal_listc                 C   sB  g }|D ]š}zVdd„ |  dg ¡D ƒ}|  di ¡}t|tƒs#ddddœ}| t|  d	d
¡|  dd¡|  dd¡|  dd¡t|  dd¡|  dd¡|  dd¡d�|  dd¡||  dd¡d�¡ W q tyž } z6td|› �ƒ | td|rw|  dd¡nd|r€|  dd¡nddtdddd�dtdddd�gd �¡ W Y d }~qd }~ww |S )!Nc                 S   s4   g | ]}t |tƒrtdi |¤Žntt|ƒd d�‘qS )z	as neededr´  r)   )r?   r@   r   rA   r8  r)   r)   r*   rx   7  s
    þþz@EnhancedMealPlanGenerator._convert_meal_list.<locals>.<listcomp>r[   rÃ  é(   r¦   r¨   rf  rô   zUnnamed Mealr°   r   rö   r°  rÂ  r   ra  rc  rd  rõ   r=   Únumber_of_servingsr}   )rô   r°   rö   rÂ  rÃ  rõ   r[   rÏ  zMeal conversion error: zDefault MealzA balanced mealzMixed ingredientsz	1 servingr^   r_   rÁ  )	r3   r?   r@   rB   r   r   rò   ró   r   )ré   rÍ  rB  rT  r[   Úmrrù   r)   r)   r*   r¹  3  sJ   
ý







ý

ôù€þz,EnhancedMealPlanGenerator._convert_meal_listr7  )NF)F)r  r  r  r   r   rê   ÚstaticmethodrA   r)  r*  r,  r1  r   r5  rH  rM  rU  r   rs  Úboolr   r¬  r   r   r¼  r“  r   r   r”  r¹  r)   r)   r)   r*   r  â  sP       _
	
/üþýü
û 
ýþý
ü
B*-r  c                   @   s¶   e Zd Zdded fdd„Zededefdd	„ƒZd
ede	de
fdd„Zdee dededededee dee dee de	eef fdd„Zedd„ ƒZedd„ ƒZedd„ ƒZdS )ÚFoodScannerNr  r   c                 C   sD   t ddt d¡d�| _|| _t d¡| _t d¡| _t d¡| _	d S )Nr  g        rã   r  a^  
        You are an expert food image analysis system.

        Your task is ONLY to identify visible food ingredients from the image.

        IMPORTANT RULES:
        1. Identify ONLY ingredients that are visually present.
        2. Do NOT use dietary logic, blood type logic, allergies, or health assumptions.
        3. Do NOT guess hidden ingredients unless visually obvious.
        4. Keep ingredient names simple and consistent.
        5. Include sauces, oils, spices, garnishes, toppings, vegetables, meats, grains, and beverages if visible.
        6. The same image should always produce the same ingredient list.
        7. Do NOT classify ingredients as healthy, harmful, beneficial, or avoid.
        8. Do NOT explain anything.

        COUNTRY CONTEXT:
        {country_guidance}

        Return ONLY valid JSON:

        {{
            "identified_ingredients": [
                "ingredient1",
                "ingredient2",
                "ingredient3"
            ]
        }}

        If no ingredients can be identified:

        {{
            "identified_ingredients": []
        }}
        u 
  
        You are a precise food compatibility classifier.

        **USER PROFILE**
        - Blood Type: {blood_type}
        - Diet: {diet_type}
        - Allergies: {allergies}
        - Country: {country}

        **BLOOD GROUP RULES** (ground truth â€“ follow these when classifying)
        {blood_group_rules}

        **REFERENCE LISTS** (same data broken out for matching)
        Beneficial foods for {blood_type}:
        {beneficial_list}

        Neutral foods:
        {neutral_list}

        Avoid foods:
        {avoid_list}

        **TASK**
        Given the list of identified ingredients below, classify each ingredient into one of three categories:
        - "safe"   (beneficial or allowed)
        - "neutral" (allowed but not particularly beneficial)
        - "avoid"  (harmful based on blood type, diet, or allergy)

        **RULES FOR CLASSIFICATION AND REASON** (MUST FOLLOW EXACTLY):
        1. If an ingredient matches an allergy â†’ status = "avoid", reason = "Not Suitable Due to Your Allergies: {{allergen}}"
        (replace {{allergen}} with the actual allergen, e.g., "Not Suitable Due to Your Allergies: peanuts")
        2. If diet is "vegan" and ingredient contains any animal product (meat, dairy, egg, honey, gelatin, etc.) â†’ status = "avoid", reason = "Not Suitable For Your Vegan Diet"
        3. If diet is "vegetarian" and ingredient contains meat or seafood â†’ status = "avoid", reason = "Not Suitable For Your Vegetarian Diet"
        4. Otherwise, use BLOOD GROUP RULES / reference lists:
        - If ingredient is in "avoid" list â†’ status = "avoid", reason = "Not Recommended For your Blood Type {blood_type} Diet"
        - If ingredient is in "beneficial" list â†’ status = "safe", reason = "" (empty string)
        - If ingredient is in "neutral" list â†’ status = "neutral", reason = "" (empty string)
        - If ingredient not in any list, use general nutritional knowledge for the given blood type and diet, and produce a reason accordingly (but prefer the exact strings above when possible).

        **IMPORTANT**: 
        - For any "avoid", the reason MUST be exactly one of the three formats above.
        - For "safe" or "neutral", reason MUST be an empty string "".
        - Accept synonyms, plurals, and common variations (e.g., "tomatoes" = "tomato").

        **IDENTIFIED INGREDIENTS** (from the image):
        {ingredients_json}

        **OUTPUT FORMAT** (valid JSON only)
        {{
        "classifications": [
            {{
            "ingredient": "exact ingredient name as given",
            "status": "safe|neutral|avoid",
            "reason": "exact reason string as specified above"
            }}
        ]
        }}
        u  
        You are a BloodFIT nutrition coach writing short explanations for a food scan result.

        USER PROFILE
        - Blood Type: {blood_type}
        - Diet: {diet_type}
        - Allergies: {allergies}

        TYPES PRESENT IN THIS SCAN (generate a description for EACH of these only):
        {present_types}

        INGREDIENTS FOUND IN THE IMAGE:
        - Beneficial: {beneficial_ingredients}
        - Neutral: {neutral_ingredients}
        - Avoid: {avoid_ingredients}

        BLOOD GROUP RULES:
        {blood_group_rules}

        TASK
        For EACH type listed under TYPES PRESENT, write ONE short description (1â€“2 sentences)
        explaining what that category means for THIS scan and this user's blood type / diet.
        Be specific to the ingredients in that category when possible.
        Tone: clear, supportive, product-ready (BloodFIT style). No markdown or bullet points.

        Return ONLY valid JSON with a key for every present type title exactly:
        {{
            "descriptions": {{
                "Beneficial": "description if Beneficial is present, else omit",
                "Neutral": "description if Neutral is present, else omit",
                "Avoid": "description if Avoid is present, else omit"
            }}
        }}
        )
r   rå   ræ   r  r  r	   r  Úfood_scan_promptÚclassify_promptÚtype_description_promptr  r)   r)   r*   rê   _  s   ý$<zFoodScanner.__init__r  r   c                 C   r  )NzMTraditional Chinese cuisine: steamed dishes, vegetables, rice, tofu, seafood.z;Korean cuisine: vegetables, rice, fermented foods, seafood.r  zXGeneral international cuisine. Focus on whole foods appropriate for blood type and diet.r!  r  r#  r   zGeneral guidance for z	 cuisine.r&  r'  r)   r)   r*   r)  ë  s   þz FoodScanner.get_country_guidanceÚ
image_datar@  c           '      ƒ   s  ��zët | dd¡ƒ}t| dd¡ƒ}| dd¡}| dd¡}g g g }}}	| jrE| j |¡I d H }| j |¡I d H }| j |¡I d H }	t||||	| d¡d	�}
d7dd„}t 	|¡ 
d¡}dd| jj|  |¡d�dœddd|› �idœgdœg}| j |¡}|j ¡ }d }zt |¡}W n) tjy¶   t d|tj¡}|r´z
t | d¡¡}W n
 tjy³   Y nw Y nw |sÆtg g g g dddg d�W S | dg ¡}|sÛtg g g g dddg d�W S | jj|| ¡ |påd|pèd|
||ƒ||ƒ||	ƒt |¡d�	}d|dœg}| j |¡}|j ¡ }zt |¡}W n# tj�y4   t d|tj¡}|�r.t | d¡¡}ntd ƒ‚Y nw | d!g ¡}g }g }g }|D ]M}|d" }|d#  ¡ }| d$d¡}|d%k�rxd&|v �rbd'} n
d(|v �rjd)} nd} | t ||| d*�¡ �qC|d+k�r‡| t!|d,�¡ �qC| t"|d,�¡ �qC|  #|||¡}!|  $|¡}"|  %|¡}#t&t'|ƒt'|ƒt'|ƒd-�}$g }%|$�rá| j(d.d/„ |$D ƒ|||�pÂd|
d0d/„ |D ƒd1d/„ |D ƒd2d/„ |D ƒd3�‰ ‡ fd4d/„|$D ƒ}%t|||||!|"|#|%d�W S  t)�y }& zt* +¡  t,d5d6|&› �ƒ‚d }&~&ww )8Nr   r   r,   r-   r  r=   r|  rz  rI   rÜ   c                 S   s   | rd  | d |… ¡S dS )Nr>   r:   rà   )Úlstr9   r)   r)   r*   Úfmt  s   z(FoodScanner.scan_food_image.<locals>.fmtzutf-8ÚuserÚtext)r…  )ÚtyperÛ  Ú	image_urlÚurlzdata:image/jpeg;base64,)rÜ  rÝ  ©Úroler>  ú(\{.*\})r}   z8Unable to analyse the image. Please try a clearer photo.)Úidentified_ingredientsÚharmful_ingredientsÚsafe_ingredientsÚneutral_ingredientsÚwarning_messageÚsafe_messageÚneutral_messageÚ
food_typesrâ  z:No ingredients detected. Please ensure the image is clear.rÝ   ÚUnknown)	r   r,   r|  r  rz  Úbeneficial_listÚneutral_listÚ
avoid_listÚingredients_jsonz(No valid JSON in classification responseÚclassificationsrW   ÚstatusÚreasonrL   Ú	AllergiesÚallergyÚDietÚdiet)r<   rñ  r°   ÚsaferP   )Úhas_beneficialÚhas_neutralÚ	has_avoidc                 S   ó   g | ]}|j ‘qS r)   )r4  ©rv   Útr)   r)   r*   rx   Ž  ó    z/FoodScanner.scan_food_image.<locals>.<listcomp>c                 S   rú  r)   rP   rî   r)   r)   r*   rx   “  rý  c                 S   rú  r)   rP   rî   r)   r)   r*   rx   ”  rý  c                 S   rú  r)   rP   rî   r)   r)   r*   rx   •  rý  )Úpresent_titlesr   r,   r|  rz  Úbeneficial_ingredientsrå  Úavoid_ingredientsc              	      s*   g | ]}t |j|jˆ  |j|j¡d �‘qS ))Úkeyr4  rõ   )r   r  r4  r3   rõ   rû  ©Úai_descriptionsr)   r*   rx   —  s    ûýÿr   zFood scanning failed: ©rÜ   )-r+   r3   r6   r  r�  r‘  Úget_avoid_foodsrM   Úbase64Ú	b64encodeÚdecoderÔ  Úformatr)  r  Úinvoker>  r%   rl  rm  rn  rk  ÚsearchÚDOTALLÚgroupr   rÕ  Ú
capitalizer’  Ú
ValueErrorr4   rB   r   r   r   Ú_warning_msgÚ	_safe_msgÚ_neutral_msgr   rÒ  Ú_generate_type_descriptionsrò   Ú	tracebackÚ	print_excr   )'ré   r×  r@  r   r,   r  r|  rJ   rK   rL   rz  rÙ  Ú	image_b64Úvision_messagesÚresponser>  Ú	scan_datarC  Ú
identifiedÚclassify_textÚclassify_messagesÚclassify_responseÚclassify_contentÚclassify_resultrï  rã  rä  rå  rE   Úing_namerð  rñ  r°   Úwarning_msgÚsafe_msgÚneutral_msgÚpresent_typesré  rù   r)   r  r*   Úscan_food_imageú  s$  €û
ÿþþùþ
ÿ€ûûû	÷
þý


ý


ýø

ú	ø€þzFoodScanner.scan_food_imagerþ  r   r,   r|  rz  rÿ  rå  r   c             
      sV  ddddœ‰ ‡ fdd„|D ƒ}	|s|	S z|| j j|| ¡ |d |¡d |¡p&dd |¡p,dd |¡p2d|d	�}
| j d
|
dœg¡}|jpDd ¡ }zt 	|¡}W n tj
yl   t d|tj¡}|rht 	| d¡¡ni }Y nw | d¡psi }t|tƒr�|D ]}| |¡pƒd ¡ }|rŒ||	|< q{|	W S  tyª } ztd|› �ƒ |	W  Y d}~S d}~ww )z?Ask the LLM for a short description for each present food type.ziFoods that are strongly aligned with your blood-type profile and are prioritised in your recommendations.znFoods that are compatible with your blood-type profile and can be enjoyed as part of your BloodFIT meal plans.zIFoods that BloodFIT recommends limiting based on your blood-type profile.)r¹   rº   ÚAvoidc                    s   i | ]	}|ˆ   |d ¡“qS r  rz   )rv   r4  ©Úfallbackr)   r*   rÇ  Ê  rµ  z;FoodScanner._generate_type_descriptions.<locals>.<dictcomp>r>   rÝ   )r   r,   r|  r$  rÿ  rå  r   rz  rÚ  rß  r=   rá  r}   Údescriptionsz2[FoodScanner] type description generation failed: N)rÖ  r	  r  rC   r  r
  r>  r%   rl  rm  rn  rk  r  r  r  r3   r?   r@   rò   ró   )ré   rþ  r   r,   r|  rz  rÿ  rå  r   rŒ   Úprompt_textr  r>  r  rC  r)  r4  rÛ  rù   r)   r'  r*   r  ¯  sN   öø
þ
€€þz'FoodScanner._generate_type_descriptionsc                 C   s^   | sdS dd„ | D ƒ}t |ƒdkrd|d › d| d j› �S dd |¡› d	|› d
| ¡ › d�S )Nz,No Avoid ingredients found for your profile!c                 S   rú  r)   rP   rî   r)   r)   r*   rx   ñ  rý  z,FoodScanner._warning_msg.<locals>.<listcomp>r}   zAvoid r   z! r>   z9! These ingredients are not suitable for your Blood Type rí   z Diet.)r�   rñ  rC   r  )Úharmfulr   r,   rD   r)   r)   r*   r  í  s   ÿÿÿzFoodScanner._warning_msgc                 C   s6   | sdS dd„ | D ƒ}t |ƒdkrdd |¡› �S dS )Nz%No beneficial ingredients identified.c                 S   rú  r)   rP   rî   r)   r)   r*   rx   ý  rý  z)FoodScanner._safe_msg.<locals>.<listcomp>r9  zBeneficial to eat: r>   z6All other ingredients are beneficial for your profile.©r�   rC   )rö  rD   r)   r)   r*   r  ù  s    zFoodScanner._safe_msgc                 C   s@   | sdS dd„ | D ƒ}t |ƒdkr|d › d�S d |¡› d�S )	Nr=   c                 S   rú  r)   rP   rî   r)   r)   r*   rx     rý  z,FoodScanner._neutral_msg.<locals>.<listcomp>r}   r   uH    is a neutral food â€“ allowed but not particularly beneficial or avoid.r>   uH    are neutral foods â€“ allowed but not particularly beneficial or avoid.r,  )rK   rD   r)   r)   r*   r     s   zFoodScanner._neutral_msgr7  )r  r  r  r   rê   rÑ  rA   r)  Úbytesr   r   r%  r   r  r  r  r  r)   r)   r)   r*   rÓ  ^  s@      6ýüûúùø	÷
ö

õ>

rÓ  )r7   )NNNNr7  r  )Mr  rl  Úasynciork  rJ  rƒ   r  r   Útypingr   r   r   r   Úfastapir   Úlangchain_openair   Úlangchain.promptsr	   Úopenair
   Údotenvr   rå   Úfitness_app.data_managerr   r   r   r   r   r   r   r   r   r   r   r   r   Úfitness_app.vector_storer   r   Ú	Semaphorerj  r<  ÚcompileÚ
IGNORECASErN   rA   r+   r6   r,  rF   rM   rQ   rV   rY   rd   rk   Ú__annotations__ÚMEAL_TIME_ELIGIBLErÒ  rp   r€   r‘   rŸ   r¥   rÕ   r®   r³   rÌ   rÔ   rÚ   rÛ   rá   râ   r  rÓ  r)   r)   r)   r*   Ú<module>   s  
 <

üûÿû
ú"ÿ
þ
ý	üÿþýü
ûB÷ý
ÿû	ÿþý
üû
ú-ÿþ
ýÿþ
ýÿþý
ü>       