mubashirhussaindev commited on
Commit
fc06ab9
·
verified ·
1 Parent(s): 3cc6154

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -110
app.py CHANGED
@@ -28,6 +28,15 @@ EXCEL_FILE = "appointments.xlsx"
28
  # === Time Slots ===
29
  TIME_SLOTS = [f"{hour:02d}:00" for hour in range(9, 18)] # 9 AM to 5 PM
30
 
 
 
 
 
 
 
 
 
 
31
  # === Google Calendar Event Link Generator ===
32
  def generate_google_calendar_link(name, email, date_str, time_str, timezone):
33
  try:
@@ -43,9 +52,7 @@ def generate_google_calendar_link(name, email, date_str, time_str, timezone):
43
  "dates": f"{start_time_utc}/{end_time_utc}",
44
  "ctz": timezone
45
  }
46
- base_url = "https://www.google.com/calendar/render"
47
- calendar_url = f"{base_url}?{urlencode(event)}"
48
- return calendar_url
49
  except Exception as e:
50
  logging.error(f"Google Calendar link error: {e}")
51
  return None
@@ -77,16 +84,16 @@ def save_to_excel(name, email, date_str, time_str, timezone, message):
77
  "Date": date_str,
78
  "Time": time_str,
79
  "Timezone": timezone,
80
- "Message": message if message else "No message provided",
81
  "Timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
82
  }
83
  try:
84
- df = pd.read_excel(EXCEL_FILE)
85
  except FileNotFoundError:
86
  df = pd.DataFrame()
87
  df = pd.concat([df, pd.DataFrame([appointment_data])], ignore_index=True)
88
- df.to_excel(EXCEL_FILE, index=False)
89
- logging.info(f"Appointment saved to {EXCEL_FILE}: {name}, {email}, {date_str}, {time_str}, {timezone}, {message}")
90
  return True
91
  except Exception as e:
92
  logging.error(f"Excel save error: {e}")
@@ -95,45 +102,45 @@ def save_to_excel(name, email, date_str, time_str, timezone, message):
95
  # === Appointment Handler ===
96
  def book_appointment(name, email, date, time, timezone, message):
97
  if not all([name, email, date, time, timezone]):
98
- return "Please fill out all required fields (Name, Email, Date, Time, Timezone).", []
99
 
100
  try:
101
- # Validate date format (YYYY-MM-DD)
102
  datetime.strptime(date, "%Y-%m-%d")
103
  tz = pytz.timezone(timezone)
