Speaking Events
Subscribe to Tech with Tim
Speaking Events
Now that we've got our functions working and we can retrieve events from any specific date it's time for the assistant to speak them out. To do this we are going to modify the get_events() function so that instead of printing out the events we will speak them.
def get_events(day, service): date = datetime.datetime.combine(day, datetime.datetime.min.time()) end_date = datetime.datetime.combine(day, datetime.datetime.max.time()) utc = pytz.UTC date = date.astimezone(utc) end_date = end_date.astimezone(utc) events_result = service.events().list(calendarId='primary', timeMin=date.isoformat(), timeMax=end_date.isoformat(), singleEvents=True, orderBy='startTime').execute() events = events_result.get('items', []) # NEW STUFF STARTS HERE if not events: speak('No upcoming events found.') else: speak(f"You have {len(events)} events on this day.") for event in events: start = event['start'].get('dateTime', event['start'].get('date')) print(start, event['summary']) start_time = str(start.split("T")[1].split("-")[0]) # get the hour the event starts if int(start_time.split(":")[0]) < 12: # if the event is in the morning start_time = start_time + "am" else: start_time = str(int(start_time.split(":")[0])-12) # convert 24 hour time to regular start_time = start_time + "pm" speak(event["summary"] + " at " + start_time)
Now when we call the get_events() function it will speak the events we have that day out in chronological order. It will say both the event and the time they start at.
Calling get_events()
Now that we have everything functioning it's time to determine how/when to use the function get_events(). It only makes sense to call it if what we are asking the assistant relates to our calendar. What we are going to do is create a list of phrases that when detected will trigger the call to get_events(). For the purpose of this tutorial I have kept the list short but you may add/remove as many phrases as you'd like.
CALENDAR_STRS = ["what do i have", "do i have plans", "am i busy"]
Now we will loop through all the phrases, see if any exist in what we said to the assistant and act accordingly.
for phrase in CALENDAR_STRS: if phrase in text.lower(): date = get_date(text) if date: get_events(date, SERVICE) else: speak("Please Try Again")
Full Code
from __future__ import print_function import datetime import pickle import os.path from googleapiclient.discovery import build from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request import os import time import pyttsx3 import speech_recognition as sr import pytz SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] MONTHS = ["january", "february", "march", "april", "may", "june","july", "august", "september","october","november", "december"] DAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] DAY_EXTENTIONS = ["rd", "th", "st", "nd"] def speak(text): engine = pyttsx3.init() engine.say(text) engine.runAndWait() def get_audio(): r = sr.Recognizer() with sr.Microphone() as source: audio = r.listen(source) said = "" try: said = r.recognize_google(audio) print(said) except Exception as e: print("Exception: " + str(e)) return said def authenticate_google(): creds = None if os.path.exists('token.pickle'): with open('token.pickle', 'rb') as token: creds = pickle.load(token) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) with open('token.pickle', 'wb') as token: pickle.dump(creds, token) service = build('calendar', 'v3', credentials=creds) return service def get_events(day, service): date = datetime.datetime.combine(day, datetime.datetime.min.time()) end_date = datetime.datetime.combine(day, datetime.datetime.max.time()) utc = pytz.UTC date = date.astimezone(utc) end_date = end_date.astimezone(utc) events_result = service.events().list(calendarId='primary', timeMin=date.isoformat(), timeMax=end_date.isoformat(), singleEvents=True, orderBy='startTime').execute() events = events_result.get('items', []) if not events: speak('No upcoming events found.') else: speak(f"You have {len(events)} events on this day.") for event in events: start = event['start'].get('dateTime', event['start'].get('date')) print(start, event['summary']) start_time = str(start.split("T")[1].split("-")[0]) if int(start_time.split(":")[0]) < 12: start_time = start_time + "am" else: start_time = str(int(start_time.split(":")[0])-12) start_time = start_time + "pm" speak(event["summary"] + " at " + start_time) def get_date(text): text = text.lower() today = datetime.date.today() if text.count("today") > 0: return today day = -1 day_of_week = -1 month = -1 year = today.year for word in text.split(): if word in MONTHS: month = MONTHS.index(word) + 1 elif word in DAYS: day_of_week = DAYS.index(word) elif word.isdigit(): day = int(word) else: for ext in DAY_EXTENTIONS: found = word.find(ext) if found > 0: try: day = int(word[:found]) except: pass if month < today.month and month != -1: year = year+1 if month == -1 and day != -1: if day < today.day: month = today.month + 1 else: month = today.month if month == -1 and day == -1 and day_of_week != -1: current_day_of_week = today.weekday() dif = day_of_week - current_day_of_week if dif < 0: dif += 7 if text.count("next") >= 1: dif += 7 return today + datetime.timedelta(dif) if day != -1: # FIXED FROM VIDEO return datetime.date(month=month, day=day, year=year) SERVICE = authenticate_google() print("Start") text = get_audio() CALENDAR_STRS = ["what do i have", "do i have plans", "am i busy"] for phrase in CALENDAR_STRS: if phrase in text.lower(): date = get_date(text) if date: get_events(date, SERVICE) else: speak("Please Try Again")