mubashirhussaindev commited on
Commit
854495c
Β·
verified Β·
1 Parent(s): 309dd55

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -93
app.py CHANGED
@@ -7,12 +7,16 @@ import pytz
7
  from email.mime.text import MIMEText
8
  from email.mime.multipart import MIMEMultipart
9
  import uuid
 
10
 
11
  import torch
12
  from transformers import AutoModelForCausalLM, AutoTokenizer
13
- from deep_translator import GoogleTranslator, single_detection
14
  import gradio as gr
15
 
 
 
 
 
16
  # === Email Configuration ===
17
  SMTP_SERVER = "mail.mubashirdev.com"
18
  SMTP_PORT = 465
@@ -29,58 +33,92 @@ except Exception as e:
29
  print(f"[Model Loading Error] {e}")
30
  raise
31
 
32
- # === Translation Model ===
33
- translator = GoogleTranslator(source="auto", target="en")
34
-
35
  # === Chat Context ===
36
  context = """
37
- I am Mubashir Hussain, a Full Stack Developer from Lahore, Pakistan. I specialize in Laravel, Livewire, MERN Stack, Vue, and Angular. I help startups build secure and scalable web apps.
 
 
 
 
 
 
 
 
 
38
  You can ask me about:
39
  - My services (e.g., web development, API integration)
40
- - My portfolio (CodeConnect, Mobile Repair App)
41
  - My blog posts (e.g., Laravel tips, MERN stack guides)
42
  - Book an appointment (e.g., 'I want an appointment on YYYY-MM-DD at HH:MM in TIMEZONE. My email is you@example.com')
43
  - Cancel an appointment (e.g., '!cancel appointment YYYY-MM-DD HH:MM TIMEZONE')
44
  - Submit feedback (e.g., '!feedback Your service is great!')
 
 
45
  - Use !help for commands
46
  """
47
 
48
  # === Portfolio Data ===
