mubashirhussaindev commited on
Commit
7a1d2a8
Β·
verified Β·
1 Parent(s): c2c5401

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -28
app.py CHANGED
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
6
  import pytz
7
  from email.mime.text import MIMEText
8
  from email.mime.multipart import MIMEMultipart
 
9
 
10
  import torch
11
  from transformers import AutoModelForCausalLM, AutoTokenizer
@@ -39,6 +40,7 @@ You can ask me about:
39
  - My portfolio (CodeConnect, Mobile Repair App)
40
  - My blog posts (e.g., Laravel tips, MERN stack guides)
41
  - Book an appointment (e.g., 'I want an appointment on YYYY-MM-DD at HH:MM in TIMEZONE. My email is you@example.com')
 
42
  - Submit feedback (e.g., '!feedback Your service is great!')
43
  - Use !help for commands
44
  """
@@ -49,23 +51,34 @@ portfolio = {
49
  "mobile repair app": "A mobile repair service app with MERN Stack, featuring real-time booking and tracking. See more: https://mobilerepair.mubashirdev.com"
50
  }
51
 
52
- # === Blog Posts (Simulated) ===
53
- blog_posts = [
54
- {"title": "Top 10 Laravel Tips", "url": "https://mubashirdev.com/blog/laravel-tips"},
55
- {"title": "Building Scalable MERN Apps", "url": "https://mubashirdev.com/blog/mern-stack"}
56
- ]
 
 
 
57
 
58
  # === Analytics Store ===
59
- analytics = {"queries": 0, "appointments": 0, "feedbacks": 0}
60
 
61
  # === Appointment Slots (Simulated) ===
62
- appointment_slots = {} # Format: {(date, time, timezone): email}
 
 
 
 
 
 
 
63
 
64
  # === Global Chat History ===
65
- chat_history = []
66
 
67
  # === Regex Patterns ===
68
  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\.-]+)"
 
69
  feedback_pattern = r"!feedback\s+(.+)"
70
  command_pattern = r"!(\w+)" # Matches commands like !portfolio, !blog, !help
71
 
@@ -103,7 +116,7 @@ def is_slot_available(date_str, time_str, timezone):
103
  # === Language Detection and Translation ===
104
  def detect_and_translate(text, target_lang="en"):
105
  try:
106
- detected_lang = single_detection(text, api_key=None) # No API key needed for GoogleTranslator
107
  if detected_lang != target_lang:
108
  translated = GoogleTranslator(source="auto", target=target_lang).translate(text)
109
  return translated, detected_lang
@@ -113,12 +126,18 @@ def detect_and_translate(text, target_lang="en"):
113
  return text, "en"
114
 
115
  # === Chatbot Core ===
116
- def chat(user_message, user_lang="en"):
117
  global chat_history
118
 
119
  if not user_message.strip():
120
  return "Please provide a valid message."
121
 
 
 
 
 
 
 
122
  # Track query
123
  track_analytics("queries")
124
 
@@ -132,27 +151,48 @@ def chat(user_message, user_lang="en"):
132
  if command == "portfolio":
133
  return "\n".join([f"{key.title()}: {value}" for key, value in portfolio.items()])
134
  elif command == "blog":
135
- return "\n".join([f"{post['title']}: {post['url']}" for post in blog_posts])
136
  elif command == "help":
137
- return "Available commands:\n!portfolio - View my projects\n!blog - See my blog posts\n!feedback <message> - Submit feedback\nOr ask about services or book an appointment!"
138
  elif command == "analytics":
139
- return f"Analytics: {analytics['queries']} queries, {analytics['appointments']} appointments, {analytics['feedbacks']} feedbacks"
140
 
141
  # Handle feedback
142
  feedback_match = re.match(feedback_pattern, translated_message.lower())
143
  if feedback_match:
 
 
144
  feedback = feedback_match.group(1)
 
145
  track_analytics("feedbacks")
146
- send_email("admin@mubashirdev.com", "πŸ“’ New Feedback", f"Feedback: {feedback}\nFrom: Anonymous")
147
  return "Thank you for your feedback! It has been recorded."
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  # Add context + message to input
150
  full_input = f"{context}\nUser: {translated_message}\nBot:"
151
  new_input = tokenizer.encode(full_input + tokenizer.eos_token, return_tensors="pt").to(torch.long)
152
 
153
- # Manage chat history (limit to 1000 tokens)
154
- if chat_history:
155
- bot_input = torch.cat([torch.tensor(chat_history[-1000:]), new_input], dim=-1)
156
  else:
157
  bot_input = new_input
158
 
@@ -172,11 +212,15 @@ def chat(user_message, user_lang="en"):
172
  reply = "Sorry, I encountered an issue while generating a response. Please try again."
173
 
174
  # Update chat history
175
- chat_history.append(new_input[0].tolist())
 
 
176
 
177
  # === Appointment Booking Logic ===
178
  match = re.search(appointment_pattern, translated_message.lower())
179
  if match:
 
 
180
  date_str, time_str, timezone, email = match.groups()
181
  try:
182
  tz = pytz.timezone(timezone)
@@ -187,10 +231,11 @@ def chat(user_message, user_lang="en"):
187
  reply += "\n❌ This time slot is already booked. Please choose another time."
188
  else:
189
  # Reserve slot
190
- appointment_slots[(date_str, time_str, timezone)] = email
 
191
  track_analytics("appointments")
192
  # Send email to admin & user
193
- admin_msg = f"πŸ“… New Appointment Request:\nDate: {date_str}\nTime: {time_str}\nTime Zone: {timezone}\nEmail: {email}"
194
  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"""
195
 
196
  if send_email("admin@mubashirdev.com", "πŸ“… New Appointment", admin_msg) and send_email(
@@ -212,18 +257,24 @@ def chat(user_message, user_lang="en"):
212
  except Exception as e:
213
  print(f"[Translation Error] {e}")
214
 
215
- return reply
216
 
217
  # === Gradio UI ===
218
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
 
 
 
 
 
219
  gr.Markdown(
220
  """
221
  # Mubashir Dev Chatbot
222
  Ask about my services, portfolio, blog posts, or book an appointment.
223
  Example: *I want an appointment on 2025-06-01 at 14:00 in Asia/Karachi. My email is you@example.com*
224
- Commands: *!portfolio*, *!blog*, *!feedback <message>*, *!help*
225
  """
226
  )
 
227
  chatbot = gr.ChatInterface(
228
  fn=chat,
229
  additional_inputs=[
@@ -231,11 +282,9 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
231
  choices=["en", "ur", "fr", "es"],
232
  label="Select Language",
233
  value="en"
234
- )
235
- ],
236
- submit_btn="πŸš€ Send",
237
- retry_btn="πŸ” Retry",
238
- clear_btn="πŸ—‘οΈ Clear",
239
  )
240
 
241
  # === Launch ===
 
6
  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
 
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
  """
 
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
 
 
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
 
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
 
 
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
198
 
 
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)
 
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(
 
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=[
 
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 ===