104
  appointment_time = datetime.strptime(f"{date} {time}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
105
  if appointment_time < datetime.now(tz):
106
- return "Appointments must be scheduled in the future.", []
107
 
108
  if not save_to_excel(name, email, date, time, timezone, message):
109
- return "Failed to save appointment. Please try again.", []
110
 
111
  calendar_link = generate_google_calendar_link(name, email, date, time, timezone)
112
  if not calendar_link:
113
- return "Failed to generate Google Calendar link, but appointment is saved.", []
114
 
115
  admin_msg = (
116
- f"New Appointment Request:\n"
117
  f"Name: {name}\n"
118
  f"Email: {email}\n"
119
  f"Date: {date}\n"
120
  f"Time: {time}\n"
121
  f"Timezone: {timezone}\n"
122
- f"Message: {message if message else 'No message provided'}"
123
  )
124
  send_email("admin@mubashirdev.com", "📅 New Appointment", admin_msg)
125
 
126
  user_msg = (
127
  f"Hi {name},\n\n"
128
  f"Your appointment is confirmed for {date} at {time} ({timezone}).\n"
129
- f"Click here to add it to your Google Calendar: {calendar_link}\n\n"
130
- f"Your message: {message if message else 'No message provided'}\n\n"
131
- f"Thank you for choosing my services!\n\n"
132
- f"Regards,\nMubashir Hussain\nhttps://mubashirdev.com"
133
  )
134
  send_email(email, "✅ Appointment Confirmed", user_msg)
135
 
136
- # Generate a styled chart for confirmation
137
  chart_data = {
138
  "type": "bar",
139
  "data": {
@@ -141,8 +148,8 @@ def book_appointment(name, email, date, time, timezone, message):
141
  "datasets": [{
142
  "label": "Appointment",
143
  "data": [1],
144
- "backgroundColor": "#1E88E5", # Blue to match UI theme
145
- "borderColor": "#1565C0",
146
  "borderWidth": 2
147
  }]
148
  },
@@ -150,170 +157,142 @@ def book_appointment(name, email, date, time, timezone, message):
150
  "scales": {
151
  "y": {
152
  "beginAtZero": True,
153
- "ticks": {
154
- "stepSize": 1,
155
- "color": "#333",
156
- "font": {
157
- "family": "Roboto, sans-serif",
158
- "size": 14
159
- }
160
- },
161
- "title": {
162
- "display": True,
163
- "text": "Appointment Confirmed",
164
- "color": "#333",
165
- "font": {
166
- "family": "Roboto, sans-serif",
167
- "size": 16
168
- }
169
- }
170
  },
171
  "x": {
172
- "title": {
173
- "display": True,
174
- "text": "Date and Time",
175
- "color": "#333",
176
- "font": {
177
- "family": "Roboto, sans-serif",
178
- "size": 16
179
- }
180
- },
181
- "ticks": {
182
- "color": "#333",
183
- "font": {
184
- "family": "Roboto, sans-serif",
185
- "size": 14
186
- }
187
- }
188
  }
189
  },
190
  "plugins": {
191
- "title": {
192
- "display": True,
193
- "text": f"Appointment for {name}",
194
- "color": "#1E88E5",
195
- "font": {
196
- "family": "Roboto, sans-serif",
197
- "size": 18
198
- }
199
- }
200
  }
201
  }
202
  }
203
 
204
  return (
205
- f"✅ Appointment confirmed for {date} at {time} ({timezone}). "
206
- f"A confirmation email with a Google Calendar link has been sent to {email}.",
207
  [chart_data]
208
  )
209
 
210
  except pytz.exceptions.UnknownTimeZoneError:
211
- return "Invalid timezone. Please select a valid timezone.", []
212
  except ValueError:
213
- return "Invalid date format. Please use YYYY-MM-DD (e.g., 2025-06-01).", []
214
 
215
  # === Gradio UI ===
216
  with gr.Blocks(theme=gr.themes.Soft(), css="""
217
  @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
218
  .gradio-container {
219
  max-width: 700px;
220
- margin: auto;
221
  font-family: 'Roboto', sans-serif;
222
- background-color: #f5f7fa;
223
- padding: 20px;
224
- border-radius: 12px;
225
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
226
  }
227
  .welcome {
228
  text-align: center;
229
- font-size: 28px;
230
- color: #1E88E5;
231
- margin-bottom: 20px;
232
  font-weight: 700;
233
  }
234
  .gr-textbox, .gr-dropdown {
235
  border-radius: 8px;
236
- border: 2px solid #E0E0E0;
237
- padding: 10px;
238
  font-size: 16px;
239
- transition: border-color 0.3s ease;
240
  }
241
  .gr-textbox:focus, .gr-dropdown:focus {
242
- border-color: #1E88E5;
243
  outline: none;
244
  }
245
- .gr-textbox[label="Date"] {
246
- padding: 10px;
247
- font-family: 'Roboto', sans-serif;
248
  }
249
  .gr-button {
250
- background-color: #1E88E5;
251
  color: white;
252
  font-size: 16px;
253
  font-weight: 600;
254
- padding: 12px 24px;
255
  border-radius: 8px;
256
  border: none;
257
- transition: background-color 0.3s ease, transform 0.2s ease;
258
- margin: 20px auto;
259
  display: block;
260
  }
261
  .gr-button:hover {
262
- background-color: #1565C0;
263
  transform: translateY(-2px);
264
  }
265
  .gr-textbox[label="Result"] {
266
- background-color: #E8F5E9;
267
- border-color: #4CAF50;
268
- color: #2E7D32;
269
  font-weight: 500;
270
- padding: 15px;
271
  border-radius: 8px;
272
  }
273
  .gr-column {
274
- background-color: white;
275
- padding: 20px;
276
- border-radius: 10px;
277
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
278
  }
279
  .footer {
280
  text-align: center;
281
  font-size: 14px;
282
- color: #666;
283
- margin-top: 20px;
 
 
 
 
 
 
 
 
 
284
  }
285
  @media (max-width: 600px) {
286
  .gradio-container {
287
- padding: 10px;
 
288
  }
289
  .welcome {
290
  font-size: 24px;
291
  }
292
  .gr-button {
293
- padding: 10px 20px;
294
  }
295
  }
296
  """) as demo:
