Exemplo n.º 1
0
 def test_open_envelope(self):
     name = 'Jerome'
     intent = IntentBuilder(name).require('Keyword')
     intent.name = name
     m = Message("register_intent", intent.__dict__)
     unpacked_intent = open_intent_envelope(m)
     self.assertEqual(intent.__dict__, unpacked_intent.__dict__)
Exemplo n.º 2
0
    def test_at_least_one_alone(self):
        intent = IntentBuilder("OptionsForLunch") \
            .one_of("Question", "Command") \
            .build()

        for result in self.parser.parse("show"):
            result_intent = intent.validate(result.get('tags'), result.get('confidence'))
            assert result_intent.get('confidence') > 0.0
            assert result_intent.get('Command') == "show"
Exemplo n.º 3
0
 def test_basic_intent_with_alternate_names(self):
     intent = IntentBuilder("play television intent")\
         .require("PlayVerb", "Play Verb")\
         .require("Television Show", "series")\
         .build()
     for result in self.parser.parse("play the big bang theory"):
         result_intent = intent.validate(result.get('tags'), result.get('confidence'))
         assert result_intent.get('confidence') > 0.0
         assert result_intent.get('Play Verb') == 'play'
         assert result_intent.get('series') == "the big bang theory"
Exemplo n.º 4
0
 def test_intent_using_alias(self):
     self.trie.insert("big bang", ("the big bang theory", "Television Show"))
     intent = IntentBuilder("play television intent")\
         .require("PlayVerb", "Play Verb")\
         .require("Television Show", "series")\
         .build()
     for result in self.parser.parse("play the big bang theory"):
         result_intent = intent.validate(result.get('tags'), result.get('confidence'))
         assert result_intent.get('confidence') > 0.0
         assert result_intent.get('Play Verb') == 'play'
         assert result_intent.get('series') == "the big bang theory"
Exemplo n.º 5
0
    def test_at_least_on_no_required(self):
        intent = IntentBuilder("play intent") \
            .one_of("Television Show", "Radio Station") \
            .build()
        for result in self.parser.parse("play the big bang theory"):
            result_intent = intent.validate(result.get('tags'), result.get('confidence'))
            assert result_intent.get('confidence') > 0.0
            assert result_intent.get('Television Show') == "the big bang theory"

        for result in self.parser.parse("play the barenaked ladies"):
            result_intent = intent.validate(result.get('tags'), result.get('confidence'))
            assert result_intent.get('confidence') > 0.0
            assert result_intent.get('Radio Station') == "barenaked ladies"
Exemplo n.º 6
0
    def test_intent_with_regex_entity(self):
        self.trie = Trie()
        self.tagger = EntityTagger(self.trie, self.tokenizer, self.regex_entities)
        self.parser = Parser(self.tokenizer, self.tagger)
        self.trie.insert("theory", ("theory", "Concept"))
        regex = re.compile(r"the (?P<Event>.*)")
        self.regex_entities.append(regex)
        intent = IntentBuilder("mock intent")\
            .require("Event")\
            .require("Concept").build()

        for result in self.parser.parse("the big bang theory"):
            result_intent = intent.validate(result.get('tags'), result.get('confidence'))
            assert result_intent.get('confidence') > 0.0
            assert result_intent.get('Event') == 'big bang'
            assert result_intent.get('Concept') == "theory"
Exemplo n.º 7
0
    def _connect(self, message):
        url = 'http://localhost:6680'
        if self.base_conf:
            url = self.base_conf.get('mopidy_url', None)
        if self.config:
            url = self.config.get('mopidy_url', url)
        try:
            self.mopidy = Mopidy(url)
        except:
            if self.connection_attempts < 1:
                logger.debug('Could not connect to server, will retry quietly')
            self.connection_attempts += 1
            time.sleep(10)
            self.emitter.emit(Message(self.name + '.connect'))
            return

        logger.info('Connected to mopidy server')
        self.albums = {}
        self.artists = {}
        self.genres = {}
        self.playlists = {}
        self.radios = {}

        logger.info('Loading content')
        self.albums['gmusic'] = self.mopidy.get_gmusic_albums()
        self.artists['gmusic'] = self.mopidy.get_gmusic_artists()
        self.genres['gmusic'] = self.mopidy.get_gmusic_radio()
        self.playlists['gmusic'] = {}

        self.albums['local'] = self.mopidy.get_local_albums()
        self.artists['local'] = self.mopidy.get_local_artists()
        self.genres['local'] = self.mopidy.get_local_genres()
        self.playlists['local'] = self.mopidy.get_local_playlists()

        self.albums['spotify'] = {}
        self.artists['spotify'] = {}
        self.genres['spotify'] = {}
        self.playlists['spotify'] = self.mopidy.get_spotify_playlists()

        self.playlist = {}
        for loc in ['local', 'gmusic', 'spotify']:
            logger.info(loc)
            self.playlist.update(self.playlists[loc])
            logger.info(loc)
            self.playlist.update(self.genres[loc])
            logger.info(loc)
            self.playlist.update(self.artists[loc])
            logger.info(loc)
            self.playlist.update(self.albums[loc])

        self.register_vocabulary(self.name, 'NameKeyword')
        for p in self.playlist.keys():
            logger.debug("Playlist: " + p)
            self.register_vocabulary(p, 'PlaylistKeyword' + self.name)
        intent = IntentBuilder('PlayPlaylistIntent' + self.name)\
            .require('PlayKeyword')\
            .require('PlaylistKeyword' + self.name)\
            .build()
        self.register_intent(intent, self.handle_play_playlist)
        intent = IntentBuilder('PlayFromIntent' + self.name)\
            .require('PlayKeyword')\
            .require('PlaylistKeyword')\
            .require('NameKeyword')\
            .build()
        self.register_intent(intent, self.handle_play_playlist)

        intent = IntentBuilder('SearchSpotifyIntent' + self.name)\
            .require('SearchKeyword')\
            .require('Source')\
            .require('SpotifyKeyword')\
            .build()
        self.register_intent(intent, self.search_spotify)
Exemplo n.º 8
0
 def initialize(self):
     i = IntentBuilder('a').require('Keyword')
     self.register_intent(i, self.handler)
 def initialize(self):
     intent = IntentBuilder("PairingIntent") \
         .require("PairingKeyword").require("DeviceKeyword").build()
     self.register_intent(intent, self.handle_pairing)
     self.emitter.on("mycroft.not.paired", self.not_paired)
class PersonDetectSkill(MycroftSkill):
    def __init__(self):
        super(PersonDetectSkill, self).__init__(name="PersonDetectSkill")

    @intent_handler(
        IntentBuilder("HowManyIntent").require("howmanykeyword").require(
            "youkeyword").build())
    def handle_how_many_intent(self, message):
        capture = cv2.VideoCapture(1)
        capture.set(3, 640)
        capture.set(4, 480)
        frame_set = []
        start_time = time.time()
        while (True):
            ret, frame = capture.read()
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame_set.append(gray)
            ##cv2.imshow('frame',gray)

            end_time = time.time()
            elapsed = end_time - start_time
            if elapsed > 2:
                break
        capture.release()
        with detection_graph.as_default():
            with tf.Session(graph=detection_graph) as sess:
                # Definite input and output Tensors for detection_graph
                image_tensor = detection_graph.get_tensor_by_name(
                    'image_tensor:0')
                # Each box represents a part of the image where a particular object was detected.
                detection_boxes = detection_graph.get_tensor_by_name(
                    'detection_boxes:0')
                # Each score represent how level of confidence for each of the objects.
                # Score is shown on the result image, together with the class label.
                detection_scores = detection_graph.get_tensor_by_name(
                    'detection_scores:0')
                detection_classes = detection_graph.get_tensor_by_name(
                    'detection_classes:0')
                num_detections = detection_graph.get_tensor_by_name(
                    'num_detections:0')
                ##for image in frame_set:
                ##image_path = frame_set[0]
                ##image = Image.open(image_path)
                # the array based representation of the image will be used later in order to prepare the
                # result image with boxes and labels on it.
                image_np = frame_set[-1]
                # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
                image_np_expanded = np.expand_dims(image_np, axis=0)
                # Actual detection.
                (boxes, scores, classes,
                 num) = sess.run([
                     detection_boxes, detection_scores, detection_classes,
                     num_detections
                 ],
                                 feed_dict={image_tensor: image_np_expanded})
                # Visualization of the results of a detection.
                ##width, height = image.size
                final_score = np.squeeze(scores)
                count = 0
                for i in range(100):
                    if scores is None or final_score[i] > 0.5:
                        count = count + 1

        if count > 1:
            self.speak("There are {} persons in front of me".format(count))
        if count == 0:
            self.speak("I cant see anyone")
        if count == 1:
            self.speak("There is one person in front of me")

    def stop(self):
        pass
