Deploy a Fake News Generator to the Web With Anvil

More customizable than Streamlit, simpler than Dash

You’ve probably heard of Streamlit and Dash, two Python-centric ways of making web apps. While Dash is focused more on the enterprise and allows extensive customization, Streamlit is much simpler and is trying to make building web apps incredibly easy.

To me, Anvil sits in between these two options. Anvil is an online tool for building web applications with nothing but Python. It offers much more customizability than Streamlit but is much simpler to build than Dash.

In this article, I will show you how to build a web front end for a machine learning model. It is important to note that Anvil is designed to be a general-purpose web application tool, and can be used for much more than just simple front ends for your analysis or models.

Let’s get started!

The Plan

The way we will deploy the model is to host the model on Google Colab and then use a built-in feature of Anvil called Uplink to connect the web app to the Colab notebook.

Uplink allows you to connect to your Anvil app from any computer, anywhere on the internet as long as you have Python and the anvil-uplink packaged installed. For our use case, Uplink will let us execute a Python function in our notebook that will perform inference from our model and return the results to the web app.

If this were a production app I would wrap up the notebook code into a FastAPI app and deploy it as a container. For demo purposes, this is much faster and easier.

The Model

The model we will deploy is a fake news creator I built using Fast.ai and a fake news dataset from Kaggle (link). I took a pre-trained general language model trained on the Wikitext-103 dataset (link to the O.G. ULMFiT paper) and then fine-tuned using the fake news dataset linked above. The result is a language model fine-tuned to generate fake news. It’s not great, and it probably won’t fool anyone, but it’s a lot of fun to play with.

The model takes a prompt and will generate as many words as you want. Here is an example prompt and output from the model:

Prompt: Data scientists believe AI

Output: “Data scientists believe AI is not a threat to science and that's why AI is not an option for science at all. They are not convinced that science is real, but they have no idea what it is. In fact, it's a pretty simple concept to predict the effects of the artificial intelligence of the world on a scale that is not in any way related to science or science. They are convinced that science is science fiction.”

Clearly not amazing journalism, but kind of truthy with a side of weird right? Anyways, let’s move on to building the app!

Building the Anvil App

Now we get to the fun (and easy) part. It’s always a good idea to figure out what user elements you need before you start building anything. We want the user to be able to:

  • Enter a text prompt.
  • Choose the number of words to output.
  • Select the number of options they want to be generated.
  • Click a button to make the fake news output.

Ok on to Anvil! On the My Apps page click the Create App button.

If you haven’t already, go through the walkthrough, it’s helpful.

You will have several options to start. Choose the Material Design option. It gives you nice styling without any effort and includes an optional sliding menu panel on the left.

Choose the Material Design option.

Now you will be taken to the Anvil IDE. This IDE allows you to interact with all elements of your app.

The Anvil IDE. There is a lot going on under the hood here.

To start with we will drag the elements we want onto the Form or the client visible page. While you can create elements programmatically, it’s a lot easier to just drag the elements to where you want them to be. Here is a GIF showing that we can add text and input boxes.

Making a UI visually makes things really easy. No HTML or CSS required.

As you can see, Anvil has a lot more built-in UI elements. After a few minutes, I built the following form the user can interact with.

A basic UI.

The prompt box accepts text, while the Number of Words and Number of Options box only allows numbers. Setting this is a simple selection in a drop-down in the form builder. Building your app UI is very flexible, so it’s a good idea to spend a bit of time tweaking it until you like what you have. No HTML and CSS are necessary!

Keep in mind the names of the import UI elements, as you will be accessing them in code soon. You can change the name of your objects by clicking on the pencil icon in the form designer. Anvil will automatically assign a name, but it is always a good idea to change it to something logical so you can easily access it in code.

We haven’t yet added where the text will output, but we will do that soon. Now we are ready to start connecting our UI with code.

Client-side Form code.

If you click on the Code button at the top of your form, you will see the client-side form code. Anything Python you write here will be executed in the user's browser as Javascript. But don’t worry, you don’t need to know Javascript. Anvil does the heavy lifting for you and automagically allows your Python to run in the browser.

Here is the code that starts by default in your form:

from ._anvil_designer import Form1Template
from anvil import *
class Form1(Form1Template): def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run when the form opens.

If you aren’t familiar with object-oriented programming, don’t worry, it’s not necessary to get started. At the top of the form are the form inputs, just like any other Python file. If you want to have some code run when the form opens, you can add it under the __init__ method. For other code that will run, for example with a button click, you can add functions under the Form class (we will see this soon).

What I would like to do is create some default values for the number of words (50) and the number of options (2). Here is the code I can write:

# Any code you write here will run when the form opens.
self.num_words.text = 50
self.num_options.text = 2

Here self is referring to the Form, and num_words and num_options is the name of the text box that I assigned. Text boxes in Anvil have a property called text that lets us retrieve or set the value in the text box. I set those values by simply using the assignment operator (=) in Python.

Now that we have our basic UI done, we can add the function that is called when the button is clicked. Go back to the Design tab and select our “Make my fake news!” button. Then on the properties panel on the right scroll all the way to the bottom. There you will see the Events section.

Look at the bottom right to see the click event.

