def favs(): db = get_db() liked = get_liked(session.get('user_id')) disliked = get_disliked(session.get('user_id')) restrictions = get_restrictions(session.get('user_id')) ingredients = [] if request.method == 'POST': try: respose = request.form['recipe_id'] # Parse out the type of button pressed (like or dislike) vote = re.search('[a-z]+', respose).group() # Parse out the recipe id from the response recipe_id = re.search('[0-9]+', respose).group() if vote == 'like': # Unlike if you click the button and it's already liked if recipe_id in liked: liked.remove(recipe_id) # Like the recipe else: liked.append(recipe_id) # Un-dislike if it is disliked if recipe_id in disliked: disliked.remove(recipe_id) else: # Un-dislike if you click the button and it's already disliked if recipe_id in disliked: disliked.remove(recipe_id) # Dislike the recipe else: disliked.append(recipe_id) # Unlike if it is liked if recipe_id in liked: liked.remove(recipe_id) db.execute('UPDATE user ' 'SET liked=?', (','.join(liked), )) db.execute('UPDATE user ' 'SET disliked=?', (','.join(disliked), )) db.commit() return redirect(url_for('blog.favs')) except BadRequestKeyError: print('No recipe_id key') recipes = get_recipes(ingredients, restrictions, session.get('user_id')) return render_template('browse.html', recipes=recipes, liked=liked, disliked=disliked, keywords=ingredients, restrictions=restrictions, recipe_num=0)
def browse(): ### Get query arguments: # Recipe number: try: recipe_num = int(request.args['recipe_num']) if recipe_num < 0: recipe_num = 0 except (ValueError, KeyError): recipe_num = 0 # Ingredients: ingredients = [] ingr_str = '' try: ingredients = request.args['ingredients'].split( ' ') # get ingr as array ingredients = [ ingr for ingr in ingredients if ingr != '' and ingr != ',' ] #remove empty and commas ingr_str = request.args['ingredients'] except BadRequestKeyError: print('No Ingredients key') ### Get link to DB db = get_db() ### Get user info liked = get_liked(session.get('user_id')) disliked = get_disliked(session.get('user_id')) restrictions = get_restrictions(session.get('user_id')) if request.method == 'POST': try: respose = request.form['recipe_id'] # Parse out the type of button pressed (like or dislike) vote = re.search('[a-z]+', respose).group() # Parse out the recipe id from the response recipe_id = re.search('[0-9]+', respose).group() if vote == 'like': # Unlike if you click the button and it's already liked if recipe_id in liked: liked.remove(recipe_id) # Like the recipe else: liked.append(recipe_id) # Un-dislike if it is disliked if recipe_id in disliked: disliked.remove(recipe_id) else: # Un-dislike if you click the button and it's already disliked if recipe_id in disliked: disliked.remove(recipe_id) # Dislike the recipe else: disliked.append(recipe_id) # Unlike if it is liked if recipe_id in liked: liked.remove(recipe_id) db.execute('UPDATE user ' 'SET liked=?', (','.join(liked), )) db.execute('UPDATE user ' 'SET disliked=?', (','.join(disliked), )) db.commit() return redirect( url_for('blog.browse', _anchor=recipe_id, recipe_num=recipe_num, ingredients=ingr_str)) except BadRequestKeyError: print('No recipe_id key') ### Finally get the recipes from DB recipes = get_recipes(ingredients, restrictions, '') recipes = recipes[recipe_num:recipe_num + 10] return render_template('browse.html', recipes=recipes, liked=liked, disliked=disliked, ingredients=ingredients, ingr_str=ingr_str, restrictions=restrictions, recipe_num=recipe_num)
def recommender(): MIN_LIKED_RECIPES = 3 # Connect to the database db = get_db() # Get data on what the user has liked so far user_query = db.execute('SELECT * ' 'FROM user ').fetchone() # Pull information on what the user likes to use in the engine try: liked_str = user_query['liked'] liked = liked_str.split(',') except: liked = [] if len(liked) < MIN_LIKED_RECIPES: flash( f'You need to like at least {MIN_LIKED_RECIPES} recipes to get ' 'recommendations', 'danger') recipes = [] return render_template("browse.html", recipes=recipes) # Get any dietary restrictions to include in the recommendation restriction_query = db.execute('SELECT restrictions ' 'FROM user ').fetchone() restrictions = restriction_query['restrictions'].split() # Build the food recommender engine and train engine = FoodFlixEngine() engine.train(restrictions=restrictions) # Pull some recipe recommendations recipes = engine.predict(cals_per_day=user_query['cals_per_day'], add_random=False) liked = get_liked(session.get('user_id')) disliked = get_disliked(session.get('user_id')) if request.method == 'POST': try: respose = request.form['recipe_id'] # Parse out the type of button pressed (like or dislike) vote = re.search('[a-z]+', respose).group() # Parse out the recipe id from the response recipe_id = re.search('[0-9]+', respose).group() if vote == 'like': # Like the recipe liked.append(recipe_id) else: # Dislike the recipe disliked.append(recipe_id) db.execute('UPDATE user ' 'SET liked=?', (','.join(liked), )) db.execute('UPDATE user ' 'SET disliked=?', (','.join(disliked), )) db.commit() return redirect(url_for('blog.recommender')) except BadRequestKeyError: print('No recipe_id key') return render_template("browse.html", recipes=recipes, recipe_num=0)
def predict(self, cals_per_day, w_like=1.5, w_dislike=0.3, n_closest=4, add_random=False): """ Generate predictions Parameters ========== cals_per_day : float Total recommended calories per day for a user. w_like : float Weighting for liked recipes in computing recommendations. w_dislike : float Weighting for disliked recipes in computing recommendations. n_closest : int Number of recommended recipes add_random : bool Whether including a random suggestion for testing """ # Divide the daily calories into five meals cals_per_day /= 5 # Connect to the database to grab user information db = get_db() # Get liked and disliked recipes liked = get_liked(session.get('user_id')) disliked = get_disliked(session.get('user_id')) # The TF-IDF db uses recipe_id as the index as integers... # TODO kjb: make all recipe_id indices either string or integer liked = [int(l) for l in liked] disliked = [int(l) for l in disliked] # Grab the TF-IDF features to compute scores tfidf_query = 'SELECT * FROM tfidf;' tfidf = pd.read_sql(sql=tfidf_query, con=db, index_col='recipe_id') # Grab the feature vectors for the liked and disliked recipes likes = tfidf.loc[liked] dislikes = tfidf.loc[disliked] # Compute the Rocchio topic topic = self.compute_rocchio_topic(likes, dislikes, w_like, w_dislike) # Find recipes similar to the Rocchio topic similarity = cosine_similarity(np.atleast_2d(topic), tfidf) similarity = pd.Series(similarity[0], index=tfidf.index) recommendations = similarity.sort_values(ascending=False) recommendations = list(recommendations.index) # Create a container to hold recommended recipes recipes = [] n_recs = 0 for rec in recommendations: recipe_query = db.execute( 'SELECT * ' 'FROM recipes ' 'WHERE recipe_id == ? ', (rec,) ).fetchone() # Only recommend things that you don't already like if recipe_query['recipe_id'] not in liked: recipe_dict = dict( recipe_query ) #convert to dict to allow addition of elements recipe_dict['generator'] = 'Recommender TF-IDF' # # Recommend only recipes around your cal/week goal # cals = int(recipe_query['calorie_count'].replace('cals','')) # if cals > cals_per_day * 0.8 and cals < cals_per_day * 1.2: recipes.append(recipe_dict) n_recs+=1 if n_recs >= n_closest: break # Include random suggestion if enabled if add_random: # Get all recipes from DB all_recipes = get_recipes('','','') recipe_rand = dict( random.choice(all_recipes) ) recipe_rand['generator'] = 'Random' recipes.append( recipe_rand ) # Shuffle around random.shuffle(recipes) return recipes