Creating an AI chatbot using CopilotKit integrated with a Flask backend can be an exciting project. Below is a step-by-step guide on how to set up your project, including the necessary components for both the frontend (using React and CopilotKit) and the backend (using Flask).
Project Overview
Components
- Flask Backend: Handles API requests and serves the frontend.
- React Frontend: Uses CopilotKit to create an interactive AI chatbot interface.
- AI Integration: Connects to an AI model (like Google's Gemini) for generating responses.
Step 1: Set Up the Flask Backend
1. Install Flask
First, create a virtual environment and install Flask:
mkdir chatbot-backend
cd chatbot-backend
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
pip install Flask flask-cors
2. Create the Flask App
Create a file named app.py
:
from flask import Flask, request, jsonify
from flask_cors import CORS
import openai # Make sure to install OpenAI SDK if you're using it
app = Flask(__name__)
CORS(app) # Allow CORS for all domains
# Set your OpenAI API key
openai.api_key = 'YOUR_OPENAI_API_KEY'
@app.route('/api/chat', methods=['POST'])
def chat():
user_message = request.json.get('message')
# Call the AI model (e.g., OpenAI GPT)
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": user_message}]
)
bot_message = response.choices[0].message['content']
return jsonify({'response': bot_message})
if __name__ == '__main__':
app.run(debug=True)
3. Run the Flask App
Run your Flask app:
python app.py
Your backend should now be running on http://127.0.0.1:5000
.
Step 2: Set Up the React Frontend with CopilotKit
1. Create a React App
In a new directory, create your React app:
npx create-react-app chatbot-frontend
cd chatbot-frontend
2. Install CopilotKit
Install CopilotKit and Axios for making API calls:
npm install @copilotkit/react axios
3. Create the Chatbot Component
Create a file named Chatbot.js
in the src
directory:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { CopilotSidebar, useCopilotChat } from '@copilotkit/react';
import './Chatbot.css'; // Importing CSS file for styling
const Chatbot = () => {
const [message, setMessage] = useState('');
const [chatHistory, setChatHistory] = useState([]);
const [selectedPrompt, setSelectedPrompt] = useState('');
const [conversations, setConversations] = useState([]);
const [prompts, setPrompts] = useState([]);
const [newPrompt, setNewPrompt] = useState('');
const [searchTerm, setSearchTerm] = useState('');
const [showPromptInput, setShowPromptInput] = useState(false); // State to toggle prompt input visibility
const { addMessage } = useCopilotChat();
useEffect(() => {
// Load conversations and prompts from local storage on component mount
const storedChats = JSON.parse(localStorage.getItem('chatHistory')) || [];
const storedPrompts = JSON.parse(localStorage.getItem('prompts')) || [];
setConversations(storedChats);
setPrompts(storedPrompts);
// Load the most recent conversation into chat history if available
if (storedChats.length > 0) {
setChatHistory(storedChats[storedChats.length - 1].history);
}
}, []);
const handleSendMessage = async () => {
const userMessage = { sender: 'User', text: message };
const updatedChatHistory = [...chatHistory, userMessage];
setChatHistory(updatedChatHistory);
setMessage('');
try {
const response = await axios.post('http://127.0.0.1:5000/api/chat', { message });
const botMessage = { sender: 'Bot', text: response.data.response };
updatedChatHistory.push(botMessage);
setChatHistory(updatedChatHistory);
// Add messages to Copilot
addMessage(userMessage);
addMessage(botMessage);
// Save updated chat history to local storage
localStorage.setItem('chatHistory', JSON.stringify(updatedChatHistory));
} catch (error) {
console.error('Error sending message:', error);
}
};
const handlePromptSelect = (prompt) => {
setSelectedPrompt(prompt);
setMessage(prompt);
};
const handleConversationClick = (conversation) => {
setChatHistory(conversation.history);
};
const handleSaveConversation = () => {
const title = prompt("Enter a title for this conversation:");
if (title) {
const newConversation = { title, history: chatHistory };
const updatedConversations = [...conversations, newConversation];
setConversations(updatedConversations);
localStorage.setItem('chatHistory', JSON.stringify(updatedConversations));
}
};
const handleAddPrompt = () => {
if (newPrompt.trim()) {
const updatedPrompts = [...prompts, newPrompt.trim()];
setPrompts(updatedPrompts);
localStorage.setItem('prompts', JSON.stringify(updatedPrompts));
setNewPrompt('');
setShowPromptInput(false); // Hide the input after adding
}
};
// Function to delete a conversation
const handleDeleteConversation = (index) => {
const updatedConversations = conversations.filter((_, i) => i !== index);
setConversations(updatedConversations);
localStorage.setItem('chatHistory', JSON.stringify(updatedConversations));
// Optionally reset chat history if the deleted conversation was currently loaded
if (chatHistory === conversations[index].history) {
setChatHistory([]);
}
};
// Filtered prompts based on search term
const filteredPrompts = prompts.filter(prompt =>
prompt.toLowerCase().includes(searchTerm.toLowerCase())
);
// Filtered conversations based on search term
const filteredConversations = conversations.filter(conversation =>
conversation.title.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="chatbot-container">
<CopilotSidebar title="Recent Conversations">
<input
type="text"
placeholder="Search Conversations..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="search-input"
/>
{filteredConversations.map((conversation, index) => (
<div key={index} className="conversation-title">
<span onClick={() => handleConversationClick(conversation)}>
{conversation.title}
</span>
<button className="delete-button" onClick={() => handleDeleteConversation(index)}>
🗑️ {/* Delete icon */}
</button>
</div>
))}
<button onClick={handleSaveConversation} className="save-button">Save Conversation</button>
</CopilotSidebar>
<div className="chat-area">
<h2>AI Chatbot</h2>
<div className="chat-history">
{chatHistory.map((chat, index) => (
<div key={index} className={`message ${chat.sender === 'User' ? 'user' : 'bot'}`}>
<strong>{chat.sender}:</strong> {chat.text}
</div>
))}
</div>
<div className="input-area">
<select
value={selectedPrompt}
onChange={(e) => handlePromptSelect(e.target.value)}
className="prompt-select"
>
<option value="">Select a prompt...</option>
{filteredPrompts.map((prompt, index) => (
<option key={index} value={prompt}>{prompt}</option>
))}
</select>
{/* Button to toggle visibility of the new prompt input */}
<button onClick={() => setShowPromptInput(!showPromptInput)} className="toggle-prompt-button">
{showPromptInput ? "Hide Prompt Input" : "Add New Prompt"}
</button>
{/* New Prompt Input Field */}
{showPromptInput && (
<input
type="text"
value={newPrompt}
onChange={(e) => setNewPrompt(e.target.value)}
placeholder="Add a new prompt..."
className="new-prompt-input"
/>
)}
{/* Button to add the new prompt */}
{showPromptInput && (
<button onClick={handleAddPrompt} className="add-prompt-button">Add Prompt</button>
)}
{/* Message Input Field */}
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Type your message..."
className="message-input"
/>
<button onClick={handleSendMessage} className="send-button">Send</button>
</div>
</div>
</div>
);
};
export default Chatbot;
4. Update App.js
Replace the contents of src/App.js
with:
import React from 'react';
import Chatbot from './Chatbot';
function App() {
return (
<div className="App">
<Chatbot />
</div>
);
}
export default App;
5. Create Chatbot.css
.chatbot-container {
display: flex;
height: 100vh;
}
.chat-area {
margin-left: 20px;
flex-grow: 1;
padding: 20px;
background-color: #f9f9f9;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.chat-history {
border: 1px solid #ccc;
padding: 10px;
height: calc(100% - 120px); /* Adjust height based on input area */
overflow-y: scroll;
border-radius: 8px;
}
.message {
margin-bottom: 10px;
}
.user {
text-align: right;
}
.bot {
text-align: left;
}
.input-area {
display: flex;
align-items: center;
}
.prompt-select {
margin-right: 10px;
}
.message-input {
flex-grow: 1;
padding: 10px;
border-radius: 4px;
border: 1px solid #ccc;
}
.send-button {
padding: 10px 15px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.send-button:hover {
background-color: #0056b3;
}
.conversation-title {
padding: 10px;
cursor: pointer;
}
.conversation-title:hover {
background-color: #f0f0f0;
}
.save-button {
margin-top: 10px;
padding: 5px 10px;
background-color: #28a745;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.save-button:hover {
background-color: #218838;
}
.prompt-select,
.new-prompt-input,
.message-input {
margin-right: 10px;
}
.search-input {
margin-bottom: 10px;
}
.new-prompt-input {
flex-grow: 1; /* Allow it to take remaining space */
padding: 10px;
border-radius: 4px;
border: 1px solid #ccc;
}
.add-prompt-button,
.send-button,
.save-button {
padding: 10px 15px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.add-prompt-button:hover,
.send-button:hover,
.save-button:hover {
background-color: #0056b3; /* Darker shade for hover */
}
.conversation-title {
padding: 10px;
cursor: pointer;
}
.conversation-title:hover {
background-color: #f0f0f0; /* Highlight on hover */
}
.toggle-prompt-button {
margin-right: 10px;
padding: 10px 15px;
background-color: #17a2b8; /* Different color for visibility */
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.toggle-prompt-button:hover {
background-color: #138496; /* Darker shade for hover */
}
5. Run the React App
Start your React app:
npm start
Your frontend should now be running on http://localhost:3000
.
Step 3: Testing Your Chatbot
- Ensure both your Flask backend and React frontend are running.
- Open your browser and navigate to
http://localhost:3000
. - Type messages into the input field and see responses from the AI chatbot.
To include a GitHub repository URL in your dev.to post about building a chatbot with CopilotKit, Flask, and React, you can format it as follows:
Building an AI Chatbot with CopilotKit, Flask, and React
In this post, we'll walk through the steps to create an interactive AI chatbot using CopilotKit for the frontend, Flask as the backend, and React for the user interface.
GitHub Repository
You can find the complete code for this project on GitHub: Chatbot with CopilotKit
Conclusion
You now have a basic AI chatbot built using CopilotKit for the frontend and Flask for the backend! You can enhance this project by adding features like user authentication, saving chat history, or improving UI/UX design.