The Events section allows us to assign specific functions to our UI elements. In this case, we want to assign a function to the click event. To assign a function click the blue >> button to the right of the click event. Once you do that Anvil will automatically create the appropriately named function in the Form code.

An automatically created function in Anvil.

In this function, we will grab our text elements and then send them to a function in our Server Code that will perform the model inference and send back the generated text.

In Anvil (and web app development in general) it is important to understand the difference between code in the browser (Form Code) and code on the server (Server Code).

Form Code is executed in the user's browser and can potentially be manipulated by the user. In addition, not everything can run in a user's browser. In our case, a Fast.ai model can’t run in the user's browser natively. So in order to perform our model inference, we will have the user inputs passed to a function running on a server.

Server Code is code that is run in a more traditional Python environment. The only limitations for running server code are the packages available the amount of compute you need (i.e. CPU and RAM).

In this case, we will be using an Uplink instead of an Anvil server module. This is because a web server isn’t typically a good place to run a machine learning model. Web servers are usually limited on RAM and CPU, and you don’t want your web app slowing down because of your model.

So let’s connect our web app to our Google Colab notebook using Anvil’s Uplink. Click the gear icon on the App Browser panel on the left. Then select Uplink. Choose the button at the top that asks you if you want to enable the uplink.

Once you have enabled the Uplink you will see a code example below. This shows you how we can install and connect to your Anvil app from our Colab notebook. Your unique Uplink key is loaded into the code example, so all you need to do is copy and paste the code.

Two lines of magic to connect to your app.

Once we have our Uplink key we can move over to our Colab Notebook and get it ready to perform inference.

The Colab Notebook

As the model has already been trained (see the links at the end of the article for the training notebook), we write a few lines of code to perform inference. Here is the full Colab notebook.

Here is what the notebook does:

  • At the top we install the libraries we need and then after import Fast.ai’s load_learner and Anvil’s anvil.server.
  • Paste in our Uplink code and run it to connect to our Anvil app.
  • Mount Google Drive and change the directory to where the model is hosted.
  • Load the pickled model.
  • Define the fix_punctuation function. Fast.ai adds spaces to punctuations (because it treats punctuation as a token), so we want to remove those for the output.
  • The predict function is the important piece. This is what actually will perform inference using our model and the user inputs.

Let’s look at the predict function:

The predict method in Colab.

Directly above the function we add @anvil.server.callable. This registers the function with the Anvil app when the Uplink is connected allows it to be called. It then returns a list of strings of our text. It accepts 4 arguments:

  • text — the prompt from the user.
  • words — the number of words to generate.
  • options — the number of options to output.
  • temp — the temperature of the output (used for this type of LSTM model). This won’t be user changeable and will be set to 0.7.

Now that we have our inference code ready and registered, we can set up a function in our app to call it. Let’s go back to Anvil and open the Form code tab.

The beginning of our text generator function in the app.

If we want to call a server function (i.e. code not in a client side form), we can use anvil.server.call(‘function_name’, arguments). Our function we want to call is called predict, and we can fill in the arguments needed as well. Anvil also gives helpful autocomplete hints to let you select what you need faster. We set the temperature to 0.7 as it works for generating fairly good and not so random text.

Now that we will have our function output, we need to put it somewhere. Our predict function outputs a Python list of strings like: [‘some string number 1’, ‘some string number 2’]. As an iterable object we can use a pretty nice Anvil element to show this, the repeating panel.

I also added a spacer below the button to give the repeating panel some space.

The repeating panel allows you to assign any iterable object. But by default it’s empty. So we need to add in a Label object and then bind the item to it.

Each item in the repeating panel will have one item assigned from our iterable list. The data binding connects the Label object to the text from our list. We can now add the code to assign our iterable list to our repeating panel. A repeating panel has a property called items where we can assign any Python iterable object.

And now we are ready to go! Anvil provides a nice debuger mode to test things before you publish your app. Click the Run button at the top of the Anvil IDE.

It’s working!

Now that it’s working we can publish it to the web. Anvil automatically creates a private link you can share with others, or you can assign a public link. You can even assign a custom domain if you have one.

Wrap Up

It is important to remember that Anvil is a general tool for making web apps with Python. You can make anything from a fully-featured ticketing system to a Calendly clone to various types of dashboards. You are really only limited by your imagination.

This puts Anvil in a very different position from Dash or Streamlit. However, I believe Anvil is a great tool for data scientists to learn, because it allows us to deploy our projects using a language we are already very familiar with. We can then add in features like Stripe payments, an integrated database, user access roles, and more with built in features.

Through this article you saw how to deploy a machine learning model to the web with Anvil. The main limitation to the method shown is that it requires your Colab notebook to be on the cells to have been executed for the app to work. Obviously this isn’t ideal if you wanted to deploy this for anything other than a demo.

For a production deployment, I recommend setting up your model to be accessed via a REST API using FastAPI, and for the inference to be performed using the fastinference package.

Also, it’s important to remember that the model I used in the demo isn’t actually very good at generating fake news.

I hope you enjoyed this tutorial. You can find the model, the training notebook, and the inference notebook on Google Drive here. You can find a clone link of the app I made here. The clone link will copy the app into your own account so you can edit it an deploy it yourself if you would like. Happy app making!

Data Scientist and Director of LETU Mongolia. Keen observer of Mongolia.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store