Day 22 of the Anvil Advent Calendar
Build a web app every day until Christmas, with nothing but Python!
Build a Chatbot UI
Did you know that there are some really good language models these days? And that quite a few are now open-source, and there are even APIs like HuggingFace that will host them for you?
Well, today, we’re going to use them to create a chatbot! Here’s the live app – try it yourself below:
You can see the source code here:
How it works
The Hugging Face API docs lay this one out nicely for us. I’ll just quote from the example in the DialoGPT model documentation (under Deploy):
import requests
API_URL = "https://api-inference.huggingface.co/models/microsoft/DialoGPT-large"
headers = {"Authorization": "Bearer {API_TOKEN}"}
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload)
return response.json()
output = query({
"inputs": {
"past_user_inputs": ["Which movie is the best ?"],
"generated_responses": ["It's Die Hard for sure."],
"text": "Can you explain why ?",
},
})
And here’s the sort of thing it produces if we try it from a REPL:
{
'generated_text': "It's the best movie ever.",
'conversation': {
'generated_responses': ["It's Die Hard for sure.", "It's the best movie ever."],
'past_user_inputs': ['Which movie is the best ?', 'Can you explain why ?']
}
}
We just need to turn that into an Anvil Server Function, so we can drive it from a Python UI. We’ll use the session state to store previous lines of dialog:
import requests
API_URL = "https://api-inference.huggingface.co/models/microsoft/DialoGPT-large"
headers = {"Authorization": f"Bearer {anvil.secrets.get_secret('api_token')}"}
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload)
return response.json()
@anvil.server.callable
def get_conversation():
if "conversation" not in anvil.server.session:
anvil.server.session["conversation"] = {
"past_user_inputs": ["Merry Christmas!"],
"generated_responses": ["And a Merry Christmas to you!"]
}
return anvil.server.session["conversation"]
@anvil.server.callable
def send_message(message):
conversation = get_conversation()
model_output = query({
"inputs": {
"text": message,
**conversation
}
})
anvil.server.session["conversation"] = model_output["conversation"]
return model_output["conversation"]
Now it’s just time to build a user interface!
We’ll use a RepeatingPanel to display the conversation. The easiest way to drive a RepeatingPanel is a list of dictionaries, so we’ll massage our conversation object into the right shape:
def refresh_conversation(self):
messages = []
user_inputs = self.conversation["past_user_inputs"]
responses = self.conversation["generated_responses"]
for idx in range(len(user_inputs)):
messages.append({"from": "user", user_inputs[i]))
messages.append({"from": "bot", responses[i]})
self.repeating_panel_1.items = messages
Then in the RepeatingPanel’s template form, we use some Python logic and a little CSS to make the user- and bot-generated lines look different. Then we just wire up a TextBox and button to submit new messages to the model – and voila!
Source code
See the source code:
Give the Gift of Python
Share this post: