This article contains affiliate links. I may earn a commission at no extra cost to you.
title: "Build Your First AI Chatbot in 30 Minutes: Complete Beginner Tutorial with OpenAI API"
published: true
description: "Learn to create a functional AI chatbot with conversation memory, error handling, and deploy it for free - all in 30 minutes!"
tags: ai, tutorial, javascript, openai, beginners
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/chatbot-tutorial-cover.png
Build Your First AI Chatbot in 30 Minutes: Complete Beginner Tutorial with OpenAI API
Ever wanted to build your own AI chatbot but felt overwhelmed by the complexity? You're in the right place! In this tutorial, we'll create a fully functional chatbot from scratch using Node.js and OpenAI's API. By the end, you'll have a working chatbot with conversation memory that you can deploy for free.
What We're Building
Our chatbot will:
- Have natural conversations using OpenAI's GPT models
- Remember conversation history within each session
- Handle errors gracefully
- Cost less than $5/month to run
- Be deployable to a free hosting service
Prerequisites
You'll need:
- Basic JavaScript knowledge
- Node.js installed on your computer
- An OpenAI account (free tier works fine)
- 30 minutes of your time
Step 1: Set Up Your OpenAI API Key
First, let's get your OpenAI API credentials:
- Visit OpenAI's platform
- Sign up or log in to your account
- Navigate to "API Keys" in the left sidebar
- Click "Create new secret key"
- Copy and save this key securely - you won't see it again!
Important: Never commit API keys to version control. We'll use environment variables to keep them safe.
Step 2: Initialize Your Project
Let's create our project structure:
mkdir ai-chatbot
cd ai-chatbot
npm init -y
npm install express openai dotenv
Create these files in your project directory:
touch app.js .env index.html
Add your API key to .env:
OPENAI_API_KEY=your_api_key_here
PORT=3000
Step 3: Build the Backend
Create app.js with our server logic:
const express = require('express');
const OpenAI = require('openai');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
// Initialize OpenAI
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// Middleware
app.use(express.json());
app.use(express.static('.'));
// Store conversation history (in production, use a database)
const conversations = new Map();
// Cost optimization: limit conversation history
const MAX_HISTORY_LENGTH = 10;
app.post('/chat', async (req, res) => {
try {
const { message, sessionId = 'default' } = req.body;
if (!message) {
return res.status(400).json({ error: 'Message is required' });
}
// Get or create conversation history
let history = conversations.get(sessionId) || [];
// Add user message to history
history.push({ role: 'user', content: message });
// Limit history length for cost control
if (history.length > MAX_HISTORY_LENGTH) {
history = history.slice(-MAX_HISTORY_LENGTH);
}
// Create chat completion
const completion = await openai.chat.completions.create({
model: 'gpt-3.5-turbo', // Cost-effective model
messages: [
{
role: 'system',
content: 'You are a helpful assistant. Keep responses concise and friendly.'
},
...history
],
max_tokens: 150, // Limit response length for cost control
temperature: 0.7,
});
const assistantMessage = completion.choices[0].message.content;
// Add assistant response to history
history.push({ role: 'assistant', content: assistantMessage });
conversations.set(sessionId, history);
res.json({
message: assistantMessage,
tokensUsed: completion.usage.total_tokens
});
} catch (error) {
console.error('Error:', error);
// Handle different types of errors
if (error.code === 'insufficient_quota') {
res.status(429).json({ error: 'API quota exceeded. Please try again later.' });
} else if (error.code === 'invalid_api_key') {
res.status(401).json({ error: 'Invalid API key.' });
} else {
res.status(500).json({ error: 'Something went wrong. Please try again.' });
}
}
});
// Clear conversation history
app.delete('/chat/:sessionId', (req, res) => {
const { sessionId } = req.params;
conversations.delete(sessionId);
res.json({ message: 'Conversation cleared' });
});
app.listen(port, () => {
console.log(`Chatbot server running at http://localhost:${port}`);
});
Step 4: Create the Frontend
Add this to index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Chatbot</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.chat-container {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.messages {
height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px;
border-radius: 5px;
}
.message {
margin-bottom: 15px;
padding: 10px;
border-radius: 5px;
}
.user {
background-color: #007bff;
color: white;
text-align: right;
}
.assistant {
background-color: #e9ecef;
color: #333;
}
.input-container {
display: flex;
gap: 10px;
}
input[type="text"] {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.error {
color: #dc3545;
font-style: italic;
}
</style>
</head>
<body>
<div class="chat-container">
<h1>AI Chatbot</h1>
<div id="messages" class="messages"></div>
<div class="input-container">
<input type="text" id="messageInput" placeholder="Type your message..." onkeypress="handleKeyPress(event)">
<button onclick="sendMessage()" id="sendButton">Send</button>
<button onclick="clearChat()" id="clearButton">Clear</button>
</div>
</div>
<script>
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const sessionId = 'session_' + Date.now();
function addMessage(content, role) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role}`;
messageDiv.textContent = content;
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
async function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
// Disable input while processing
messageInput.disabled = true;
sendButton.disabled = true;
sendButton.textContent = 'Sending...';
// Add user message to chat
addMessage(message, 'user');
messageInput.value = '';
try {
const response = await fetch('/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message, sessionId }),
});
const data = await response.json();
if (response.ok) {
addMessage(data.message, 'assistant');
} else {
addMessage(`Error: ${data.error}`, 'error');
}
} catch (error) {
addMessage('Network error. Please check your connection.', 'error');
}
// Re-enable input
messageInput.disabled = false;
sendButton.disabled = false;
sendButton.textContent = 'Send';
messageInput.focus();
}
function handleKeyPress(event) {
if (event.key === 'Enter') {
sendMessage();
}
}
async function clearChat() {
try {
await fetch(`/chat/${sessionId}`, { method: 'DELETE' });
messagesDiv.innerHTML = '';
} catch (error) {
console.error('Error clearing chat:', error);
}
}
// Focus input on page load
messageInput.focus();
</script>
</body>
</html>
Step 5: Test Your Chatbot
Run your chatbot locally:
node app.js
Open your browser to http://localhost:3000 and start chatting!
Step 6: Deploy to Railway (Free)
Railway offers free hosting perfect for our chatbot:
- Create a Railway account
- Install Railway CLI:
npm install -g @railway/cli - Login:
railway login - Deploy:
railway deploy
Railway will automatically detect your Node.js app and deploy it. Don't forget to add your environment variables in the Railway dashboard!
Cost Optimization Tips
To keep costs under $5/month:
- Use GPT-3.5-turbo: Much cheaper than GPT-4
- Limit conversation history: We keep only 10 messages
- Set max_tokens: Prevents overly long responses
- Monitor usage: Check your OpenAI dashboard regularly
- Add rate limiting: Prevent abuse in production
Common Troubleshooting
"Invalid API Key" error: Double-check your .env file and ensure the key is correct.
"Quota exceeded" error: You've hit your API limit. Check your OpenAI billing dashboard.
Deployment issues: Ensure all environment variables are set in your hosting platform.
Slow responses: This is normal - AI models take time to generate responses.
Download the Complete Code
You can find the complete starter code on GitHub with additional examples and improvements.
What's Next?
Now that you have a working chatbot, consider these enhancements:
- Add user authentication
- Implement persistent storage with a database
- Add file upload capabilities
- Create different chatbot personalities
- Add voice input/output
- Implement rate limiting for production use
Conclusion
Congratulations! You've built a fully functional AI chatbot with conversation memory, error handling, and cost optimization. The best part? It's deployable for free and costs less than a coffee per month to run.
This foundation gives you everything you need to start experimenting with AI in your projects. The key is to start simple and iterate - exactly what we've done here.
What will you build next with your new AI skills? Share your creations in the comments below!
Found this tutorial helpful? Give it a ❤️ and follow for more practical AI tutorials!
Tools mentioned:
Top comments (0)