49
  portfolio = {
50
- "codeconnect": "CodeConnect is a social platform for developers to collaborate on projects. Built with Laravel, Livewire, and Vue. Check it out: https://codeconnect.mubashirdev.com",
51
- "mobile repair app": "A mobile repair service app with MERN Stack, featuring real-time booking and tracking. See more: https://mobilerepair.mubashirdev.com"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
 
54
- # === Blog Posts (Simulated Dynamic Fetch) ===
55
  def fetch_blog_posts():
56
- # Simulate fetching from an API or website
57
  return [
58
- {"title": "Top 10 Laravel Tips", "url": "https://mubashirdev.com/blog/laravel-tips"},
59
  {"title": "Building Scalable MERN Apps", "url": "https://mubashirdev.com/blog/mern-stack"},
60
  {"title": "Vue vs Angular: A Comparison", "url": "https://mubashirdev.com/blog/vue-vs-angular"}
61
  ]
62
 
 
 
 
 
 
 
63
  # === Analytics Store ===
64
- analytics = {"queries": 0, "appointments": 0, "feedbacks": 0, "cancellations": 0}
65
 
66
  # === Appointment Slots (Simulated) ===
67
- appointment_slots = {} # Format: {(date, time, timezone): (email, session_id)}
68
 
69
  # === Session Management ===
70
- sessions = {} # Format: {session_id: {"feedback_count": int, "appointment_count": int}}
71
 
72
  # === Rate Limits ===
73
- FEEDBACK_LIMIT = 3 # Max feedback submissions per session
74
- APPOINTMENT_LIMIT = 2 # Max appointments per session
 
75
 
76
  # === Global Chat History ===
77
  chat_history = {}
78
 
79
  # === Regex Patterns ===
80
- appointment_pattern = r"appointment.*?on\s*(\d{4}-\d{2}-\d{2})\s*at\s*(\d{2}:\d{2}).*?in\s*([A-Za-z/]+).*?email\s*is\s*([\w\.-]+@[\w\.-]+)"
81
  cancel_pattern = r"!cancel appointment\s*(\d{4}-\d{2}-\d{2})\s*(\d{2}:\d{2})\s*([A-Za-z/]+)"
82
  feedback_pattern = r"!feedback\s+(.+)"
83
- command_pattern = r"!(\w+)" # Matches commands like !portfolio, !blog, !help
 
84
 
85
  # === Email Utility ===
86
  def send_email(to_email, subject, body):
@@ -90,7 +128,6 @@ def send_email(to_email, subject, body):
90
  msg["To"] = to_email
91
  msg["Subject"] = subject
92
  msg.attach(MIMEText(body, "plain"))
93
-
94
  context = ssl.create_default_context()
95
  with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
96
  server.login(SMTP_USERNAME, SMTP_PASSWORD)
@@ -101,8 +138,9 @@ def send_email(to_email, subject, body):
101
  return False
102
 
103
  # === Analytics Tracking ===
104
- def track_analytics(event):
105
  analytics[event] = analytics.get(event, 0) + 1
 
106
 
107
  # === Appointment Slot Check ===
108
  def is_slot_available(date_str, time_str, timezone):
@@ -113,85 +151,105 @@ def is_slot_available(date_str, time_str, timezone):
113
  except pytz.exceptions.UnknownTimeZoneError:
114
  return False
115
 
116
- # === Language Detection and Translation ===
117
- def detect_and_translate(text, target_lang="en"):
118
  try:
119
- detected_lang = single_detection(text, api_key=None)
120
- if detected_lang != target_lang:
121
- translated = GoogleTranslator(source="auto", target=target_lang).translate(text)
122
- return translated, detected_lang
123
- return text, detected_lang
 
124
  except Exception as e:
125
- print(f"[Translation Error] {e}")
126
- return text, "en"
127
 
128
  # === Chatbot Core ===
129
- def chat(user_message, user_lang="en", session_id=None):
130
- global chat_history
131
-
132
  if not user_message.strip():
133
- return "Please provide a valid message."
134
 
135
- # Initialize session if none provided
136
  if not session_id:
137
  session_id = str(uuid.uuid4())
138
- sessions[session_id] = {"feedback_count": 0, "appointment_count": 0}
139
  chat_history[session_id] = []
140
 
141
- # Track query
142
- track_analytics("queries")
 
 
 
143
 
144
- # Translate input to English if needed
145
- translated_message, detected_lang = detect_and_translate(user_message, "en")
146
 
147
  # Handle commands
148
- command_match = re.match(command_pattern, translated_message.lower())
149
  if command_match:
150
  command = command_match.group(1)
151
  if command == "portfolio":
152
- return "\n".join([f"{key.title()}: {value}" for key, value in portfolio.items()])
153
  elif command == "blog":
154
- return "\n".join([f"{post['title']}: {post['url']}" for post in fetch_blog_posts()])
 
 
155
  elif command == "help":
156
- return "Available commands:\n!portfolio - View my projects\n!blog - See my blog posts\n!feedback <message> - Submit feedback\n!cancel appointment YYYY-MM-DD HH:MM TIMEZONE - Cancel an appointment\nOr ask about services or book an appointment!"
157
  elif command == "analytics":
158
- return f"Analytics: {analytics['queries']} queries, {analytics['appointments']} appointments, {analytics['feedbacks']} feedbacks, {analytics['cancellations']} cancellations"
159
 
160
  # Handle feedback
161
- feedback_match = re.match(feedback_pattern, translated_message.lower())
162
  if feedback_match:
163
  if sessions[session_id]["feedback_count"] >= FEEDBACK_LIMIT:
164
- return "❌ Feedback limit reached for this session. Please try again later."
165
  feedback = feedback_match.group(1)
166
  sessions[session_id]["feedback_count"] += 1
167
- track_analytics("feedbacks")
168
- send_email("admin@mubashirdev.com", "πŸ“’ New Feedback", f"Feedback: {feedback}\nFrom: Session {session_id}")
169
- return "Thank you for your feedback! It has been recorded."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  # Handle appointment cancellation
172
- cancel_match = re.match(cancel_pattern, translated_message.lower())
173
  if cancel_match:
174
  date_str, time_str, timezone = cancel_match.groups()
175
  try:
176
  tz = pytz.timezone(timezone)
177
  slot_key = (date_str, time_str, timezone)
178
  if slot_key in appointment_slots:
179
- email, _ = appointment_slots[slot_key]
180
  del appointment_slots[slot_key]
181
- track_analytics("cancellations")
182
- send_email(email, "❌ Appointment Cancelled", f"Your appointment on {date_str} at {time_str} ({timezone}) has been cancelled.")
183
- return f"βœ… Appointment on {date_str} at {time_str} ({timezone}) has been cancelled."
 
184
  else:
185
- return "❌ No appointment found for the specified date and time."
186
  except pytz.exceptions.UnknownTimeZoneError:
187
- return "❌ Invalid time zone. Please use a valid time zone (e.g., Asia/Karachi)."
188
 
189
  # Add context + message to input
190
- full_input = f"{context}\nUser: {translated_message}\nBot:"
191
  new_input = tokenizer.encode(full_input + tokenizer.eos_token, return_tensors="pt").to(torch.long)
192
 
193
- # Manage chat history (limit to 1000 tokens per session)
194
- if session_id in chat_history and chat_history[session_id]:
 
 
195
  bot_input = torch.cat([torch.tensor(chat_history[session_id][-1000:]), new_input], dim=-1)
196
  else:
197
  bot_input = new_input
@@ -212,16 +270,15 @@ def chat(user_message, user_lang="en", session_id=None):
212
  reply = "Sorry, I encountered an issue while generating a response. Please try again."
213
 
214
  # Update chat history
215
- if session_id not in chat_history:
216
- chat_history[session_id] = []
217
  chat_history[session_id].append(new_input[0].tolist())
218
 
219
  # === Appointment Booking Logic ===
220
- match = re.search(appointment_pattern, translated_message.lower())
221
  if match:
222
  if sessions[session_id]["appointment_count"] >= APPOINTMENT_LIMIT:
223
- return "❌ Appointment limit reached for this session. Please try again later."
224
- date_str, time_str, timezone, email = match.groups()
 
225
  try:
226
  tz = pytz.timezone(timezone)
227
  appointment_time = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
@@ -231,17 +288,21 @@ def chat(user_message, user_lang="en", session_id=None):
231
  reply += "\n❌ This time slot is already booked. Please choose another time."
232
  else:
233
  # Reserve slot
234
- appointment_slots[(date_str, time_str, timezone)] = (email, session_id)
235
  sessions[session_id]["appointment_count"] += 1
236
- track_analytics("appointments")
 
 
237
  # Send email to admin & user
238
- admin_msg = f"πŸ“… New Appointment Request:\nDate: {date_str}\nTime: {time_str}\nTime Zone: {timezone}\nEmail: {email}\nSession: {session_id}"
239
- user_msg = f"""Hi,\n\nβœ… Your appointment with Mubashir is confirmed for {date_str} at {time_str} ({timezone}).\n\nRegards,\nMubashir Hussain\nhttps://mubashirdev.com"""
240
 
241
  if send_email("admin@mubashirdev.com", "πŸ“… New Appointment", admin_msg) and send_email(
242
  email, "βœ… Appointment Confirmed", user_msg
243
  ):
244
  reply += f"\n\nβœ… Your appointment on {date_str} at {time_str} ({timezone}) is confirmed. A confirmation email has been sent to {email}."
 
 
245
  else:
246
  reply += "\n❌ Failed to send confirmation emails. Please try again later."
247
  except pytz.exceptions.UnknownTimeZoneError:
@@ -250,42 +311,66 @@ def chat(user_message, user_lang="en", session_id=None):
250
  print(f"[Date Parse Error] {e}")
251
  reply += "\n❌ Invalid date/time format. Please use: 'I want an appointment on YYYY-MM-DD at HH:MM in TIMEZONE. My email is you@example.com'"
252
 
253
- # Translate response back to user's language
254
- if detected_lang != "en":
255
- try:
256
- reply = GoogleTranslator(source="en", target=detected_lang).translate(reply)
257
- except Exception as e:
258
- print(f"[Translation Error] {e}")
259
-
260
  return reply, session_id
261
 
262
  # === Gradio UI ===
263
  with gr.Blocks(theme=gr.themes.Soft(), css="""
264
- .gradio-container { max-width: 800px; margin: auto; }
265
- .markdown { font-family: Arial, sans-serif; }
266
- .chatbot { border: 1px solid #ddd; border-radius: 8px; padding: 10px; }
267
- .gr-button { font-size: 16px; }
 
 
268
  """) as demo:
269
  gr.Markdown(
270
  """
271
- # Mubashir Dev Chatbot
272
- Ask about my services, portfolio, blog posts, or book an appointment.
273
  Example: *I want an appointment on 2025-06-01 at 14:00 in Asia/Karachi. My email is you@example.com*
274
- Commands: *!portfolio*, *!blog*, *!feedback <message>*, *!cancel appointment YYYY-MM-DD HH:MM TIMEZONE*, *!help*
275
  """
276
  )
 
 
 
 
 
 
 
 
277
  session_id = gr.State(value=None)
278
- chatbot = gr.ChatInterface(
279
- fn=chat,
280
- additional_inputs=[
281
- gr.Dropdown(
282
- choices=["en", "ur", "fr", "es"],
283
- label="Select Language",
284
- value="en"
285
- ),
286
- gr.State(value=session_id)
287
- ]
288
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  # === Launch ===
291
  if __name__ == "__main__":
 
7
  from email.mime.text import MIMEText
8
  from email.mime.multipart import MIMEMultipart
9
  import uuid
10
+ import logging
11
 
12
  import torch
13
  from transformers import AutoModelForCausalLM, AutoTokenizer
 
14
  import gradio as gr
15
 
16
+ # === Logging Setup ===
17
+ logging.basicConfig(filename='chatbot_analytics.log', level=logging.INFO,
18
+ format='%(asctime)s - %(levelname)s - %(message)s')
19
+
20
  # === Email Configuration ===
21
  SMTP_SERVER = "mail.mubashirdev.com"
22
  SMTP_PORT = 465
 
33
  print(f"[Model Loading Error] {e}")
34
  raise
35
 
 
 
 
36
  # === Chat Context ===
37
  context = """
38
+ I am Mubashir Hussain, a Full Stack Developer based in Lahore, Pakistan, with over 5 years of experience building secure, scalable, and high-performance web applications. I specialize in Laravel, Livewire, MERN Stack (MongoDB, Express.js, React, Node.js), Vue, and Angular. My expertise includes backend development (APIs, databases), frontend development (responsive UIs), and DevOps (cloud deployment, CI/CD). I help startups and businesses create custom web solutions, from e-commerce platforms to social apps.
39
+
40
+ Services I offer:
41
+ - Custom web app development
42
+ - API development and integration
43
+ - Frontend development with Vue/Angular/React
44
+ - Backend development with Laravel/Node.js
45
+ - Database design (MySQL, MongoDB)
46
+ - Cloud deployment (AWS, DigitalOcean)
47
+
48
  You can ask me about:
49
  - My services (e.g., web development, API integration)
50
+ - My portfolio (CodeConnect, Mobile Repair App, E-Commerce Platform)
51
  - My blog posts (e.g., Laravel tips, MERN stack guides)
52
  - Book an appointment (e.g., 'I want an appointment on YYYY-MM-DD at HH:MM in TIMEZONE. My email is you@example.com')
53
  - Cancel an appointment (e.g., '!cancel appointment YYYY-MM-DD HH:MM TIMEZONE')
54
  - Submit feedback (e.g., '!feedback Your service is great!')
55
+ - View testimonials (e.g., '!testimonials')
56
+ - Request a service quote (e.g., '!quote <project details>')
57
  - Use !help for commands
58
  """
59
 
60
  # === Portfolio Data ===
61
  portfolio = {
62
+ "codeconnect": {
63
+ "title": "CodeConnect",
64
+ "description": "A social platform for developers to collaborate on projects, share code, and network.",
65
+ "tech": "Laravel, Livewire, Vue, MySQL",
66
+ "features": "Real-time chat, project management, code sharing",
67
+ "url": "https://codeconnect.mubashirdev.com"
68
+ },
69
+ "mobile repair app": {
70
+ "title": "Mobile Repair App",
71
+ "description": "A service app for booking mobile repair appointments with real-time tracking.",
72
+ "tech": "MERN Stack (MongoDB, Express.js, React, Node.js)",
73
+ "features": "Booking system, live tracking, payment integration",
74
+ "url": "https://mobilerepair.mubashirdev.com"
75
+ },
76
+ "e-commerce platform": {
77
+ "title": "E-Commerce Platform",
78
+ "description": "A scalable online store with advanced search and payment features.",
79
+ "tech": "Laravel, Angular, MySQL, AWS",
80
+ "features": "Product catalog, secure payments, admin dashboard",
81
+ "url": "https://ecommerce.mubashirdev.com"
82
+ }
83
  }
84
 
85
+ # === Blog Posts (Simulated) ===
86
  def fetch_blog_posts():
 
87
  return [
88
+ {"title": "Top 10 Laravel Tips for 2025", "url": "https://mubashirdev.com/blog/laravel-tips"},
89
  {"title": "Building Scalable MERN Apps", "url": "https://mubashirdev.com/blog/mern-stack"},
90
  {"title": "Vue vs Angular: A Comparison", "url": "https://mubashirdev.com/blog/vue-vs-angular"}
91
  ]
92
 
93
+ # === Testimonials ===
94
+ testimonials = [
95
+ {"client": "Tech Startup Inc.", "quote": "Mubashir delivered our app on time with exceptional quality. His expertise in Laravel and Vue was a game-changer!"},
96
+ {"client": "Mobile Repair Co.", "quote": "The MERN-based app Mubashir built transformed our business. Highly recommended!"}
97
+ ]
98
+
99
  # === Analytics Store ===
100
+ analytics = {"queries": 0, "appointments": 0, "feedbacks": 0, "cancellations": 0, "quotes": 0}
101
 
102
  # === Appointment Slots (Simulated) ===
103
+ appointment_slots = {} # Format: {(date, time, timezone): (email, session_id, name)}
104
 
105
  # === Session Management ===
106
+ sessions = {} # Format: {session_id: {"feedback_count": int, "appointment_count": int, "quote_count": int, "user_info": {name, email}}}
107
 
108
  # === Rate Limits ===
109
+ FEEDBACK_LIMIT = 3
110
+ APPOINTMENT_LIMIT = 2
111
+ QUOTE_LIMIT = 2
112
 
113
  # === Global Chat History ===
114
  chat_history = {}
115
 
116
  # === Regex Patterns ===
117
+ appointment_pattern = r"appointment.*?on\s*(\d{4}-\d{2}-\d{2})\s*at\s*(\d{2}:\d{2}).*?in\s*([A-Za-z/]+).*?email\s*is\s*([\w\.-]+@[\w\.-]+)(?:.*?name\s*is\s*([\w\s]+))?"
118
  cancel_pattern = r"!cancel appointment\s*(\d{4}-\d{2}-\d{2})\s*(\d{2}:\d{2})\s*([A-Za-z/]+)"
119
  feedback_pattern = r"!feedback\s+(.+)"
120
+ quote_pattern = r"!quote\s+(.+)"
121
+ command_pattern = r"!(\w+)"
122
 
123
  # === Email Utility ===
124
  def send_email(to_email, subject, body):
 
128
  msg["To"] = to_email
129
  msg["Subject"] = subject
130
  msg.attach(MIMEText(body, "plain"))
 
131
  context = ssl.create_default_context()
132
  with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
133
  server.login(SMTP_USERNAME, SMTP_PASSWORD)
 
138
  return False
139
 
140
  # === Analytics Tracking ===
141
+ def track_analytics(event, session_id, details=""):
142
  analytics[event] = analytics.get(event, 0) + 1
143
+ logging.info(f"Event: {event}, Session: {session_id}, Details: {details}")
144
 
145
  # === Appointment Slot Check ===
146
  def is_slot_available(date_str, time_str, timezone):
 
151
  except pytz.exceptions.UnknownTimeZoneError:
152
  return False
153
 
154
+ # === Appointment Reminder ===
155
+ def send_reminder(date_str, time_str, timezone, email, name=""):
156
  try:
157
+ tz = pytz.timezone(timezone)
158
+ appointment_time = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
159
+ reminder_time = appointment_time - timedelta(hours=24)
160
+ if datetime.now(tz) >= reminder_time and datetime.now(tz) < appointment_time:
161
+ send_email(email, "⏰ Appointment Reminder",
162
+ f"Hi {name or 'User'},\n\nThis is a reminder for your appointment on {date_str} at {time_str} ({timezone}).\n\nRegards,\nMubashir Hussain\nhttps://mubashirdev.com")
163
  except Exception as e:
164
+ print(f"[Reminder Error] {e}")
 
165
 
166
  # === Chatbot Core ===
167
+ def chat(user_message, session_id=None, user_name="", user_email="", project_details="", budget=""):
 
 
168
  if not user_message.strip():
169
+ return "Please provide a valid message.", session_id
170
 
171
+ # Initialize session
172
  if not session_id:
173
  session_id = str(uuid.uuid4())
174
+ sessions[session_id] = {"feedback_count": 0, "appointment_count": 0, "quote_count": 0, "user_info": {"name": user_name, "email": user_email}}
175
  chat_history[session_id] = []
176
 
177
+ # Update user info if provided
178
+ if user_name:
179
+ sessions[session_id]["user_info"]["name"] = user_name
180
+ if user_email:
181
+ sessions[session_id]["user_info"]["email"] = user_email
182
 
183
+ # Track query
184
+ track_analytics("queries", session_id, f"Message: {user_message}")
185
 
186
  # Handle commands
187
+ command_match = re.match(command_pattern, user_message.lower())
188
  if command_match:
189
  command = command_match.group(1)
190
  if command == "portfolio":
191
+ return "\n".join([f"{item['title']}: {item['description']}\nTech: {item['tech']}\nFeatures: {item['features']}\nURL: {item['url']}" for item in portfolio.values()]), session_id
192
  elif command == "blog":
193
+ return "\n".join([f"{post['title']}: {post['url']}" for post in fetch_blog_posts()]), session_id
194
+ elif command == "testimonials":
195
+ return "\n".join([f"{t['client']}: {t['quote']}" for t in testimonials]), session_id
196
  elif command == "help":
197
+ return "Available commands:\n!portfolio - View my projects\n!blog - See my blog posts\n!testimonials - View client testimonials\n!feedback <message> - Submit feedback\n!quote <project details> - Request a service quote\n!cancel appointment YYYY-MM-DD HH:MM TIMEZONE - Cancel an appointment\nOr ask about services or book an appointment!", session_id
198
  elif command == "analytics":
199
+ return f"Analytics: {analytics['queries']} queries, {analytics['appointments']} appointments, {analytics['feedbacks']} feedbacks, {analytics['cancellations']} cancellations, {analytics['quotes']} quotes", session_id
200
 
201
  # Handle feedback
202
+ feedback_match = re.match(feedback_pattern, user_message.lower())
203
  if feedback_match:
204
  if sessions[session_id]["feedback_count"] >= FEEDBACK_LIMIT:
205
+ return "❌ Feedback limit reached for this session. Please try again later.", session_id
206
  feedback = feedback_match.group(1)
207
  sessions[session_id]["feedback_count"] += 1
208
+ track_analytics("feedbacks", session_id, f"Feedback: {feedback}")
209
+ send_email("admin@mubashirdev.com", "πŸ“’ New Feedback",
210
+ f"Feedback: {feedback}\nFrom: {sessions[session_id]['user_info']['name'] or 'Anonymous'} (Session: {session_id})")
211
+ return "Thank you for your feedback! It has been recorded.", session_id
212
+
213
+ # Handle quote request
214
+ quote_match = re.match(quote_pattern, user_message.lower())
215
+ if quote_match:
216
+ if sessions[session_id]["quote_count"] >= QUOTE_LIMIT:
217
+ return "❌ Quote request limit reached for this session. Please try again later.", session_id
218
+ project_details = project_details or quote_match.group(1)
219
+ budget = budget or "Not specified"
220
+ sessions[session_id]["quote_count"] += 1
221
+ track_analytics("quotes", session_id, f"Project: {project_details}, Budget: {budget}")
222
+ send_email("admin@mubashirdev.com", "πŸ“ New Quote Request",
223
+ f"Project Details: {project_details}\nBudget: {budget}\nFrom: {sessions[session_id]['user_info']['name'] or 'Anonymous'}\nEmail: {sessions[session_id]['user_info']['email'] or 'Not provided'}\nSession: {session_id}")
224
+ return "βœ… Your quote request has been submitted. I'll get back to you soon!", session_id
225
 
226
  # Handle appointment cancellation
227
+ cancel_match = re.match(cancel_pattern, user_message.lower())
228
  if cancel_match:
229
  date_str, time_str, timezone = cancel_match.groups()
230
  try:
231
  tz = pytz.timezone(timezone)
232
  slot_key = (date_str, time_str, timezone)
233
  if slot_key in appointment_slots:
234
+ email, _, name = appointment_slots[slot_key]
235
  del appointment_slots[slot_key]
236
+ track_analytics("cancellations", session_id, f"Cancelled: {date_str} {time_str} {timezone}")
237
+ send_email(email, "❌ Appointment Cancelled",
238
+ f"Hi {name or 'User'},\n\nYour appointment on {date_str} at {time_str} ({timezone}) has been cancelled.\n\nRegards,\nMubashir Hussain")
239
+ return f"βœ… Appointment on {date_str} at {time_str} ({timezone}) has been cancelled.", session_id
240
  else:
241
+ return "❌ No appointment found for the specified date and time.", session_id
242
  except pytz.exceptions.UnknownTimeZoneError:
243
+ return "❌ Invalid time zone. Please use a valid time zone (e.g., Asia/Karachi).", session_id
244
 
245
  # Add context + message to input
246
+ full_input = f"{context}\nUser: {user_message}\nBot:"
247
  new_input = tokenizer.encode(full_input + tokenizer.eos_token, return_tensors="pt").to(torch.long)
248
 
249
+ # Manage chat history
250
+ if session_id not in chat_history:
251
+ chat_history[session_id] = []
252
+ if chat_history[session_id]:
253
  bot_input = torch.cat([torch.tensor(chat_history[session_id][-1000:]), new_input], dim=-1)
254
  else:
255
  bot_input = new_input
 
270
  reply = "Sorry, I encountered an issue while generating a response. Please try again."
271
 
272
  # Update chat history
 
 
273
  chat_history[session_id].append(new_input[0].tolist())
274
 
275
  # === Appointment Booking Logic ===
276
+ match = re.search(appointment_pattern, user_message.lower())
277
  if match:
278
  if sessions[session_id]["appointment_count"] >= APPOINTMENT_LIMIT:
279
+ return "❌ Appointment limit reached for this session. Please try again later.", session_id
280
+ date_str, time_str, timezone, email, name = match.groups()
281
+ name = name or sessions[session_id]["user_info"]["name"] or "User"
282
  try:
283
  tz = pytz.timezone(timezone)
284
  appointment_time = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
 
288
  reply += "\n❌ This time slot is already booked. Please choose another time."
289
  else:
290
  # Reserve slot
291
+ appointment_slots[(date_str, time_str, timezone)] = (email, session_id, name)
292
  sessions[session_id]["appointment_count"] += 1
293
+ sessions[session_id]["user_info"]["email"] = email
294
+ sessions[session_id]["user_info"]["name"] = name
295
+ track_analytics("appointments", session_id, f"Booked: {date_str} {time_str} {timezone} for {email}")
296
  # Send email to admin & user
297
+ admin_msg = f"πŸ“… New Appointment Request:\nDate: {date_str}\nTime: {time_str}\nTime Zone: {timezone}\nEmail: {email}\nName: {name}\nSession: {session_id}"
298
+ user_msg = f"Hi {name},\n\nβœ… Your appointment with Mubashir is confirmed for {date_str} at {time_str} ({timezone}).\n\nRegards,\nMubashir Hussain\nhttps://mubashirdev.com"
299
 
300
  if send_email("admin@mubashirdev.com", "πŸ“… New Appointment", admin_msg) and send_email(
301
  email, "βœ… Appointment Confirmed", user_msg
302
  ):
303
  reply += f"\n\nβœ… Your appointment on {date_str} at {time_str} ({timezone}) is confirmed. A confirmation email has been sent to {email}."
304
+ # Simulate reminder
305
+ send_reminder(date_str, time_str, timezone, email, name)
306
  else:
307
  reply += "\n❌ Failed to send confirmation emails. Please try again later."
308
  except pytz.exceptions.UnknownTimeZoneError:
 
311
  print(f"[Date Parse Error] {e}")
312
  reply += "\n❌ Invalid date/time format. Please use: 'I want an appointment on YYYY-MM-DD at HH:MM in TIMEZONE. My email is you@example.com'"
313
 
 
 
 
 
 
 
 
314
  return reply, session_id
315
 
316
  # === Gradio UI ===
317
  with gr.Blocks(theme=gr.themes.Soft(), css="""
318
+ .gradio-container { max-width: 900px; margin: auto; font-family: Arial, sans-serif; }
319
+ .markdown { padding: 20px; background: #f0f4f8; border-radius: 8px; }
320
+ .chatbot { border: 1px solid #ccc; border-radius: 8px; padding: 15px; background: #fff; }
321
+ .gr-button { font-size: 16px; margin: 5px; border-radius: 5px; }
322
+ .quick-btn { background: #007bff; color: white; padding: 10px; }
323
+ .welcome { text-align: center; font-size: 24px; color: #333; margin-bottom: 20px; }
324
  """) as demo:
325
  gr.Markdown(
326
  """
327
+ <div class="welcome">Welcome to Mubashir Hussain's Chatbot</div>
328
+ I'm here to showcase my expertise as a Full Stack Developer, share my portfolio, and help you with service inquiries or appointments.
329
  Example: *I want an appointment on 2025-06-01 at 14:00 in Asia/Karachi. My email is you@example.com*
330
+ Commands: *!portfolio*, *!blog*, *!testimonials*, *!feedback <message>*, *!quote <project details>*, *!cancel appointment YYYY-MM-DD HH:MM TIMEZONE*, *!help*
331
  """
332
  )
333
+ with gr.Row():
334
+ user_name = gr.Textbox(label="Your Name (Optional)", placeholder="Enter your name")
335
+ user_email = gr.Textbox(label="Your Email (Optional)", placeholder="Enter your email")
336
+ with gr.Row():
337
+ project_details = gr.Textbox(label="Project Details (For Quote)", placeholder="Describe your project (optional)")
338
+ budget = gr.Textbox(label="Budget (Optional)", placeholder="Enter your budget (e.g., $5000)")
339
+ chatbot = gr.Chatbot()
340
+ msg = gr.Textbox(label="Message", placeholder="Type your message here...")
341
  session_id = gr.State(value=None)
342
+ with gr.Row():
343
+ gr.Button("πŸš€ Send", variant="primary").click(
344
+ fn=chat,
345
+ inputs=[msg, session_id, user_name, user_email, project_details, budget],
346
+ outputs=[chatbot, session_id]
347
+ )
348
+ gr.Button("πŸ—‘οΈ Clear", variant="secondary").click(
349
+ fn=lambda: ([], None),
350
+ inputs=[],
351
+ outputs=[chatbot, session_id]
352
+ )
353
+ with gr.Row():
354
+ gr.Button("Portfolio", variant="primary", elem_classes="quick-btn").click(
355
+ fn=lambda x=msg, s=session_id, n=user_name, e=user_email, p=project_details, b=budget: chat("!portfolio", s, n, e, p, b),
356
+ inputs=[msg, session_id, user_name, user_email, project_details, budget],
357
+ outputs=[chatbot, session_id]
358
+ )
359
+ gr.Button("Blog", variant="primary", elem_classes="quick-btn").click(
360
+ fn=lambda x=msg, s=session_id, n=user_name, e=user_email, p=project_details, b=budget: chat("!blog", s, n, e, p, b),
361
+ inputs=[msg, session_id, user_name, user_email, project_details, budget],
362
+ outputs=[chatbot, session_id]
363
+ )
364
+ gr.Button("Testimonials", variant="primary", elem_classes="quick-btn").click(
365
+ fn=lambda x=msg, s=session_id, n=user_name, e=user_email, p=project_details, b=budget: chat("!testimonials", s, n, e, p, b),
366
+ inputs=[msg, session_id, user_name, user_email, project_details, budget],
367
+ outputs=[chatbot, session_id]
368
+ )
369
+ gr.Button("Request Quote", variant="primary", elem_classes="quick-btn").click(
370
+ fn=lambda x=msg, s=session_id, n=user_name, e=user_email, p=project_details, b=budget: chat(f"!quote {p or 'Project inquiry'}", s, n, e, p, b),
371
+ inputs=[msg, session_id, user_name, user_email, project_details, budget],
372
+ outputs=[chatbot, session_id]
373
+ )
374
 
375
  # === Launch ===
376
  if __name__ == "__main__":