DEV Community

Victor Pascal Dike
Victor Pascal Dike

Posted on • Edited on

Building a Full-Stack AI Chatbot with FastAPI (Backend) and React (Frontend)

A diagram illustrating the connection between a chatbot interface, a FastAPI backend, and a React frontend.

AI-powered chatbots are transforming how we interact with technology. From automating customer support to serving as personal assistants, their applications are vast and continually growing. This article is your comprehensive guide to building a fully functional AI chatbot from the ground up, demystifying the core principles of full-stack AI development.

We will construct the backend using FastAPI, a modern and high-speed Python framework, and craft the frontend interface with React, the leading JavaScript library for building dynamic user interfaces. This step-by-step tutorial will walk you through the entire process of connecting a powerful AI model to a user-friendly chat window, covering everything from capturing user input to displaying an AI-generated response.

What You'll Build

By the end of this guide, you will have a sleek, web-based chat application. You'll be able to type a message, send it to a secure backend, get an intelligent response from an AI model like OpenAI's GPT, and see the entire conversation unfold on your screen.

Prerequisites

  • Python 3.7+ and a basic understanding of its syntax.
  • Node.js and npm installed on your machine.
  • A foundational knowledge of React and JavaScript.
  • An OpenAI API key.

The Anatomy of Our AI Chatbot

Before we jump into the code, let's understand the three core components that work together to bring our chatbot to life.

1. The Brains of the Operation: Our FastAPI Backend

The backend is the engine of our application. It lives on a server, receives user messages from the frontend, communicates with the AI model, and sends the AI's response back. We're using FastAPI for several compelling reasons:

  • Blazing-Fast Performance: Built with modern, asynchronous Python, FastAPI is one of the fastest web frameworks available, ensuring your chatbot responds quickly.
  • Intuitive and Simple: Its clean syntax allows you to build powerful APIs with minimal code, making development faster and more enjoyable.
  • Automatic Interactive Docs: FastAPI automatically generates a user-friendly interface (Swagger UI) for you to test your API endpoints directly in the browser—an invaluable tool for development.
  • Built-in Data Validation: By using Python type hints, it automatically validates incoming data, catching bugs before they cause problems.

2. The Face of Our Chatbot: The React Frontend

The frontend is everything the user sees and interacts with. It provides the chat window, the input field, and the send button. React is the perfect tool for this job because:

  • Component-Based Architecture: It allows you to build self-contained, reusable components (like a message bubble or a chat input form), making your UI organized and easy to manage.
  • Efficient Updates with the Virtual DOM: React intelligently updates only the specific parts of the page that have changed. This is like having a blueprint of your house and only rebuilding the single wall you moved, instead of the entire house, resulting in a much faster and smoother user experience.
  • A Massive Ecosystem: The huge community behind React means you have access to countless libraries and tools to add any feature you can imagine.

3. The Waiter in the Middle: API Communication

The frontend and backend need a way to talk to each other. This is done through an API (Application Programming Interface). Think of it like ordering food at a restaurant:

  1. You give your order (User Action): The user types a message in the React app and hits "Send."
  2. The waiter takes the order to the kitchen (HTTP Request): The React app sends the message in an HTTP POST request to a specific URL on the FastAPI backend (e.g., /chat).
  3. The kitchen prepares the food (Backend Processing): The backend receives the message and sends it to the OpenAI API to get a response from the language model.
  4. The waiter brings the food back (HTTP Response): Once the AI model replies, the backend sends its answer back to the React app.
  5. You get your meal (UI Update): The React app receives the response and adds the new message to the chat window for the user to see.

The intelligence of our chatbot comes from a Large Language Model (LLM), which we'll access via the OpenAI API. Remember to never expose your API key in your frontend code. We will use environment variables on the backend to keep it secure.

Let's Build It! A Step-by-Step Guide

Now, it's time to bring our chatbot to life.

Part 1: Setting Up the FastAPI Backend

First, let's create our backend service.

1. Initialize Your Project
Open your terminal and run these commands to create a project directory, set up a virtual environment, and install the necessary libraries.

