Build a rule-based and AI-powered chatbot in Python step-by-step. Create intent detection, pattern matching, conversation management, and integrate with the OpenAI API for intelligent responses.
Build a fully functional chatbot from a simple rule-based system to an AI-powered conversational agent.
Project Overview
What you'll build: A chatbot with pattern matching and optional AI integration
Skills practiced: String processing, OOP, dictionaries, regex, API calls
Estimated time: 4–5 hours
Step 1: Simple Rule-Based Chatbot
# chatbot_v1.py — Rule-based chatbot with pattern matching
import re
import random
from datetime import datetime
# Response database: pattern → list of possible responses
RESPONSES = {
r'\b(hi|hello|hey|howdy|greetings)\b': [
"Hi there! How can I help you today?",
"Hello! Great to see you!",
"Hey! What's on your mind?",
],
r'\b(bye|goodbye|see you|exit|quit)\b': [
"Goodbye! Have a great day!",
"See you later! Take care!",
"Bye! It was nice chatting with you!",
],
r'\b(how are you|how do you do|how\'s it going)\b': [
"I'm doing great, thanks for asking! How about you?",
"Feeling wonderful! Ready to help.",
"I'm fantastic! What can I do for you?",
],
r'\bwhat is your name\b': [
"My name is PyBot! I'm your Python assistant.",
"I'm PyBot, a chatbot built with Python!",
],
r'\bwhat can you do\b': [
"I can answer questions, chat, tell jokes, check the time, and more!",
"I'm here to help! Ask me anything — jokes, time, or just for a chat.",
],
r'\btell me a joke\b': [
"Why don't scientists trust atoms? Because they make up everything!",
"Why did the Python programmer go broke? Because he lost his cache!",
"What do you call a bear with no teeth? A gummy bear!",
"Why was the math book sad? It had too many problems.",
],
r'\bwhat time is it\b': [
lambda: f"The current time is {datetime.now().strftime('%I:%M %p')}.",
],
r'\bwhat is the date today\b': [
lambda: f"Today is {datetime.now().strftime('%A, %B %d, %Y')}.",
],
r'\b(thank you|thanks|thx)\b': [
"You're welcome! Anything else I can help with?",
"Happy to help! Is there anything else?",
"My pleasure! 😊",
],
r'\b(sorry|apologize|my bad)\b': [
"No worries at all! How can I help?",
"It's totally fine! What can I do for you?",
],
r'\bpython\b': [
"Python is an awesome programming language! I'm built with it.",
"Great choice! Python is versatile, readable, and powerful.",
"Python is my favorite language — after all, that's what I'm written in!",
],
r'\b(help|assist|support)\b': [
"Sure! You can ask me about: jokes, time, date, Python, or just chat!",
"I'm here to help! What would you like to know?",
],
}
DEFAULT_RESPONSES = [
"Interesting! Tell me more.",
"I'm not sure about that. Can you rephrase?",
"Hmm, I need to learn more about that!",
"That's a good question! I'm still learning.",
]
def get_response(user_input):
"""Get a chatbot response for user input."""
user_input_lower = user_input.lower().strip()
for pattern, responses in RESPONSES.items():
if re.search(pattern, user_input_lower):
response = random.choice(responses)
# Handle callable responses (for dynamic content)
if callable(response):
return response()
return response
return random.choice(DEFAULT_RESPONSES)
def run_chatbot_v1():
"""Run the basic chatbot."""
print("=" * 50)
print(" 🤖 PyBot — Simple Chatbot")
print(" Type 'bye' to exit")
print("=" * 50)
while True:
user_input = input("\n You: ").strip()
if not user_input:
continue
response = get_response(user_input)
print(f" Bot: {response}")
if re.search(r'\b(bye|goodbye|exit|quit)\b', user_input.lower()):
break
if __name__ == '__main__':
run_chatbot_v1()
Step 2: Intent-Based Chatbot
# chatbot_v2.py — Intent detection with entities
import re
import random
import json
from datetime import datetime
INTENTS = {
'greeting': {
'patterns': [r'\b(hi|hello|hey|howdy)\b', r'^good (morning|afternoon|evening)'],
'responses': ["Hello! 😊 How can I help?", "Hi there! What's up?", "Hey! Great to see you!"],
},
'farewell': {
'patterns': [r'\b(bye|goodbye|see you|cya)\b', r"that's all|i'm done"],
'responses': ["Goodbye! Come back soon! 👋", "See you! Have a great day!", "Bye! Take care! 😊"],
},
'help': {
'patterns': [r'\b(help|assist|support|what can you do)\b'],
'responses': [
"I can help with:\n • Math calculations\n • Current time/date\n • Jokes\n • General chat\n • Python tips!",
],
},
'time': {
'patterns': [r'\b(time|what time|current time|clock)\b'],
'handler': lambda: f"⏰ It's {datetime.now().strftime('%I:%M %p')}",
},
'date': {
'patterns': [r'\b(date|today|what day)\b'],
'handler': lambda: f"📅 Today is {datetime.now().strftime('%A, %B %d, %Y')}",
},
'math': {
'patterns': [r'\d+\s*[\+\-\*\/\^]\s*\d+'],
'handler': 'calculate',
},
'joke': {
'patterns': [r'\b(joke|funny|laugh|humor|make me laugh)\b'],
'responses': [
"Why don't scientists trust atoms? Because they make up everything! 😄",
"Why did Python break up with Java? It wanted someone more dynamic! 🐍",
"How many programmers does it take to change a lightbulb? None — it's a hardware problem! 💡",
"Why was the JavaScript developer sad? Because he didn't know how to 'null' his feelings! 😢",
],
},
'name': {
'patterns': [r'\byour name\b', r'\bwho are you\b', r'\bwhat are you\b'],
'responses': ["I'm PyBot, your Python-powered assistant! 🐍", "My name is PyBot! Made with Python ❤️"],
},
'python_tip': {
'patterns': [r'\b(python tip|tip|learn python|python help)\b'],
'handler': 'python_tip',
},
'thanks': {
'patterns': [r'\b(thanks|thank you|thx|appreciate)\b'],
'responses': ["You're welcome! 😊", "Happy to help!", "Anytime! That's what I'm here for!"],
},
'how_are_you': {
'patterns': [r"how are you|how\'s it going|how do you do|feeling today"],
'responses': ["I'm doing great, thanks! 😄", "Feeling wonderful! Ready to help 🚀", "Excellent! How about you?"],
},
}
PYTHON_TIPS = [
"Use list comprehension: `[x**2 for x in range(10)]` — faster than for loops!",
"f-strings are the fastest way to format strings: `f'Hello, {name}!'`",
"Use `enumerate()` when you need both index and value: `for i, v in enumerate(lst):`",
"The walrus operator `:=` assigns and tests in one line: `if (n := len(lst)) > 10:`",
"Use `zip()` to iterate two lists: `for a, b in zip(list1, list2):`",
"Dictionary comprehension: `{k: v for k, v in items.items() if v > 0}`",
"Use `pathlib.Path` instead of `os.path` for modern path handling!",
"Type hints improve code readability: `def greet(name: str) -> str:`",
]
def calculate(expression):
"""Safely evaluate a math expression."""
try:
expression = expression.replace('^', '**')
allowed = set('0123456789+-*/.(). ')
if all(c in allowed for c in expression):
result = eval(expression)
return f"🔢 {expression} = {result}"
return "❌ Invalid math expression"
except ZeroDivisionError:
return "❌ Cannot divide by zero!"
except Exception:
return "❌ Couldn't calculate that expression"
def get_python_tip():
return f"💡 Python Tip: {random.choice(PYTHON_TIPS)}"
HANDLERS = {
'calculate': calculate,
'python_tip': lambda _: get_python_tip(),
}
class IntentChatbot:
def __init__(self):
self.conversation_history = []
self.context = {}
def detect_intent(self, text):
"""Find the matching intent for input text."""
text_lower = text.lower()
for intent_name, intent_data in INTENTS.items():
for pattern in intent_data.get('patterns', []):
match = re.search(pattern, text_lower)
if match:
return intent_name, match
return None, None
def get_response(self, user_input):
"""Generate a response for user input."""
self.conversation_history.append({'role': 'user', 'content': user_input})
intent, match = self.detect_intent(user_input)
if intent:
intent_data = INTENTS[intent]
# Check for handler
if 'handler' in intent_data:
handler = intent_data['handler']
if callable(handler):
response = handler()
elif isinstance(handler, str) and handler in HANDLERS:
response = HANDLERS[handler](user_input)
else:
response = "I can handle that, but something went wrong."
elif 'responses' in intent_data:
response = random.choice(intent_data['responses'])
else:
response = "I understood that, but I don't have a response!"
else:
# Unknown intent — check for math expression
if re.search(r'\d+\s*[\+\-\*\/\^]\s*\d+', user_input):
response = calculate(user_input)
else:
response = random.choice([
"I'm not sure about that. Try asking about time, jokes, or math!",
"Interesting! Could you rephrase that? I'm still learning.",
"Hmm, I don't quite understand. Type 'help' to see what I can do.",
])
self.conversation_history.append({'role': 'bot', 'content': response})
return response
def run(self):
print("\n" + "=" * 55)
print(" 🤖 PyBot v2 — Intent-Based Chatbot")
print(" Commands: 'help', 'history', 'clear', 'bye'")
print("=" * 55)
while True:
user_input = input("\n You: ").strip()
if not user_input:
continue
if user_input.lower() == 'history':
print("\n 💬 Conversation History:")
for entry in self.conversation_history[-10:]:
role = "You" if entry['role'] == 'user' else "Bot"
print(f" {role}: {entry['content']}")
continue
if user_input.lower() == 'clear':
self.conversation_history = []
print(" ✅ History cleared!")
continue
response = self.get_response(user_input)
print(f" Bot: {response}")
if re.search(r'\b(bye|goodbye|exit)\b', user_input.lower()):
break
Step 3: Context-Aware Chatbot
# chatbot_v3.py — Chatbot with context memory and personality
import random
from datetime import datetime
class ContextualChatbot:
"""Chatbot with conversation context and personality."""
def __init__(self, name="PyBot", personality="friendly"):
self.name = name
self.personality = personality
self.user_name = None
self.context = {}
self.history = []
self.mood = "neutral" # neutral, happy, curious
self.topics_discussed = set()
def _update_mood(self, user_input):
"""Adjust mood based on conversation."""
positive = ['thanks', 'great', 'awesome', 'love', 'amazing', 'wonderful']
negative = ['hate', 'terrible', 'awful', 'bad', 'stupid', 'useless']
if any(w in user_input.lower() for w in positive):
self.mood = 'happy'
elif any(w in user_input.lower() for w in negative):
self.mood = 'empathetic'
elif '?' in user_input:
self.mood = 'curious'
def _get_mood_prefix(self):
mood_prefixes = {
'happy': ["That's wonderful! ", "Great! ", "Awesome! "],
'curious': ["That's a good question! ", "Hmm, interesting! ", "Let me think... "],
'empathetic': ["I understand. ", "I hear you. ", "I'm sorry to hear that. "],
'neutral': ["", "Sure! ", "Of course! "],
}
return random.choice(mood_prefixes.get(self.mood, [""]))
def respond(self, user_input):
"""Generate a contextually aware response."""
self._update_mood(user_input)
self.history.append(('user', user_input, datetime.now()))
lower = user_input.lower()
prefix = self._get_mood_prefix()
# Learn user's name
import re
name_match = re.search(r"my name is ([a-zA-Z]+)|i'm ([a-zA-Z]+)|call me ([a-zA-Z]+)", lower)
if name_match:
name = next(g for g in name_match.groups() if g)
self.user_name = name.title()
response = f"{prefix}Nice to meet you, {self.user_name}! 😊 I'm {self.name}."
elif 'remember' in lower and 'name' in lower:
if self.user_name:
response = f"Of course! Your name is {self.user_name}. How could I forget? 😄"
else:
response = "I don't know your name yet! Tell me — what should I call you?"
elif self.user_name and any(w in lower for w in ['hi', 'hello', 'hey']):
response = f"{prefix}Hey, {self.user_name}! Great to see you again! 👋"
elif 'tell me about yourself' in lower or 'who are you' in lower:
self.topics_discussed.add('intro')
response = (f"I'm {self.name}, a Python-powered chatbot! "
f"I can chat, answer questions, tell jokes, and help with math. "
f"We've talked about: {', '.join(self.topics_discussed) or 'not much yet'}. "
f"What would you like to know?")
elif 'what do you remember' in lower or 'what do you know about me' in lower:
if self.user_name:
response = (f"I know your name is {self.user_name}, "
f"we've had {len(self.history)} exchanges, "
f"and you seem to be in a {self.mood} mood!")
else:
response = "I know we've been chatting, but you haven't told me your name yet!"
elif len(self.history) > 0 and 'what did i say' in lower:
last_msg = self.history[-2][1] if len(self.history) >= 2 else "nothing yet"
response = f"Your last message was: \"{last_msg}\""
else:
# Fall back to intent detection
from chatbot_v2 import IntentChatbot
temp_bot = IntentChatbot()
response = prefix + temp_bot.get_response(user_input)
self.history.append(('bot', response, datetime.now()))
return response
def run(self):
print(f"\n{'='*55}")
print(f" 🤖 {self.name} — Contextual Chatbot")
print(f" I remember your name and track context!")
print(f"{'='*55}")
while True:
greeting = f"\n {self.user_name if self.user_name else 'You'}: "
user_input = input(greeting).strip()
if not user_input:
continue
response = self.respond(user_input)
print(f" {self.name}: {response}")
import re
if re.search(r'\b(bye|goodbye|exit)\b', user_input.lower()):
break
if __name__ == '__main__':
bot = ContextualChatbot(name="PyBot", personality="friendly")
bot.run()
Step 4: OpenAI-Powered Chatbot
# chatbot_ai.py — OpenAI GPT-powered chatbot (requires API key)
# pip install openai
# Set: OPENAI_API_KEY environment variable
import os
from openai import OpenAI
class AIChatbot:
def __init__(self, model="gpt-3.5-turbo", system_prompt=None):
self.client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
self.model = model
self.messages = []
# System prompt defines the bot's personality
system = system_prompt or (
"You are PyBot, a friendly and helpful Python programming assistant. "
"You're knowledgeable about Python, data science, and web development. "
"Keep responses concise and helpful. Use emojis occasionally."
)
self.messages.append({"role": "system", "content": system})
def chat(self, user_message):
"""Send message and get AI response."""
self.messages.append({"role": "user", "content": user_message})
try:
response = self.client.chat.completions.create(
model=self.model,
messages=self.messages,
max_tokens=500,
temperature=0.7,
)
assistant_message = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": assistant_message})
return assistant_message
except Exception as e:
return f"Error communicating with AI: {e}"
def reset_conversation(self):
"""Clear conversation history (keep system prompt)."""
self.messages = [self.messages[0]] # Keep system message
def run(self):
print("\n" + "=" * 55)
print(" 🤖 PyBot AI — Powered by OpenAI")
print(" Commands: 'reset' to clear history, 'bye' to exit")
print("=" * 55)
while True:
user_input = input("\n You: ").strip()
if not user_input:
continue
if user_input.lower() == 'reset':
self.reset_conversation()
print(" ✅ Conversation reset!")
continue
if user_input.lower() in ['bye', 'exit', 'quit']:
print(" Bot: Goodbye! Happy coding! 🐍")
break
print(" Bot: ", end='', flush=True)
response = self.chat(user_input)
print(response)
# Run with fallback to rule-based
if __name__ == '__main__':
api_key = os.environ.get("OPENAI_API_KEY")
if api_key:
print(" Using OpenAI API...")
bot = AIChatbot()
else:
print(" No API key found. Using rule-based chatbot...")
from chatbot_v3 import ContextualChatbot
bot = ContextualChatbot()
bot.run()
Summary
In this project, you built:
- ✅ V1: Pattern-matching chatbot with regex
- ✅ V2: Intent-based chatbot with handlers
- ✅ V3: Context-aware chatbot with memory
- ✅ V4: AI-powered chatbot with OpenAI API
Key skills practiced:
- Regular expressions (
re) - Dictionary-based dispatch
- OOP with state management
- API integration
- Conversation context tracking
*Next Project: Weather App →*