Joalon a software engineer

The villager-or-not web application reveal

If you’ve ever wanted to host your own Villager-or-not app you’re in luck! I understand this might be a niche interest, though. Anyway, I’ve put it up on Docker hub and I’ve put the source code on Github (under the webapp/ dir). If you want to run it right now and you have docker installed, you can try this: docker run -d -p 8080:8080 joalon/villager-or-not.

The GUI isn’t really polished yet, here’s a preview in all its glory:

Villager or not

Project setup

The project is a Flask backend running under uwsgi and Nginx which is supervised by supervisord. Quite a mouthful! This is how the file structure looks:

villager-or-not/
     ...
     webapp/
         Dockerfile
         Makefile
         export.pkl
         nginx.conf
         supervisord.conf
         uwsgi.ini
         requirements.txt
         villager-or-not.conf
         app/
         templates/

Where export.pkl was generated as a step in my earlier blog post about training a nerual network.

I also wrote a Makefile to simplyfy testing. It can execute the run, build and clean verbs.

Flask api

Here’s a shortened version of the Flask api which takes a file in a HTTP Post method and applies it to the machine learning model.

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        if file and allowed_file(file.filename):
            image = open_image(file)
            prediction = str(learn.predict(image)[0])
            if prediction == 'villager':
                flash('It\'s a villager!')
            else:
                flash('It\'s not a villager!')
    return render_template('upload_image.html')

The front end is a simple template, the interesting part is in upload_file.html:

{% extends "layout.html" %}
{% block body %}
<div align="center">
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
        <p><input type=file name=file>
        <input type=submit value=Upload>
    </form>
</div>
{% endblock %}

Nginx configuration

To get the nginx + uwsgi + supervisord configuration working serving the Flask api I followed the steps in this tutorial by Gabriela Melo. Here’s how it is setup in the dockerfile:

FROM python:3.7

RUN apt update &&\
    apt install -y supervisor nginx &&\
    pip3 install uwsgi

RUN useradd --no-create-home nginx
RUN rm /etc/nginx/sites-enabled/default

WORKDIR /opt/villager-or-not

COPY supervisord.conf /etc/supervisor/
COPY uwsgi.ini /etc/uwsgi/
COPY nginx.conf /etc/nginx/
COPY villager-or-not.conf /etc/nginx/conf.d/

COPY ./requirements.txt .
COPY ./export.pkl .
COPY ./templates ./app/templates

RUN pip3 install -r requirements.txt

COPY ./app/* /opt/villager-or-not/app/

CMD ["/usr/bin/supervisord"]

Summary

Check it out by running docker run -d -p 8080:8080 joalon/villager-or-not. I’ll eventually host it for the curious at https://joalon.se/apps/villager-or-not/ as well.

comments powered by Disqus