Beispiel #1
0
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        
        if not username:
            error = 'Username is required.'
        elif not password:
            error = 'Password is required.'
        elif db.execute(
        'SELECT id FROM user WHERE username = ?', (username,)
        ).fetchone() is not None:
            error = 'User {} is already registered.'.format(username)
            
        if error is None:
            db.execute(
                'INSERT INTO user (username, password) VALUES (?, ?)',
                (username, generate_password_hash(password))
            )
            db.commit()
            return redirect(url_for('blog.profile'))
        
        flash(error)
        
    return render_template('auth/register.html')
Beispiel #2
0
def profile():
    db = get_db()
    if request.method == 'POST':
        try:
            bmi = calc_bmi(request.form['weight'],request.form['feet'],request.form['inches'])
            bmr = calc_bmr(request.form['gender'],
                           request.form['age'],
                           request.form['weight'],
                           request.form['feet'],
                           request.form['inches'])
            cals_per_day = calc_calperday(request.form['activity'],
                                          request.form['goal'],
                                          bmr)
        except Exception as err:
            print( type(err) )
            bmi = '--'
            bmr = '--'
            cals_per_day = '--'
        db.execute(
            'UPDATE user '
            'SET fullname=?, '
            'gender=?, '
            'age=?, '
            'weight=?, '
            'feet=?, '
            'inches=?, '
            'activity=?, '
            'goal=?, '
            'bmi=?, '
            'bmr=?, '
            'cals_per_day=?, '
            'restrictions=?, '
            'is_config=?',
            (request.form['fullname'],
             request.form['gender'],
             request.form['age'],
             request.form['weight'],
             request.form['feet'],
             request.form['inches'],
             request.form['activity'],
             request.form['goal'],
             bmi,
             bmr,
             cals_per_day,
             request.form['restrictions'],
             1)
            )
        db.commit()
        flash('Saved!','success')
        return redirect(url_for('blog.profile'))
    else:
        user_info = db.execute(
            'SELECT * '
            'FROM user '
            'WHERE id = ?',
            (session.get('user_id'),)
        ).fetchone()
        return render_template('profile.html', user=user_info)
Beispiel #3
0
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)
Beispiel #4
0
def load_logged_in_user():
    user_id = session.get('user_id')
    
    if user_id is None:
        g.user = None
    else:
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()
Beispiel #5
0
    def train(self, restrictions, min_df=10, n_closest=3):
        """
        Fit the engine model to the given data
        Parameters
        ==========
        restrictions : list
            List containing strings of dietary restrictions.
        min_df : int
            Minimum number of occurences of a given ingredient in recipes.
        n_closest : int
            The number of closest recipes.
        """

        # Read in cleaned data from CSV
        data = pd.read_csv('FoodFlix/static/data/clean_ingredients.csv',
                           header=0)
        data.set_index('recipe_id', inplace=True)

        # Drop recipes that contain keywords from the dietary restrictions
        if restrictions:
            data = (
                data[~data['ingredients'].str.contains('|'.join(restrictions))]
            )

        # Put ingredients in a list to be passed to TF-IDF
        ingredients = list(data['ingredients'])

        # Build the TF-IDF Model using 1, 2, and 3-grams on words
        vectorizer = TfidfVectorizer(analyzer='word',
                                     ngram_range=(1, 3),
                                     min_df=min_df,
                                     stop_words='english',
                                     max_features=512)

        # Fit the TF-IDF model using the given data
        X = vectorizer.fit_transform(ingredients)

        # Store this to a SQL database
        db = get_db()

        # Store TF-IDF features to database as well
        tfidf_df = pd.DataFrame(X.toarray(), index=data.index)
        tfidf_df.to_sql(name='tfidf', con=db, if_exists='replace')

        return
Beispiel #6
0
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        user = db.execute(
            'SELECT * FROM user WHERE username = ?', (username,)
        ).fetchone()
        
        if user is None:
            error = 'Incorrect username.'
        elif not check_password_hash(user['password'], password):
            error = 'Incorrect password.'
            
        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('blog.browse'))
        
        flash(error)
        
    return render_template('auth/login.html')
Beispiel #7
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)
Beispiel #8
0
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)
Beispiel #9
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