Interactive Tutorial: AI Chat App
This tutorial will walk you through building an AI chat app with Reflex. This app is fairly complex, but don't worry - we'll break it down into small steps.
You can find the full source code for this app here.
What You'll Learn
In this tutorial you'll learn how to:
- Install
reflex
and set up your development environment. - Create components to define and style your UI.
- Use state to add interactivity to your app.
- Deploy your app to share with others.
Setting up Your Project
We will start by creating a new project and setting up our development environment. First, create a new directory for your project and navigate to it.
Next, we will create a virtual environment for our project. This is optional, but recommended. In this example, we will use venv to create our virtual environment.
Now, we will install Reflex and create a new project. This will create a new directory structure in our project directory.
Note: When prompted to select a template, choose option 0 for a blank project.
You can run the template app to make sure everything is working.
You should see your app running at http://localhost:3000.
Reflex also starts the backend server which handles all the state management and communication with the frontend. You can test the backend server is running by navigating to http://localhost:8000/ping.
Now that we have our project set up, in the next section we will start building our app!
Basic Frontend
Let's start with defining the frontend for our chat app. In Reflex, the frontend can be broken down into independent, reusable components. See the components docs for more information.
Display A Question And Answer
We will modify the index
function in chatapp/chatapp.py
file to return a component that displays a single question and answer.
Components can be nested inside each other to create complex layouts. Here we create a parent container that contains two boxes for the question and answer.
We also add some basic styling to the components. Components take in keyword arguments, called props, that modify the appearance and functionality of the component. We use the text_align
prop to align the text to the left and right.
Reusing Components
Now that we have a component that displays a single question and answer, we can reuse it to display multiple questions and answers. We will move the component to a separate function question_answer
and call it from the index
function.
Chat Input
Now we want a way for the user to input a question. For this, we will use the input component to have the user add text and a button component to submit the question.
Styling
Let's add some styling to the app. More information on styling can be found in the styling docs. To keep our code clean, we will move the styling to a separate file chatapp/style.py
.
We will import the styles in chatapp.py
and use them in the components. At this point, the app should look like this:
What is Reflex?
A way to build web apps in pure Python!
What can I make with it?
Anything from a simple website to a complex web app!
The app is looking good, but it's not very useful yet! In the next section, we will add some functionality to the app.
State
Now let’s make the chat app interactive by adding state. The state is where we define all the variables that can change in the app and all the functions that can modify them. You can learn more about state in the state docs.
Defining State
We will create a new file called state.py
in the chatapp
directory. Our state will keep track of the current question being asked and the chat history. We will also define an event handler answer
which will process the current question and add the answer to the chat history.
Binding State to Components
Now we can import the state in chatapp.py
and reference it in our frontend components. We will modify the chat
component to use the state instead of the current fixed questions and answers.
Normal Python for
loops don't work for iterating over state vars because these values can change and aren't known at compile time. Instead, we use the foreach component to iterate over the chat history.
We also bind the input's on_change
event to the set_question
event handler, which will update the question
state var while the user types in the input. We bind the button's on_click
event to the answer
event handler, which will process the question and add the answer to the chat history. The set_question
event handler is a built-in implicitly defined event handler. Every base var has one. Learn more in the events docs under the Setters section.
Clearing the Input
Currently the input doesn't clear after the user clicks the button. We can fix this by binding the value of the input to question
, with value=State.question
, and clear it when we run the event handler for answer
, with self.question = ''
.
Streaming Text
Normally state updates are sent to the frontend when an event handler returns. However, we want to stream the text from the chatbot as it is generated. We can do this by yielding from the event handler. See the yield events docs for more info.
In the next section, we will finish our chatbot by adding AI!
Final App
We will use OpenAI's API to give our chatbot some intelligence.
Configure the OpenAI API Key
Ensure you have an active OpenAI subscription. Save your API key as an environment variable named OPENAI_API_KEY
:
Install the openai
pypi package:
Using the API
We need to modify our event handler to send a request to the API.
Finally, we have our chatbot!
Final Code
We wrote all our code in three files, which you can find below.
Next Steps
Congratulations! You have built your first chatbot. From here, you can read through the rest of the documentations to learn about Reflex in more detail. The best way to learn is to build something, so try to build your own app using this as a starting point!
One More Thing
With our hosting service, you can deploy this app with a single command within minutes. Check out our Hosting Quick Start.