Exemplo n.º 11
0
class AlgorithmSkill(MycroftSkill):
    def __init__(self):
        super(AlgorithmSkill, self).__init__(name="AlgorithmSkill")

    @intent_handler(
        IntentBuilder("MergeSortIntent").require("Algorithm").require(
            "MergeSort"))
    def handle_merge_sort_best_intent(self, message):
        self.speak_dialog("merge.sort")

    @intent_handler(
        IntentBuilder("CountingSortIntent").require("Algorithm").require(
            "CountingSort"))
    def handle_counting_sort_intent(self, message):
        self.speak_dialog("counting.sort")

    @intent_handler(
        IntentBuilder("LinearSortIntent").require("Algorithm").require(
            "LinearSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("linear.sort")

    @intent_handler(
        IntentBuilder("HeapSortIntent").require("Algorithm").require(
            "HeapSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("heap.sort")

    @intent_handler(
        IntentBuilder("QuickSortIntent").require("Algorithm").require(
            "QuickSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("quick.sort")

    @intent_handler(
        IntentBuilder("RadixSortIntent").require("Algorithm").require(
            "RadixSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("radix.sort")

    @intent_handler(
        IntentBuilder("TimSortIntent").require("Algorithm").require("TimSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("tim.sort")

    @intent_handler(
        IntentBuilder("BubbleSortIntent").require("Algorithm").require(
            "BubbleSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("bubble.sort")

    @intent_handler(
        IntentBuilder("SelectionSortIntent").require("Algorithm").require(
            "SelectionSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("selection.sort")

    @intent_handler(
        IntentBuilder("TreeSortIntent").require("Algorithm").require(
            "TreeSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("tree.sort")

    @intent_handler(
        IntentBuilder("BucketSortIntent").require("Algorithm").require(
            "BucketSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("bucket.sort")

    @intent_handler(
        IntentBuilder("ShellSortIntent").require("Algorithm").require(
            "ShellSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("shell.sort")

    @intent_handler(
        IntentBuilder("CubeSortIntent").require("Algorithm").require(
            "CubeSort"))
    def handle_linear_sort_intent(self, message):
        self.speak_dialog("cube.sort")

    def stop(self):
        pass
Exemplo n.º 12
0
    engine.register_entity(wk, "WeatherKeyword", domain='Domain1')

weather_types = ["snow", "rain", "wind", "sleet", "sun"]

for wt in weather_types:
    engine.register_entity(wt, "WeatherType", domain='Domain1')

locations = ["Seattle", "San Francisco", "Tokyo"]

for l in locations:
    engine.register_entity(l, "Location", domain='Domain1')

# structure intent
weather_intent = IntentBuilder("WeatherIntent")\
    .require("WeatherKeyword")\
    .optionally("WeatherType")\
    .require("Location")\
    .build()

# define music vocabulary
artists = [
    "third eye blind", "the who", "the clash", "john mayer", "kings of leon",
    "adelle"
]

for a in artists:
    engine.register_entity(a, "Artist", domain='Domain2')

music_verbs = ["listen", "hear", "play"]

for mv in music_verbs:
Exemplo n.º 13
0
class RegSkill(MycroftSkill):
    def __init__(self):
        super(RegSkill, self).__init__(name="Regskill")

    #def initialize(self):
    #add_event_intent = IntentBuilder('EventIntent') \
    #.require('Add') \
    #.require('Event') \
    #.require('Person') \
    #.optionally('Location') \
    #.optionally('time') \
    #.build()
    #self.register_intent(add_event_intent, self.createevent)
    @property
    def utc_offset(self):
        return timedelta(seconds=self.location['timezone']['offset'] / 1000)

    @intent_handler(
        IntentBuilder("add_event_intent").require('Add').require(
            'Person').optionally('Location').optionally('time').build())
    def createevent(self, message):
        storage1 = Storage(
            '/opt/mycroft/skills/finalregskill.hanabouzid/info3.dat')
        credentials = storage1.get()
        if credentials is None or credentials.invalid == True:
            credentials = tools.run_flow(FLOW, storage1)
        print(credentials)
        # Create an httplib2.Http object to handle our HTTP requests and
        # authorize it with our good Credentials.
        http = httplib2.Http()
        http = credentials.authorize(http)
        service = build('calendar', 'v3', http=http)
        people_service = build(serviceName='people', version='v1', http=http)
        print("authorized")

        # To get the person information for any Google Account, use the following code:
        # profile = people_service.people().get('people/me', pageSize=100, personFields='names,emailAddresses').execute()
        # To get a list of people in the user's contacts,
        # results = service.people().connections().list(resourceName='people/me',personFields='names,emailAddresses',fields='connections,totalItems,nextSyncToken').execute()
        results = people_service.people().connections().list(
            resourceName='people/me',
            pageSize=100,
            personFields='names,emailAddresses,events',
            fields='connections,totalItems,nextSyncToken').execute()
        connections = results.get('connections', [])
        print("connections:", connections)
        utt = message.data.get("utterance", None)

        # extract the location
        #location = message.data.get("Location", None)
        print(utt)
        #listname1=utt.split(" named ")
        #listname2=listname1[1].split(" with ")
        #title =listname2[0]
        lister = utt.split(" in ")
        lister2 = lister[1].split(" starts ")
        location = lister2[0]
        print(location)
        strtdate = lister2[1]
        st = extract_datetime(strtdate)
        st = st[0] - self.utc_offset
        et = st + timedelta(hours=1)
        datestart = st.strftime('%Y-%m-%dT%H:%M:00')
        datend = et.strftime('%Y-%m-%dT%H:%M:00')
        datestart += UTC_TZ
        datend += UTC_TZ
        print(datestart)
        print(datend)
        listp = []
        list1 = utt.split(" with ")

        #extract attendees
        list2 = list1[1].split(" in ")
        if ("and") in list2[0]:
            listp = list2[0].split(" and ")
        else:
            listp.append(list2[0])
        print(listp)

        attendee = []
        namerooms = [
            'midoune room', 'aiguilles room', 'barrouta room', 'kantaoui room',
            'gorges room', 'ichkeul room', 'khemir room', 'tamaghza room',
            'friguia room', 'ksour room', 'medeina room', 'thyna room'
        ]
        emailrooms = [
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**"
        ]
        #freerooms
        freemails = []
        freerooms = []
        for i in range(0, len(emailrooms)):
            body = {
                "timeMin": datestart,
                "timeMax": datend,
                "timeZone": 'America/Los_Angeles',
                "items": [{
                    "id": emailrooms[i]
                }]
            }
            roomResult = service.freebusy().query(body=body).execute()
            room_dict = roomResult[u'calendars']
            for cal_room in room_dict:
                print(cal_room, ':', room_dict[cal_room])
                case = room_dict[cal_room]
                for j in case:
                    if (j == 'busy' and case[j] == []):
                        # la liste freerooms va prendre  les noms des salles free
                        freerooms.append(namerooms[i])
                        freemails.append(emailrooms[i])
        suggroom = freerooms[0]
        suggmail = freemails[0]
        # extraire l'email des invitees et de la salle
        indiceroom = None
        for j, e in enumerate(namerooms):
            if e == location:
                indiceroom = j
        if (indiceroom != None):
            #register the room mail
            idmailr = emailrooms[indiceroom]
            #freebusy
            # freebusy
            body = {
                "timeMin": datestart,
                "timeMax": datend,
                "timeZone": 'America/Los_Angeles',
                "items": [{
                    "id": idmailr
                }]
            }
            eventsResult = service.freebusy().query(body=body).execute()
            cal_dict = eventsResult[u'calendars']
            print(cal_dict)
            for cal_name in cal_dict:
                print(cal_name, ':', cal_dict[cal_name])
                statut = cal_dict[cal_name]
                for i in statut:
                    if (i == 'busy' and statut[i] == []):
                        self.speak_dialog("roomfree", data={"room": location})
                        # ajouter l'email de x ala liste des attendee
                        meetroom = location
                        attendee.append(idmailr)
                    elif (i == 'busy' and statut[i] != []):
                        self.speak_dialog("roombusy", data={"room": location})
                        self.speak_dialog("suggestionroom",
                                          data={"suggroom": suggroom})
                        x = self.get_response(
                            "Do you agree making a reservation for this meeting room"
                        )
                        if x == "yes":
                            meetroom = suggroom
                            attendee.append(suggmail)
                        else:
                            s = ",".join(freerooms)
                            # print("les salles disponibles a cette date sont", freerooms)
                            self.speak_dialog("freerooms", data={"s": s})
                            room = self.get_response(
                                'which Room do you want to make a reservation for??'
                            )
                            for i in range(0, len(freerooms)):
                                if (freerooms[i] == room):
                                    # ajouter l'email de room dans la liste des attendees
                                    meetroom = room
                                    attendee.append(freemails[i])

        else:
            self.speak_dialog("notRoom")
            meetroom = "Focus corporation"

        # liste de contacts
        nameliste = []
        adsmails = []
        for person in connections:
            emails = person.get('emailAddresses', [])
            adsmails.append(emails[0].get('value'))
            names = person.get('names', [])
            nameliste.append(names[0].get('displayName'))
        #recherche des mails des invités
        n = len(listp)
        for i in listp:
            indiceperson = None
            for j, e in enumerate(nameliste):
                if e == i:
                    att = i
                    indiceperson = j
            if (indiceperson != None):
                self.speak_dialog("exist", data={"att": att})
                idmailp = adsmails[indiceperson]
                print(idmailp)
                print(att)
                #freebusy
                body = {
                    "timeMin": datestart,
                    "timeMax": datend,
                    "timeZone": 'America/Los_Angeles',
                    "items": [{
                        "id": idmailp
                    }]
                }
                eventsResult = service.freebusy().query(body=body).execute()
                cal_dict = eventsResult[u'calendars']
                print(cal_dict)
                for cal_name in cal_dict:
                    print(cal_name, ':', cal_dict[cal_name])
                    statut = cal_dict[cal_name]
                    for i in statut:
                        if (i == 'busy' and statut[i] == []):
                            self.speak_dialog("attendeefree",
                                              data={"att": att})
                            # ajouter l'email de x ala liste des attendee
                            attendee.append(idmailp)
                        elif (i == 'busy' and statut[i] != []):
                            self.speak_dialog("attendeebusy",
                                              data={"att": att})
                            n -= 1
            else:
                self.speak_dialog("notExist", data={"att": att})

            # creation d'un evenement
        attendeess = []
        for i in range(len(attendee)):
            email = {'email': attendee[i]}
            attendeess.append(email)
        event = {
            'summary': 'meeting',
            'location': meetroom,
            'description': '',
            'start': {
                'dateTime': datestart,
                'timeZone': 'America/Los_Angeles',
            },
            'end': {
                'dateTime': datend,
                'timeZone': 'America/Los_Angeles',
            },
            'recurrence': ['RRULE:FREQ=DAILY;COUNT=1'],
            'attendees': attendeess,
            'reminders': {
                'useDefault':
                False,
                'overrides': [
                    {
                        'method': 'email',
                        'minutes': 24 * 60
                    },
                    {
                        'method': 'popup',
                        'minutes': 10
                    },
                ],
            },
        }
        if n == 0:
            self.speak_dialog("cancellEvent")
        elif n == len(listp):
            event = service.events().insert(calendarId='primary',
                                            sendNotifications=True,
                                            body=event).execute()
            print('Event created: %s' % (event.get('htmlLink')))
            self.speak_dialog("eventCreated")
        else:
            res = self.get_response(
                'Some of the attendees are busy would you like to continue creating the event yes or no?'
            )
            if res == 'yes':
                event = service.events().insert(calendarId='primary',
                                                sendNotifications=True,
                                                body=event).execute()
                print('Event created: %s' % (event.get('htmlLink')))
                self.speak_dialog("eventCreated")
            elif res == 'no':
                self.speak_dialog("eventCancelled")
Exemplo n.º 14
0
class WhiteNoise(MycroftSkill):
    def __init__(self):
        MycroftSkill.__init__(self)
        self.endtime = None
        self.process = None
        self.stopped = False
        self.audio_length = 0

    def initialize(self):
        #Build play list
        self.play_list = {
            'ocean': join(abspath(dirname(__file__)), 'sounds', 'ocean.wav'),
            'wind': join(abspath(dirname(__file__)), 'sounds', 'wind.wav'),
            'rain': join(abspath(dirname(__file__)), 'sounds', 'rain.wav'),
        }

    #Play random noise or a specific noise from list
    @intent_file_handler('noise.white.intent')
    def handle_single_whitenoise(self, message):
        print("inside handler")
        wait_while_speaking()
        self.stopped = False
        now = datetime.now()
        print(message.data.get('sound'))
        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]
                #Loop Infinitely
                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:
                self.speak('Sorry I could not find that sound in my library')
                return None
        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)
            #Loop Infinitely
            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)

    #Handles Loop Call
    @intent_file_handler('whitenoiseloop.intent')
    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 update_time(self, message):
        print("inside update_time")
        # Check if there is an expired timer
        now = datetime.now()
        # Calc remaining time and show using faceplate
        if (self.timer["expires"] > now):
            if self.stopped == False:
                # Timer still running
                remaining = (self.timer["expires"] - now).seconds
                print(remaining)
                self.cancel_scheduled_event('ShowTimer')
                self.schedule_repeating_event(self.update_time,
                                              None,
                                              1,
                                              name='ShowTimer')
        else:
            # Timer has expired but not been cleared, flash eyes
            overtime = (now - self.timer["expires"]).seconds
            print(overtime)
            if (self.stopped == False):
                self.speak("Playtime is over!")
            self.cancel_scheduled_event('ShowTimer')
            self.stop()

    def check_replay(self, message):
        print("inside check_replay")
        # Check if there is an expired timer
        now = datetime.now()
        if self.stopped == False:
            # Calc remaining time and show using faceplate
            if (self.songTimer["expires"] > now):
                if self.stopped == False:
                    # Timer still running
                    remaining = (self.songTimer["expires"] - now).seconds
                    print(remaining)
                    self.cancel_scheduled_event('Replay')
                    self.schedule_repeating_event(self.check_replay,
                                                  None,
                                                  1,
                                                  name='Replay')
            else:
                # Timer has expired but not been cleared, flash eyes
                overtime = (now - self.songTimer["expires"]).seconds
                print(overtime)
                self.cancel_scheduled_event('Replay')
                sound_file = self.songTimer["file"]
                self.process = play_wav(sound_file)
                self.songTimer = {
                    "file": sound_file,
                    "expires": now + timedelta(seconds=self.audio_length)
                }
                self.schedule_repeating_event(self.check_replay,
                                              None,
                                              1,
                                              name='Replay')
        else:
            self.cancel_scheduled_event('Replay')
            self.stop()

    def stop_playing(self):
        if self.process is not None:
            self.process.terminate()
            return True
        return False

    @intent_handler(IntentBuilder("").require("Stop"))
    def stop(self):
        # abort current laugh
        self.stopped = self.stop_playing()
        return self.stopped
Exemplo n.º 15
0
 def initialize(self):
     self.load_data_files(dirname(__file__))
     intent = IntentBuilder("TimeIntent").require("TimeKeyword") \
         .optionally("Location").build()
     self.register_intent(intent, self.handle_intent)
Exemplo n.º 16
0
class LaughSkill(MycroftSkill):
    def __init__(self):
        MycroftSkill.__init__(self)
        self.random_laugh = False
        self.sounds = {"male": [], "female": []}
        if "gender" not in self.settings:
            self.settings["gender"] = "male"
        if "sounds_dir" not in self.settings:
            self.settings["sounds_dir"] = join(dirname(__file__), "sounds")
        self.p = None
        self.settings.set_changed_callback(self._fix_gender)

    def _fix_gender(self):
        if "f" in self.settings["gender"].lower():
            self.settings["gender"] = "female"
        else:
            self.settings["gender"] = "male"

    def initialize(self):
        sounds_dir = join(self.settings["sounds_dir"], "male")
        self.sounds["male"] = [
            join(sounds_dir, sound) for sound in listdir(sounds_dir)
            if ".wav" in sound or ".mp3" in sound
        ]
        sounds_dir = join(self.settings["sounds_dir"], "female")
        self.sounds["female"] = [
            join(sounds_dir, sound) for sound in listdir(sounds_dir)
            if ".wav" in sound or ".mp3" in sound
        ]

        # stop laughs for speech execution
        self.add_event("speak", self.stop_laugh)

    def laugh(self):
        # dont laugh over a speech message
        if is_speaking():
            wait_while_speaking()

        sound = random.choice(self.sounds[self.settings["gender"]])
        if ".mp3" in sound:
            self.p = play_mp3(sound)
        else:
            self.p = play_wav(sound)

    @intent_file_handler("Laugh.intent")
    def handle_laugh_intent(self, message):
        self.laugh()

    @intent_file_handler("RandomLaugh.intent")
    def handle_random_intent(self, message):
        # initiate random laughing
        self.log.info("Laughing skill: Triggering random laughing")
        self.random_laugh = True
        self.handle_laugh_event(message)

    @intent_handler(
        IntentBuilder('StopLaughing').require('Stop').require('Laugh'))
    def halt_laughing(self, message):
        self.log.info("Laughing skill: Stopping")
        # if in random laugh mode, cancel the scheduled event
        if self.random_laugh:
            self.log.info("Laughing skill: Stopping random laugh event")
            self.random_laugh = False
            self.cancel_scheduled_event('random_laugh')
            self.speak_dialog("cancel")
        else:
            self.speak_dialog("cancel_fail")

    def handle_laugh_event(self, message):
        # create a scheduled event to laugh at a random interval between 1
        # minute and half an hour
        if not self.random_laugh:
            return
        self.log.info("Laughing skill: Handling laugh event")
        self.laugh()
        self.cancel_scheduled_event('random_laugh')
        self.schedule_event(self.handle_laugh_event,
                            datetime.now() +
                            timedelta(seconds=random.randrange(60, 1800)),
                            name='random_laugh')

    def stop_laugh(self):
        if self.p is not None:
            self.p.terminate()
            return True
        return False

    def stop(self):
        # abort current laugh
        stopped = self.stop_laugh()
        # stop random laughs
        if self.random_laugh:
            self.halt_laughing(None)
            stopped = True
        return stopped
Exemplo n.º 17
0
class WhatCanYouDoSkill(MycroftSkill):
    def __init__(self):
        super(WhatCanYouDoSkill, self).__init__(name="WhatCanYouDoSkill")

    @intent_handler(
        IntentBuilder("").require("What").require("Can").require("Do"))
    def handle_what_can_do__intent(self, message):
        self.speak_dialog("what.i.can")  # tell user what he can do
        self.getSkills(
        )  # execute function getSkills -> get list of installed skills

    def getSkills(self):
        self.myskills = os.popen('msm list | grep installed').read(
        )  # get list of skills via msm and search for "installed"
        self.myskills = self.myskills.replace('\n', ', ').replace(
            '\r', ', ').replace('[installed],', ',').replace(
                '\t', '')  # replace unwanted characters and make nice list
        nr_skills = len(self.myskills.split())  # get number of skills
        if nr_skills < 1:  # if msm did not give us what we want (no matter why) do alternative skill search
            self.myskills = os.popen('ls /opt/mycroft/skills/').read(
            )  # Get folders in /opt/mycroft/skills
            self.myskills = self.myskills.replace('\n', ', ').replace(
                '\r', ', ').replace(
                    '\t', '')  # replace unwanted characters and make nice list
            nr_skills = len(self.myskills.split())  # get number of skills
        if nr_skills < 1:  # if msm and alternative skill search fails than tell user that we couldn't do the job
            wait_while_speaking()  # always wait
            self.speak_dialog(
                "not.found")  # tell user that we couldn't do the job
            return  # if all fails, return
        wait_while_speaking()  # always wait
        self.speak_dialog('found',
                          {'nrskills': nr_skills
                           })  # we found skills -> yeah. tell user how many!
        wait_while_speaking()  # always wait
        self.should_getskills = self.get_response(
            'ask.getskills'
        )  # ask user if we should give him a list of all his skills.
        self.yes_words = set(
            self.translate_list('yes'))  # get list of confirmation words
        self.listSkills(
        )  # execute function listSkills -> if user confirmed -> give him a list of all his skills, else -> exit

    def listSkills(self):
        if self.should_getskills:  # if user said something
            resp_getskills = self.should_getskills.split(
            )  # split user sentence into list
            if any(word in resp_getskills for word in self.yes_words
                   ):  # if any of the words from the user sentences is yes
                self.speak_dialog(
                    'my.skills'
                )  # Introduction that we will give user list of skills
                self.speak(self.myskills.strip())  # tell user list of skills
            else:  # no word in sentence from user was yes
                self.speak_dialog('no.skills')  # give user feedback

    def shutdown(self):
        super(WhatCanYouDoSkill, self).shutdown()

    def stop(self):
        pass
Exemplo n.º 18
0
class PVOutputSkill(MycroftSkill):
    def __init__(self):
        super().__init__(name="PVOutput")
        # import httplib2
        # httplib2.debuglevel = 1

    @property
    def use_24hour(self):
        return self.config_core.get('time_format') == 'full'

    @property
    def timezone(self):
        timezone = self.location_timezone
        if not timezone:
            return None
        return pytz.timezone(timezone)

    def time_to_str(self, time):
        if self.use_24hour:
            return time.strftime("%H:%M")
        return time.strftime("%I:%M %p")

    def get_pvoutput(self) -> Optional[PVOutput]:
        api_key = self.settings.get("api_key")
        system_id = self.settings.get("system_id")
        if api_key and system_id:
            LOG.info("Set up pv output for system id: {}".format(system_id))
            return PVOutput(api_key=api_key, system_id=system_id)
        self.speak_dialog("pvoutput.not.setup")
        LOG.info("No pvoutput setup id: {}".format(system_id))
        return None

    def format_date(self, date: datetime.date):
        return nice_date(datetime.datetime(date.year, date.month, date.day),
                         now=datetime.datetime.now(tz=self.timezone))

    def nice_format_period(self, date1, date2):
        if date1 == date2:
            return self.format_date(date1)
        return self.format_period(date1, date2)

    def format_period(self, date1, date2):
        return self.translate("between.dates",
                              data={
                                  "date1": self.format_date(date1),
                                  "date2": self.format_date(date2)
                              })

    def get_date(self, message):
        utterance = message.data.get("utterance", "")
        now = datetime.datetime.now(tz=self.timezone)
        today = now.date()
        result = extract_datetime(utterance, anchorDate=now)
        if result is None:
            return today
        date = result[0].date()
        if (date - today).days > 3:  # date is in the future
            result = extract_datetime(
                utterance, anchorDate=(now - datetime.timedelta(days=365)))
            date = result[0].date()
        return date

    def get_this_week_start_date(self):
        today = datetime.datetime.now(tz=self.timezone).date()
        weekday = (
            today.weekday() + 1
        ) % 7  # TODO only add 1 if that's normal for someone's language/region
        return today - datetime.timedelta(days=weekday)

    def get_period(self, message: Message):
        utterance = message.data.get("utterance", "")
        today = datetime.datetime.now(tz=self.timezone).date()
        start = None
        end = None
        if self.voc_match(utterance, "LastMonth"):
            if today.month == 1:
                start = datetime.date(today.year - 1, 12, 1)
            else:
                start = datetime.date(today.year, today.month - 1, 1)
            end = datetime.date(
                start.year, start.month,
                calendar.monthrange(start.year, start.month)[1])
        elif self.voc_match(utterance, "ThisMonth"):
            start = datetime.date(today.year, today.month, 1)
            end = today
        elif self.voc_match(utterance, "LastYear"):
            start = datetime.date(today.year - 1, 1, 1)
            end = datetime.date(today.year - 1, 12, 31)
        elif self.voc_match(utterance, "ThisYear"):
            start = datetime.date(today.year, 1, 1)
            end = today
        elif self.voc_match(utterance, "LastWeek"):
            start = self.get_this_week_start_date() - datetime.timedelta(
                days=7)
            end = start + datetime.timedelta(days=6)
        elif self.voc_match(utterance, "ThisWeek"):
            start = self.get_this_week_start_date()
            end = start + datetime.timedelta(days=6)

        if not start:
            return None
        return start, end

    def handle_errors(self, function, date_string):
        date_string = date_string or self.format_date(
            datetime.datetime.now(tz=self.timezone).date())
        try:
            function()
        except (NoStatusPVOutputException, NoOutputsPVOutputException) as e:
            LOG.info(e)
            self.speak_dialog("no.status.for.date", {"date": date_string})
        except InvalidApiKeyPVOutputException as e:
            LOG.info(e)
            self.speak_dialog("invalid.api.key")

    def process_message_for_statistic(self,
                                      message,
                                      process_statistic,
                                      consumption_and_import=False):
        pvo = self.get_pvoutput()
        if not pvo:
            return
        period = self.get_period(message)
        if not period:
            date = self.get_date(message)
            period = (date, date)

        def period_function():
            statistic = pvo.get_statistic(
                date_from=period[0],
                date_to=period[1],
                consumption_and_import=consumption_and_import)
            date_string = self.nice_format_period(statistic.actual_date_from,
                                                  statistic.actual_date_to)
            process_statistic(statistic, date_string)

        self.handle_errors(period_function,
                           self.nice_format_period(period[0], period[1]))

    @intent_handler(
        IntentBuilder("Energy Generated").require("Energy").require(
            "Generated").optionally("Solar").optionally("PVOutput"))
    def energy_generated(self, message):
        def process_statistic(statistic, date_string):
            generated_watt_hours = statistic.energy_generated
            self.speak_dialog("energy.generated",
                              data={
                                  "amount": generated_watt_hours / 1000.0,
                                  "date": date_string
                              })

        self.process_message_for_statistic(message, process_statistic)

    @intent_handler(
        IntentBuilder("Energy Used").require("Energy").require(
            "Used").optionally("Solar").optionally("PVOutput"))
    def energy_used(self, message):
        def process_statistic(statistic, date_string):
            consumed_watt_hours = statistic.energy_consumed
            self.speak_dialog("energy.used",
                              data={
                                  "amount": consumed_watt_hours / 1000.0,
                                  "date": date_string
                              })

        self.process_message_for_statistic(message,
                                           process_statistic,
                                           consumption_and_import=True)

    @intent_handler(
        IntentBuilder("Power Generating Now").require("Power").require(
            "Generating").optionally("Now").optionally("Solar").optionally(
                "PVOutput"))
    def power_generating_now(self, message):
        pvo = self.get_pvoutput()
        if not pvo:
            return

        def function():
            generating_watts = pvo.get_status().power_generation
            self.speak_dialog("power.generating.now",
                              data={"amount": generating_watts / 1000.0})

        self.handle_errors(function, None)

    @intent_handler(
        IntentBuilder("Power Using Now").require("Power").require("Using").
        optionally("Now").optionally("Solar").optionally("PVOutput"))
    def power_using_now(self, message):
        pvo = self.get_pvoutput()
        if not pvo:
            return

        def function():
            using_watts = pvo.get_status().power_consumption
            self.speak_dialog("power.using.now",
                              data={"amount": using_watts / 1000.0})

        self.handle_errors(function, None)

    @intent_handler(
        IntentBuilder("Peak Power").require("PeakPower").optionally(
            "Solar").optionally("PVOutput"))
    def peak_power(self, message):
        pvo = self.get_pvoutput()
        if not pvo:
            return
        date = self.get_date(message)

        def function():
            status: DayStatistics = pvo.get_status(date=date,
                                                   day_statistics=True)
            peak_power = status.standard.peak_power
            time: datetime.time = status.standard.peak_power_time
            self.speak_dialog("peak.power",
                              data={
                                  "amount": peak_power / 1000.0,
                                  "time": self.time_to_str(time),
                                  "date": self.format_date(date)
                              })

        self.handle_errors(function, self.format_date(date))
Exemplo n.º 19
0
class PairingSkill(MycroftSkill):

    poll_frequency = 10  # secs between checking server for activation

    def __init__(self):
        super(PairingSkill, self).__init__("PairingSkill")
        self.api = DeviceApi()
        self.data = None
        self.time_code_expires = None
        self.state = str(uuid4())
        self.activator = None
        self.activator_lock = Lock()
        self.activator_cancelled = False

        self.counter_lock = Lock()
        self.count = -1  # for repeating pairing code. -1 = not running

        self.nato_dict = None

        self.mycroft_ready = False
        self.pair_dialog_lock = Lock()
        self.paired_dialog = 'pairing.paired'
        self.pairing_performed = False

        self.num_failed_codes = 0

    def initialize(self):
        self.add_event("mycroft.not.paired", self.not_paired)
        self.nato_dict = self.translate_namedvalues('codes')

        # If the device isn't paired catch mycroft.ready to report
        # that the device is ready for use.
        # This assumes that the pairing skill is loaded as a priority skill
        # before the rest of the skills are loaded.
        if not is_paired():
            self.add_event("mycroft.ready", self.handle_mycroft_ready)

        platform = self.config_core['enclosure'].get('platform', 'unknown')
        if platform in PLATFORMS_WITH_BUTTON:
            self.paired_dialog = 'pairing.paired'
        else:
            self.paired_dialog = 'pairing.paired.no.button'

    def handle_mycroft_ready(self, message):
        """Catch info that skills are loaded and ready."""
        with self.pair_dialog_lock:
            if is_paired() and self.pairing_performed:
                self.speak_dialog(self.paired_dialog)
            else:
                self.mycroft_ready = True

    def not_paired(self, message):
        if not message.data.get('quiet', True):
            self.speak_dialog("pairing.not.paired")
        self.handle_pairing()

    @intent_handler(IntentBuilder("PairingIntent")
                    .require("PairingKeyword").require("DeviceKeyword"))
    def handle_pairing(self, message=None):
        if check_remote_pairing(ignore_errors=True):
            # Already paired! Just tell user
            self.speak_dialog("already.paired")
        elif not self.data:
            # Kick off pairing...
            with self.counter_lock:
                if self.count > -1:
                    # We snuck in to this handler somehow while the pairing
                    # process is still being setup.  Ignore it.
                    self.log.debug("Ignoring call to handle_pairing")
                    return
                # Not paired or already pairing, so start the process.
                self.count = 0
            self.reload_skill = False  # Prevent restart during the process

            self.log.debug("Kicking off pairing sequence")

            try:
                # Obtain a pairing code from the backend
                self.data = self.api.get_code(self.state)

                # Keep track of when the code was obtained.  The codes expire
                # after 20 hours.
                self.time_code_expires = time.monotonic() + 72000  # 20 hours
            except Exception:
                time.sleep(10)
                # Call restart pairing here
                # Bail out after Five minutes (5 * 6 attempts at 10 seconds
                # interval)
                if self.num_failed_codes < 5 * 6:
                    self.num_failed_codes += 1
                    self.abort_and_restart(quiet=True)
                else:
                    self.end_pairing('connection.error')
                    self.num_failed_codes = 0
                return

            self.num_failed_codes = 0  # Reset counter on success

            mycroft.audio.wait_while_speaking()

            self.gui.show_page("pairing_start.qml", override_idle=True)
            self.speak_dialog("pairing.intro")

            self.enclosure.deactivate_mouth_events()
            self.enclosure.mouth_text("home.mycroft.ai      ")
            # HACK this gives the Mark 1 time to scroll the address and
            # the user time to browse to the website.
            # TODO: mouth_text() really should take an optional parameter
            # to not scroll a second time.
            time.sleep(7)
            mycroft.audio.wait_while_speaking()

            if not self.activator:
                self.__create_activator()

    def check_for_activate(self):
        """Method is called every 10 seconds by Timer. Checks if user has
        activated the device yet on home.mycroft.ai and if not repeats
        the pairing code every 60 seconds.
        """
        try:
            # Attempt to activate.  If the user has completed pairing on the,
            # backend, this will succeed.  Otherwise it throws and HTTPError()

            token = self.data.get("token")
            login = self.api.activate(self.state, token)  # HTTPError() thrown

            # When we get here, the pairing code has been entered on the
            # backend and pairing can now be saved.
            # The following is kinda ugly, but it is really critical that we
            # get this saved successfully or we need to let the user know that
            # they have to perform pairing all over again at the website.
            try:
                IdentityManager.save(login)
            except Exception as e:
                self.log.debug("First save attempt failed: " + repr(e))
                time.sleep(2)
                try:
                    IdentityManager.save(login)
                except Exception as e2:
                    # Something must be seriously wrong
                    self.log.debug("Second save attempt failed: " + repr(e2))
                    self.abort_and_restart()

            if mycroft.audio.is_speaking():
                # Assume speaking is the pairing code.  Stop TTS of that.
                mycroft.audio.stop_speaking()

            self.enclosure.activate_mouth_events()  # clears the display

            # Notify the system it is paired
            self.gui.show_page("pairing_done.qml", override_idle=False)
            self.bus.emit(Message("mycroft.paired", login))

            self.pairing_performed = True
            with self.pair_dialog_lock:
                if self.mycroft_ready:
                    # Tell user they are now paired
                    self.speak_dialog(self.paired_dialog)
                    mycroft.audio.wait_while_speaking()
                else:
                    self.speak_dialog("wait.for.startup")
                    mycroft.audio.wait_while_speaking()

            # Un-mute.  Would have been muted during onboarding for a new
            # unit, and not dangerous to do if pairing was started
            # independently.
            self.bus.emit(Message("mycroft.mic.unmute", None))

            # Send signal to update configuration
            self.bus.emit(Message("configuration.updated"))

            # Allow this skill to auto-update again
            self.reload_skill = True
        except HTTPError:
            # speak pairing code every 60th second
            with self.counter_lock:
                if self.count == 0:
                    self.speak_code()
                self.count = (self.count + 1) % 6

            if time.monotonic() > self.time_code_expires:
                # After 20 hours the token times out.  Restart
                # the pairing process.
                with self.counter_lock:
                    self.count = -1
                self.data = None
                self.handle_pairing()
            else:
                # trigger another check in 10 seconds
                self.__create_activator()
        except Exception as e:
            self.log.debug("Unexpected error: " + repr(e))
            self.abort_and_restart()

    def end_pairing(self, error_dialog):
        """Resets the pairing and don't restart it.

        Arguments:
            error_dialog: Reason for the ending of the pairing process.
        """
        self.speak_dialog(error_dialog)
        self.bus.emit(Message("mycroft.mic.unmute", None))

        self.data = None
        self.count = -1

    def abort_and_restart(self, quiet=False):
        # restart pairing sequence
        self.log.debug("Aborting Pairing")
        self.enclosure.activate_mouth_events()
        if not quiet:
            self.speak_dialog("unexpected.error.restarting")

        # Reset state variables for a new pairing session
        with self.counter_lock:
            self.count = -1
        self.activator = None
        self.data = None  # Clear pairing code info
        self.log.info("Restarting pairing process")
        self.bus.emit(Message("mycroft.not.paired",
                              data={'quiet': quiet}))

    def __create_activator(self):
        # Create a timer that will poll the backend in 10 seconds to see
        # if the user has completed the device registration process
        with self.activator_lock:
            if not self.activator_cancelled:
                self.activator = Timer(PairingSkill.poll_frequency,
                                       self.check_for_activate)
                self.activator.daemon = True
                self.activator.start()

    def speak_code(self):
        """Speak pairing code."""
        code = self.data.get("code")
        self.log.info("Pairing code: " + code)
        data = {"code": '. '.join(map(self.nato_dict.get, code)) + '.'}

        # Make sure code stays on display
        self.enclosure.deactivate_mouth_events()
        self.enclosure.mouth_text(self.data.get("code"))
        self.gui['code'] = self.data.get("code")
        self.gui.show_page("pairing.qml", override_idle=True)
        self.speak_dialog("pairing.code", data)

    def shutdown(self):
        with self.activator_lock:
            self.activator_cancelled = True
            if self.activator:
                self.activator.cancel()
        if self.activator:
            self.activator.join()
Exemplo n.º 20
0
class DesktopControlSkill(MycroftSkill):
    def __init__(self):
        super(DesktopControlSkill, self).__init__(name="DesktopControlSkill")

    def initialize(self):

        self.sm_amount = 2
        self.med_amount = 6
        self.lg_amount = 12

        self.register_entity_file("smallscroll.entity")
        self.register_entity_file("medscroll.entity")
        self.register_entity_file("largescroll.entity")
        self.register_entity_file("down.entity")
        self.register_entity_file("up.entity")

        self.register_entity_file("x.entity")
        self.register_entity_file("y.entity")

        self.register_entity_file("key.entity")

        select_combination_intent = IntentBuilder("SelectCombinationIntent"). \
            require("SelectAllKeyword").optionally("CopyKeyword"). \
                                        optionally("CutKeyword"). \
                                        optionally("PasteKeyword").\
                                        optionally("DeleteKeyword").build()
        self.register_intent(select_combination_intent,
                             self.handle_select_combination_intent)

    @intent_file_handler("scroll.intent")
    def handle_scroll(self, message):
        if message.data.get("smallscroll"):
            if message.data.get("down"):
                scroll_down = self.sm_amount * -1
                pyautogui.scroll(scroll_down)
            if message.data.get("up"):
                scroll_up = self.sm_amount
                pyautogui.scroll(scroll_up)
        elif message.data.get("medscroll"):
            if message.data.get("down"):
                scroll_down = self.med_amount * -1
                pyautogui.scroll(scroll_down)
            if message.data.get("up"):
                scroll_up = self.med_amount
                pyautogui.scroll(scroll_up)
        elif message.data.get("largescroll"):
            if message.data.get("down"):
                scroll_down = self.lg_amount * -1
                pyautogui.scroll(scroll_down)
            if message.data.get("up"):
                scroll_up = self.lg_amount
                pyautogui.scroll(scroll_up)

    @intent_handler(
        IntentBuilder("TypeIntent").require("TypeKeyword").require("Text"))
    def handle_type_intent(self, message):
        self.speak_dialog("typing")
        text = message.data.get('Text')
        pyautogui.typewrite(text, interval=0.05)

    @intent_file_handler("absolutemousemove.intent")
    def handle_absolute_mouse_move_intent(self, message):
        x = message.data.get("x")
        y = message.data.get("y")
        pyautogui.moveTo(int(x), int(y))
        self.speak_dialog("absolutemousemove", {"x": x, "y": y})

    @intent_handler(
        IntentBuilder("ScreenResIntent").require("ScreenResKeyword"))
    def handle_screen_res_intent(self, message):
        screen = pyautogui.size()
        resx = screen[0]
        resy = screen[1]
        responsex = num2words(resx)
        responsey = num2words(resy)
        self.speak_dialog("screenresolution", {"x": responsex, "y": responsey})

    @intent_file_handler("presskey.intent")
    def handle_press_key_intent(self, message):
        key = message.data.get("key")
        self.speak_dialog("keypress", {"key": key})
        key = str(key)
        pyautogui.press(key)

    @intent_file_handler("holdkey.intent")
    def handle_hold_key_intent(self, message):
        key = message.data.get("key")
        self.speak_dialog("keyhold", {"key": key})
        pyautogui.keyDown(key)

    @intent_file_handler("releasekey.intent")
    def handle_release_key_intent(self, message):
        key = message.data.get('key')
        self.speak_dialog("keyrelease", {"key": key})
        pyautogui.keyUp(key)

    @intent_handler(IntentBuilder("CopyIntent").require("CopyKeyword"))
    def handle_copy_intent(self, message):
        pyautogui.hotkey("ctrl", "c")
        self.speak("Okay Copied!")

    @intent_handler(IntentBuilder("CutIntent").require("CutKeyword"))
    def handle_cut_intent(self, message):
        self.speak("Cutting to clipboard")
        pyautogui.hotkey("ctrl", "x")

    @intent_handler(IntentBuilder("PasteIntent").require("PasteKeyword"))
    def handle_paste_intent(self, message):
        self.speak("Pasting from clipboard")
        pyautogui.hotkey("ctrl", "v")

    def handle_select_combination_intent(self, message):
        self.speak("Selecting all")
        pyautogui.hotkey("ctrl", "a")
        time.sleep(1)
        if message.data.get("PasteKeyword"):
            self.handle_paste_intent(message)
        elif message.data.get("CopyKeyword"):
            self.handle_copy_intent(message)
        elif message.data.get("CutKeyword"):
            self.handle_cut_intent(message)
        elif message.data.get("DeleteKeyword"):
            self.speak("deleting")
            pyautogui.keyDown("delete")
            pyautogui.keyUp("delete")
        else:
            pass

    def stop(self):
        pass
Exemplo n.º 21
0
class LectureSkill(MycroftSkill):



    def __init__(self):
        super(LectureSkill, self).__init__(name="LectureSkill")



    @intent_handler(IntentBuilder("LectureIntent").require("LectureKeyword").require("SubjectKeyword"))



    def handle_lecture_intent(self, message):

        f = open("/opt/mycroft/skills/lecture-subjects-skill/dates.txt", "r")     #open textfile
        dateFound = False
        lectureNumber = 0
        line = f.readline()
        g = open("/opt/mycroft/skills/lecture-subjects-skill/settings.txt", "r")     #open textfile
        line2 = g.readline()
        if line2[0] == "0":
            self.speak_dialog("default")
            dateFound = True
        g.close()
        while(line and not dateFound):                 #while right date hasn't been found and there is lines in the textfile, the program will read new lines from textfile
            lectureNumber += 1         #for each line the lectureNumber will go up
            y = int(line[0:4])         #yyyy
            m = int(line[4:6])         #mm
            d = int(line[6:8])       #dd
            date = datetime.date(y, m, d)
            if datetime.date.today() == date:    #check if date is today, speak accordingly
                self.speak_dialog("lecture" + str(lectureNumber))
                dateFound = True
            line = f.readline()

        if not dateFound:       #"no lecture today" if no date is found
            self.speak_dialog("nolecture")



        f.close()                      #close textfile


    @intent_handler(IntentBuilder("SettingsIntent").require("LectureKeyword").require("SettingsKeyword").require("ChangeKeyword"))

    def handle_settings_intent(self, message):

            f = open("/opt/mycroft/skills/lecture-subjects-skill/settings.txt", "r")     #open textfile
            line = f.readline()
            f.close()
            f  = open("/opt/mycroft/skills/lecture-subjects-skill/settings.txt", "w")     #open textfile
            if line[0] == "1":
                    f.write("0")
                    self.speak_dialog("defset")
            else:
                    f.write("1")
                    self.speak_dialog("specset")

            f.close()                      #close textfile

    def stop(self):
        pass
Exemplo n.º 22
0
class WinkIoTSkill(MycroftSkill):
    debug_level = 3  # 0-10, 10 showing the most debugging info

    def __init__(self):
        super(WinkIoTSkill, self).__init__(name="WinkIoTSkill")
        self.settings["access_token"] = None
        self.settings["refresh_token"] = None
        self.settings["token_expiration"] = to_timestamp(
            datetime.datetime.utcnow())
        self.settings['email'] = ""
        self.settings['password'] = ""
        self._device_cache = None
        self._group_cache = None
        self._active_room = None

    def debug(self, message, level=1, char=None):
        # Debugging assistance.
        # Lower number are More important.  Only number less than the
        # debug_level get logged.  Indentation is the inverse of this,
        # with level 0 having 10 dashes as a prefix, 1 have 9, etc.
        if level > WinkIoTSkill.debug_level:
            return

        if not char:
            char = "-"
        self.log.debug(char * (10 - level) + " " + message)

    # TODO: Move in to MycroftSkill
    def translate_namedvalues(self, name, delim=None):
        """
        Load translation dict containing names and values.

        This loads a simple CSV from the 'dialog' folders.
        The name is the first list item, the value is the
        second.  Lines prefixed with # or // get ignored

        Args:
            name (str): name of the .value file, no extension needed
            delim (char): delimiter character used, default is ','

        Returns:
            dict: name and value dictionary, or [] if load fails
        """
        import csv
        from os.path import join

        delim = delim or ','
        result = {}
        if not name.endswith(".value"):
            name += ".value"

        try:
            with open(join(self.root_dir, 'dialog', self.lang, name)) as f:
                reader = csv.reader(f, delimiter=delim)
                for row in reader:
                    # skip comment lines
                    if not row or row[0].startswith("#"):
                        continue
                    if len(row) != 2:
                        continue

                    result[row[0]] = row[1]

            return result
        except:
            return {}

    def get_remainder(self, message):
        # Remove words "consumed" by the intent match, e.g. if they
        # say 'Turn on the family room light' and there are entity
        # matches for "turn on" and "light", then it will leave
        # behind "the family room", which we normalize to "family room"
        utt = message.data["utterance"]
        for token in message.data["__tags__"]:
            utt = utt.replace(token["key"], "")
        return normalize(utt)

    @property
    def room_name(self):
        # Assume the "name" of the device is the "room name"
        device = DeviceApi().get()
        return device["name"]

    def _winkapi_auth(self):
        now = datetime.datetime.utcnow()

        # Check if access token exists and hasn't expired
        if (self.settings["access_token"]
                and to_timestamp(now) < self.settings["token_expiration"]):
            # Already logged in
            return True

        if not self.settings['email'] or not self.settings['password']:
            self.speak_dialog("need.to.configure")
            raise Exception("need.to.configure")

        # Attempt to authorize with the users ID and password
        body = {
            "client_id": client_id,
            "client_secret": client_secret,
            "username": self.settings['email'],
            "password": self.settings['password'],
            "grant_type": "password"
        }

        # Post
        res = requests.post("https://api.wink.com/oauth2/token", body)
        if res.status_code == requests.codes.ok:
            # Save the token for ongoing use
            data = json.loads(res.text)
            self.settings["access_token"] = data["access_token"]
            self.settings["refresh_token"] = data["refresh_token"]

            exp_secs = data["expires_in"]  # seconds until expires
            expiration = now + datetime.timedelta(0, exp_secs)

            self.settings["token_expiration"] = to_timestamp(expiration)
            return True
        else:
            # Notify the user then exit completely (nothing else can
            # be done if not registered)
            self.speak_dialog("unable.to.login")
            raise Exception('unable.to.login')

    def _winkapi_get(self, path):
        if not self._winkapi_auth():
            self.log.error("Failed to login")
            return False

        headers = {'Authorization': 'Bearer ' + self.settings["access_token"]}
        res = requests.get("https://winkapi.quirky.com" + path,
                           headers=headers)
        if res.status_code == requests.codes.ok:
            # success
            self.debug("Read devices!", 9, char="*")
            return res.json()
        else:
            self.debug("Failed to read devices!", char="!")
            self.debug(res.status_code, 5)
            self.debug(res.text, 5)
            return None

    def _winkapi_put(self, path, body):
        if not self._winkapi_auth():
            self.log.error("Failed to login")
            return False

        headers = {
            'Authorization': 'Bearer ' + self.settings["access_token"],
            'Content-Type': 'application/json'
        }
        res = requests.put("https://winkapi.quirky.com" + path,
                           headers=headers,
                           data=json.dumps(body))

        if res.status_code == requests.codes.ok:
            # success
            self.debug("Successful PUT to device!", 2)
            return res.json()
        else:
            self.debug("Failed to PUT devices", char="!")
            self.debug("URL: " + "https://winkapi.quirky.com" + path, 5)
            self.debug(res.status_code, 5)
            self.debug(res.text, 5)
            return None

    @property
    def wink_devices(self):
        # Retrieve a list of devices associated with the account
        if not self._device_cache:
            self._device_cache = self._winkapi_get("/users/me/wink_devices")
        return self._device_cache

    @property
    def wink_groups(self):
        # Retrieve a list of groups of devices associated with the account
        if not self._group_cache:
            self._group_cache = self._winkapi_get("/users/me/groups")
        return self._group_cache

    def get_lights(self, search_name):
        if not search_name:
            return None
        name = normalize(search_name)
        self.debug("Searching for: " + name, 2, char="=")

        # First fuzzy search the groups
        best = None
        best_score = 0
        if self.wink_groups:
            for group in self.wink_groups["data"]:
                groupname = normalize(group["name"])
                score = fuzzy_match(groupname, name)
                self.debug(groupname + " : " + str(score), 5)
                if score > 0.6 and score > best_score:
                    best_score = score
                    best = group

        if not self.wink_devices:
            # can't even return group matches without device info
            return None

        best_group_score = best_score
        group_lights = []
        group_IDs = []
        if best:
            # Collect the light IDs from the group that was found
            for member in best["members"]:
                if member["object_type"] == "light_bulb":
                    group_IDs.append(member["object_id"])

        best = None
        for dev in self.wink_devices["data"]:
            if "light_bulb_id" in dev:  # check if light_bulb

                # Gather group lights (just in case the group wins)
                if dev["light_bulb_id"] in group_IDs:
                    group_lights.append(dev)

                # score the bulb name match
                lightname = normalize(dev["name"])
                score = fuzzy_match(lightname, name)
                self.debug(lightname + " : " + str(score), 5)
                if score > best_score:
                    best_score = score
                    best = dev

        if group_lights and best_group_score >= best_score:
            self.debug("Group wins", 3, char="*")
            return group_lights
        elif best and best_score > 0.6:
            return [best]

        return None

    def set_light(self, lights, state, brightness=1.0):
        self.debug("Setting lights: " + str(state) + "@" + str(brightness), 1,
                   "=")
        if not lights:
            return False

        for light in lights:
            self.debug(
                "Light: " + light["name"] + ":" + light["light_bulb_id"], 5)
            body = {
                "desired_state": {
                    "powered": state,
                    "brightness": brightness
                }
            }
            self._winkapi_put("/light_bulbs/" + light["light_bulb_id"], body)
        return True

    def find_lights(self, remainder, room):
        if room:
            remainder = None

        # First, see if the user specified a room ("turn on the light in
        # the kitchen") or just mentioned it in the request ("turn on the
        # kitchen light")
        lights = self.get_lights(room)
        if lights:
            self._active_room = room
        else:
            lights = self.get_lights(remainder)
            if lights:
                self._active_room = remainder

        # If no location specified, default to using the device name as
        # a room name...
        if not lights and not room:
            lights = self.get_lights(self.room_name)
            self._active_room = self.room_name

        return lights

    def scale_lights(self, message, scale_by):
        try:
            remainder = self.get_remainder(message)
            room = message.data.get("Room")

            self._device_cache = None  # force update of states
            lights = self.find_lights(remainder, room)
            if lights:
                brightness = lights[0]["last_reading"]["brightness"] * scale_by
                self.set_light(lights, True, brightness)
            else:
                self.speak_dialog("couldnt.find.light")
        except:
            pass

    @intent_handler(
        IntentBuilder("").require("Light").require("Brighten").optionally(
            "Room"))
    def handle_dim_light(self, message):
        self.scale_lights(message, 1.5)

    @intent_handler(
        IntentBuilder("").require("Light").require("Dim").optionally("Room"))
    def handle_dim_light(self, message):
        self.scale_lights(message, 0.5)

    @intent_handler(
        IntentBuilder("").require("Light").optionally("Switch").require(
            "OnOff").optionally("Room"))
    def handle_change_light(self, message):
        try:
            on_off = message.data.get("OnOff")
            switch = message.data.get("Switch", "")
            room = message.data.get("Room")
            remainder = self.get_remainder(message)

            lights = self.find_lights(remainder, room)
            if lights:
                # Allow user to say "half", "full", "dim", etc.
                brightness = 1.0
                intensities = self.translate_namedvalues("Intensities")
                for i in intensities:
                    if contains_word(message.data.get("utterance"), i):
                        self.debug("Match intensity: " + i)
                        brightness = intensities[i]

                self.set_light(lights, on_off != "off", brightness)
            else:
                self.speak_dialog("couldnt.find.light")
        except:
            pass

    # Disabling for now.  "What is your name" is triggering this intent
    # Might need Padatious to handle this?
    #
    # @intent_handler(IntentBuilder("").optionally("Light").
    #                 require("Query").optionally("Room"))
    def handle_query_light(self, message):
        try:
            remainder = self.get_remainder(message)

            self._device_cache = None  # force update of states
            lights = self.find_lights(remainder, message.data.get("Room"))
            if lights:
                # Just give the value of the first light
                if (not lights[0]["last_reading"]["powered"]
                        or lights[0]["last_reading"]["brightness"] < 0.001):
                    state = self.translate("off")
                elif lights[0]["last_reading"]["brightness"] < 0.75:
                    state = self.translate("dimmed")
                else:
                    state = self.translate("on")

                self.speak_dialog("light.level.is", data={"state": state})
            else:
                self.speak_dialog("couldnt.find.light")
        except:
            pass

    def converse(self, utterances, lang='en-us'):
        if self._active_room:
            self._device_cache = None  # force update of states
            lights = self.get_lights(self._active_room)
            if contains_word(utterances[0], self.translate_list("brighter")):
                self.debug("Conversational brighting")
                brightness = lights[0]["last_reading"]["brightness"] * 1.5
                return self.set_light(lights, True, brightness)
            elif contains_word(utterances[0], self.translate_list("dimmer")):
                self.debug("Conversational dimming")
                brightness = lights[0]["last_reading"]["brightness"] * 0.5
                return self.set_light(lights, True, brightness)
        return False
Exemplo n.º 23
0
class WolframAlphaSkill(FallbackSkill):
    PIDS = ['Value', 'NotableFacts:PeopleData', 'BasicInformation:PeopleData',
            'Definition', 'DecimalApproximation']

    def __init__(self):
        FallbackSkill.__init__(self, name="WolframAlphaSkill")
        self.__init_client()
        self.question_parser = EnglishQuestionParser()
        self.last_query = None
        self.last_answer = None

    def __init_client(self):
        # TODO: Storing skill-specific settings in mycroft.conf is deprecated.
        # Should be stored in the skill's local settings.json instead.
        appID = self.config.get('api_key')
        if not appID:
            # Attempt to get an AppID skill settings instead (normally this
            # doesn't exist, but privacy-conscious might want to do this)
            appID = self.settings.get('appID', None)

        if appID and not self.config.get('proxy'):
            # user has a private AppID
            self.client = wolframalpha.Client(appID)
        else:
            # use the default API for Wolfram queries
            self.client = WAApi()

    def initialize(self):
        self.register_fallback(self.handle_fallback, 10)

    def get_result(self, res):
        try:
            return next(res.results).text
        except:
            result = None
            try:
                for pid in self.PIDS:
                    result = self.__find_pod_id(res.pods, pid)
                    if result:
                        result = result[:5]
                        break
                if not result:
                    result = self.__find_num(res.pods, '200')
                return result
            except:
                return result

    def handle_fallback(self, message):
        utt = message.data.get('utterance')
        self.log.debug("WolframAlpha fallback attempt: " + utt)
        lang = message.data.get('lang')
        if not lang:
            lang = "en-us"

        # TODO: Localization.  Wolfram only allows queries in English,
        #       so perhaps autotranslation or other languages?  That
        #       would also involve auto-translation of the result,
        #       which is a lot of room for introducting translation
        #       issues.

        utterance = normalize(utt, lang, remove_articles=False)
        parsed_question = self.question_parser.parse(utterance)

        query = utterance
        if parsed_question:
            # Try to store pieces of utterance (None if not parsed_question)
            utt_word = parsed_question.get('QuestionWord')
            utt_verb = parsed_question.get('QuestionVerb')
            utt_query = parsed_question.get('Query')
            query = "%s %s %s" % (utt_word, utt_verb, utt_query)
            phrase = "know %s %s %s" % (utt_word, utt_query, utt_verb)
            self.log.debug("Querying WolframAlpha: " + query)
        else:
            # This utterance doesn't look like a question, don't waste
            # time with WolframAlpha.
            self.log.debug("Non-question, ignoring: " + utterance)
            return False

        try:
            self.enclosure.mouth_think()
            res = self.client.query(query)
            result = self.get_result(res)
        except HTTPError as e:
            if e.response.status_code == 401:
                self.emitter.emit(Message("mycroft.not.paired"))
            return True
        except Exception as e:
            self.log.exception(e)
            return False

        if result:
            response = self.process_wolfram_string(result)

            # remember for any later 'source' request
            self.last_query = query
            self.last_answer = response

            self.speak(response)
            return True
        else:
            return False

    @staticmethod
    def __find_pod_id(pods, pod_id):
        # Wolfram returns results in "pods".  This searches a result
        # structure for a specific pod ID.
        # See https://products.wolframalpha.com/api/documentation/
        for pod in pods:
            if pod_id in pod.id:
                return pod.text
        return None

    @staticmethod
    def __find_num(pods, pod_num):
        for pod in pods:
            if pod.node.attrib['position'] == pod_num:
                return pod.text
        return None

    def process_wolfram_string(self, text):
        # Remove extra whitespace
        text = re.sub(r" \s+", r" ", text)

        # Convert | symbols to commas
        text = re.sub(r" \| ", r", ", text)

        # Convert newlines to commas
        text = re.sub(r"\n", r", ", text)

        # Convert !s to factorial
        text = re.sub(r"!", r",factorial", text)

        with open(join(dirname(__file__), 'regex',
                       self.lang, 'list.rx'), 'r') as regex:
            list_regex = re.compile(regex.readline())

        match = list_regex.match(text)
        if match:
            text = match.group('Definition')

        return text

    @intent_handler(IntentBuilder("Info").require("Give").require("Source"))
    def handle_get_sources(self, message):
        if (self.last_query):
            # Send an email to the account this device is registered to
            data = {"query": self.last_query,
                    "answer": self.last_answer,
                    "url_query": self.last_query.replace(" ", "+")}

            self.send_email(self.__translate("email.subject", data),
                            self.__translate("email.body", data))
            self.speak_dialog("sent.email")

    def shutdown(self):
        self.remove_fallback(self.handle_fallback)
        super(WolframAlphaSkill, self).shutdown()

    def __translate(self, template, data=None):
        return self.dialog_renderer.render(template, data)
Exemplo n.º 24
0
weather_keyword = ['weather']
for wk in weather_keyword:
    engine.register_entity(wk, "WeatherKeyword")

weather_types = ['snow', 'rain', 'wind', 'sleet', 'sun']
for wt in weather_types:
    engine.register_entity(wt, "WeatherType")

locations = ['Seattle', 'San Fransisco', 'Tokyo']
for loc in locations:
    engine.register_entity(loc, 'Location')

weather_intent = IntentBuilder("WeatherIntent")\
        .require("WeatherKeyword")\
        .optionally("WeatherType")\
        .require('Location')\
        .build()

hide_keyword = ['hide']
for hk in hide_keyword:
    engine.register_entity(hk, "HideKeyword")

hide_intent = IntentBuilder("HideIntent").require("HideKeyword").build()

engine.register_intent_parser(weather_intent)
engine.register_intent_parser(hide_intent)

# Existing user
token = client.login_with_password(username="******",
                                   password=password)
Exemplo n.º 25
0
class MaintenanceReportingSkill(MycroftSkill):
    def __init__(self):
        MycroftSkill.__init__(self)

    def initialize(self):
        # Set the address of your Rasa's REST endpoint
        self.conversation_active = False
        self.convoID = 1
        self.RASA_API = "https://b230ed1edc6c.eu.ngrok.io/webhooks/rest/webhook"
        self.messages = []

    def query_rasa(self, prompt=None):
        if self.conversation_active == False:
            return
        if prompt is None and len(self.messages) > 0:
            prompt = self.messages[-1]
        # Speak message to user and save the response
        msg = self.get_response(prompt)
        # If user doesn't respond, quietly stop, allowing user to resume later
        if msg is None:
            return
        # Else reset messages
        self.messages = []
        # Send post requests to said endpoint using the below format.
        # "sender" is used to keep track of dialog streams for different users
        data = requests.post(self.RASA_API,
                             json={
                                 "message": msg,
                                 "sender": "user{}".format(self.convoID)
                             })
        # A JSON Array Object is returned: each element has a user field along
        # with a text, image, or other resource field signifying the output
        # print(json.dumps(data.json(), indent=2))
        for next_response in data.json():
            if "text" in next_response:
                self.messages.append(next_response["text"])
        # Output all but one of the Rasa dialogs
        if len(self.messages) > 1:
            for rasa_message in self.messages[:-1]:
                print(rasa_message)

        # Kills code when Rasa stop responding
        if len(self.messages) == 0:
            self.messages = ["no response from rasa"]
            return
        # Use the last dialog from Rasa to prompt for next input from the user
        prompt = self.messages[-1]
        # Allows a stream of user inputs by re-calling query_rasa recursively
        # It will only stop when either user or Rasa stops providing data
        return self.query_rasa(prompt)

    @intent_handler(IntentBuilder("StartChat").require("Chatwithrasa"))
    def handle_talk_to_rasa_intent(self, message):
        self.convoID += 1
        self.conversation_active = True
        prompt = "start"
        self.query_rasa(prompt)

    # Resume chat activator that would resume the conversation thread of a chat
    @intent_handler(IntentBuilder("ResumeChat").require("Resume"))
    def handle_resume_chat(self, message):
        self.conversation_active = True
        self.query_rasa()

    def stop(self):
        self.conversation_active = False
Exemplo n.º 26
0
class PptControllerSkill(MycroftSkill):
    def __init__(self):
        super(PptControllerSkill, self).__init__(name="PptControllerSkill")
        self.url = "http://135.222.162.94:8001"
        self.file_opened = False

    @intent_handler(IntentBuilder("PPTIntent").require('PptController'))
    def handle_ppt_controller(self, message):
        self.speak_dialog('ppt.controller')

    @intent_handler(
        IntentBuilder("OpenPPTIntent").require('OpenPPT').require("Filename"))
    def handle_ppt_open(self, message):
        filename = message.data.get("Filename")
        self.enclosure.mouth_text("Nova opening file " + filename)
        self.file_opened = True
        # Send a rest request
        param = {'filename': filename}
        self.enclosure.mouth_text("Sending request to " + self.url)
        response = requests.get(self.url, param)
        resp = {'filename': filename}
        if response.status_code == requests.codes.ok:
            self.speak_dialog('ppt.open', data=resp)
        else:
            self.speak_dialog('ppt.filenotfound')

    @intent_handler(IntentBuilder("NextSlideIntent").require('NextSlide'))
    def handle_next_slide(self, message):
        if self.file_opened:
            # Send a rest request
            nurl = self.url + "/nextpage"
            self.enclosure.mouth_text("Sending request to " + nurl)
            response = requests.get(nurl)
            if response.status_code == requests.codes.ok:
                self.speak_dialog('ppt.next')
            else:
                self.speak_dialog('ppt.filenotfound')
        else:
            self.speak_dialog('ppt.filenotopen')

    @intent_handler(IntentBuilder("PrevSlideIntent").require('PrevSlide'))
    def handle_prev_slide(self, message):
        # Send a rest request
        if self.file_opened:
            # Send a rest request
            purl = self.url + "/prevpage"
            self.enclosure.mouth_text("Sending request to " + purl)
            response = requests.get(purl)
            if response.status_code == requests.codes.ok:
                self.speak_dialog('ppt.prev')
            else:
                self.speak_dialog('ppt.filenotfound')
        else:
            self.speak_dialog('ppt.filenotopen')

    @intent_handler(IntentBuilder("ClosePPTIntent").require('ClosePPT'))
    def handle_ppt_close(self, message):
        # Send a rest request
        if self.file_opened:
            purl = self.url + "/close"
            self.enclosure.mouth_text("Sending request to " + purl)
            response = requests.get(purl)
            if response.status_code == requests.codes.ok:
                self.speak_dialog('ppt.close')
            else:
                self.speak_dialog('ppt.filenotfound')
        else:
            self.speak_dialog('ppt.filenotopen')
Exemplo n.º 27
0
 def initialize(self):
     intent = IntentBuilder("BBCRadioIntent").require(
         "BBCRadioKeyword").build()
     self.register_intent(intent, self.handle_intent)
class MagicMirrorVoiceControlSkill(MycroftSkill):
    def __init__(self):
        super(MagicMirrorVoiceControlSkill,
              self).__init__(name="MagicMirrorVoiceControlSkill")

# This skill requires MMM-Remote-Control be installed and working properly.
# MMM-Remote-Control requires the module identifier to know which module to
# perform ModuleActionKeywords on (HIDE|SHOW). This code parses the MODULE_DATA returned from
# the MMM-Remote-Control and compares it to the file "AvailableModules.json"
# It then creates another file called file "AvailableModulesWithIdentifier.json"
# To store the module identifier that matches the ModuleKeyword. Modules identifiers may change
# depending on their order in the MagicMirror config.js file. Everytime you install a new module
# the module identifiers may change. If you run into issues, restart MagicMirror and Mycroft,
# and this code should update the changed module identifiers.

# The if statements match what Mycroft hears to a module. For instance a user would say
# weather but if MMM-WunderGround is installed it would be considered "weather".
# These adjustments are made by changing the "mycroftname" in the file "AvailableModules.json"
# For example: search for "weather" in the file "AvailableModules.json" and change it's
# mycroftname to something other than weather like 'weather old'or 'current weather'.
# Then search for MMM-Wunderground and change it's mycroftname to 'weather'.
# The change must be to a module name that is also reflected in the ModuleKeywords.voc
# otherwise mycroft will not recognize the name.

# ///////////DO NOT CHANGE THE FILE "AvailableModulesWithIdentifier.json"//////////////////
# The "AvailableModulesWithIdentifier.json" file is recreated everytime the skill initiates.
# For your changes to persist all modifications should be made to the file "AvailableModules.json"

    def initialize(self):
        self.url = 'http://0.0.0.0:8080/remote'
        self.voiceurl = 'http://0.0.0.0:8080/kalliope'
        self.mycroft_utterance = ''
        self.moduleData = ''
        self.connectionStatus = ''
        self.kalliopeStatus = ''
        self.ipAddress = ''

        try:
            with open(join(self._dir, 'ip.json')) as f:
                ip = json.load(f)
            ipAddress = ip['ipAddress']
            self.ipAddress = ipAddress
            self.url = 'http://' + ipAddress + ':8080/remote'
            self.voiceurl = 'http://' + ipAddress + ':8080/kalliope'
            self.mycroft_utterance = ''
            payload = {'action': 'MODULE_DATA'}
            r = requests.get(url=self.url, params=payload)
            data = r.json()

            with open(join(self._dir, 'AvailableModules.json')) as f:
                AvailableData = json.load(f)

            for moduleData in AvailableData['moduleData']:
                for item in data['moduleData']:
                    if moduleData['name'] == item['name']:
                        moduleData['identifier'] = item['identifier']
            self.moduleData = AvailableData
            # Added code to see if kalliope module is installed. if not, there is no need to send events to kalliope module
            data = self.moduleData
            installed_modules = ''
            for moduleData in data['moduleData']:
                mycroftname = moduleData['mycroftname']
                identifier = moduleData['identifier']
                if mycroftname == 'kalliope':
                    if identifier != '':
                        self.kalliopeStatus = 'installed'
                    else:
                        self.kalliopeStatus = 'not installed'

            self.connectionStatus = 'connected'
            self.speak('I have successfully connected to the magic mirror.')

        except requests.exceptions.ConnectionError:
            if ipAddress == '0.0.0.0':
                self.connectionStatus = 'disconnected'
                self.speak(
                    'I was unable to connect to the magic mirror at the default ip address. To activate the magic-mirror-voice-control-skill I need to know the I P address of the magic mirror. What is the I P address of the magic mirror you would like to control with your voice?',
                    expect_response=True)

            else:
                self.connectionStatus = 'disconnected'
                self.speak_dialog('not.connected')

        except IOError:
            self.connectionStatus = 'disconnected'
            self.speak(
                'To activate the magic-mirror-voice-control-skill I need to know the I P address of the magic mirror. What is the I P address of the magic mirror you would like to control with your voice',
                expect_response=True)

        self.add_event('recognizer_loop:wakeword', self.handle_listen)
        self.add_event('recognizer_loop:utterance', self.handle_utterance)
        self.add_event('speak', self.handle_speak)
        self.add_event('recognizer_loop:audio_output_start',
                       self.handle_output)
        self.add_event('recognizer_loop:audio_output_end',
                       self.handle_output_end)

    def handle_listen(self, message):
        if self.connectionStatus == 'connected':
            if self.kalliopeStatus == 'installed':
                voice_payload = {
                    "notification": "KALLIOPE",
                    "payload": "Listening"
                }
                r = requests.post(url=self.voiceurl, data=voice_payload)

    def handle_utterance(self, message):
        if self.connectionStatus == 'connected':
            if self.kalliopeStatus == 'installed':
                utterance = message.data.get('utterances')
                voice_payload = {
                    "notification": "KALLIOPE",
                    "payload": utterance
                }
                r = requests.post(url=self.voiceurl, data=voice_payload)

    def handle_speak(self, message):
        if self.connectionStatus == 'connected':
            if self.kalliopeStatus == 'installed':
                self.mycroft_utterance = message.data.get('utterance')
                #voice_payload = {"notification":"KALLIOPE", "payload": self.mycroft_utterance}
                #r = requests.post(url=self.voiceurl, data=voice_payload)

    def handle_output(self, message):
        if self.connectionStatus == 'connected':
            if self.kalliopeStatus == 'installed':
                voice_payload = {
                    "notification": "KALLIOPE",
                    "payload": self.mycroft_utterance
                }
                r = requests.post(url=self.voiceurl, data=voice_payload)

    def handle_output_end(self, message):
        if self.connectionStatus == 'connected':
            if self.kalliopeStatus == 'installed':
                voice_payload = {
                    "notification": "REMOVE_MESSAGE",
                    "payload": "REMOVE_MESSAGE"
                }
                r = requests.post(url=self.voiceurl, data=voice_payload)

    def handle_not_connected(self):
        if self.ipAddress == '0.0.0.0':
            self.speak(
                'I was unable to connect to the magic mirror at the default ip address. To activate the magic-mirror-voice-control-skill I need to know the I P address of the magic mirror. What is the I P address of the magic mirror you would like to control with your voice?',
                expect_response=True)

        else:
            self.speak_dialog('not.connected')

# The following intent handler is used to set the ip address of the MagicMirror by saving it to a file ip.json
# The file is saved into the skill's directory which causes Mycroft to reload the skill. After the skill reloads
# the above initialize self code will find the ip.json file and load the MagicMirror ip address. If it is not the
# correct address, or if the MagicMirror is not accessible the initilize self code will prompt the user to check the ip address

    @intent_handler(
        IntentBuilder('SetMirrorIpAddress').require(
            'SetIpKeywords').optionally('IpAddress'))
    def handle_Set_Ip_command(self, message):
        keywords = message.data.get('SetIpKeywords')
        utterance = message.data['utterance']
        utterance = utterance.replace(keywords, '')
        utterance = utterance.replace(' ', '')
        self.speak('I am setting the I P address to {}'.format(utterance))
        try:
            ipaddress.ip_address(utterance)
            ip = {'ipAddress': utterance}
            with open(join(self._dir, 'ip.json'), 'w') as f:
                json.dump(ip, f)
        except:
            self.speak(
                'Im sorry that is not a valid ip address. please try again',
                expect_response=True)

# This code builds the SystemActionIntent which are commands that are not directed at a specific module

    @intent_handler(
        IntentBuilder('SystemActionIntent').require(
            'SystemActionKeywords').require('SystemKeywords'))
    def handle_System_command(self, message):
        if self.connectionStatus == 'connected':

            system_action = message.data.get('SystemActionKeywords')
            if system_action in ('hide', 'conceal'):
                system_action = 'HIDE'
            if system_action in ('show', 'display'):
                system_action = 'SHOW'

            System = message.data.get('SystemKeywords')

            # This part of the SystemActionIntent handles one word remote System actions like shutdown, reboot, restart, refresh and update
            # if commands do not make sense as far as 'raspberry pi', 'pi', 'mirror', 'screen',
            # errors will result in mycroft asking the user to rephrase

            if System in ('raspberry pi', 'pi', 'mirror', 'screen'):
                if system_action in ('shutdown', 'reboot', 'restart',
                                     'refresh', 'update', 'save'):
                    system_action = system_action.upper(
                    )  # MMM-Remote-Control wants actions in uppercase
                    payload = {'action': system_action}
                if system_action == 'turn off':
                    if System in ('raspberry pi', 'pi'):
                        system_action = 'SHUTDOWN'
                        payload = {'action': system_action}
                if System in ('raspberry pi', 'pi'):
                    if system_action in ('turn on', 'SHOW', 'HIDE', 'save'):
                        self.speak_dialog('incorrect_command',
                                          expect_response=True)

    # This part of the SystemActionIntent turns on/off the monitor

            if System in ('monitor', 'mirror', 'screen', 'modules'):
                if system_action in ('turn on', 'wake up', 'SHOW'):
                    system_action = 'MONITORON'
                    payload = {'action': system_action}
                if system_action in ('turn off', 'go to sleep', 'HIDE'):
                    system_action = 'MONITOROFF'
                    payload = {'action': system_action}

    # This part of the SystemActionIntent will show/hide neewsfeed article details.
    # It defaults to hide article details

            if System == 'article details':
                if system_action in ('SHOW', 'turn on', 'refresh'):
                    system_action = 'NOTIFICATION'
                    System = 'ARTICLE_MORE_DETAILS'
                else:
                    system_action = 'NOTIFICATION'
                    System = 'ARTICLE_LESS_DETAILS'
                payload = {'action': system_action, 'notification': System}
            r = requests.get(url=self.url, params=payload)
            status = r.json()
            response = status['status']
            if response == 'success':
                self.speak_dialog('success')
            else:
                reason = status['reason']
                reason = reason.replace('_', ' ')
                self.speak(
                    'There was an error processing your request. The error was caused by',
                    reason)
        else:
            self.handle_not_connected()

# This intent will have mycroft read the installed modules 'mycroftname' so that the user knows which mdules are installed

    @intent_handler(
        IntentBuilder('ListInstalledModulesIntent').require(
            'ListInstalledKeywords').require('SingleModuleKeywords'))
    def handle_list_installed_modules_command(self, message):
        if self.connectionStatus == 'connected':
            data = self.moduleData
            installed_modules = ''
            for moduleData in data['moduleData']:
                mycroftname = moduleData['mycroftname']
                identifier = moduleData['identifier']
                if identifier != "":
                    installed_modules = installed_modules + ', ' + mycroftname
            self.speak('The currently installed modules are{}'.format(
                installed_modules))
        else:
            self.handle_not_connected()

# This intent handles change page commands to be used with the MMM-pages module. The MMM-pages module must be installed
# for this intent to work. Find it on github @ https://github.com/edward-shen/MMM-pages

    @intent_handler(
        IntentBuilder('ChangePagesIntent').require(
            'PageActionKeywords').require('PageKeywords'))
    def handle_change_pages_command(self, message):
        if self.connectionStatus == 'connected':
            page = message.data.get('PageKeywords')
            if page in ('one', '1', 'home'):
                integer = 0
            if page in ('two', '2'):
                integer = 1
            if page in ('three', '3'):
                integer = 2
            if page in ('four', '4', 'for'):
                integer = 3
            if page in ('five', '5'):
                integer = 4
            if page in ('six', '6'):
                integer = 5
            if page in ('seven', '7'):
                integer = 6
            if page in ('eight', '8'):
                integer = 7
            if page in ('nine', '9'):
                integer = 8
            if page in ('ten', '10'):
                integer = 9
            notification = 'PAGE_CHANGED'
            action = 'NOTIFICATION'
            payload = {
                'action': action,
                'notification': notification,
                'payload': integer
            }
            r = requests.get(url=self.url, params=payload)
            status = r.json()
            response = status['status']
            if response == 'success':
                self.speak_dialog('success')
            else:
                reason = status['reason']
                reason = reason.replace('_', ' ')
                self.speak(
                    'There was an error processing your request. The error was caused by',
                    reason)
        else:
            self.handle_not_connected()

# This intent handles swipe commands to be used with the MMM-pages module. The MMM-pages module must be installed
# for the swipe intent to work. Find it on github @ https://github.com/edward-shen/MMM-pages

    @intent_handler(
        IntentBuilder('HandleSwipeIntent').require(
            'SwipeActionKeywords').require('LeftRightKeywords'))
    def handle_pages_command(self, message):
        if self.connectionStatus == 'connected':
            direction = message.data.get('LeftRightKeywords')
            if direction == 'right':
                System = 'PAGE_DECREMENT'
            if direction == 'left':
                System = 'PAGE_INCREMENT'
            action = 'NOTIFICATION'
            payload = {'action': action, 'notification': System}
            r = requests.get(url=self.url, params=payload)
            status = r.json()
            response = status['status']
            if response == 'success':
                self.speak_dialog('success')
            else:
                reason = status['reason']
                reason = reason.replace('_', ' ')
                self.speak(
                    'There was an error processing your request. The error was caused by',
                    reason)
        else:
            self.handle_not_connected()


# This intent handles a number of different user utterances for the brightness value, including
# numbers, numbers followed by %, numbers as words, numbers as words including the word percent.
# Not all references need to include (%|percent), this can be a value between 10 - 200

    @intent_handler(
        IntentBuilder('AdjustBrightnessIntent').require(
            'BrightnessActionKeywords').require('BrightnessValueKeywords'))
    def handle_adjust_brightness_command(self, message):
        if self.connectionStatus == 'connected':
            action = 'BRIGHTNESS'
            value = message.data.get('BrightnessValueKeywords')
            value_without_spaces = value.replace(' ', '')
            iswords = str.isalpha(value_without_spaces)
            if iswords == True:
                percent_present = re.search('percent', value)
                if percent_present != None:
                    value = value.replace(' percent', '')
                    with open(join(self._dir, 'numberwords.json')) as f:
                        data = json.load(f)
                        for item in data['numberwords']:
                            if value == item['word']:
                                value = item['number']
                                break
                    value = ((value / 100) * 200)
                else:
                    with open(join(self._dir, 'numberwords.json')) as f:
                        data = json.load(f)
                        for item in data['numberwords']:
                            if value == item['word']:
                                value = item['number']
                                break
            # This else handles numbers including numbers with the '%' sign
            else:
                percent_present = (re.search('%', value))
                if percent_present != None:
                    value = (re.sub('[%]', '', value))
                    value = int(value)
                    value = ((value / 100) * 200)
                    action = 'BRIGHTNESS'
                    if value < 10:
                        value = 10
                else:
                    value = int(value)
            payload = {'action': action, 'value': value}
            r = requests.get(url=self.url, params=payload)
            status = r.json()
            response = status['status']
            if response == 'success':
                self.speak_dialog('success')
            else:
                reason = status['reason']
                reason = reason.replace('_', ' ')
                self.speak(
                    'There was an error processing your request. The error was caused by',
                    reason)
        else:
            self.handle_not_connected()

    # This intent handles commands directed at specific modules. Commands include: hide
    #  show, display, conceal, install, add, turn on, turn off, update.
    # TODO The add module needs to be changed to 'add' the recently installed module's configuration
    # to the config.js of the MagicMirror. this is the intended functionallity. currently it is
    # set up to be another way to say install the module.

    @intent_handler(
        IntentBuilder('ModuleActionIntent').require(
            'ModuleActionKeywords').require('ModuleKeywords'))
    def handle_module_command(self, message):
        if self.connectionStatus == 'connected':
            module_action = message.data.get('ModuleActionKeywords')
            if module_action in ('hide', 'conceal', 'turn off'):
                module_action = 'HIDE'
            if module_action in ('show', 'display', 'turn on'):
                module_action = 'SHOW'

            module = message.data.get('ModuleKeywords')
            data = self.moduleData
            for item in data['moduleData']:
                if module == item['mycroftname']:
                    module_id = item['identifier']
                    module_url = item['URL']
                    module_name = item['name']

            if module_action in ('HIDE', 'SHOW'):
                module_action = module_action.upper()
                payload = {'action': module_action, 'module': module_id}
            if module_action in ('install', 'add'):
                module_action = 'INSTALL'
                payload = {'action': module_action, 'url': module_url}
            if module_action == 'update':
                module_action = module_action.upper()
                payload = {'action': module_action, 'module': module_name}

            r = requests.get(url=self.url, params=payload)
            status = r.json()
            response = status['status']
            if response == 'success':
                self.speak_dialog('success')
            else:
                reason = status['reason']
                reason = reason.replace('_', ' ')
                self.speak_dialog('No.Such.Module')
        else:
            self.handle_not_connected()

    def stop(self):
        pass
Exemplo n.º 29
0
 def __build_lighting_intent(self):
     intent = IntentBuilder("LightingIntent").require(
         "LightActionKeyword").require("Action").require("Entity").build()
     # TODO - Locks, Temperature, Identity location
     self.register_intent(intent, self.handle_lighting_intent)
Exemplo n.º 30
0
class SpotifySkill(MycroftSkill):
    """Spotify control through the Spotify Connect API."""
    def __init__(self):
        super(SpotifySkill, self).__init__()
        self.index = 0
        self.spotify = None
        self.process = None
        self.device_name = None
        self.dev_id = None
        self.idle_count = 0
        self.ducking = False
        self.mouth_text = None

        self.__device_list = None
        self.__devices_fetched = 0
        self.OAUTH_ID = 1
        self.DEFAULT_VOLUME = 65
        self._playlists = None

    def launch_librespot(self):
        """ Launch the librespot binary for the Mark-1.
        TODO: Discovery mode
        """
        platform = self.config_core.get("enclosure").get("platform", "unknown")
        path = self.settings.get('librespot_path', None)
        if platform == 'mycroft_mark_1' and not path:
            path = 'librespot'

        if (path and self.device_name and 'user' in self.settings
                and 'password' in self.settings):
            # TODO: Error message when provided username/password don't work
            self.process = Popen([
                path, '-n', self.device_name, '-u', self.settings['user'],
                '-p', self.settings['password']
            ])

            time.sleep(3)  # give libreSpot time to start-up

            # Lower the volume since max volume sounds terrible on the Mark-1
            dev = self.device_by_name(self.device_name)
            if dev:
                self.spotify.volume(dev['id'], self.DEFAULT_VOLUME)

    def initialize(self):
        # Setup handlers for playback control messages
        self.add_event('mycroft.audio.service.next', self.next_track)
        self.add_event('mycroft.audio.service.prev', self.prev_track)
        self.add_event('mycroft.audio.service.pause', self.pause)
        self.add_event('mycroft.audio.service.resume', self.resume)

        # Check and then monitor for credential changes
        self.settings.set_changed_callback(self.on_websettings_changed)
        self.on_websettings_changed()

    def on_websettings_changed(self):
        if not self.spotify:
            if 'user' in self.settings and 'password' in self.settings:
                try:
                    self.load_credentials()
                except:
                    # Retry in 5 minutes
                    self.schedule_repeating_event(self.on_websettings_changed,
                                                  None,
                                                  5 * 60,
                                                  name='SpotifyLogin')

    def load_credentials(self):
        """ Retrieve credentials from the backend and connect to Spotify """
        try:
            creds = MycroftSpotifyCredentials(self.OAUTH_ID)
            self.spotify = SpotifyConnect(client_credentials_manager=creds)
        except HTTPError:
            LOG.info('Couldn\'t fetch credentials')
            self.spotify = None

        if self.spotify:
            # Spotfy connection worked, prepare for usage
            # TODO: Repeat occasionally on failures?
            # If not able to authorize, the method will be repeated after 60
            # seconds
            self.create_intents()
            # Should be safe to set device_name here since home has already
            # been connected
            self.device_name = DeviceApi().get().get('name')
            self.cancel_scheduled_event('SpotifyLogin')
            self.launch_librespot()

    ######################################################################
    # Handle auto ducking when listener is started.

    def handle_listener_started(self, message):
        """ Handle auto ducking when listener is started. """
        if self.spotify.is_playing():
            self.__pause()
            self.ducking = True

            # Start idle check
            self.idle_count = 0
            self.cancel_scheduled_event('IdleCheck')
            self.schedule_repeating_event(self.check_for_idle,
                                          None,
                                          1,
                                          name='IdleCheck')

    def check_for_idle(self):
        """ Repeating event checking for end of auto ducking. """
        if not self.ducking:
            self.cancel_scheduled_event('IdleCheck')
            return

        active = DisplayManager.get_active()
        if not active == '' or active == "SpotifySkill":
            # No activity, start to fall asleep
            self.idle_count += 1

            if self.idle_count >= 5:
                # Resume playback after 5 seconds of being idle
                self.cancel_scheduled_event('IdleCheck')
                self.ducking = False
                self.resume()
        else:
            self.idle_count = 0

    ######################################################################
    # Mycroft display handling

    def start_monitor(self):
        """ Monitoring and current song display. """
        # Clear any existing event
        self.stop_monitor()

        # Schedule a new one every 5 seconds to monitor/update display
        self.schedule_repeating_event(self._update_display,
                                      None,
                                      5,
                                      name='MonitorSpotify')
        self.add_event('recognizer_loop:record_begin',
                       self.handle_listener_started)

    def stop_monitor(self):
        # Clear any existing event
        self.cancel_scheduled_event('MonitorSpotify')

    def _update_display(self, message):
        # Checks once a second for feedback
        status = self.spotify.status() if self.spotify else {}

        if not status or not status.get('is_playing'):
            self.stop_monitor()
            self.mouth_text = None
            self.enclosure.mouth_reset()
            return

        # Get the current track info
        try:
            text = status["item"]["artists"][0]["name"] + ": "
        except:
            text = ""
        try:
            text += status["item"]["name"]
        except:
            pass

        # Update the "Now Playing" display if needed
        if text != self.mouth_text:
            self.mouth_text = text
            self.enclosure.mouth_text(text)

    ######################################################################
    # Intent handling

    def create_intents(self):
        """ Create intents for start playback handlers."""
        # play playlists
        self.register_intent_file('Play.intent', self.play_playlist)
        self.register_intent_file('PlayOn.intent', self.play_playlist_on)

        # play album
        intent = IntentBuilder('').require('Play').require('AlbumTitle') \
                                  .optionally('Spotify')
        self.register_intent(intent, self.play_album)
        # play artist
        intent = IntentBuilder('').require('Play').require('Artist') \
                                  .optionally('Spotify')
        self.register_intent(intent, self.play_artist)

    @property
    def playlists(self):
        """ Playlists, cached for 5 minutes """
        now = time.time()
        if not self._playlists or (now - self.__playlists_fetched > 5 * 60):
            self._playlists = {}
            playlists = self.spotify.current_user_playlists().get('items', [])
            for p in playlists:
                self._playlists[p['name']] = p
            self.__playlists_fetched = now
        return self._playlists

    @property
    def devices(self):
        """ Devices, cached for 60 seconds """
        now = time.time()
        if not self.__device_list or (now - self.__devices_fetched > 60):
            self.__device_list = self.spotify.get_devices()
            self.__devices_fetched = now
        return self.__device_list

    def device_by_name(self, name):
        """ Get a Spotify devices from the API

        Args:
            name (str): The device name (fuzzy matches)
        Returns:
            (dict) None or the matching device's description
        """
        devices = self.devices
        if devices and len(devices) > 0:
            # Otherwise get a device with the selected name
            devices_by_name = {d['name']: d for d in devices}
            key, confidence = match_one(name, devices_by_name.keys())
            if confidence > 0.5:
                return devices_by_name[key]

        return None

    def get_default_device(self):
        """ Get preferred playback device """
        if self.spotify:
            # When there is an active Spotify device somewhere, use it
            if (self.devices and len(self.devices) > 0
                    and self.spotify.is_playing()):
                for dev in self.devices:
                    if dev['is_active']:
                        return dev  # Use this device

            # No playing device found, use the local Spotify instance
            dev = self.device_by_name(self.device_name)
            if not dev:
                dev = self.device_by_name(gethostname())
            if dev and not dev['is_active']:
                self.spotify.transfer_playback(dev["id"], False)
            return dev

        return None

    def get_best_playlist(self, playlist):
        """ Get best playlist matching the provided name

        Arguments:
            playlist (str): Playlist name

        Returns: (str) best match
        """
        key, confidence = match_one(playlist, self.playlists.keys())
        if confidence > 0.5:
            return key
        else:
            return None

    def play_playlist(self, message):
        """ Play user playlist on default device. """
        playlist = message.data.get('playlist')
        if not playlist or playlist == 'spotify':
            self.continue_current_playlist(message)
        elif self.playback_prerequisits_ok():
            dev = self.get_default_device()
            self.start_playback(dev, self.get_best_playlist(playlist))

    def playback_prerequisits_ok(self):
        """ Check that playback is possible, launch client if neccessary. """
        if self.spotify is None:
            self.speak_dialog('NotAuthorized')
            return False

        if not self.process:
            self.launch_librespot()
        return True

    @intent_handler(IntentBuilder('').require('Play').require('Spotify'))
    def play_spotify(self, message):
        # Play anything
        if self.playback_prerequisits_ok():
            message.data['utterance'] = 'play spotify'  # play anything!
            self.play_playlist(message)
        else:
            self.speak_dialog("NotAuthorized")

    def spotify_play(self, dev_id, uris=None, context_uri=None):
        """ Start spotify playback and catch any exceptions. """
        try:
            LOG.info(u'spotify_play: {}'.format(dev_id))
            self.spotify.play(dev_id, uris, context_uri)
            self.start_monitor()
            self.dev_id = dev_id
            # self.show_notes()
        except spotipy.SpotifyException as e:
            # TODO: Catch other conditions?
            self.speak_dialog('NotAuthorized')
        except Exception as e:
            LOG.exception(e)
            self.speak_dialog('NotAuthorized')

    def start_playback(self, dev, playlist_name):
        LOG.info(u'Playlist: {}'.format(playlist_name))

        playlist = None
        if playlist_name:
            playlist = self.get_best_playlist(playlist_name)
        if not playlist:
            LOG.info(u'Playlists: {}'.format(self.playlists))
            if not self.playlists:
                return  # different default action when no lists defined?
            playlist = self.get_best_playlist(self.playlists.keys()[0])

        if dev and playlist:
            LOG.info(u'playing {} using {}'.format(playlist, dev['name']))
            self.speak_dialog('listening_to', data={'tracks': playlist})
            time.sleep(2)
            pl = self.playlists[playlist]
            tracks = self.spotify.user_playlist_tracks(pl['owner']['id'],
                                                       pl['id'])
            uris = [t['track']['uri'] for t in tracks['items']]
            self.spotify_play(dev['id'], uris=uris)
            # self.show_notes()
        elif dev:
            LOG.info(u'couldn\'t find {}'.format(playlist))
        else:
            LOG.info('No spotify devices found')

    def play_playlist_on(self, message):
        """ Play playlist on specific device. """
        if self.playback_prerequisits_ok():
            playlist = self.get_best_playlist(message.data.get('playlist'))
            dev = self.device_by_name(message.data.get('device'))
            if dev:
                # Assume we are about to act on this device,
                # transfer playback to it.
                if not dev['is_active']:
                    self.spotify.transfer_playback(dev["id"], False)
                self.start_playback(dev, playlist)

    @intent_file_handler('PlaySpotify.intent')
    def continue_current_playlist(self, message):
        if self.playback_prerequisits_ok():
            dev = self.get_default_device()
            if dev:
                self.spotify_play(dev['id'])
            else:
                self.speak_dialog('NoDevicesAvailable')

    @intent_handler(
        IntentBuilder('').require('Search').require('AlbumTitle').require(
            'Spotify'))
    def search_album(self, message):
        if self.playback_prerequisits_ok():
            return self.search(message.data['AlbumTitle'], 'album')

    def play_album(self, message):
        if self.playback_prerequisits_ok():
            return self.search(message.data['AlbumTitle'], 'album')

    def play_artist(self, message):
        if self.playback_prerequisits_ok():
            return self.search(message.data['Artist'], 'artist')

    def search(self, query, search_type):
        """ Search for an album, playlist or artist.
        Arguments:
            query:       search query (album title, artist, etc.)
            search_type: weather to search for an 'album', 'artist' or
                         'playlist'

            TODO: improve results of albums by checking artist
        """
        dev = self.get_default_device()
        res = None
        if search_type == 'album' and len(query.split('by')) > 1:
            title, artist = query.split('by')
            result = self.spotify.search(title, type=search_type)
        else:
            result = self.spotify.search(query, type=search_type)

        if search_type == 'album':
            if len(result['albums']['items']) > 0 and dev:
                album = result['albums']['items'][0]
                LOG.info(album)
                res = album
        elif search_type == 'artist':
            LOG.info(result['artists'])
            artist = result['artists']['items'][0]
            LOG.info(artist)
            res = artist
        else:
            LOG.info('ERROR')
            return

        self.speak_dialog('listening_to', data={'tracks': res['name']})
        time.sleep(2)
        self.spotify_play(dev['id'], context_uri=res['uri'])

    def __pause(self):
        # if authorized and playback was started by the skill
        if self.spotify:
            LOG.info('Pausing Spotify...')
            self.spotify.pause(self.dev_id)

    def pause(self, message=None):
        """ Handler for playback control pause. """
        self.ducking = False
        self.__pause()

    def resume(self, message=None):
        """ Handler for playback control resume. """
        # if authorized and playback was started by the skill
        if self.spotify:
            LOG.info('Resume Spotify')
            if not self.dev_id:
                self.dev_id = self.get_default_device()
            self.spotify_play(self.dev_id)

    def next_track(self, message):
        """ Handler for playback control next. """
        # if authorized and playback was started by the skill
        if self.spotify and self.dev_id:
            LOG.info('Next Spotify track')
            self.spotify.next(self.dev_id)
            self.start_monitor()

    def prev_track(self, message):
        """ Handler for playback control prev. """
        # if authorized and playback was started by the skill
        if self.spotify and self.dev_id:
            LOG.info('Previous Spotify track')
            self.spotify.prev(self.dev_id)
            self.start_monitor()

    @intent_handler(IntentBuilder('').require('Spotify').require('Device'))
    def list_devices(self, message):
        """ List available devices. """
        LOG.info(self)
        if self.spotify:
            devices = [d['name'] for d in self.spotify.get_devices()]
            if len(devices) == 1:
                self.speak(devices[0])
            elif len(devices) > 1:
                self.speak_dialog(
                    'AvailableDevices', {
                        "devices":
                        '. '.join(devices[:-1]) + ". " +
                        self.translate("And") + ". " + devices[-1]
                    })
            else:
                self.speak_dialog('NoDevicesAvailable')
        else:
            self.speak_dialog('NotAuthorized')

    @intent_handler(
        IntentBuilder('').require('Transfer').require('Spotify').require(
            'ToDevice'))
    def transfer_playback(self, message):
        """ Move playback from one device to another. """
        if self.spotify and self.spotify.is_playing():
            dev = self.device_by_name(message.data['ToDevice'])
            if dev:
                self.spotify.transfer_playback(dev['id'])

    def show_notes(self):
        """ show notes, HA HA """
        self.schedule_repeating_event(self._update_notes,
                                      datetime.datetime.now(),
                                      2,
                                      name='dancing_notes')

    def display_notes(self):
        """ Start timer thread displaying notes on the display. """
        pass

    def clear_display(self):
        """ Clear display. """
        self.enclosure.mouth_display(img_code="HIAAAAAAAAAAAAAA",
                                     refresh=False)
        self.enclosure.mouth_display(img_code="HIAAAAAAAAAAAAAA",
                                     x=24,
                                     refresh=False)

    def draw_notes(self, index):
        """ Draw notes on display. """

        notes = [['IIAEAOOHGAGEGOOHAA', 'IIAAACAHPDDADCDHPD'],
                 ['IIAAACAHPDDADCDHPD', 'IIAEAOOHGAGEGOOHAA']]

        #  draw notes
        for pos in range(4):
            self.enclosure.mouth_display(img_code=notes[index][pos % 2],
                                         x=pos * 8,
                                         refresh=False)

    def _update_notes(self):
        """ Repeating event updating the display. """
        if self._should_display_notes():
            self.draw_notes(self.index)
            self.index = ((self.index + 1) % 2)

    def stop(self):
        """ Stop playback. """
        if not self.spotify or not self.spotify.is_playing():
            self.dev_id = None
            return False

        dev = self.get_default_device()
        self.dev_id = dev['id']
        if self.dev_id:
            # self.remove_event('dancing_notes')
            self.pause(None)

            # Clear playing device id
            self.dev_id = None
            return True

    def stop_librespot(self):
        """ Send Terminate signal to librespot if it's running. """
        if self.process and self.process.poll() is None:
            self.process.send_signal(signal.SIGTERM)
            self.process.communicate()  # Communicate to remove zombie

    def shutdown(self):
        """ Remove the monitor at shutdown. """
        # Do normal shutdown procedure
        super(SpotifySkill, self).shutdown()

        self.stop_monitor()
        self.stop_librespot()

    def _should_display_notes(self):
        _get_active = DisplayManager.get_active
        if _get_active() == '' or _get_active() == self.name:
            return True
        else:
            return False
Exemplo n.º 31
0
class MozillaIotGateway(MycroftSkill):
    def __init__(self):
        MycroftSkill.__init__(self)

        self.host = 'https://gateway.local'
        self.token = ''

    def get_headers(self):
        return {
            'Authorization': 'Bearer ' + self.token,
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        }

    def get_oauth_token(self):
        try:
            token = DeviceApi().get_oauth_token(1172752248686736379)
        except requests.HTTPError:
            return None
        return token['access_token']

    def get_oauth_host(self):
        try:
            token = DeviceApi().get_oauth_token(1172752248686736379)
        except requests.HTTPError:
            return None
        jwt = token['access_token']
        parts = jwt.split(".")
        if len(parts) < 2:
            return None
        payload_raw = parts[1]
        if len(payload_raw) % 3 > 0:
            payload_raw += "=" * (3 - (len(payload_raw) % 3))
        try:
            payload_medium_rare = base64.b64decode(payload_raw)
            payload = json.loads(payload_medium_rare)
            return payload['iss']
        except ValueError:
            return None

    @intent_handler(
        IntentBuilder('CommandIntent').require('Action').require('Type'))
    # .require('Thing'))
    def handle_command_intent(self, message):
        host = self.settings.get('host')
        if not host:
            host = self.get_oauth_host()
        if host:
            self.host = host
        token = self.settings.get('token')
        if not token:
            token = self.get_oauth_token()
        if token:
            self.token = token

        if not self.token:
            self.speak_dialog('needs.configure')
            return

        utt = message.data.get('utterance')
        response = requests.post(self.host + '/commands',
                                 json={'text': utt},
                                 headers=self.get_headers())
        data = response.json()

        if response.status_code != 201:
            self.speak(data['message'])
            return
        verb = ''
        preposition = ''

        keyword = data['payload']['keyword']
        if keyword == 'make':
            verb = 'making'
        elif keyword == 'change':
            verb = 'changing'
        elif keyword == 'set':
            verb = 'setting'
            preposition = 'to '
        elif keyword == 'dim':
            verb = 'dimming'
            preposition = 'by '
        elif keyword == 'brighten':
            verb = 'brightening'
            preposition = 'by '
        else:
            verb = keyword + 'ing'

        value = data['payload']['value']
        if value is None:
            value = ''

        thing = data['payload']['thing']
        message = 'Okay, ' + verb + ' the ' + thing + ' ' + preposition + value
        self.speak(message)
    def initialize(self):
        self.load_data_files(dirname(__file__))

        intent = IntentBuilder("BitcoinPriceIntent").require("BitcoinPriceKeyword").build()
        self.register_intent(intent, self.handle_intent)
Exemplo n.º 33
0
 def initialize(self):
     self.load_vocab_files(join(dirname(__file__), 'vocab', self.lang))
     self.load_regex_files(join(dirname(__file__), 'regex', self.lang))
     intent = IntentBuilder("SendSMSIntent").require(
         "SendSMSKeyword").require("Contact").require("Message").build()
     self.register_intent(intent, self.handle_intent)
Exemplo n.º 34
0
class SonosSkill(CommonPlaySkill):
    """Sonos control through the Sonos Connect API."""
    def __init__(self):
        super(SonosSkill, self).__init__()
        self.index = 0
        self.spotify = None
        self.process = None
        self.device_name = None
        self.dev_id = None
        self.idle_count = 0
        self.ducking = False
        self.mouth_text = None
        self.librespot_starting = False

        self.__device_list = None
        self.__devices_fetched = 0
        self.OAUTH_ID = 1
        self.DEFAULT_VOLUME = 80
        self._playlists = None

    def launch_librespot(self):
        """ Launch the librespot binary for the Mark-1.
        TODO: Discovery mode
        """
        self.librespot_starting = True
        platform = self.config_core.get('enclosure').get('platform', 'unknown')
        path = self.settings.get('librespot_path', None)
        if platform == 'mycroft_mark_1' and not path:
            path = 'librespot'

        if (path and self.device_name and 'user' in self.settings
                and 'password' in self.settings):

            # Disable librespot logging if not specifically requested
            outs = None if 'librespot_log' in self.settings else DEVNULL

            # TODO: Error message when provided username/password don't work
            self.process = Popen([
                path, '-n', self.device_name, '-u', self.settings['user'],
                '-p', self.settings['password']
            ],
                                 stdout=outs,
                                 stderr=outs)

            time.sleep(3)  # give libreSpot time to start-up
            if self.process and self.process.poll() is not None:
                # libreSpot shut down immediately.  Bad user/password?
                if self.settings['user']:
                    self.speak_dialog("FailedToStart")
                self.process = None
                self.librespot_starting = False
                return

            # Lower the volume since max volume sounds terrible on the Mark-1
            dev = self.device_by_name(self.device_name)
            if dev:
                self.spotify.volume(dev['id'], self.DEFAULT_VOLUME)
        self.librespot_starting = False

    def initialize(self):
        # Make sure the spotify login scheduled event is shutdown
        super().initialize()
        self.cancel_scheduled_event('SonosLogin')
        # Setup handlers for playback control messages
        self.add_event('mycroft.audio.service.next', self.next_track)
        self.add_event('mycroft.audio.service.prev', self.prev_track)
        self.add_event('mycroft.audio.service.pause', self.pause)
        self.add_event('mycroft.audio.service.resume', self.resume)
        # Check and then monitor for credential changes
        self.settings.set_changed_callback(self.on_websettings_changed)
        # Retry in 5 minutes
        self.schedule_repeating_event(self.on_websettings_changed,
                                      None,
                                      5 * 60,
                                      name='SonosLogin')
        self.on_websettings_changed()

    def on_websettings_changed(self):
        pass

    ######################################################################
    # Handle auto ducking when listener is started.

    def handle_listener_started(self, message):
        """ Handle auto ducking when listener is started.

        The ducking is enabled/disabled using the skill settings on home.

        TODO: Evaluate the Idle check logic
        """
        if self.spotify.is_playing() and \
                self.settings.get('use_ducking', False):
            self.__pause()
            self.ducking = True

            # Start idle check
            self.idle_count = 0
            self.cancel_scheduled_event('IdleCheck')
            self.schedule_repeating_event(self.check_for_idle,
                                          None,
                                          1,
                                          name='IdleCheck')

    def check_for_idle(self):
        """ Repeating event checking for end of auto ducking. """
        if not self.ducking:
            self.cancel_scheduled_event('IdleCheck')
            return

        active = self.enclosure.display_manager.get_active()
        if not active == '' or active == 'SonosSkill':
            # No activity, start to fall asleep
            self.idle_count += 1

            if self.idle_count >= 5:
                # Resume playback after 5 seconds of being idle
                self.cancel_scheduled_event('IdleCheck')
                self.ducking = False
                self.resume()
        else:
            self.idle_count = 0

    ######################################################################
    # Mycroft display handling

    def start_monitor(self):
        """ Monitoring and current song display. """
        # Clear any existing event
        self.stop_monitor()

        # Schedule a new one every 5 seconds to monitor/update display
        self.schedule_repeating_event(self._update_display,
                                      None,
                                      5,
                                      name='MonitorSonos')
        self.add_event('recognizer_loop:record_begin',
                       self.handle_listener_started)

    def stop_monitor(self):
        # Clear any existing event
        self.cancel_scheduled_event('MonitorSonos')

    def _update_display(self, message):
        # Checks once a second for feedback
        status = self.spotify.status() if self.spotify else {}

        if not status or not status.get('is_playing'):
            self.stop_monitor()
            self.mouth_text = None
            self.enclosure.mouth_reset()
            return

        # Get the current track info
        try:
            text = status['item']['artists'][0]['name'] + ': '
        except:
            text = ""
        try:
            text += status['item']['name']
        except:
            pass

        # Update the "Now Playing" display if needed
        if text != self.mouth_text:
            self.mouth_text = text
            self.enclosure.mouth_text(text)

    ######################################################################
    # Intent handling

    def CPS_match_query_phrase(self, phrase):
        # Not ready to play
        if not self.playback_prerequisits_ok():
            return None

        if 'spotify' in phrase:
            bonus = 0.1
        else:
            bonus = 0

        phrase = re.sub(self.translate('on_spotify_regex'), '', phrase)

        confidence, data = self.continue_playback(phrase, bonus)
        if not data:
            confidence, data = self.specific_query(phrase, bonus)
            if not data:
                confidence, data = self.generic_query(phrase, bonus)

        if data:
            if confidence > 0.9:
                confidence = CPSMatchLevel.EXACT
            elif confidence > 0.7:
                confidence = CPSMatchLevel.MULTI_KEY
            elif confidence > 0.5:
                confidence = CPSMatchLevel.TITLE
            else:
                confidence = CPSMatchLevel.CATEGORY
            return phrase, confidence, data

    def continue_playback(self, phrase, bonus):
        if phrase.strip() == 'spotify':
            return (1.0, {'data': None, 'name': None, 'type': 'continue'})
        else:
            return None, None

    def specific_query(self, phrase, bonus):
        # Check if playlist
        match = re.match(self.translate('playlist_regex'), phrase)
        if match:
            bonus += 0.1
            playlist, conf = self.get_best_playlist(
                match.groupdict()['playlist'])
            confidence = min(conf + bonus, 1.0)
            if not playlist:
                return
            uri = self.playlists[playlist]
            return (conf, {'data': uri, 'name': playlist, 'type': 'playlist'})
        # Check album
        match = re.match(self.translate('album_regex'), phrase)
        if match:
            bonus += 0.1
            album = match.groupdict()['album']
            return self.query_album(album, bonus)

        # Check artist
        match = re.match(self.translate('artist_regex'), phrase)
        if match:
            bonus += 0.1
            artist = match.groupdict()['artist']
            data = self.spotify.search(artist, type='artist')
            if data and data['artists']['items']:
                best = data['artists']['items'][0]['name']
                confidence = min(
                    fuzzy_match(best, artist.lower()) + bonus, 1.0)
                return (confidence, {
                    'data': data,
                    'name': None,
                    'type': 'artist'
                })
        match = re.match(self.translate('song_regex'), phrase)
        if match:
            data = self.spotify.search(match.groupdict()['track'],
                                       type='track')
            if data:
                return (1.0, {'data': data, 'name': None, 'type': 'track'})
        return None, None

    def generic_query(self, phrase, bonus):
        playlist, conf = self.get_best_playlist(phrase)
        if conf > 0.5:
            uri = self.playlists[playlist]
            return (conf, {'data': uri, 'name': playlist, 'type': 'playlist'})
        else:
            return self.query_album(phrase, bonus)

    def query_album(self, album, bonus):
        data = None
        by_word = ' {} '.format(self.translate('by'))
        if len(album.split(by_word)) > 1:
            album, artist = album.split(by_word)
            album = '*{}* artist:{}'.format(album, artist)
            bonus += 0.1
        data = self.spotify.search(album, type='album')
        if data and data['albums']['items']:
            best = data['albums']['items'][0]['name']
            confidence = min(fuzzy_match(best.lower(), album) + bonus, 1.0)
            return (confidence, {'data': data, 'name': None, 'type': 'album'})
        return None, None

    def CPS_start(self, phrase, data):
        # Wait for librespot to start
        if self.librespot_starting:
            self.log.info('Restarting Librespot...')
            for i in range(10):
                time.sleep(0.5)
                if not self.librespot_starting:
                    break
            else:
                self.log.error('LIBRESPOT NOT STARTED')

        dev = self.get_default_device()

        if data['type'] == 'continue':
            self.continue_current_playlist(None)
        elif data['type'] == 'playlist':
            self.start_playlist_playback(dev, data['name'], data['data'])
        else:  # artist, album track
            print('playing {}'.format(data['type']))
            try:
                self.play(data=data['data'], data_type=data['type'])
            except:
                self.log.exception()

    def create_intents(self):
        # Create intents
        intent = IntentBuilder('').require('Sonos').require('Search') \
                                  .require('For')
        self.register_intent(intent, self.search_spotify)
        self.register_intent_file('ShuffleOn.intent', self.shuffle_on)
        self.register_intent_file('ShuffleOff.intent', self.shuffle_off)

    @property
    def playlists(self):
        """ Playlists, cached for 5 minutes """
        if not self.spotify:
            return []  # No connection, no playlists
        now = time.time()
        if not self._playlists or (now - self.__playlists_fetched > 5 * 60):
            self._playlists = {}
            playlists = self.spotify.current_user_playlists().get('items', [])
            for p in playlists:
                self._playlists[p['name'].lower()] = p
            self.__playlists_fetched = now
        return self._playlists

    @property
    def devices(self):
        """ Devices, cached for 60 seconds """
        if not self.spotify:
            return []  # No connection, no devices
        now = time.time()
        if not self.__device_list or (now - self.__devices_fetched > 60):
            self.__device_list = self.spotify.get_devices()
            self.__devices_fetched = now
        return self.__device_list

    def device_by_name(self, name):
        """ Get a Sonos devices from the API

        Args:
            name (str): The device name (fuzzy matches)
        Returns:
            (dict) None or the matching device's description
        """
        devices = self.devices
        if devices and len(devices) > 0:
            # Otherwise get a device with the selected name
            devices_by_name = {d['name']: d for d in devices}
            key, confidence = match_one(name, list(devices_by_name.keys()))
            if confidence > 0.5:
                return devices_by_name[key]
        return None

    def get_default_device(self):
        """ Get preferred playback device """
        if self.spotify:
            # When there is an active Sonos device somewhere, use it
            if (self.devices and len(self.devices) > 0
                    and self.spotify.is_playing()):
                for dev in self.devices:
                    if dev['is_active']:
                        return dev  # Use this device

            # No playing device found, use the default Sonos device
            default_device = self.settings.get('default_device', '')
            dev = None
            if default_device:
                dev = self.device_by_name(default_device)
            # if not set or missing try playing on this device
            if not dev:
                dev = self.device_by_name(self.device_name)
            # if not check if a desktop spotify client is playing
            if not dev:
                dev = self.device_by_name(gethostname())
            # use first best device if none of the prioritized works
            if not dev and len(self.devices) > 0:
                dev = self.devices[0]
            if dev and not dev['is_active']:
                self.spotify.transfer_playback(dev['id'], False)
            return dev

        return None

    def get_best_playlist(self, playlist):
        """ Get best playlist matching the provided name

        Arguments:
            playlist (str): Playlist name

        Returns: (str) best match
        """
        key, confidence = match_one(playlist.lower(),
                                    list(self.playlists.keys()))
        if confidence > 0.7:
            return key, confidence
        else:
            return None, 0

    def continue_current_playlist(self, message):
        if self.playback_prerequisits_ok():
            dev = self.get_default_device()
            if dev:
                self.spotify_play(dev['id'])
            else:
                self.speak_dialog('NoDevicesAvailable')

    def playback_prerequisits_ok(self):
        """ Check that playback is possible, launch client if neccessary. """
        if self.spotify is None:
            return False

        devs = [d['name'] for d in self.devices]
        if self.process and self.device_name not in devs:
            self.log.info('Librespot not responding, restarting...')
            self.stop_librespot()
            self.__devices_fetched = 0  # Make sure devices are fetched again
        if not self.process:
            self.schedule_event(self.launch_librespot,
                                0,
                                name='launch_librespot')
        return True

    def spotify_play(self, dev_id, uris=None, context_uri=None):
        """ Start spotify playback and catch any exceptions. """
        try:
            LOG.info(u'spotify_play: {}'.format(dev_id))
            self.spotify.play(dev_id, uris, context_uri)
            self.start_monitor()
            self.dev_id = dev_id
        except spotipy.SonosException as e:
            # TODO: Catch other conditions?
            self.speak_dialog('NotAuthorized')
        except Exception as e:
            LOG.exception(e)
            self.speak_dialog('NotAuthorized')

    def start_playlist_playback(self, dev, name, uri):
        if dev and uri:
            LOG.info(u'playing {} using {}'.format(name, dev['name']))
            self.speak_dialog('ListeningToPlaylist', data={'playlist': name})
            time.sleep(2)
            tracks = self.spotify.user_playlist_tracks(uri['owner']['id'],
                                                       uri['id'])
            uris = [t['track']['uri'] for t in tracks['items']]
            self.spotify_play(dev['id'], uris=uris)
            return True
        elif not dev:
            LOG.info('No spotify devices found')
        else:
            LOG.info('No playlist found')
        return False

    def play(self, data, data_type='track', genre_name=None):
        """
        Plays the provided data in the manner appropriate for 'data_type'
        If the type is 'genre' then genre_name should be specified to populate
        the output dialog.

        A 'track' is played as just an individual track.
        An 'album' queues up all the tracks contained in that album and starts
        with the first track.
        A 'genre' expects data returned from self.spotify.search, and will use
        that genre to play a selection similar to it.

        Args:
            data (dict):        Data returned by self.spotify.search
            data_type (str):    The type of data contained in the passed-in
                                object. 'track', 'album', or 'genre' are
                                currently supported.
            genre_name (str):   If type is 'genre', also include the genre's
                                name here, for output purposes. default None
        """
        dev = self.get_default_device()
        if dev is None:
            LOG.error("Unable to get a default device while trying "
                      "to play something.")
            self.speak_dialog('NoDevicesAvailable')
        else:
            try:
                if data_type == 'track':
                    (song, artists, uri) = get_song_info(data)
                    self.speak_dialog('ListeningToSongBy',
                                      data={
                                          'tracks': song,
                                          'artist': artists[0]
                                      })
                    time.sleep(2)
                    self.spotify_play(dev['id'], uris=[uri])
                elif data_type == 'artist':
                    (artist, uri) = get_artist_info(data)
                    self.speak_dialog('ListeningToArtist',
                                      data={'artist': artist})
                    time.sleep(2)
                    self.spotify_play(dev['id'], context_uri=uri)
                elif data_type == 'album':
                    (album, artists, uri) = get_album_info(data)
                    self.speak_dialog('ListeningToAlbumBy',
                                      data={
                                          'album': album,
                                          'artist': artists[0]
                                      })
                    time.sleep(2)
                    self.spotify_play(dev['id'], context_uri=uri)
                elif data_type == 'genre':
                    items = data['tracks']['items']
                    random.shuffle(items)
                    uris = []
                    for item in items:
                        uris.append(item['uri'])
                    datai = {
                        'genre': genre_name,
                        'track': items[0]['name'],
                        'artist': items[0]['artists'][0]['name']
                    }
                    self.speak_dialog('ListeningToGenre', data)
                    time.sleep(2)
                    self.spotify_play(dev['id'], uris=uris)
                else:
                    print('wrong data_type')
            except Exception as e:
                LOG.error("Unable to obtain the name, artist, "
                          "and/or URI information while asked to play "
                          "something. " + str(e))

    def search(self, query, search_type):
        """ Search for an album, playlist or artist.
        Arguments:
            query:       search query (album title, artist, etc.)
            search_type: whether to search for an 'album', 'artist',
                         'playlist', 'track', or 'genre'

            TODO: improve results of albums by checking artist
        """
        res = None
        if search_type == 'album' and len(query.split('by')) > 1:
            title, artist = query.split('by')
            result = self.spotify.search(title, type=search_type)
        else:
            result = self.spotify.search(query, type=search_type)

        if search_type == 'album':
            if len(result['albums']['items']) > 0:
                album = result['albums']['items'][0]
                LOG.info(album)
                res = album
        elif search_type == 'artist':
            LOG.info(result['artists'])
            if len(result['artists']['items']) > 0:
                artist = result['artists']['items'][0]
                LOG.info(artist)
                res = artist
        elif search_type == 'genre':
            LOG.info("TODO! Genre")
        else:
            LOG.info('ERROR')
            return

        return res

    def search_spotify(self, message):
        """ Intent handler for "search spotify for X". """

        utterance = message.data['utterance']
        if len(utterance.split(self.translate('ForAlbum'))) == 2:
            query = utterance.split(self.translate('ForAlbum'))[1].strip()
            data = self.spotify.search(query, type='album')
            self.play(data=data, data_type='album')
        elif len(utterance.split(self.translate('ForArtist'))) == 2:
            query = utterance.split(self.translate('ForArtist'))[1].strip()
            data = self.spotify.search(query, type='artist')
            self.play(data=data, data_type='artist')
        else:
            for_word = ' ' + self.translate('For')
            query = for_word.join(utterance.split(for_word)[1:]).strip()
            data = self.spotify.search(query, type='track')
            self.play(data=data, data_type='track')

    def shuffle_on(self):
        """ Get preferred playback device """
        if self.spotify:
            self.spotify.shuffle(True)

    def shuffle_off(self):
        """ Get preferred playback device """
        if self.spotify:
            self.spotify.shuffle(False)

    def __pause(self):
        # if authorized and playback was started by the skill
        if self.spotify:
            LOG.info('Pausing Sonos...')
            self.spotify.pause(self.dev_id)

    def pause(self, message=None):
        """ Handler for playback control pause. """
        self.ducking = False
        self.__pause()

    def resume(self, message=None):
        """ Handler for playback control resume. """
        # if authorized and playback was started by the skill
        if self.spotify:
            LOG.info('Resume Sonos')
            if not self.dev_id:
                self.dev_id = self.get_default_device()
            self.spotify_play(self.dev_id)

    def next_track(self, message):
        """ Handler for playback control next. """
        # if authorized and playback was started by the skill
        if self.spotify and self.dev_id:
            LOG.info('Next Sonos track')
            self.spotify.next(self.dev_id)
            self.start_monitor()
            return True
        return False

    def prev_track(self, message):
        """ Handler for playback control prev. """
        # if authorized and playback was started by the skill
        if self.spotify and self.dev_id:
            LOG.info('Previous Sonos track')
            self.spotify.prev(self.dev_id)
            self.start_monitor()

    @intent_handler(IntentBuilder('').require('Sonos').require('Device'))
    def list_devices(self, message):
        """ List available devices. """
        if self.spotify:
            devices = [d['name'] for d in self.spotify.get_devices()]
            if len(devices) == 1:
                self.speak(devices[0])
            elif len(devices) > 1:
                self.speak_dialog(
                    'AvailableDevices', {
                        'devices':
                        ' '.join(devices[:-1]) + ' ' + self.translate('And') +
                        ' ' + devices[-1]
                    })
            else:
                self.speak_dialog('NoDevicesAvailable')
        else:
            self.speak_dialog('NotAuthorized')

    @intent_handler(
        IntentBuilder('').require('Transfer').require('Sonos').require(
            'ToDevice'))
    def transfer_playback(self, message):
        """ Move playback from one device to another. """
        if self.spotify and self.spotify.is_playing():
            dev = self.device_by_name(message.data['ToDevice'])
            if dev:
                self.spotify.transfer_playback(dev['id'])

    def stop(self):
        """ Stop playback. """
        if self.spotify and self.spotify.is_playing():
            dev = self.get_default_device()
            self.dev_id = dev['id']
            if self.dev_id:
                self.pause(None)

                # Clear playing device id
                self.dev_id = None
                return True
        self.dev_id = None
        return False

    def stop_librespot(self):
        """ Send Terminate signal to librespot if it's running. """
        if self.process and self.process.poll() is None:
            self.process.send_signal(signal.SIGTERM)
            self.process.communicate()  # Communicate to remove zombie
            self.process = None

    def shutdown(self):
        """ Remove the monitor at shutdown. """
        self.cancel_scheduled_event('SonosLogin')
        self.stop_monitor()
        self.stop_librespot()

        # Do normal shutdown procedure
        super(SonosSkill, self).shutdown()
Exemplo n.º 35
0
class AudioRecordSkill(MycroftSkill):
    def __init__(self):
        super(AudioRecordSkill, self).__init__("AudioRecordSkill")
        self.play_process = None
        self.record_process = None
        self.start_time = 0
        self.last_index = 24  # index of last pixel in countdowns

        self.settings["min_free_disk"] = 100  # min mb to leave free on disk
        self.settings["rate"] = 16000  # sample rate, hertz
        self.settings["channels"] = 1  # recording channels (1 = mono)
        self.settings["file_path"] = "/tmp/mycroft-recording.wav"
        self.settings["duration"] = -1  # default = unknown

    def remaining_time(self):
        return self.settings["duration"] - (now_local() -
                                            self.start_time).total_seconds()

    def has_free_disk_space(self):
        space = (self.remaining_time() * self.settings["channels"] *
                 self.settings["rate"] / 1024 / 1024)
        free_mb = psutil.disk_usage('/')[2] / 1024 / 1024
        return free_mb - space > self.settings["min_free_disk"]

    @staticmethod
    def stop_process(process):
        if process.poll() is None:  # None means still running
            process.terminate()
            # No good reason to wait, plus it interferes with
            # how stop button on the Mark 1 operates.
            # process.wait()
            return True
        else:
            return False

    # Handle: "Delete recording"
    @intent_handler(IntentBuilder('').require('Delete').require('Recording'))
    def handle_delete(self, message):
        if not exists(self.settings["file_path"]):
            self.speak_dialog('audio.record.no.recording')
        else:
            try:
                os.remove(self.settings["file_path"])
                self.speak_dialog('audio.record.removed')
            except:
                pass

    # Standard Stop handler
    def stop(self):
        if self.record_process:
            self.end_recording()
            return True
        if self.play_process:
            self.end_playback()
            return True
        return False

    # Show a countdown using the eyes
    def render_countdown(self, r_fore, g_fore, b_fore):
        display_owner = self.enclosure.display_manager.get_active()
        if display_owner == "":
            # Initialization, first time we take ownership
            self.enclosure.mouth_reset()  # clear any leftover bits
            self.enclosure.eyes_color(r_fore, g_fore, b_fore)  # foreground
            self.last_index = 24

        if display_owner == "AudioRecordSkill":
            remaining_pct = self.remaining_time() / self.settings["duration"]
            fill_to_index = int(24 * remaining_pct)
            while self.last_index > fill_to_index:
                if self.last_index < 24 and self.last_index > -1:
                    # fill background with gray
                    self.enclosure.eyes_setpixel(self.last_index, 64, 64, 64)
                self.last_index -= 1

    ######################################################################
    # Recording

    @intent_file_handler('StartRecording.intent')
    def handle_record(self, message):
        utterance = message.data.get('utterance')

        # Calculate how long to record
        self.start_time = now_local()
        stop_time, _ = extract_datetime(utterance, lang=self.lang)
        self.settings["duration"] = (stop_time -
                                     self.start_time).total_seconds()
        if self.settings["duration"] <= 0:
            self.settings["duration"] = 60  # default recording duration

        # Throw away any previous recording
        try:
            os.remove(self.settings["file_path"])
        except:
            pass

        if self.has_free_disk_space():
            record_for = nice_duration(self,
                                       self.settings["duration"],
                                       lang=self.lang)
            self.speak_dialog('audio.record.start.duration',
                              {'duration': record_for})

            # Initiate recording
            wait_while_speaking()
            self.start_time = now_local()  # recalc after speaking completes
            self.record_process = record(self.settings["file_path"],
                                         int(self.settings["duration"]),
                                         self.settings["rate"],
                                         self.settings["channels"])
            self.enclosure.eyes_color(255, 0, 0)  # set color red
            self.last_index = 24
            self.schedule_repeating_event(self.recording_feedback,
                                          None,
                                          1,
                                          name='RecordingFeedback')
        else:
            self.speak_dialog("audio.record.disk.full")

    def recording_feedback(self, message):
        if not self.record_process:
            self.end_recording()
            return

        # Show recording countdown
        self.render_countdown(255, 0, 0)

        # Verify there is still adequate disk space to continue recording
        if self.record_process.poll() is None:
            if not self.has_free_disk_space():
                # Out of space
                self.end_recording()
                self.speak_dialog("audio.record.disk.full")
        else:
            # Recording ended for some reason
            self.end_recording()

    def end_recording(self):
        self.cancel_scheduled_event('RecordingFeedback')

        if self.record_process:
            # Stop recording
            self.stop_process(self.record_process)
            self.record_process = None
            # Calc actual recording duration
            self.settings["duration"] = (now_local() -
                                         self.start_time).total_seconds()

        # Reset eyes
        self.enclosure.eyes_color(34, 167, 240)  # Mycroft blue
        self.bus.emit(Message('mycroft.eyes.default'))

    ######################################################################
    # Playback

    @intent_file_handler('PlayRecording.intent')
    def handle_play(self, message):
        if exists(self.settings["file_path"]):
            # Initialize for playback
            self.start_time = now_local()

            # Playback the recording, with visual countdown
            self.play_process = play_wav(self.settings["file_path"])
            self.enclosure.eyes_color(64, 255, 64)  # set color greenish
            self.last_index = 24
            self.schedule_repeating_event(self.playback_feedback,
                                          None,
                                          1,
                                          name='PlaybackFeedback')
        else:
            self.speak_dialog('audio.record.no.recording')

    def playback_feedback(self, message):
        if not self.play_process or self.play_process.poll() is not None:
            self.end_playback()
            return

        if self.settings["duration"] > -1:
            # Show playback countdown
            self.render_countdown(64, 255, 64)  # greenish color
        else:
            # unknown duration, can't display countdown
            pass

    def end_playback(self):
        self.cancel_scheduled_event('PlaybackFeedback')
        if self.play_process:
            self.stop_process(self.play_process)
            self.play_process = None

        # Reset eyes
        self.enclosure.eyes_color(34, 167, 240)  # Mycroft blue
        self.bus.emit(Message('mycroft.eyes.default'))
Exemplo n.º 36
0
class NoAgendaSkill(MycroftSkill):
    def __init__(self):
        super(NoAgendaSkill, self).__init__(name="NoAgendaSkill")
        self.process = None
        self.audioservice = None

    def initialize(self):
        if AudioService:
            self.audioservice = AudioService(self.emitter)

    @property
    def url_rss(self):
        pre_select = self.settings.get("pre_select", "")
        url_rss = self.settings.get("url_rss")
        if "not_set" in pre_select:
            # Use a custom RSS URL
            url_rss = self.settings.get("url_rss")
        else:
            # Use the selected preset's URL
            url_rss = pre_select

        if not url_rss and 'url_rss' in self.config:
            url_rss = self.config['url_rss']

        return url_rss

    @intent_handler(
        IntentBuilder("anycollusion").require("anycollusion").build())
    def handle_anycollusion_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('anycollusion')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("mymillenials").require("mymillenials").build())
    def handle_mymillenials_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('mymillenials')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(IntentBuilder("buildawall").require("buildawall").build())
    def handle_buildawall_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('buildawall')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("resistwemuch").require("resistwemuch").build())
    def handle_resistwemuch_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('resistwemuch')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(IntentBuilder("needs").require("needs").build())
    def handle_needs_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('needs')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("inthemorning").require("inthemorning").build())
    def handle_inthemorning_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('inthemorning')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(IntentBuilder("triggered").require("triggered").build())
    def handle_triggered_intent(self, message):
        try:
            self.stop()

            self.speak_dialog('NoAgenda')
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('triggered')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            sleep(1.0)
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("penultimate").optionally("Play").require(
            "penultimate").require("NoAgenda").build())
    def handle_penultimate_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[1]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('penultimate')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("third").optionally("Play").require("3rd").require(
            "NoAgenda").build())
    def handle_third_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[2]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('third')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("fourth").optionally("Play").require("4th").require(
            "NoAgenda").build())
    def handle_fourth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[3]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('fourth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("fifth").optionally("Play").require("5th").require(
            "NoAgenda").build())
    def handle_fifth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[4]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('fifth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("sixth").optionally("Play").require("6th").require(
            "NoAgenda").build())
    def handle_sixth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[5]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('sixth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("seventh").optionally("Play").require("7th").require(
            "NoAgenda").build())
    def handle_seventh_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[6]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('seventh')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("eighth").optionally("Play").require("8th").require(
            "NoAgenda").build())
    def handle_eighth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[7]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('eighth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("ninth").optionally("Play").require("9th").require(
            "NoAgenda").build())
    def handle_ninth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[8]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('ninth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("tenth").optionally("Play").require("10th").require(
            "NoAgenda").build())
    def handle_tenth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[9]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('tenth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("eleventh").optionally("Play").require("11th").require(
            "NoAgenda").build())
    def handle_eleventh_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[10]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('eleventh')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("twelfth").optionally("Play").require("12th").require(
            "NoAgenda").build())
    def handle_twelfth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[11]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('twelfth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("thirteenth").optionally("Play").require("13th").require(
            "NoAgenda").build())
    def handle_thirteenth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[12]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('thirteenth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("fourteenth").optionally("Play").require("14th").require(
            "NoAgenda").build())
    def handle_fourteenth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[13]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('fourteenth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("fifteenth").optionally("Play").require("15th").require(
            "NoAgenda").build())
    def handle_fifteenth_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[14]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('fifteenth')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("live").require("Jack").require("Live").optionally(
            "NoAgenda").require("Stream").build())
    def handle_live_intent(self, message):
        try:
            # Stop anything already playing
            self.stop()

            url = 'https://listen.noagendastream.com/noagenda.pls'
            LOG.info('live')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("query").require("query").optionally("latest").require(
            "NoAgenda").build())
    def handle_query_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('query')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    def stop(self):
        if self.audioservice:
            self.audioservice.stop()
        else:
            if self.process and self.process.poll() is None:
                self.process.terminate()
                self.process.wait()

    @intent_handler(
        IntentBuilder("random").optionally("Play").optionally(
            "random").require("NoAgenda").build())
    def handle_random_intent(self, message):
        try:
            self.stop()

            random_episode = random.randint(0, 14)
            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[random_episode]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('random')
            LOG.info(random_episode)
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))

    @intent_handler(
        IntentBuilder("latest").optionally("Play").optionally(
            "latest").require("NoAgenda").build())
    def handle_latest_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('latest')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))
Exemplo n.º 37
0
from adapt.intent import IntentBuilder
from adapt.engine import IntentDeterminationEngine

engine = IntentDeterminationEngine()

schema = json.loads(sys.argv[1])

for entity in schema["entities"]:
	if entity["type"] == "string":
		for value in entity["values"]:
			engine.register_entity(value, entity["name"])
	elif entity["type"] == "regex":
		engine.register_regex_entity(entity["pattern"])

for intent in schema["intents"]:
	ib = IntentBuilder(intent["name"].encode("utf-8"))
	for requirement in intent["requirements"]:
		ib.require(requirement["entity"], requirement["attribute"])
	for optional in intent["optionals"]:
		ib.optionally(optional["entity"], optional["attribute"])
	engine.register_intent_parser(ib.build())

if __name__ == "__main__":
	while True:
		line = sys.stdin.readline()
		query = json.loads(line)
		intents = list(engine.determine_intent(query["input"]))
		response = {"intents": intents}
		print(json.dumps(response))
		sys.stdout.flush()