Kabilash10 commited on
Commit
4c96918
1 Parent(s): 769a147

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -0
app.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pickle
3
+ from google.oauth2.credentials import Credentials
4
+ from google_auth_oauthlib.flow import InstalledAppFlow
5
+ from google.auth.transport.requests import Request
6
+ from googleapiclient.discovery import build
7
+ from datetime import datetime, timedelta
8
+ import gradio as gr
9
+
10
+ # SCOPES for Google Calendar API
11
+ SCOPES = ['https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/calendar']
12
+
13
+ def authenticate_google():
14
+ """Authenticate and return Google Calendar service."""
15
+ creds = None
16
+ try:
17
+ if os.path.exists('token.pickle'):
18
+ try:
19
+ with open('token.pickle', 'rb') as token:
20
+ creds = pickle.load(token)
21
+
22
+ if not creds or not creds.valid:
23
+ if creds and creds.expired and creds.refresh_token:
24
+ try:
25
+ creds.refresh(Request())
26
+ except Exception:
27
+ os.remove('token.pickle')
28
+ creds = None
29
+ else:
30
+ os.remove('token.pickle')
31
+ creds = None
32
+ except Exception:
33
+ os.remove('token.pickle')
34
+ creds = None
35
+
36
+ if not creds:
37
+ if not os.path.exists('credentials.json'):
38
+ raise FileNotFoundError(
39
+ "credentials.json file not found. Please download it from Google Cloud Console."
40
+ )
41
+
42
+ flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
43
+ creds = flow.run_local_server(port=0)
44
+
45
+ with open('token.pickle', 'wb') as token:
46
+ pickle.dump(creds, token)
47
+
48
+ return build('calendar', 'v3', credentials=creds)
49
+
50
+ except Exception as e:
51
+ raise Exception(f"Authentication failed: {str(e)}")
52
+
53
+ def create_event(service, event_name, start_time, end_time, time_zone='Asia/Kolkata'):
54
+ """Create an event in Google Calendar."""
55
+ try:
56
+ event = {
57
+ 'summary': event_name,
58
+ 'start': {
59
+ 'dateTime': start_time.isoformat(),
60
+ 'timeZone': time_zone,
61
+ },
62
+ 'end': {
63
+ 'dateTime': end_time.isoformat(),
64
+ 'timeZone': time_zone,
65
+ },
66
+ }
67
+
68
+ created_event = service.events().insert(calendarId='primary', body=event).execute()
69
+ return f'Event "{event_name}" created successfully!'
70
+ except Exception as e:
71
+ error_msg = f"Failed to create event: {str(e)}"
72
+ if "invalid_grant" in str(e):
73
+ if os.path.exists('token.pickle'):
74
+ os.remove('token.pickle')
75
+ error_msg += "\nPlease restart the application to re-authenticate."
76
+ raise Exception(error_msg)
77
+
78
+ def parse_date_time(date_str, time_str):
79
+ """Parse date and time strings."""
80
+ try:
81
+ date_parts = date_str.split('-')
82
+ if len(date_parts) != 3:
83
+ raise ValueError("Date must be in DD-MM-YYYY format")
84
+
85
+ day, month, year = map(int, date_parts)
86
+
87
+ try:
88
+ time_obj = datetime.strptime(time_str.strip().upper(), '%I:%M %p')
89
+ except ValueError:
90
+ raise ValueError("Time must be in HH:MM AM/PM format")
91
+
92
+ start_time = datetime(year, month, day,
93
+ time_obj.hour, time_obj.minute)
94
+
95
+ return start_time
96
+ except ValueError as e:
97
+ raise ValueError(str(e))
98
+
99
+ def get_conversation_stage(history):
100
+ """Determine the current stage of the conversation."""
101
+ user_messages = [msg for role, msg in history if role == "User"]
102
+ if not user_messages:
103
+ return 0
104
+ return len(user_messages)
105
+
106
+ def conversational_flow(history, user_input):
107
+ """Handle the conversation flow with improved input processing."""
108
+ if not user_input:
109
+ return history
110
+
111
+ # Check for restart command at any point
112
+ if user_input.lower() in ['restart', 'start over', 'reset']:
113
+ history.clear()
114
+ history.append(("Bot", "Conversation restarted. Hi! How may I assist you?"))
115
+ return history
116
+
117
+ # Add user input to history
118
+ history.append(("User", user_input))
119
+ stage = get_conversation_stage(history)
120
+
121
+ # Process based on conversation stage
122
+ if stage == 1: # After first input (Book an appointment)
123
+ if "appointment" in user_input.lower() or "book" in user_input.lower():
124
+ history.append(("Bot", "What is the purpose of the appointment?"))
125
+ else:
126
+ history.pop() # Remove invalid input
127
+ history.append(("Bot", "I can help you book an appointment. Please say 'Book an appointment' to start."))
128
+
129
+ elif stage == 2: # After purpose
130
+ event_name = user_input
131
+ history.append(("Bot", f"Great! You want to create an event for '{event_name}'. What is the date? (DD-MM-YYYY)"))
132
+
133
+ elif stage == 3: # After date
134
+ date_str = user_input
135
+ try:
136
+ # Validate date format
137
+ date_parts = date_str.split('-')
138
+ if len(date_parts) != 3 or not all(part.isdigit() for part in date_parts):
139
+ raise ValueError("Date must be in DD-MM-YYYY format")
140
+ history.append(("Bot", "What is the start time? (HH:MM AM/PM)"))
141
+ except ValueError as e:
142
+ history.pop() # Remove invalid date
143
+ history.append(("Bot", f"Invalid date format: {str(e)}. Please enter the date in DD-MM-YYYY format."))
144
+
145
+ elif stage == 4: # After start time
146
+ start_time_str = user_input
147
+ try:
148
+ datetime.strptime(start_time_str.strip().upper(), '%I:%M %p')
149
+ history.append(("Bot", "What is the end time? (HH:MM AM/PM)"))
150
+ except ValueError:
151
+ history.pop()
152
+ history.append(("Bot", "Invalid time format. Please enter the time in HH:MM AM/PM format (e.g., 02:30 PM)."))
153
+
154
+ elif stage == 5: # After end time
155
+ end_time_str = user_input
156
+ try:
157
+ # Extract event details from history
158
+ event_name = [msg for role, msg in history if role == "User"][1]
159
+ date_str = [msg for role, msg in history if role == "User"][2]
160
+ start_time_str = [msg for role, msg in history if role == "User"][3]
161
+
162
+ # Parse start and end times
163
+ start_time = parse_date_time(date_str, start_time_str)
164
+ end_time = parse_date_time(date_str, end_time_str)
165
+
166
+ # Validate end time is after start time
167
+ if end_time <= start_time:
168
+ raise ValueError("End time must be after start time")
169
+
170
+ # Create event
171
+ try:
172
+ service = authenticate_google()
173
+ result = create_event(service, event_name, start_time, end_time)
174
+ history.append(("Bot", result))
175
+ history.append(("Bot", "Do you need to book any other appointments? (yes/no)"))
176
+ except Exception as e:
177
+ history.append(("Bot", f"Error: {str(e)}"))
178
+ except ValueError as e:
179
+ history.pop()
180
+ history.append(("Bot", f"Invalid time: {str(e)}. Please enter a valid end time in HH:MM AM/PM format."))
181
+
182
+ elif stage == 6: # After yes/no
183
+ if user_input.lower() == "yes":
184
+ history.clear()
185
+ history.append(("Bot", "Hi! How may I assist you?"))
186
+ elif user_input.lower() == "no":
187
+ history.append(("Bot", "Thank you! Have a nice day."))
188
+ else:
189
+ history.pop()
190
+ history.append(("Bot", "Please answer with 'yes' or 'no'."))
191
+
192
+ return history
193
+
194
+ def display_chat(history):
195
+ """Display chat messages."""
196
+ chat_display = []
197
+ for role, message in history:
198
+ if role == "User":
199
+ chat_display.append([message, None])
200
+ else:
201
+ chat_display.append([None, message])
202
+ return chat_display
203
+
204
+ # Create Gradio interface
205
+ with gr.Blocks() as iface:
206
+ gr.Markdown("""
207
+ <h1>Google Calendar Appointment Bot</h1>
208
+ <p>Type 'restart' at any time to start over.</p>
209
+ """)
210
+ chatbot = gr.Chatbot()
211
+ user_input = gr.Textbox(placeholder="Type your response here...")
212
+ send_button = gr.Button("Send")
213
+ restart_button = gr.Button("Restart Conversation")
214
+
215
+ def reset_conversation():
216
+ history = [("Bot", "Hi! How may I assist you?")]
217
+ return display_chat(history), history
218
+
219
+ def handle_input(user_input, history):
220
+ if not user_input.strip():
221
+ return display_chat(history), history, ""
222
+ history = conversational_flow(history, user_input)
223
+ return display_chat(history), history, ""
224
+
225
+ history_state = gr.State([])
226
+ send_button.click(handle_input, inputs=[user_input, history_state], outputs=[chatbot, history_state, user_input])
227
+ user_input.submit(handle_input, inputs=[user_input, history_state], outputs=[chatbot, history_state, user_input])
228
+ restart_button.click(reset_conversation, outputs=[chatbot, history_state])
229
+ iface.load(reset_conversation, outputs=[chatbot, history_state])
230
+
231
+ if __name__ == "__main__":
232
+ iface.launch()