The Flavor Network | Demo
This repository contains the website source code for flavorpair.me, a creativity tool that empowers chefs and bartenders to build recipes starting from flavor pairing fundamentals.
This is a graphical search tool that provides an interactive network graph connecting ingredients by flavor, through a concensus of flavor pairing relationships obtained from treating the The Flavor Bible as a dataset. Prototype recipe ideas from these connections, and some selected recipes from food.com will display to the side. This way, you can visually cycle through a near endless commbination of ingredients in an intuitive playground.
The website is built with Hugo, a static site generator, using the papermod theme, which is served through a nginx reverse proxy.
The visualization makes use of two main libraries:
The network was constructed by creating a dataset out of The Flavor Bible, which is hosted statically on the website via JSON files. The code to generate this dataset can be found in a companion repository here.
The third module is a custom recipe searcher. This uses a dataset constructed from over 200,000 recipes on food.com (fmr. genius kitchen), which can be found on kaggle.
That dataset was turned into a SQLite database (see: notebooks/csv-to-sql.ipynb), where a custom WSGI API was built over Flask. Recipes are dynamically updated as new ingredients are added or removed from the "proto" recipe ingredient list. In short, all three modules (ingredient search, network visualization, recipe database) are kept in sync with the user's input.
Hugo has a built in developement server. In site/, run
hugo serverThis is typically accessible at http://localhost:1313.
You will need two terminal windows open. One for the hugo server, and one for the API backend server.
In order to use the recipe API, you'll need to initialize the SQL database.
-
Download the kaggle dataset and unpack it into
./notebooks/data/ -
Run a jupyter notebook server,
jupyter notebookinnotebooks/, then loadcsv-to-sql.ipynband begin running executing the cells. This can take some time. -
This will create a
food_dotcom.dbfile. On my production machine, I keep this database file in the same directory asbackend.py:/var/www/recipe-api/food_dotcom.db -
The API can be started with
python backend.py
which is what one does locally. On the production machine https://flavorpair.me, however, the
systemdservice file used is provided inserver/systemd/recipe-api.servicewhich adds an additional WSGI layer.
-
Much of the deployment of the site is encapsulated in the
deployshell script. This will build the site files locally viahugo, clean the site directory on the remote server, and then transfer the static site files to the remote server. -
The remote, as mentioned, also makes use of a
systemdservice file that controls the WSGI/Flask server API. This is a separate process from hugo. This only needs to be enabled once (located in/etc/systemd/system/):sudo systemctl enable recipe-api.serviceReload the daemon
sudo systemctl daemon-reload
and start the service
sudo systemctl start recipe-api.service
-
What
nginxdoes is forwards the local port of the flask API to an outward facing URL path.This file is provided in
server/nginx/flavorpair.meand belongs in/etc/nginx/sites-available/and symlinked to/etc/nginx/sites-enabled.Nginxis also controlled by systemd. Similar to above:sudo cp server/nginx/flavorpair.me /etc/ngins/sites-available/ sudo ln -s /etc/ngins/sites-available/flavorpair.me /etc/ngins/sites-enabled/flavorpair.me sudo systemctl daemon-reload sudo systemctl restart nginx
The site is secured with Let's Encrypt via
certbot'snginx plugin. These days, this is incredibly easy. Without restarting nginx:sudo certbot --nginx -d flavorpair.me.
The way you develop javascript on top of a hugo site is usually done through shortcodes and partials. One word of caution here is that there is inherently two different variable declarations happening in such javascript, as often times you need to have hugo translate a local path to a relative URL or vice versa. One handy trick is to pass paths through HTML tag attributes within shortcodes. The syntax can admittedly be confusing even to experienced hugo users.
