def handle_create_event(self, message): """ Handler to create a new event in the calendar. It checked first if a title or date is given in the intent message. Then the user is asked for missing information as start time, duration or full-day event. If all information are present the event is created using the CalDav interface. :param message: the intent message :return: None """ title, date = get_title_date_from_message(message) fullday = False while title is None: title = self.get_response("ask.for.title", {"action": "create"}) self.log.info(f"set title of new event to: {title}") if date is None: date_response = self.get_response("ask.for.date") date, rest = extract_datetime(date_response) self.log.info(f"set date of new event to: {date}") title = self.remove_time_from_title(title) if date.time() == dt.time(0): time, rest = None, None pattern = re.compile(r"full\s*day") while time is None or time.time() == dt.time(0): rest = self.get_response("new.event.starttime", {"event": title}) if rest is not None: extracted = extract_datetime(rest) if extracted is not None: time, rest = extracted if re.search(pattern, rest): fullday = True break if not fullday: date = datetime.combine(date.date(), time.time()) duration = None while duration is None: if not fullday: duration_utterance = self.get_response( "ask.duration.new.event") duration, rest = extract_duration(duration_utterance) else: duration_utterance = self.get_response("ask.fullday.duration") duration = extract_number(duration_utterance) self.log.info( f"New calendar event will be created. Title: {title}, Date: {str(date)}" ) self.caldav_interface.create_new_event(title, date, duration, fullday) self.speak_dialog("successful.create.event", { "event": title, "date": nice_date(date) })
def handle_rain_waves_wind_intent(self, message): utterance = message.data.get('utterance', "") match, confidence = match_one(utterance, self.play_list) try: track_duration = int( extract_duration(utterance)[0].total_seconds()) except AttributeError: return None self.play_track(match, track_duration, utterance)
def handle_white_noise_intent(self, message): utterance = message.data.get('utterance', "") try: track_duration = int( extract_duration(utterance)[0].total_seconds()) except AttributeError: return None self.play_track(join(dirname(__file__), "whitenoise.mp3"), track_duration, utterance)
def _seek_relative(self, message, controller): direction = 1 if "Forward" in message.data else -1 duration = extract_duration(message.utterance_remainder())[0] duration = duration.seconds if duration else self._default_duration duration *= direction current_time = controller.status.current_time controller.seek(current_time + duration) LOGGER.info("Seek {duration} on {device}".format(duration=duration, device=controller))
def _fetch_movie_details(self, movie): # Fetch extra movie data from dedicated webpage movie_page = get(movie.getchildren()[5].getchildren()[0].get('href')) movie_data = html.fromstring(movie_page.content) # TODO cache result - is it worth creating a movie class? duration_mins = movie.getchildren()[2].text[0:-1] + ' minutes' synopsis_element = movie_data.xpath( '//div[@id="main_content"]/div[@class="container"] \ /div[@class="row"]/div[@class="span8"] \ /div[@class="content"]/p') # Sometimes they put a span tag around the synopsis text... synopsis = synopsis_element[0].text if synopsis_element[0].text \ else synopsis_element[0].getchildren()[0].text # Remaining details in relatively consistent locations on right side. right_panel = movie_data.xpath( '//div[@id="main_content"]/div[@class="container"] \ /div[@class="row"]/div[@class="span4"]')[0] def get_info(info_type): # Find element containing info as heading, then return next element heading = next((x for x in right_panel if x.text == info_type)) info = heading.getnext().text if heading.getnext().text \ else heading.getnext().getchildren().text return info # Construct return object movie_details = { # First details from program page 'title': movie.getchildren()[0].getchildren()[0].text, 'length': nice_duration(extract_duration(duration_mins)[0]), 'rating': movie.getchildren()[3].text, 'screening_location': movie.getchildren()[4].text, # Remaining from movie_data 'synopsis': synopsis, 'director': get_info('Director'), 'year': get_info('Year'), 'country': get_info('Country of Origin'), 'language': get_info('Language'), } return movie_details
def _extract_duration(self, text): """ Extract duration in seconds Args: text (str): Full request, e.g. "set a 30 second timer" Returns: (int): Seconds requested, or None (str): Remainder of utterance """ if not text: return None, None # Some STT engines return "30-second timer" not "30 second timer" # Deal with that before calling extract_duration(). # TODO: Fix inside parsers utt = text.replace("-", " ") duration, str_remainder = extract_duration(utt, self.lang) if duration: # Remove " and" left behind from "for 1 hour and 30 minutes" # prevents it being interpretted as a name "for and" str_remainder = re.sub(r'\s\sand', '', str_remainder, flags=re.I) return duration.total_seconds(), str_remainder return None, text
def seek_intent(self, message): global time_actual init(self) power_on(self) # TODO solve API delay in fast seeking if status_power == "ON": self.log.debug("DEBUG CHANNEL SEEK") if status_device(self) == "NOPLAY": self.log.info("KUKI IS NOT PLAYING ANY VIDEO") self.speak_dialog('shifting.no.play') sys.exit() # TODO need refactor # check where actual video time is time_now = datetime.now().timestamp() # actual time in UTC if time_actual == "": time_actual = time_now - 5 # set actual time right now minus 5 sec (one chunk protection) self.log.debug("USE UTC TIME") else: if time_actual / 1000 > time_now: time_actual = time_now - 5 self.log.debug("BACK FROM FUTURE") else: actual_time_position = datetime.fromtimestamp(time_actual) self.log.debug("USE ACTUAL TIME POSITION") # check if duration of datetime is present duration = message.data.get('duration') date_or_time = message.data.get('datetime') if duration is not None: self.log.debug("DURATION FOUND") move = extract_duration( message.data["utterance"])[1] # seek direction duration = duration.replace( "-", " ") # some STT engines return "5-minutes" not "5 minutes" time = extract_duration(duration)[ 0] # seek duration in seconds time_clean = int(time.seconds) # duration like integer # words of seek direction. TODO need refactor to detect locales and read data from localized files, self.lang etc. self.move_word = { 'zpět': "zpět", 'nazpět': "zpět", 'zpátky': "zpět", 'dozadu': "zpět", 'vrátit': "zpět", 'dopředu': "dopředu", 'vpřed': "dopředu", 'back': "back", 'rewind': "back", 'forward': "forward", 'fast forward': "forward", 'ahead': "forward" } move_direction = self.move_word[move] # select move from word if move_direction == "zpět" or "back": self.log.debug("SEEK BACK") time_position = time_actual - time_clean elif move_direction == "dopředu" or "forward": self.log.debug("SEEK FORWARD") time_position = time_actual + time_clean else: self.log.error("ERROR IN SEEKING") sys.exit() elif date_or_time is not None: self.log.info("DATETIME FOUND") when = message.data.get('utterance').lower() when = extract_datetime(when)[0] time_position = datetime.timestamp(when) move_direction = '' else: self.log.error("SEEK DATA NOT FOUND") sys.exit() #API POST self.api_headers = {'X-SessionKey': session} self.api_post = { 'action': "seek", 'position': time_position * 1000 } # Kuki platform needs milisecond self.api_remote = requests.post(url=API_REMOTE_URL + preferred_device_id, headers=self.api_headers, data=self.api_post) self.speak_dialog('shifting', data={'move': move_direction})
def validate_duration(string): """Check that extract_duration returns a valid duration.""" res = extract_duration(string, self.lang) return res and res[0]
def test_extract_duration_en(self): self.assertEqual(extract_duration("10 seconds"), (timedelta(seconds=10.0), "")) self.assertEqual(extract_duration("5 minutes"), (timedelta(minutes=5), "")) self.assertEqual(extract_duration("2 hours"), (timedelta(hours=2), "")) self.assertEqual(extract_duration("3 days"), (timedelta(days=3), "")) self.assertEqual(extract_duration("25 weeks"), (timedelta(weeks=25), "")) self.assertEqual(extract_duration("seven hours"), (timedelta(hours=7), "")) self.assertEqual(extract_duration("7.5 seconds"), (timedelta(seconds=7.5), "")) self.assertEqual( extract_duration("eight and a half days thirty" " nine seconds"), (timedelta(days=8.5, seconds=39), "")) self.assertEqual(extract_duration("Set a timer for 30 minutes"), (timedelta(minutes=30), "set a timer for")) self.assertEqual( extract_duration("Four and a half minutes until" " sunset"), (timedelta(minutes=4.5), "until sunset")) self.assertEqual(extract_duration("Nineteen minutes past the hour"), (timedelta(minutes=19), "past the hour")) self.assertEqual( extract_duration("wake me up in three weeks, four" " hundred ninety seven days, and" " three hundred 91.6 seconds"), (timedelta(weeks=3, days=497, seconds=391.6), "wake me up in , , and")) self.assertEqual( extract_duration("The movie is one hour, fifty seven" " and a half minutes long"), (timedelta(hours=1, minutes=57.5), "the movie is , long")) self.assertEqual(extract_duration(""), None)
def handle_loop_whitenoise(self, message): print("inside loop handler") wait_while_speaking() print(message.data.get('sound')) self.stopped = False now = datetime.now() if message.data.get('sound') is not None: print("inside not None") title = message.data.get('sound') score = match_one(title, self.play_list) print(score) if score[1] > 0.5: self.process = play_wav(score[0]) fname = score[0] with contextlib.closing(wave.open(fname, 'r')) as f: frames = f.getnframes() rate = f.getframerate() duration = frames / float(rate) self.audio_length = duration print(duration) self.songTimer = { "file": fname, "expires": now + timedelta(seconds=self.audio_length) } self.check_replay(None) else: return None self.speak('Sorry I could not find that sound in my library') else: print("inside None") sound_file = list(self.play_list.values()) sound_file = random.choice(sound_file) print(sound_file) #if os.path.isfile(sound_file): wait_while_speaking() self.process = play_wav(sound_file) fname = sound_file with contextlib.closing(wave.open(fname, 'r')) as f: frames = f.getnframes() rate = f.getframerate() duration = frames / float(rate) self.audio_length = duration print(duration) self.songTimer = { "file": fname, "expires": now + timedelta(seconds=self.audio_length) } self.check_replay(None) #Extract Time and Duration of Audio Play utt = normalize(message.data.get('utterance', "").lower()) extract = extract_duration(utt) print(extract) if extract: total_duration = extract[0] self.endtime = extract[0] utt = extract[1] utc = pytz.UTC print("Current Duration:") secs = self.endtime.total_seconds() time_expires = now + timedelta(seconds=secs) self.timer = {"duration": secs, "expires": time_expires} self.update_time(None)
def handle_add_event_intent(self, message): utt = message.data['utterance'] time_delta, remaining_utt = extract_duration( utt) # get time duration from utterance start_time, remaining_utt = extract_datetime( remaining_utt) # get time from utterance owner = message.data.get('Owner') # get calendar owner utt = normalize(utt).replace("'s", "") # normalize and drop 's in utterance parsed_utt = asjson( self.PEGParser.parse(utt)) # parse utterance for owner owner = parsed_utt.get('calendar_owner') if owner is None: # if parser failed to get owner, prompt user owner = self.get_response('ask.calendar.owner') self.log.info('using owner: {}'.format(owner)) try: # get the calendar belonging to owner calName = self.nameToCalendar[owner] # throw error if none found except KeyError: self.speak_dialog('no.calendar.found.error', {'name': owner}) return if start_time is None: # if start time not found start_time, _ = extract_datetime( self.get_response('ask.start.time')) # ask the user if time_delta is None: # if duration not found time_delta, _ = extract_duration( self.get_response('ask.duration')) # ask the user if time_delta is None or start_time is None: # if duration of start time STILL unkonwn self.speak( 'sorry. i was not able to understand. please start over.' ) # fail return end_time = start_time + time_delta # calculate end time eventName = self.get_response( 'ask.event.name').title() # ask for event name confirmation = self.ask_yesno( 'confirm.event', # confirm details { 'event_name': eventName, 'confirmation_text': self.confirmEventDetails( start_time, end_time), 'owner': self.calendarToName[calName] }) if confirmation == 'no': self.speak_dialog('confirmation.failed') elif confirmation == 'yes': url, user, password = self.getConfigs() # get configs if url is None: # if getConfigs returned None, it failed and pass # already spoke to user else: calendar = self.getCalendar( calName, url, user, password) # get calendar and create the event self.makeEvent(calendar, start_time, end_time, eventName, owner=self.calendarToName[calName]) else: self.speak('sorry i did not understand.')
def test_extract_duration_en(self): self.assertEqual(extract_duration("10 seconds"), (timedelta(seconds=10.0), "")) self.assertEqual(extract_duration("5 minutes"), (timedelta(minutes=5), "")) self.assertEqual(extract_duration("2 hours"), (timedelta(hours=2), "")) self.assertEqual(extract_duration("3 days"), (timedelta(days=3), "")) self.assertEqual(extract_duration("25 weeks"), (timedelta(weeks=25), "")) self.assertEqual(extract_duration("seven hours"), (timedelta(hours=7), "")) self.assertEqual(extract_duration("7.5 seconds"), (timedelta(seconds=7.5), "")) self.assertEqual(extract_duration("eight and a half days thirty" " nine seconds"), (timedelta(days=8.5, seconds=39), "")) self.assertEqual(extract_duration("Set a timer for 30 minutes"), (timedelta(minutes=30), "set a timer for")) self.assertEqual(extract_duration("Four and a half minutes until" " sunset"), (timedelta(minutes=4.5), "until sunset")) self.assertEqual(extract_duration("Nineteen minutes past the hour"), (timedelta(minutes=19), "past the hour")) self.assertEqual(extract_duration("wake me up in three weeks, four" " hundred ninety seven days, and" " three hundred 91.6 seconds"), (timedelta(weeks=3, days=497, seconds=391.6), "wake me up in , , and")) self.assertEqual(extract_duration("The movie is one hour, fifty seven" " and a half minutes long"), (timedelta(hours=1, minutes=57.5), "the movie is , long"))