TastyPiano / src /cocktails /utilities /cocktail_utilities.py
Cédric Colas
initial commit
e775f6d
raw
history blame
9.27 kB
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