297
  gr.Markdown(
298
  """
299
- <div class="welcome">Appointment Booking Bot</div>
300
- Fill out the form below to book an appointment with Mubashir Hussain. You'll receive a confirmation email with a Google Calendar link, and a chart will confirm your booking.
 
301
  """
302
  )
303
  with gr.Column():
304
- name = gr.Textbox(label="Your Name", placeholder="Enter your name")
305
- email = gr.Textbox(label="Your Email", placeholder="Enter your email")
306
- date = gr.Textbox(label="Date", placeholder="YYYY-MM-DD (e.g., 2025-06-01)", type="text")
307
- time = gr.Dropdown(label="Time", choices=TIME_SLOTS, value="09:00")
308
- timezone = gr.Dropdown(label="Timezone", choices=pytz.all_timezones, value="Asia/Karachi")
309
- message = gr.Textbox(label="Message (Optional)", placeholder="Enter any additional details or notes", lines=4)
310
- submit_btn = gr.Button("Book Appointment", variant="primary")
311
  output = gr.Textbox(label="Result", interactive=False)
312
- chart_output = gr.Plot(label="Appointment Confirmation")
313
 
314
  gr.Markdown(
315
  """
316
- <div class="footer">Powered by <a href="https://mubashirdev.com" style="color: #1E88E5; text-decoration: none;">mubashirdev.com</a></div>
317
  """
318
  )
319
 
 
28
  # === Time Slots ===
29
  TIME_SLOTS = [f"{hour:02d}:00" for hour in range(9, 18)] # 9 AM to 5 PM
30
 
31
+ # === Common Timezones (for performance) ===
32
+ COMMON_TIMEZONES = [
33
+ "UTC", "US/Pacific", "US/Eastern", "US/Central", "US/Mountain",
34
+ "Europe/London", "Europe/Paris", "Europe/Berlin", "Asia/Karachi",
35
+ "Asia/Tokyo", "Asia/Shanghai", "Asia/Dubai", "Australia/Sydney",
36
+ "America/New_York", "America/Los_Angeles", "America/Chicago",
37
+ "America/Toronto", "America/Sao_Paulo", "Asia/Kolkata", "Asia/Singapore"
38
+ ] # Curated list for faster dropdown rendering
39
+
40
  # === Google Calendar Event Link Generator ===
41
  def generate_google_calendar_link(name, email, date_str, time_str, timezone):
42
  try:
 
52
  "dates": f"{start_time_utc}/{end_time_utc}",
53
  "ctz": timezone
54
  }
55
+ return f"https://www.google.com/calendar/render?{urlencode(event)}"
 
 
56
  except Exception as e:
57
  logging.error(f"Google Calendar link error: {e}")
58
  return None
 
84
  "Date": date_str,
85
  "Time": time_str,
86
  "Timezone": timezone,
87
+ "Message": message if message else "No message",
88
  "Timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
89
  }
90
  try:
91
+ df = pd.read_excel(EXCEL_FILE, engine='openpyxl')
92
  except FileNotFoundError:
93
  df = pd.DataFrame()
94
  df = pd.concat([df, pd.DataFrame([appointment_data])], ignore_index=True)