# Create and navigate into the project folder
mkdir chatbot-backend
cd chatbot-backend

# Create and activate a virtual environment
# On Linux/macOS:
python3 -m venv .venv
source .venv/bin/activate

# On Windows:
python -m venv .venv
.venv\Scripts\activate

# Install required packages
pip install fastapi "uvicorn[standard]" python-dotenv openai
Enter fullscreen mode Exit fullscreen mode

2. Secure Your API Key
Create a new file named .env inside the chatbot-backend directory. This file will store your secret OpenAI API key.

Important: Add .env to your .gitignore file to prevent accidentally committing your key to version control.

# .env
OPENAI_API_KEY="YOUR_OPENAI_API_KEY_HERE"
Enter fullscreen mode Exit fullscreen mode

3. Create the Main Application File (main.py)
This file will contain all of our backend logic.

# main.py
import os
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from openai import OpenAI
from dotenv import load_dotenv

# Load environment variables from the .env file
load_dotenv()

# --- 1. Initialize FastAPI and OpenAI Client ---
app = FastAPI()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# --- 2. Configure CORS ---
# This is crucial for allowing your React frontend to communicate with this backend.
# It's a security feature that browsers enforce.
origins = [
    "http://localhost:5173",  # Default Vite React dev server
    "http://localhost:3000",  # Common Create React App dev server
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"], # Allow all methods (GET, POST, etc.)
    allow_headers=["*"], # Allow all headers
)

# --- 3. Define the Request Data Structure ---
# Pydantic model ensures the incoming data has the correct format.
class ChatInput(BaseModel):
    user_message: str

# --- 4. Create API Endpoints ---
@app.get("/")
async def health_check():
    """A simple endpoint to confirm the server is running."""
    return {"status": "ok"}

@app.post("/chat")
async def chat_with_ai(input_data: ChatInput):
    """The main endpoint to handle chat interactions."""
    try:
        # Forward the user's message to the OpenAI API
        completion = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "You are a helpful assistant."},
                {"role": "user", "content": input_data.user_message},
            ],
        )
        # Extract and return the AI's response
        bot_response = completion.choices[0].message.content
        return {"bot_response": bot_response}

    except Exception as e:
        # Properly handle potential API errors
        raise HTTPException(status_code=500, detail=str(e))
Enter fullscreen mode Exit fullscreen mode

4. Run the Backend Server
Start your FastAPI server using Uvicorn.

uvicorn main:app --reload
Enter fullscreen mode Exit fullscreen mode

The --reload flag automatically restarts the server whenever you save changes to your code. Your API is now live and accessible at http://127.0.0.1:8000.

Part 2: Building the React Frontend

Now, let's create the user interface.

1. Initialize Your Project
In your terminal (outside the backend folder), create a new React application using Vite for a fast and modern setup.

# Create a new React project
npm create vite@latest chatbot-frontend --template react

# Navigate into the new folder and install dependencies
cd chatbot-frontend
npm install
Enter fullscreen mode Exit fullscreen mode

2. Create the Chat Component (src/App.jsx)
Replace the default content of src/App.jsx with the code below. This component will manage the chat state, handle user input, and communicate with our backend.

// src/App.jsx
import React, { useState, useEffect } from 'react';
import './App.css';

