Spaces:
Runtime error
Runtime error
| import numpy as np | |
| import pickle | |
| from src.cocktails.utilities.cocktail_utilities import get_profile, profile_keys | |
| from src.cocktails.utilities.ingredients_utilities import extract_ingredients, ingredient_list, ingredient_profiles | |
| from src.cocktails.utilities.glass_and_volume_utilities import glass_volume, volume_ranges | |
| one_dash = 1 | |
| one_splash = 6 | |
| one_tablespoon = 15 | |
| one_barspoon = 5 | |
| fill_rate = 0.8 | |
| quantity_factors ={'ml':1, | |
| 'cl':10, | |
| 'splash':one_splash, | |
| 'splashes':one_splash, | |
| 'dash':one_dash, | |
| 'dashes':one_dash, | |
| 'spoon':one_barspoon, | |
| 'spoons':one_barspoon, | |
| 'tablespoon':one_tablespoon, | |
| 'barspoons':one_barspoon, | |
| 'barspoon':one_barspoon, | |
| 'bar spoons': one_barspoon, | |
| 'bar spoon': one_barspoon, | |
| 'tablespoons':one_tablespoon, | |
| 'teaspoon':5, | |
| 'teaspoons':5, | |
| 'drop':0.05, | |
| 'drops':0.05} | |
| quantitiy_keys = sorted(quantity_factors.keys()) | |
| indexes_keys = np.flip(np.argsort([len(k) for k in quantitiy_keys])) | |
| quantity_factors_keys = list(np.array(quantitiy_keys)[indexes_keys]) | |
| keys_to_track = ['names', 'urls', 'glass', 'garnish', 'recipe', 'how_to', 'review', 'taste_rep', 'valid'] | |
| keys_to_add = ['category', 'subcategory', 'ingredients_str', 'ingredients', 'quantities', 'to_keep'] | |
| keys_to_update = ['glass'] | |
| keys_for_csv = ['names', 'category', 'subcategory', 'ingredients_str', 'urls', 'glass', 'garnish', 'how_to', 'review', 'taste_rep'] + profile_keys | |
| to_replace_q = {' fresh': ''} | |
| to_replace_ing = {'maple syrup': 'honey syrup', | |
| 'agave syrup': 'honey syrup', | |
| 'basil': 'mint'} | |
| def print_recipe(unit='mL', ingredient_str=None, ingredients=None, quantities=None, name='', cat='', to_print=True): | |
| str_out = '' | |
| if ingredient_str is None: | |
| assert len(ingredients) == len(quantities), 'provide either ingredient_str, or list ingredients and quantities' | |
| else: | |
| assert ingredients is None and quantities is None, 'provide either ingredient_str, or list ingredients and quantities' | |
| ingredients, quantities = extract_ingredients(ingredient_str) | |
| str_out += f'\nRecipe:' | |
| if name != '' and name is not None: str_out += f' {name}' | |
| if cat != '': str_out += f' ({cat})' | |
| str_out += '\n' | |
| for i in range(len(ingredients)): | |
| # get quantifier | |
| if ingredients[i] == 'egg': | |
| quantities[i] = 1 | |
| ingredients[i] = 'egg white' | |
| if unit == 'mL': | |
| quantifier = ' (30 mL)' | |
| elif unit == 'oz': | |
| quantifier = ' (1 fl oz)' | |
| else: | |
| raise ValueError | |
| elif ingredients[i] in ['angostura', 'orange bitters']: | |
| quantities[i] = max(1, int(quantities[i] / 0.6)) | |
| quantifier = ' dash' | |
| if quantities[i] > 1: quantifier += 'es' | |
| elif ingredients[i] == 'mint': | |
| if quantities[i] > 1: quantifier = ' leaves' | |
| else: quantifier = ' leaf' | |
| else: | |
| if unit == "oz": | |
| quantities[i] = float(f"{quantities[i] * 0.033814:.3f}") # convert to fl oz | |
| quantifier = ' fl oz' | |
| else: | |
| quantifier = ' mL' | |
| str_out += f' {quantities[i]}{quantifier} - {ingredients[i]}\n' | |
| if to_print: | |
| print(str_out) | |
| return str_out | |
| def test_datapoint(datapoint, category, ingredients, quantities): | |
| # run checks | |
| ingredient_indexes = [ingredient_list.index(ing) for ing in ingredients] | |
| profile = get_profile(category, ingredients, quantities) | |
| volume = profile['end volume'] | |
| alcohol = profile['end alcohol'] | |
| acid = profile['end acid'] | |
| sugar = profile['end sugar'] | |
| # check volume | |
| if datapoint['glass'] != None: | |
| if volume > glass_volume[datapoint['glass']] * fill_rate: | |
| # recompute quantities for it to match | |
| ratio = fill_rate * glass_volume[datapoint['glass']] / volume | |
| for i_q in range(len(quantities)): | |
| quantities[i_q] = float(f'{quantities[i_q] * ratio:.2f}') | |
| # check alcohol | |
| assert alcohol < 30, 'too boozy' | |
| assert alcohol < 5, 'not boozy enough' | |
| assert acid < 2, 'too much acid' | |
| assert sugar < 20, 'too much sugar' | |
| assert len(ingredients) > 1, 'only one ingredient' | |
| if len(set(ingredients)) != len(ingredients): | |
| i_doubles = [] | |
| s_ing = set() | |
| for i, ing in enumerate(ingredients): | |
| if ing in s_ing: | |
| i_doubles.append(i) | |
| else: | |
| s_ing.add(ing) | |
| ingredient_double_ok = ['mint', 'cointreau', 'lemon juice', 'cuban rum', 'double syrup'] | |
| if len(i_doubles) == 1 and ingredients[i_doubles[0]] in ingredient_double_ok: | |
| ing_double = ingredients[i_doubles[0]] | |
| double_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] == ing_double]) | |
| ingredients.pop(i_doubles[0]) | |
| quantities.pop(i_doubles[0]) | |
| quantities[ingredients.index(ing_double)] = double_q | |
| else: | |
| assert False, f'double ingredient, not {ingredient_double_ok}' | |
| lemon_lime_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] in ['lime juice', 'lemon juice']]) | |
| assert lemon_lime_q <= 45, 'too much lemon and lime' | |
| salt_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] == 'salt']) | |
| assert salt_q <= 8, 'too much salt' | |
| bitter_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] in ['angostura', 'orange bitters']]) | |
| assert bitter_q <= 5 * one_dash, 'too much bitter' | |
| absinthe_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] == 'absinthe']) | |
| if absinthe_q > 4 * one_dash: | |
| mix_volume = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] != 'mint']) | |
| assert absinthe_q < 0.5 * mix_volume, 'filter absinthe glasses' | |
| if any([w in datapoint['how_to'] or any([w in ing.lower() for ing in datapoint['recipe'][1]]) for w in ['warm', 'boil', 'hot']]) and 'shot' not in datapoint['how_to']: | |
| assert False | |
| water_q = np.sum([quantities[i] for i in range(len(ingredients)) if ingredients[i] == 'water']) | |
| assert water_q < 40 | |
| # n_liqueur = np.sum([ingredient_profiles['type'][i].lower() == 'liqueur' for i in ingredient_indexes]) | |
| # assert n_liqueur <= 2 | |
| n_liqueur_and_vermouth = np.sum([ingredient_profiles['type'][i].lower() in ['liqueur', 'vermouth'] for i in ingredient_indexes]) | |
| assert n_liqueur_and_vermouth <= 3 | |
| return ingredients, quantities | |
| def run_battery_checks_difford(datapoint, category, ingredients, quantities): | |
| flag = False | |
| try: | |
| ingredients, quantities = test_datapoint(datapoint, category, ingredients, quantities) | |
| except: | |
| flag = True | |
| print(datapoint["names"]) | |
| print(datapoint["urls"]) | |
| ingredients, quantities = None, None | |
| return flag, ingredients, quantities | |
| def tambouille(q, ingredients_scrubbed, quantities_scrubbed, cat): | |
| # ugly | |
| ing_scrubbed = ingredients_scrubbed[len(quantities_scrubbed)] | |
| if q == '4 cube' and ing_scrubbed == 'pineapple juice': | |
| q = '20 ml' | |
| elif 'top up with' in q: | |
| volume_so_far = np.sum([quantities_scrubbed[i] for i in range(len(quantities_scrubbed)) if ingredients_scrubbed[i] != 'mint']) | |
| volume_mix = np.sum(volume_ranges[cat]) / 2 | |
| if (volume_mix - volume_so_far) < 15: | |
| q = '15 ml'# | |
| else: | |
| q = str(int(volume_mix - volume_so_far)) + ' ml' | |
| elif q == '1 pinch' and ing_scrubbed == 'salt': | |
| q = '2 drops' | |
| elif 'cube' in q and ing_scrubbed == 'double syrup': | |
| q = f'{float(q.split(" ")[0]) * 2 * 1.7:.2f} ml' #2g per cube, 1.7 is ratio solid / syrup | |
| elif 'wedge' in q: | |
| if ing_scrubbed == 'orange juice': | |
| vol = 70 | |
| elif ing_scrubbed == 'lime juice': | |
| vol = 30 | |
| elif ing_scrubbed == 'lemon juice': | |
| vol = 45 | |
| elif ing_scrubbed == 'pineapple juice': | |
| vol = 140 | |
| factor = float(q.split(' ')[0]) * 0.15 # consider a wedge to be 0.15*the fruit. | |
| q = f'{factor * vol:.2f} ml' | |
| elif 'slice' in q: | |
| if ing_scrubbed == 'orange juice': | |
| vol = 70 | |
| elif ing_scrubbed == 'lime juice': | |
| vol = 30 | |
| elif ing_scrubbed == 'lemon juice': | |
| vol = 45 | |
| elif ing_scrubbed == 'pineapple juice': | |
| vol = 140 | |
| f = q.split(' ')[0] | |
| if len(f.split('⁄')) > 1: | |
| frac = f.split('⁄') | |
| factor = float(frac[0]) / float(frac[1]) | |
| else: | |
| factor = float(f) | |
| factor *= 0.1 # consider a slice to be 0.1*the fruit. | |
| q = f'{factor * vol:.2f} ml' | |
| elif q == '1 whole' and ing_scrubbed == 'luxardo maraschino': | |
| q = '10 ml' | |
| elif ing_scrubbed == 'egg' and 'ml' not in q: | |
| q = f'{float(q) * 30:.2f} ml' # 30 ml per egg | |
| return q | |
| def compute_eucl_dist(a, b): | |
| return np.sqrt(np.sum((a - b)**2)) | |
| def evaluate_with_quadruplets(representations, strategy='all'): | |
| with open(QUADRUPLETS_PATH, 'rb') as f: | |
| data = pickle.load(f) | |
| data = list(data.values()) | |
| quadruplets = [] | |
| if strategy != 'all': | |
| for d in data: | |
| if d[0] == strategy: | |
| quadruplets.append(d[1:]) | |
| elif strategy == 'all': | |
| for d in data: | |
| quadruplets.append(d[1:]) | |
| else: | |
| raise ValueError | |
| scores = [] | |
| for q in quadruplets: | |
| close = q[0] | |
| if len(close) == 2: | |
| far = q[1] | |
| distance_close = compute_eucl_dist(representations[close[0]], representations[close[1]]) | |
| distances_far = [compute_eucl_dist(representations[far[i][0]], representations[far[i][1]]) for i in range(len(far))] | |
| scores.append(distance_close < np.min(distances_far)) | |
| if len(scores) == 0: | |
| score = np.nan | |
| else: | |
| score = np.mean(scores) | |
| return score | |