<img src="https://certify.alexametrics.com/atrk.gif?account=J5kSo1IWhd105T" style="display:none" height="1" width="1" alt="">

Nexosis @ Work & Play

Building the Bigfoot Classinator: The Website

April 14, 2018 @ 10:37 AM | Musings, Technical


In the final part 5, Guy explains how he built and deployed the Bigfoot Classinator site.


¬°Finalmente! We're almost done with the Bigfoot Classinator. This is part five of the four-part series on building it. You should read the other parts if you haven't already. Today, we'll be talking about how I built and deployed the client-side code. Hint: I used Vue.js. Second Hint: I used a cool feature of GitHub Pages.

And, of course, all the code I wrote is up on GitHub. I'll just be showing the interesting bits so if you want to see it in all it's glory, you should go there.


Building the site

The site was built as a single page named, unsurpisingly, index.html with a CSS fie named site.css. Most of this is pretty basic HTML and CSS. I used HTML5 semantic elements where it made sense so the HTML has a <header> and a <main> and <footer>. For the CSS, there are some @media queries to make it look nice on big screens and small. You can check out the details in the code, if you'd like.

At the bottom of the HTML I added <script> tags to load in the JavaScript libraries I needed. You'll notice three things here. First, I'm used a CDN. Just made things easier to deploy. Second, I used axios for my HTTP calls to the AWS Lambda we created in the previous post. It seemed to be the most fashionable library for this purpose. Third, all my code is in app.js.

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
<script src="app.js"></script>

app.js starts with a bunch of const statements defining the URL to the AWS Lambda, messages for the different classes that can be returned by the Lambda, a wait message, and an error message.

const classinateUrl = 'https://rccptdhzsa.execute-api.us-east-1.amazonaws.com/prod/bigfootClassinator';

const classMessages = {
    'class a': "You saw bigfoot! That's a Class A sighting.",
    'class b': "You found some evidence of bigfoot like a footprint! That's a Class B sighting.",
    'class c': "Someone told you about seeing bigfoot! That's a Class C sighting"
};

const waitMessage = "Analyzing your sighting...";
const errorMessage = "There was an error processing your classination.";

The application code itself binds to the DOM on the HTML element that has an ID of app. This is in the el property that is passed into the constructor call into Vue. In my case, this ended up being <main>.

el: '#app'
<main id="app">

There are two things in our model that Vue needs to manage in the data property. The report and the classination. The report is the text of the Bigfoot sighting. This is the thing that a user enters. The classination is the output. This is the thing that the user wants to find out. The classination is also used to display errors and the wait message so it does it a little bit of double duty. It could probably have a better name but someone told me once that naming things is hard so... ya.

data: {
    report: '',
    classination: ''
}

I used a <textarea> for the report. Bigfoot sightings can sometimes be lengthy so this seemed apropriate. Since it was an input element, the v-model attribute was required so that Vue could bind to it.

The classination was simpler, as it was just basic text on the screen. So it got shoved into a <p> element. It is interesting to note, however, that I put two of these into the HTML. This is because the <aside> is hidden for smaller screen widths. So, I needed Vue to update this is both places. If you look in the CSS you can see the @media queries that show and hide these two elements.

<section>

    ... snip ...

    <div>
        <textarea v-model="report" placeholder="Enter the text of your bigfoot sighting here"></textarea>
    </div>

    ... snip ...

    <p class="result"></p>

</section>

<aside>
    <img src="sasquatch-face.jpg">
    <p class="result"></p>
</aside>

I also added a button that triggers the classination. The v-on:click attibutes tells Vue to call the classinate function in the methods property.

<button v-on:click="classinate">Classinate My Sighting!</button>

And what does classinate do? Well, the first thing it does is display the wait message. Then is uses axios to POST against the URL of the AWS Lambda that does the classination. Well, the AWS Lambda that calls the classifcation model on the Nexosis API that does the classination. It passes the report text on this call, since that's the thing I needed to classinate against.

Assuming the post returns successfully, I extract the class from the response and then looked up the user-friendly message in the classMessages object. This message is then written to the model and will display on the user's screen. If, instead, there is an error, it is logged to the console and the error message is dispalyed.

methods: {
    classinate: function() {
        this.classination = waitMessage;
        axios.post(classinateUrl, { reportText: this.report })
            .then(response => {
                var reportClass = response.data.reportClass;
                this.classination = classMessages[reportClass];
            })
            .catch(error => {
                console.log(error);
                this.classination = errorMessage;
            });
    }
}

And that's it for code. On to the deployment.


Deploying the site

Many of you probably know that if you create a repository on GitHub called <username>.github.io that Google will host the contents of the repository as pages at that domain. So if your username is, say squatch, and you create a repo named squatch.github.io then whatever you put in the repository on the master branch will be hosted at that URL. For free. This makes it cheap and easy to host a website. Thanks GitHub!

If you have a domain, you can even set that up by pointing the domain's DNS settings to GitHub and adding that domain name in the settings for the repository. This would allow squatch to point, say squatchornot.org, to this repository. You can read all about that at GitHub.

github-settings-guyroyse-com

I have done both of these things to host my website at guyroyse.com. You will note, however, that my repository is named guyroyse.github.com. At one point, this was acceptable and I am grandfathered in with this repository name. If you are doing this yourself, you should use <username>.github.io. I'm not changing mine as I'm afraid I'll break it. Something about letting sleeping code lie.

What you might not know, however, is that you can create other repositories that act as "folders" to your main site. By going into the exact same settings you can make any of your repositories on GitHub part of your website. The URL will be whatever your main site's URL is with the repository name tacked on. So, if the user squatch had a repository named beefjerky then the URL to the root of that repository would be http://squatch.github.io/beefjerky/ (or http://squatchornot.org/beefjerky/ if Bigfoot was using his own domain name).

This is exactly what I have done with Bigfoot Classinator.

github-settings-bigfoot-classinator

You may have noticed that I divided my repository into data, lambda, and site folders. data contains all the data that I transformed to build the model that does the classificaiton. lambda contains all the AWS Lambda code. site contains the actual site for the Bigfoot Classinator.

This makes the actual root of the Bigfoot Classinator site http://guyroyse.com/bigfoot-classinator/site/ but also means my code repository and the site itself are one and the same. This makes it easy to import my data into the Nexosis API, host my site, and share the code with y'all. And, frankly, I thought it was worth sharing.


All done!

And that's it. I've showed you one way you can integrate the Nexosis API into your applications by building a silly thing. The key point here is that fitting our API into your application isn't hard. The bulk of my code was the application itself.

There are certainly many other ways this could have been done and I hope you are considering them now. I'd love to hear them so feel free to share them with us on social media or on our community forums. Or, come and talk to me when I'm on the road.


Other Bigfoot Classinator posts:


Ready to start building machine learning applications?

Sign up for free  Talk to an expert


Guy Royse

Guy is one of our developer evangelists at Nexosis. He spends his days sharing with developers why our API is so great and his nights reminiscing about Hogwarts and dreaming of retiring to his dream job: Santa Claus.