function App() {
    const [userInput, setUserInput] = useState('');
    const [chatLog, setChatLog] = useState([]);
    const [loading, setLoading] = useState(false);

    // Effect to load chat history from local storage when the app starts
    useEffect(() => {
        const storedChatLog = localStorage.getItem('chatLog');
        if (storedChatLog) {
            setChatLog(JSON.parse(storedChatLog));
        }
    }, []);

    const handleSubmit = async (event) => {
        event.preventDefault();
        if (!userInput.trim()) return; // Don't send empty messages

        const userMessage = { type: 'user', text: userInput };
        const newChatLog = [...chatLog, userMessage];
        setChatLog(newChatLog);
        setUserInput('');
        setLoading(true);

        try {
            // The API call to our FastAPI backend
            const response = await fetch('http://localhost:8000/chat', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ user_message: userInput }),
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            const botMessage = { type: 'bot', text: data.bot_response };

            // Update the chat log with the bot's response
            const finalChatLog = [...newChatLog, botMessage];
            setChatLog(finalChatLog);

            // Save the updated chat log to local storage for persistence
            localStorage.setItem('chatLog', JSON.stringify(finalChatLog));

        } catch (error) {
            console.error('Error fetching chat response:', error);
            const errorMessage = { type: 'error', text: 'Sorry, something went wrong. Please try again.' };
            setChatLog(prev => [...prev, errorMessage]);
        } finally {
            setLoading(false);
        }
    };

    return (
        <div className="App">
            <h1>AI Chatbot</h1>
            <div className="chat-window">
                {chatLog.map((message, index) => (
                    <div key={index} className={`message ${message.type}`}>
                        {message.text}
                    </div>
                ))}
                {loading && <div className="message bot">Loading...</div>}
            </div>
            <form onSubmit={handleSubmit} className="chat-form">
                <input
                    type="text"
                    value={userInput}
                    onChange={(e) => setUserInput(e.target.value)}
                    placeholder="Type your message..."
                    disabled={loading}
                />
                <button type="submit" disabled={loading}>Send</button>
            </form>
        </div>
    );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

3. Add Some Style (src/App.css)
Replace the contents of src/App.css with the following CSS to make the chat interface look clean and modern.

/* src/App.css */
body {
    background-color: #f4f7f6;
    margin: 0;
}

.App {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    height: 100vh;
    padding: 20px;
    box-sizing: border-box;
}

h1 {
    color: #333;
}

.chat-window {
    width: 100%;
    max-width: 600px;
    height: 80vh;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
    overflow-y: auto;
    padding: 16px;
    margin-bottom: 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    background-color: white;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}

.message {
    padding: 10px 16px;
    border-radius: 20px;
    max-width: 75%;
    word-wrap: break-word;
    line-height: 1.5;
}

.user {
    background-color: #007bff;
    color: white;
    align-self: flex-end;
    border-bottom-right-radius: 4px;
}

.bot, .error {
    background-color: #e9e9eb;
    color: #333;
    align-self: flex-start;
    border-bottom-left-radius: 4px;
}

.error {
    background-color: #f8d7da;
    color: #721c24;
}

.chat-form {
    display: flex;
    width: 100%;
    max-width: 600px;
}

input[type="text"] {
    flex-grow: 1;
    padding: 12px;
    border: 1px solid #ccc;
    border-radius: 8px;
    margin-right: 10px;
    font-size: 1rem;
}

button {
    padding: 12px 24px;
    border: none;
    border-radius: 8px;
    background-color: #007bff;
    color: white;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.2s;
}

button:hover {
    background-color: #0056b3;
}

button:disabled {
    background-color: #cccccc;
    cursor: not-allowed;
}
Enter fullscreen mode Exit fullscreen mode

4. Run the Frontend Server
Start the React development server.

npm run dev
Enter fullscreen mode Exit fullscreen mode

Your React application should now be running, typically at http://localhost:5173. Open it in your browser, and you can start chatting!

Conclusion

Congratulations! You have successfully built a full-stack AI chatbot, bridging the gap between a powerful Python backend and a dynamic React frontend. You now have a scalable and user-friendly foundation for any AI application you can dream of.

This project is just the beginning. Here are a few ideas to take it to the next level:

  • Stream Responses: Modify the backend and frontend to stream the AI's response token-by-token, creating a real-time typing effect like in ChatGPT.
  • Integrate More Models: Experiment with open-source models from providers like Hugging Face or other APIs like Google's Gemini.
  • Enhance the UI: Improve the user interface with features like user avatars, message timestamps, and a "copy message" button.
  • Deploy Your Chatbot: Deploy your backend and frontend to services like Vercel, Netlify, or a cloud provider to share your creation with the world. Use Arrow Up and Arrow Down to select a turn, Enter to jump to it, and Escape to return to the chat.

Top comments (0)