95
+ df.to_excel(EXCEL_FILE, engine='openpyxl', index=False)
96
+ logging.info(f"Appointment saved: {name}, {email}, {date_str}, {time_str}, {timezone}, {message}")
97
  return True
98
  except Exception as e:
99
  logging.error(f"Excel save error: {e}")
 
102
  # === Appointment Handler ===
103
  def book_appointment(name, email, date, time, timezone, message):
104
  if not all([name, email, date, time, timezone]):
105
+ return "Please fill out all required fields.", []
106
 
107
  try:
108
+ # Validate date format
109
  datetime.strptime(date, "%Y-%m-%d")
110
  tz = pytz.timezone(timezone)
111
  appointment_time = datetime.strptime(f"{date} {time}", "%Y-%m-%d %H:%M").replace(tzinfo=tz)
112
  if appointment_time < datetime.now(tz):
113
+ return "Appointments must be in the future.", []
114
 
115
  if not save_to_excel(name, email, date, time, timezone, message):
116
+ return "Failed to save appointment.", []
117
 
118
  calendar_link = generate_google_calendar_link(name, email, date, time, timezone)
119
  if not calendar_link:
120
+ return "Failed to generate calendar link, but appointment saved.", []
121
 
122
  admin_msg = (
123
+ f"New Appointment:\n"
124
  f"Name: {name}\n"
125
  f"Email: {email}\n"
126
  f"Date: {date}\n"
127
  f"Time: {time}\n"
128
  f"Timezone: {timezone}\n"
129
+ f"Message: {message if message else 'No message'}"
130
  )
131
  send_email("admin@mubashirdev.com", "📅 New Appointment", admin_msg)
132
 
133
  user_msg = (
134
  f"Hi {name},\n\n"
135
  f"Your appointment is confirmed for {date} at {time} ({timezone}).\n"
136
+ f"Add to Google Calendar: {calendar_link}\n\n"
137
+ f"Your message: {message if message else 'No message'}\n\n"
138
+ f"Thank you for choosing my services!\n"
139
+ f"Mubashir Hussain\nhttps://mubashirdev.com"
140
  )
141
  send_email(email, "✅ Appointment Confirmed", user_msg)
142
 
