import numpy as np from src.cocktails.utilities.ingredients_utilities import ingredient2ingredient_id, ingredient_profiles, ingredients_per_type, ingredient_list, find_ingredient_from_str from src.cocktails.utilities.cocktail_category_detection_utilities import * import time # representation_keys = ['pH', 'sour', 'sweet', 'booze', 'bitter', 'fruit', 'herb', # 'complex', 'spicy', 'strong', 'oaky', 'fizzy', 'colorful', 'eggy'] representation_keys = ['sour', 'sweet', 'booze', 'bitter', 'fruit', 'herb', 'complex', 'spicy', 'oaky', 'fizzy', 'colorful', 'eggy'] representation_keys_linear = list(set(representation_keys) - set(['pH', 'complex'])) ing_reps = np.array([[ingredient_profiles[k][ing_id] for ing_id in ingredient2ingredient_id.values()] for k in representation_keys]).transpose() def compute_cocktail_representation(profile, ingredients, quantities): # computes representation of a cocktail from the recipe (ingredients, quantities) and volume n = len(ingredients) assert n == len(quantities) quantities = np.array(quantities) weights = quantities / np.sum(quantities) rep = dict() ing_ids = np.array([ingredient2ingredient_id[ing] for ing in ingredients]) # compute features as linear combination of ingredient features for k in representation_keys_linear: k_ing = np.array([ingredient_profiles[k][ing_id] for ing_id in ing_ids]) rep[k] = np.dot(weights, k_ing) # for ph # ph = - log10 x phs = np.array([ingredient_profiles['pH'][ing_id] for ing_id in ing_ids]) concentrations = 10 ** (- phs) mix_c = np.dot(weights, concentrations) rep['pH'] = - np.log10(mix_c) rep['complex'] = np.mean([ingredient_profiles['complex'][ing_id] for ing_id in ing_ids]) + len(ing_ids) # compute profile after dilution volume_ratio = profile['mix volume'] / profile['end volume'] for k in representation_keys: rep['end ' + k] = rep[k] * volume_ratio concentration = 10 ** (-rep['pH']) end_concentration = concentration * volume_ratio rep['end pH'] = - np.log10(end_concentration) return rep def get_alcohol_profile(ingredients, quantities): ingredients = ingredients.copy() quantities = quantities.copy() assert len(ingredients) == len(quantities) if 'mint' in ingredients: mint_ind = ingredients.index('mint') ingredients.pop(mint_ind) quantities.pop(mint_ind) alcohol = [] volume_mix = np.sum(quantities) weights = quantities / volume_mix assert np.abs(np.sum(weights) - 1) < 1e-4 ingredients_list = [ing.lower() for ing in ingredient_list] for ing, q in zip(ingredients, quantities): id = ingredients_list.index(ing) alcohol.append(ingredient_profiles['ethanol'][id]) alcohol = np.dot(alcohol, weights) return alcohol, volume_mix def get_mix_profile(ingredients, quantities): ingredients = ingredients.copy() quantities = quantities.copy() assert len(ingredients) == len(quantities) if 'mint' in ingredients: mint_ind = ingredients.index('mint') ingredients.pop(mint_ind) quantities.pop(mint_ind) alcohol, sugar, acid = [], [], [] volume_mix = np.sum(quantities) weights = quantities / volume_mix assert np.abs(np.sum(weights) - 1) < 1e-4 ingredients_list = [ing.lower() for ing in ingredient_list] for ing, q in zip(ingredients, quantities): id = ingredients_list.index(ing) sugar.append(ingredient_profiles['sugar'][id]) alcohol.append(ingredient_profiles['ethanol'][id]) acid.append(ingredient_profiles['acid'][id]) sugar = np.dot(sugar, weights) acid = np.dot(acid, weights) alcohol = np.dot(alcohol, weights) return alcohol, sugar, acid def extract_preparation_type(instructions, recipe): flag = False instructions = instructions.lower() egg_in_recipe = any([find_ingredient_from_str(ing_str)[1]=='egg' for ing_str in recipe[1]]) if 'shake' in instructions: if egg_in_recipe: prep_type = 'egg_shaken' else: prep_type = 'shaken' elif 'stir' in instructions: prep_type = 'stirred' elif 'blend' in instructions: prep_type = 'blended' elif any([w in instructions for w in ['build', 'mix', 'pour', 'combine', 'place']]): prep_type = 'built' else: prep_type = 'built' if egg_in_recipe and 'shaken' not in prep_type: stop = 1 return flag, prep_type def get_dilution_ratio(category, alcohol): # formulas from the Liquid Intelligence book # The formula for built was invented if category == 'stirred': return -1.21 * alcohol**2 + 1.246 * alcohol + 0.145 elif category in ['shaken', 'egg_shaken']: return -1.567 * alcohol**2 + 1.742 * alcohol + 0.203 elif category == 'built': return (-1.21 * alcohol**2 + 1.246 * alcohol + 0.145) /2 else: return 1 def get_cocktail_rep(category, ingredients, quantities, keys): ingredients = ingredients.copy() quantities = quantities.copy() assert len(ingredients) == len(quantities) volume_mix = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] != 'mint']) # compute alcohol content without mint ingredient ingredients2 = [ing for ing in ingredients if ing != 'mint'] quantities2 = [q for ing, q in zip(ingredients, quantities) if ing != 'mint'] weights2 = quantities2 / np.sum(quantities2) assert np.abs(np.sum(weights2) - 1) < 1e-4 ing_ids2 = np.array([ingredient2ingredient_id[ing] for ing in ingredients2]) alcohol = np.array([ingredient_profiles['ethanol'][ing_id] for ing_id in ing_ids2]) alcohol = np.dot(alcohol, weights2) dilution_ratio = get_dilution_ratio(category, alcohol) end_volume = volume_mix + volume_mix * dilution_ratio volume_ratio = volume_mix / end_volume end_alcohol = alcohol * volume_ratio # computes representation of a cocktail from the recipe (ingredients, quantities) and volume weights = quantities / np.sum(quantities) assert np.abs(np.sum(weights) - 1) < 1e-4 ing_ids = np.array([ingredient2ingredient_id[ing] for ing in ingredients]) reps = ing_reps[ing_ids] cocktail_rep = np.dot(weights, reps) i_complex = keys.index('end complex') cocktail_rep[i_complex] = np.mean(reps[:, i_complex]) + len(ing_ids) # complexity increases with number of ingredients # compute profile after dilution cocktail_rep = cocktail_rep * volume_ratio cocktail_rep = np.concatenate([[end_volume], cocktail_rep]) return cocktail_rep, end_volume, end_alcohol def get_profile(category, ingredients, quantities): volume_mix = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] != 'mint']) alcohol, sugar, acid = get_mix_profile(ingredients, quantities) dilution_ratio = get_dilution_ratio(category, alcohol) end_volume = volume_mix + volume_mix * dilution_ratio volume_ratio = volume_mix / end_volume profile = {'mix volume': volume_mix, 'mix alcohol': alcohol, 'mix sugar': sugar, 'mix acid': acid, 'dilution ratio': dilution_ratio, 'end volume': end_volume, 'end alcohol': alcohol * volume_ratio, 'end sugar': sugar * volume_ratio, 'end acid': acid * volume_ratio} cocktail_rep = compute_cocktail_representation(profile, ingredients, quantities) profile.update(cocktail_rep) return profile profile_keys = ['mix volume', 'end volume', 'dilution ratio', 'mix alcohol', 'end alcohol', 'mix sugar', 'end sugar', 'mix acid', 'end acid'] \ + representation_keys \ + ['end ' + k for k in representation_keys] def update_profile_in_datapoint(datapoint, category, ingredients, quantities): profile = get_profile(category, ingredients, quantities) for k in profile_keys: datapoint[k] = profile[k] return datapoint # define representation keys def get_bunch_of_rep_keys(): dict_rep_keys = dict() # all rep_keys = profile_keys dict_rep_keys['all'] = rep_keys # only_end rep_keys = [k for k in profile_keys if 'end' in k ] dict_rep_keys['only_end'] = rep_keys # except_end rep_keys = [k for k in profile_keys if 'end' not in k ] dict_rep_keys['except_end'] = rep_keys # custom to_remove = ['end alcohol', 'end sugar', 'end acid', 'end pH', 'end strong'] rep_keys = [k for k in profile_keys if 'end' in k ] for k in to_remove: if k in rep_keys: rep_keys.remove(k) dict_rep_keys['custom'] = rep_keys # custom restricted to_remove = ['end alcohol', 'end sugar', 'end acid', 'end pH', 'end strong', 'end spicy', 'end oaky'] rep_keys = [k for k in profile_keys if 'end' in k ] for k in to_remove: if k in rep_keys: rep_keys.remove(k) dict_rep_keys['restricted'] = rep_keys dict_rep_keys['affective'] = ['end booze', 'end sweet', 'end sour', 'end fizzy', 'end complex', 'end bitter', 'end spicy', 'end colorful'] return dict_rep_keys