mubashirhussaindev commited on
Commit
fed1437
Β·
verified Β·
1 Parent(s): 4c96eb0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -46
app.py CHANGED
@@ -2,41 +2,72 @@ import os
2
  import re
3
  import ssl
4
  import smtplib
5
- from datetime import datetime
 
6
  from email.mime.text import MIMEText
7
  from email.mime.multipart import MIMEMultipart
8
 
9
  import torch
10
  from transformers import AutoModelForCausalLM, AutoTokenizer
 
11
  import gradio as gr
12
 
13
  # === Email Configuration ===
14
  SMTP_SERVER = "mail.mubashirdev.com"
15
  SMTP_PORT = 465
16
- SMTP_USERNAME = os.getenv("SMTP_USERNAME") # Set in HF Secrets
17
  SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
18
  FROM_EMAIL = SMTP_USERNAME
19
  FROM_NAME = "Mubashir Hussain"
20
 
21
  # === AI Model Initialization ===
22
- tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-large")
23
- model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-large")
 
 
 
 
 
 
 
24
 
25
  # === Chat Context ===
26
  context = """
27
  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.
28
  You can ask me about:
29
- - My services
30
  - My portfolio (CodeConnect, Mobile Repair App)
31
- - My blog posts
32
- - Or book an appointment!
 
 
33
  """
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # === Global Chat History ===
36
  chat_history = []
37
 
38
- # === Regex for Appointment Booking ===
39
- appointment_pattern = r"appointment.*?on\s*(\d{4}-\d{2}-\d{2})\s*at\s*(\d{2}:\d{2}).*?email\s*is\s*([\w\.-]+@[\w\.-]+)"
 
 
40
 
41
  # === Email Utility ===
42
  def send_email(to_email, subject, body):
@@ -56,63 +87,160 @@ def send_email(to_email, subject, body):
56
  print(f"[Email Error] {e}")
57
  return False
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  # === Chatbot Core ===
60
- def chat(user_message):
61
  global chat_history
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  # Add context + message to input
64
- full_input = f"{context}\nUser: {user_message}\nBot:"
65
  new_input = tokenizer.encode(full_input + tokenizer.eos_token, return_tensors="pt").to(torch.long)
66
 
67
- # Manage chat history
68
- bot_input = new_input if not chat_history else torch.cat([torch.tensor(chat_history), new_input], dim=-1)
 
 
 
69
 
70
  # Generate response
71
- output = model.generate(
72
- bot_input,
73
- max_length=500,
74
- pad_token_id=tokenizer.eos_token_id,
75
- temperature=0.7,
76
- top_k=50,
77
- top_p=0.95,
78
- )
 
 
 
 
 
79
 
80
- reply = tokenizer.decode(output[0], skip_special_tokens=True).split("Bot:")[-1].strip()
81
  chat_history.append(new_input[0].tolist())
82
 
83
  # === Appointment Booking Logic ===
84
- match = re.search(appointment_pattern, user_message.lower())
85
  if match:
86
- date_str, time_str, email = match.groups()
87
  try:
88
- datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M") # Validate date/time
89
- # Send email to admin & user
90
- admin_msg = f"πŸ“… New Appointment Request:\nDate: {date_str}\nTime: {time_str}\nEmail: {email}"
91
- user_msg = f"""Hi,\n\nβœ… Your appointment with Mubashir is confirmed for {date_str} at {time_str}.\n\nRegards,\nMubashir Hussain\nhttps://mubashirdev.com"""
92
-
93
- send_email("admin@mubashirdev.com", "πŸ“… New Appointment", admin_msg)
94
- send_email(email, "βœ… Appointment Confirmed", user_msg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- reply += f"\n\nβœ… Your appointment on {date_str} at {time_str} is confirmed. A confirmation email has been sent to {email}."
 
 
 
97
  except Exception as e:
98
- print(f"[Date Parse Error] {e}")
99
- reply += "\n❌ Invalid date/time format. Please use: 'I want an appointment on YYYY-MM-DD at HH:MM. My email is you@example.com'"
100
 
101
  return reply
102
 
103
  # === Gradio UI ===
104
- demo = gr.ChatInterface(
105
- fn=chat,
106
- title="Mubashir Dev Chatbot",
107
- description=(
108
- "Ask about my services or book an appointment.\n"
109
- "Example: I want an appointment on 2025-06-01 at 14:00. My email is you@example.com"
110
- ),
111
- theme="soft",
112
- retry_btn="πŸ” Retry",
113
- submit_btn="πŸš€ Send",
114
- )
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  # === Launch ===
117
  if __name__ == "__main__":
118
- demo.launch()
 
 
 
 
2
  import re
3
  import ssl
4
  import smtplib
5
+ 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
12
+ from googletrans import Translator, LANGUAGES
13
  import gradio as gr
14
 
15
  # === Email Configuration ===
16
  SMTP_SERVER = "mail.mubashirdev.com"
17
  SMTP_PORT = 465
18
+ SMTP_USERNAME = os.getenv("SMTP_USERNAME") # Set in environment variables
19
  SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
20
  FROM_EMAIL = SMTP_USERNAME
21
  FROM_NAME = "Mubashir Hussain"
22
 
23
  # === AI Model Initialization ===
24
+ try:
25
+ tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-large")
26
+ model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-large")
27
+ except Exception as e:
28
+ print(f"[Model Loading Error] {e}")
29
+ raise
30
+
31
+ # === Translation Model ===
32
+ translator = Translator()
33
 
34
  # === Chat Context ===
35
  context = """
36
  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.
37
  You can ask me about:
38
+ - My services (e.g., web development, API integration)
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
  """
45
 
46
+ # === Portfolio Data ===
47
+ portfolio = {
48
+ "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",
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
 
72
  # === Email Utility ===
73
  def send_email(to_email, subject, body):
 
87
  print(f"[Email Error] {e}")
88
  return False
89
 
90
+ # === Analytics Tracking ===
91
+ def track_analytics(event):
92
+ analytics[event] = analytics.get(event, 0) + 1
93
+
94
+ # === Appointment Slot Check ===
95
+ def is_slot_available(date_str, time_str, timezone):
96
+ try:
97
+ tz = pytz.timezone(timezone)
98
+ slot_key = (date_str, time_str, timezone)
99
+ return slot_key not in appointment_slots
100
+ except pytz.exceptions.UnknownTimeZoneError:
101
+ return False
102
+
103
+ # === Language Detection and Translation ===
104
+ def detect_and_translate(text, target_lang="en"):
105
+ try:
106
+ detected_lang = translator.detect(text).lang
107
+ if detected_lang != target_lang and target_lang in LANGUAGES:
108
+ translated = translator.translate(text, dest=target_lang).text
109
+ return translated, detected_lang
110
+ return text, detected_lang
111
+ except Exception as e:
112
+ print(f"[Translation Error] {e}")
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
+
125
+ # Translate input to English if needed
126
+ translated_message, detected_lang = detect_and_translate(user_message, "en")
127
+
128
+ # Handle commands
129
+ command_match = re.match(command_pattern, translated_message.lower())
130
+ if command_match:
131
+ command = command_match.group(1)
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
 
159
  # Generate response
160
+ try:
161
+ output = model.generate(
162
+ bot_input,
163
+ max_length=500,
164
+ pad_token_id=tokenizer.eos_token_id,
165
+ temperature=0.7,
166
+ top_k=50,
167
+ top_p=0.95,
168
+ )
169
+ reply = tokenizer.decode(output[0], skip_special_tokens=True).split("Bot:")[-1].strip()
170
+ except Exception as e:
171
+ print(f"[Model Generation Error] {e}")
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)
183
+ appointment_time = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
184
+ if appointment_time < datetime.now(tz):
185
+ reply += "\n❌ Appointments must be scheduled in the future. Please choose a valid date and time."
186
+ elif not is_slot_available(date_str, time_str, timezone):
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(
197
+ email, "βœ… Appointment Confirmed", user_msg
198
+ ):
199
+ reply += f"\n\nβœ… Your appointment on {date_str} at {time_str} ({timezone}) is confirmed. A confirmation email has been sent to {email}."
200
+ else:
201
+ reply += "\n❌ Failed to send confirmation emails. Please try again later."
202
+ except pytz.exceptions.UnknownTimeZoneError:
203
+ reply += "\n❌ Invalid time zone. Please use a valid time zone (e.g., Asia/Karachi)."
204
+ except ValueError as e:
205
+ print(f"[Date Parse Error] {e}")
206
+ 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'"
207
 
208
+ # Translate response back to user's language
209
+ if detected_lang != "en" and detected_lang in LANGUAGES:
210
+ try:
211
+ reply = translator.translate(reply, dest=detected_lang).text
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=[
230
+ gr.Dropdown(
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 ===
242
  if __name__ == "__main__":
243
+ try:
244
+ demo.launch(server_name="0.0.0.0", server_port=7860)
245
+ except Exception as e:
246
+ print(f"[Gradio Launch Error] {e}")