143
+ # Generate styled chart
144
  chart_data = {
145
  "type": "bar",
146
  "data": {
 
148
  "datasets": [{
149
  "label": "Appointment",
150
  "data": [1],
151
+ "backgroundColor": "#1976D2",
152
+ "borderColor": "#0D47A1",
153
  "borderWidth": 2
154
  }]
155
  },
 
157
  "scales": {
158
  "y": {
159
  "beginAtZero": True,
160
+ "ticks": {"stepSize": 1, "color": "#333", "font": {"family": "Roboto", "size": 14}},
161
+ "title": {"display": True, "text": "Confirmed", "color": "#333", "font": {"family": "Roboto", "size": 16}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  },
163
  "x": {
164
+ "title": {"display": True, "text": "Date & Time", "color": "#333", "font": {"family": "Roboto", "size": 16}},
165
+ "ticks": {"color": "#333", "font": {"family": "Roboto", "size": 14}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
  },
168
  "plugins": {
169
+ "title": {"display": True, "text": f"Appointment for {name}", "color": "#1976D2", "font": {"family": "Roboto", "size": 18}}
 
 
 
 
 
 
 
 
170
  }
171
  }
172
  }
173
 
174
  return (
175
+ f"✅ Appointment confirmed for {date} at {time} ({timezone}). Email sent to {email}.",
 
176
  [chart_data]
177
  )
178
 
179
  except pytz.exceptions.UnknownTimeZoneError:
180
+ return "Invalid timezone.", []
181
  except ValueError:
182
+ return "Invalid date format. Use YYYY-MM-DD (e.g., 2025-06-01).", []
183
 
184
  # === Gradio UI ===
185
  with gr.Blocks(theme=gr.themes.Soft(), css="""
186
  @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
187
  .gradio-container {
188
  max-width: 700px;
189
+ margin: 20px auto;
190
  font-family: 'Roboto', sans-serif;
191
+ background: #F5F6F5;
192
+ padding: 24px;
193
+ border-radius: 16px;
194
+ box-shadow: 0 4px 16px rgba(0,0,0,0.1);
195
  }
196
  .welcome {
197
  text-align: center;
198
+ font-size: 32px;
199
+ color: #1976D2;
200
+ margin: 0 0 24px;
201
  font-weight: 700;
202
  }
203
  .gr-textbox, .gr-dropdown {
204
  border-radius: 8px;
205
+ border: 2px solid #B0BEC5;
206
+ padding: 12px;
207
  font-size: 16px;
208
+ transition: border-color 0.2s;
209
  }
210
  .gr-textbox:focus, .gr-dropdown:focus {
211
+ border-color: #1976D2;
212
  outline: none;
213
  }
214
+ .gr-textbox[label="Date"]::before {
215
+ content: "📅 ";
 
216
  }
217
  .gr-button {
218
+ background: #1976D2;
219
  color: white;
220
  font-size: 16px;
221
  font-weight: 600;
222
+ padding: 12px 32px;
223
  border-radius: 8px;
224
  border: none;
225
+ transition: background 0.2s, transform 0.1s;
226
+ margin: 24px auto;
227
  display: block;
228
  }
229
  .gr-button:hover {
230
+ background: #0D47A1;
231
  transform: translateY(-2px);
232
  }
233
  .gr-textbox[label="Result"] {
234
+ background: #C8E6C9;
235
+ border-color: #388E3C;
236
+ color: #1B5E20;
237
  font-weight: 500;
238
+ padding: 16px;
239
  border-radius: 8px;
240
  }
241
  .gr-column {
242
+ background: white;
243
+ padding: 24px;
244
+ border-radius: 12px;
245
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
246
  }
247
  .footer {
248
  text-align: center;
249
  font-size: 14px;
250
+ color: #546E7A;
251
+ margin-top: 24px;
252
+ }
253
+ .logo {
254
+ display: block;
255
+ margin: 0 auto 16px;
256
+ max-width: 150px;
257
+ }
258
+ .required::after {
259
+ content: " *";
260
+ color: #D32F2F;
261
  }
262
  @media (max-width: 600px) {
263
  .gradio-container {
264
+ padding: 16px;
265
+ margin: 10px;
266
  }
267
  .welcome {
268
  font-size: 24px;
269
  }
270
  .gr-button {
271
+ padding: 10px 24px;
272
  }
273
  }
274
  """) as demo:
275
  gr.Markdown(
276
  """
277
+ <img src="/static/logo.png" class="logo" alt="Mubashir Hussain Logo">
278
+ <div class="welcome">Book Your Appointment</div>
279
+ Complete the form below to schedule an appointment with Mubashir Hussain. You'll receive a confirmation email with a Google Calendar link.
280
  """
281
  )
282
  with gr.Column():
283
+ name = gr.Textbox(label="Your Name", placeholder="Enter your name", elem_classes="required")
284
+ email = gr.Textbox(label="Your Email", placeholder="Enter your email", elem_classes="required")
285
+ date = gr.Textbox(label="Date", placeholder="YYYY-MM-DD (e.g., 2025-06-01)", type="text", elem_classes="required")
286
+ time = gr.Dropdown(label="Time", choices=TIME_SLOTS, value="09:00", elem_classes="required")
287
+ timezone = gr.Dropdown(label="Timezone", choices=COMMON_TIMEZONES, value="Asia/Karachi", elem_classes="required")
288
+ message = gr.Textbox(label="Message (Optional)", placeholder="Add any details or notes", lines=4)
289
+ submit_btn = gr.Button("Book Appointment")
290
  output = gr.Textbox(label="Result", interactive=False)
291
+ chart_output = gr.Plot(label="Confirmation")
292
 
293
  gr.Markdown(
294
  """
295
+ <div class="footer">Powered by <a href="https://mubashirdev.com" style="color: #1976D2; text-decoration: none;">mubashirdev.com</a></div>
296
  """
297
  )
298