Building a Chatbot from Scratch: Part 4 - Adding Intelligence
Our chatbot responds to messages. Now let's make it actually useful with pattern matching and response logic.
Series Recap
- [Part 1](/blog/building-chatbot-from-scratch-part-1-setup): Project setup
- [Part 2](/blog/building-chatbot-from-scratch-part-2-ui): Chat UI
- [Part 3](/blog/building-chatbot-part-3-websockets): Real-time WebSocket communication
Now we make it smart.
Response Patterns
The simplest approach: pattern matching.
// server/responses.js
const patterns = [
{
match: /hello|hi|hey/i,
responses: [
"Hey there! How can I help?",
"Hello! What's on your mind?",
"Hi! Nice to chat with you."
]
},
{
match: /how are you/i,
responses: [
"I'm just code, but I'm functioning optimally!",
"All systems nominal. How about you?"
]
},
{
match: /help|support/i,
responses: [
"I can help with questions about our product. What would you like to know?",
"Sure! Try asking about pricing, features, or getting started."
]
},
{
match: /bye|goodbye|later/i,
responses: [
"Take care! Come back anytime.",
"Goodbye! Have a great day!"
]
}
];
const defaultResponses = [
"I'm not sure I understand. Could you rephrase that?",
"Interesting! Tell me more.",
"I'm still learning. Can you try asking differently?"
];
function getResponse(message) {
for (const pattern of patterns) {
if (pattern.match.test(message)) {
const responses = pattern.responses;
return responses[Math.floor(Math.random() * responses.length)];
}
}
return defaultResponses[Math.floor(Math.random() * defaultResponses.length)];
}
module.exports = { getResponse };
Integrating with WebSocket
// server/index.js
const { getResponse } = require('./responses');
io.on('connection', (socket) => {
socket.on('message', (userMessage) => {
// Echo user message
io.emit('message', {
text: userMessage,
sender: 'user',
timestamp: Date.now()
});
// Generate and send bot response
setTimeout(() => {
const botResponse = getResponse(userMessage);
io.emit('message', {
text: botResponse,
sender: 'bot',
timestamp: Date.now()
});
}, 500 + Math.random() * 1000); // Simulate thinking
});
});
The random delay makes it feel more natural.
Adding Context
Track conversation state:
const conversations = new Map();
function getContextualResponse(socketId, message) {
const context = conversations.get(socketId) || { history: [], state: 'greeting' };
context.history.push(message);
// State machine for conversation flow
if (context.state === 'greeting' && /pricing|cost/i.test(message)) {
context.state = 'discussing_pricing';
return "Our basic plan starts at $10/month. Want to know what's included?";
}
if (context.state === 'discussing_pricing' && /yes|sure|tell me/i.test(message)) {
context.state = 'explaining_features';
return "Basic includes: 5 projects, 10GB storage, and email support.";
}
conversations.set(socketId, context);
return getResponse(message);
}
What's Next
Pattern matching works for simple bots, but for real intelligence you'd want:
- NLP libraries (compromise.js, natural)
- Integration with AI APIs (OpenAI, Claude)
- Intent classification
- Entity extraction
We'll keep this tutorial focused on fundamentals, but the architecture supports adding these later.
Try It
Clone simple-chatbot and experiment with adding your own patterns!
Next up: Part 5 - Styling and deployment.