Repository navigation
Expand file tree
/
Copy pathchatbot.py
More file actions
289 lines (223 loc) · 9.89 KB
/
Copy pathchatbot.py
File metadata and controls
289 lines (223 loc) · 9.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
"""
CodeAlpha_BasicChatbot
Task 4: Basic Rule-Based Chatbot (Advanced Version 2)
Concepts: if-elif, functions, loops, input/output, re, json, datetime
Features:
- Rule-based responses using keyword matching (regex)
- Remembers the user's name during the conversation
- Simple calculator (add, subtract, multiply, divide)
- Wider topics: weather, food, hobbies, mood, jokes
- Persistent chat history saved to JSON (view past conversations)
- Colorful terminal UI
"""
import re
import random
import json
import os
from datetime import datetime
# ---------- Colors ----------
class C:
HEADER = "\033[95m"
CYAN = "\033[96m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
BLUE = "\033[94m"
BOLD = "\033[1m"
END = "\033[0m"
BOT_NAME = "CodeBot"
HISTORY_FILE = "chatbot_history.json"
# ---------- Persistent history (JSON) ----------
def load_history():
if os.path.exists(HISTORY_FILE):
try:
with open(HISTORY_FILE, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
return []
return []
def save_history(all_sessions):
try:
with open(HISTORY_FILE, "w", encoding="utf-8") as f:
json.dump(all_sessions, f, indent=2)
except (IOError, OSError) as e:
print(f"{C.RED}Could not save history: {e}{C.END}")
def show_past_conversations(all_sessions):
if not all_sessions:
print(f"{C.YELLOW}No past conversations found.{C.END}")
return
print(f"\n{C.BOLD}Past Conversations:{C.END}")
for i, session in enumerate(all_sessions, start=1):
print(f" {i}. {session['date']} ({len(session['messages'])} messages)"
f"{' - ' + session['user_name'] if session.get('user_name') else ''}")
choice = input("\nEnter a number to view that conversation (or press Enter to skip): ").strip()
if choice.isdigit() and 1 <= int(choice) <= len(all_sessions):
session = all_sessions[int(choice) - 1]
print(f"\n{C.CYAN}--- Conversation from {session['date']} ---{C.END}")
for speaker, msg in session["messages"]:
color = C.BOLD if speaker == "You" else C.GREEN
print(f"{color}{speaker}: {msg}{C.END}")
print(f"{C.CYAN}--- End of conversation ---{C.END}\n")
# ---------- Simple calculator ----------
def try_calculate(text):
match = re.search(
r"(-?\d+(?:\.\d+)?)\s*([\+\-\*x×/])\s*(-?\d+(?:\.\d+)?)", text
)
if not match:
return None
num1 = float(match.group(1))
op = match.group(2)
num2 = float(match.group(3))
try:
if op == "+":
result = num1 + num2
elif op == "-":
result = num1 - num2
elif op in ("*", "x", "×"):
result = num1 * num2
elif op == "/":
if num2 == 0:
return "I can't divide by zero!"
result = num1 / num2
else:
return None
if result == int(result):
result = int(result)
return f"That equals {result}."
except (ValueError, ZeroDivisionError):
return "Sorry, I couldn't calculate that."
# ---------- Rules ----------
RULES = [
(r"\b(hi|hello|hey|hii+|helo)\b",
["Hi there! How can I help you today?",
"Hello! Nice to see you.",
"Hey! What's up?"]),
(r"\bhow are you\b",
["I'm fine, thanks for asking! How about you?",
"Doing great! Just here chatting with you.",
"I'm a bot, so I'm always doing well :)"]),
(r"\b(i am|i'm) (fine|good|great|okay|ok|happy)\b",
["Glad to hear that!", "Awesome, good to know!"]),
(r"\b(i am|i'm) (sad|tired|upset|not okay|not good|down)\b",
["I'm sorry to hear that. I hope things get better soon.",
"Take care of yourself. Want to talk about it?"]),
(r"\bwhat('?s| is) your name\b",
[f"I'm {BOT_NAME}, your friendly rule-based chatbot.",
f"You can call me {BOT_NAME}!"]),
(r"\bwho (made|created|built) you\b",
["I was built as part of a CodeAlpha Python internship project!"]),
(r"\bwhat can you do\b",
["I can chat, remember your name, do basic math (try '5 + 3'), "
"tell jokes, show past conversations, or just have a casual chat!"]),
(r"\b(thank you|thanks|thankyou)\b",
["You're welcome!", "Anytime!", "No problem at all!"]),
(r"\b(help|assist)\b",
["Sure! Ask me about the time, date, do some math, tell you a joke, "
"or just chat. Type 'bye' to end our chat."]),
(r"\b(joke|funny)\b",
["Why do programmers prefer dark mode? Because light attracts bugs!",
"Why did the Python developer wear glasses? Because they couldn't C!",
"I would tell you a UDP joke, but you might not get it."]),
(r"\byour age\b|\bhow old are you\b",
["I don't have an age - I'm just lines of Python code!"]),
(r"\b(love|like) (you|this)\b",
["That's sweet of you to say!"]),
(r"\bweather\b",
["I can't check live weather right now, but I hope it's nice where you are!",
"No live weather access here, but stay prepared either way!"]),
(r"\b(food|hungry|eat)\b",
["I don't eat, but I hear pizza is popular among humans!",
"Food sounds great - what's your favorite dish?"]),
(r"\b(hobby|hobbies|free time)\b",
["I like chatting with people! What do you enjoy doing?"]),
(r"\b(movie|film|series|show)\b",
["I don't watch movies, but I'd love to hear your favorite one!"]),
(r"\b(music|song)\b",
["Music sounds fun! What genre do you like?"]),
(r"\bstudy|exam|college|internship\b",
["Studying and internships build great skills - keep going, you're doing well!"]),
]
FALLBACK_RESPONSES = [
"I'm not sure I understand. Could you rephrase that?",
"Hmm, I don't have an answer for that yet.",
"Sorry, I didn't quite get that. Try asking something else!",
"I'm still learning - can you try a different question?",
]
def get_response(user_input, user_name):
text = user_input.lower().strip()
if not text:
return "Please say something!", user_name
calc_result = try_calculate(text)
if calc_result and re.search(r"\d+\s*[\+\-\*x×/]\s*\d+", text):
return calc_result, user_name
name_match = re.search(
r"my name is (\w+)|i am (\w+)|i'm (\w+)|call me (\w+)", text
)
if name_match:
name = next(g for g in name_match.groups() if g)
name = name.capitalize()
if name.lower() not in ("fine", "good", "great", "okay", "ok", "happy",
"sad", "tired", "upset", "down", "not"):
return f"Nice to meet you, {name}! I'll remember your name.", name
if re.search(r"what('?s| is) my name", text):
if user_name:
return f"Your name is {user_name}!", user_name
return "I don't know your name yet - tell me by saying 'my name is ...'.", user_name
if re.search(r"\b(bye|goodbye|see you|exit|quit)\b", text):
farewell = f"Goodbye, {user_name}! Take care!" if user_name else "Goodbye! Take care!"
return farewell, user_name
if re.search(r"time is it|current time", text):
return f"The current time is {datetime.now().strftime('%I:%M %p')}.", user_name
if re.search(r"the date|today'?s date", text):
return f"Today's date is {datetime.now().strftime('%d %B %Y')}.", user_name
for pattern, responses in RULES:
if re.search(pattern, text):
return random.choice(responses), user_name
return random.choice(FALLBACK_RESPONSES), user_name
def is_exit_command(text):
return bool(re.search(r"\b(bye|goodbye|exit|quit|see you)\b", text.lower()))
def main():
print(f"{C.HEADER}{C.BOLD}" + "=" * 50 + C.END)
print(f"{C.HEADER}{C.BOLD}" + " " * 14 + f"{BOT_NAME} - CHATBOT" + C.END)
print(f"{C.HEADER}{C.BOLD}" + "=" * 50 + C.END)
print(f"{C.CYAN}Tip: try 'my name is Alex', '5 + 3', or 'tell me a joke'.{C.END}")
print(f"{C.CYAN}Type 'history' to see past chats, 'bye' or 'quit' to exit.{C.END}\n")
all_sessions = load_history()
first_input = input(f"{C.BOLD}You: {C.END}").strip()
conversation_log = []
user_name = None
if first_input.lower() == "history":
show_past_conversations(all_sessions)
first_input = input(f"{C.BOLD}You: {C.END}").strip()
try:
user_input = first_input
while True:
if not user_input:
print(f"{C.YELLOW}{BOT_NAME}: Please type something!{C.END}")
user_input = input(f"{C.BOLD}You: {C.END}").strip()
continue
if user_input.lower() == "history":
show_past_conversations(all_sessions)
user_input = input(f"{C.BOLD}You: {C.END}").strip()
continue
conversation_log.append(("You", user_input))
response, user_name = get_response(user_input, user_name)
print(f"{C.GREEN}{BOT_NAME}: {response}{C.END}")
conversation_log.append((BOT_NAME, response))
if is_exit_command(user_input):
break
user_input = input(f"{C.BOLD}You: {C.END}").strip()
except KeyboardInterrupt:
print(f"\n{C.YELLOW}(Chat interrupted){C.END}")
farewell = f"Goodbye, {user_name}! Take care!" if user_name else "Goodbye! Take care!"
print(f"{C.GREEN}{BOT_NAME}: {farewell}{C.END}")
if conversation_log:
all_sessions.append({
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"user_name": user_name,
"messages": conversation_log,
})
save_history(all_sessions)
print(f"{C.CYAN}(Conversation saved to {HISTORY_FILE}){C.END}")
if __name__ == "__main__":
main()