From d378caee59df005e94ba6f891976ceb64c2a48d2 Mon Sep 17 00:00:00 2001 From: schneefux Date: Tue, 30 Sep 2014 20:14:17 +0200 Subject: Remove music mode --- client/conversation.py | 33 +----- client/music.py | 261 ------------------------------------------------ client/musicmode.py | 183 --------------------------------- client/vocabcompiler.py | 2 - 4 files changed, 1 insertion(+), 478 deletions(-) delete mode 100644 client/music.py delete mode 100644 client/musicmode.py diff --git a/client/conversation.py b/client/conversation.py index 0746b7f..9b86295 100644 --- a/client/conversation.py +++ b/client/conversation.py @@ -1,10 +1,7 @@ # -*- coding: utf-8-*- import logging from notifier import Notifier -from musicmode import * from brain import Brain -from mpd import MPDClient - class Conversation(object): @@ -16,34 +13,6 @@ class Conversation(object): self.brain = Brain(mic, profile) self.notifier = Notifier(profile) - def delegateInput(self, texts): - """A wrapper for querying brain.""" - - # check if input is meant to start the music module - for text in texts: - if any(x in text.upper() for x in ["SPOTIFY", "MUSIC"]): - self._logger.debug("Preparing to start music module") - # check if mpd client is running - try: - client = MPDClient() - client.timeout = None - client.idletimeout = None - client.connect("localhost", 6600) - except: - self._logger.critical("Can't connect to mpd client, cannot start music mode.", exc_info=True) - self.mic.say( - "I'm sorry. It seems that Spotify is not enabled. Please read the documentation to learn how to configure Spotify.") - return - - self.mic.say("Please give me a moment, I'm loading your Spotify playlists.") - self._logger.debug("Starting music mode") - music_mode = MusicMode(self.persona, self.mic) - music_mode.handleForever() - self._logger.debug("Exiting music mode") - return - - self.brain.query(texts) - def handleForever(self): """Delegates user input to the handling function when activated.""" self._logger.info("Starting to handle conversation with keyword '%s'.", self.persona) @@ -67,6 +36,6 @@ class Conversation(object): self._logger.debug("Stopped to listen actively with threshold: %r", threshold) if input: - self.delegateInput(input) + self.brain.query(input) else: self.mic.say("Pardon?") diff --git a/client/music.py b/client/music.py deleted file mode 100644 index ca9b776..0000000 --- a/client/music.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- coding: utf-8-*- -import re -import difflib -from mpd import MPDClient - - -def reconnect(func, *default_args, **default_kwargs): - """ - Reconnects before running - """ - - def wrap(self, *default_args, **default_kwargs): - try: - self.client.connect("localhost", 6600) - except: - pass - - # sometimes not enough to just connect - try: - return func(self, *default_args, **default_kwargs) - except: - self.client = MPDClient() - self.client.timeout = None - self.client.idletimeout = None - self.client.connect("localhost", 6600) - - return func(self, *default_args, **default_kwargs) - - return wrap - - -class Song: - - def __init__(self, id, title, artist, album): - - self.id = id - self.title = title - self.artist = artist - self.album = album - - -class Music: - - client = None - songs = [] # may have duplicates - playlists = [] - - # capitalized strings - song_titles = [] - song_artists = [] - - def __init__(self): - """ - Prepare the client and music variables - """ - # prepare client - self.client = MPDClient() - self.client.timeout = None - self.client.idletimeout = None - self.client.connect("localhost", 6600) - - # gather playlists - self.playlists = [x["playlist"] for x in self.client.listplaylists()] - - # gather songs - self.client.clear() - for playlist in self.playlists: - self.client.load(playlist) - - soup = self.client.playlist() - for i in range(0, len(soup) / 10): - index = i * 10 - id = soup[index].strip() - title = soup[index + 3].strip().upper() - artist = soup[index + 2].strip().upper() - album = soup[index + 4].strip().upper() - - self.songs.append(Song(id, title, artist, album)) - - self.song_titles.append(title) - self.song_artists.append(artist) - - @reconnect - def play(self, songs=False, playlist_name=False): - """ - Plays the current song or accepts a song to play. - - Arguments: - songs -- a list of song objects - playlist_name -- user-defined, something like "Love Song Playlist" - """ - if songs: - self.client.clear() - for song in songs: - try: # for some reason, certain ids don't work - self.client.add(song.id) - except: - pass - - if playlist_name: - self.client.clear() - self.client.load(playlist_name) - - self.client.play() - - @reconnect - def current_song(self): - item = self.client.playlistinfo(int(self.client.status()["song"]))[0] - result = "%s by %s" % (item["title"], item["artist"]) - return result - - @reconnect - def volume(self, level=None, interval=None): - - if level: - self.client.setvol(int(level)) - return - - if interval: - level = int(self.client.status()['volume']) + int(interval) - self.client.setvol(int(level)) - return - - @reconnect - def pause(self): - self.client.pause() - - @reconnect - def stop(self): - self.client.stop() - - @reconnect - def next(self): - self.client.next() - return - - @reconnect - def previous(self): - self.client.previous() - return - - def get_soup(self): - """ - returns the list of unique words that comprise song and artist titles - """ - - soup = [] - - for song in self.songs: - song_words = song.title.split(" ") - artist_words = song.artist.split(" ") - soup.extend(song_words) - soup.extend(artist_words) - - title_trans = ''.join( - chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) - soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", "") - for x in soup] - soup = [x for x in soup if x != ""] - - return list(set(soup)) - - def get_soup_playlist(self): - """ - returns the list of unique words that comprise playlist names - """ - - soup = [] - - for name in self.playlists: - soup.extend(name.split(" ")) - - title_trans = ''.join( - chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) - soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", "") - for x in soup] - soup = [x for x in soup if x != ""] - - return list(set(soup)) - - def get_soup_separated(self): - """ - returns the list of PHRASES that comprise song and artist titles - """ - - title_soup = [song.title for song in self.songs] - artist_soup = [song.artist for song in self.songs] - - soup = list(set(title_soup + artist_soup)) - - title_trans = ''.join( - chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) - soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", " ") - for x in soup] - soup = [re.sub(' +', ' ', x) for x in soup if x != ""] - - return soup - - def fuzzy_songs(self, query): - """ - Returns songs matching a query best as possible on either artist field, etc - """ - - query = query.upper() - - matched_song_titles = difflib.get_close_matches( - query, self.song_titles) - matched_song_artists = difflib.get_close_matches( - query, self.song_artists) - - # if query is beautifully matched, then forget about everything else - strict_priority_title = [x for x in matched_song_titles if x == query] - strict_priority_artists = [ - x for x in matched_song_artists if x == query] - - if strict_priority_title: - matched_song_titles = strict_priority_title - if strict_priority_artists: - matched_song_artists = strict_priority_artists - - matched_songs_bytitle = [ - song for song in self.songs if song.title in matched_song_titles] - matched_songs_byartist = [ - song for song in self.songs if song.artist in matched_song_artists] - - matches = list(set(matched_songs_bytitle + matched_songs_byartist)) - - return matches - - def fuzzy_playlists(self, query): - """ - returns playlist names that match query best as possible - """ - query = query.upper() - lookup = {n.upper(): n for n in self.playlists} - results = [lookup[r] for r in difflib.get_close_matches(query, lookup)] - return results - -if __name__ == "__main__": - """ - Plays music and performs unit-testing - """ - - print "Creating client" - - music = Music() - - print "Playing" - - music.play(songs=[music.songs[3]]) - - print music.get_soup_separated() - - while True: - query = raw_input("Query: ") - songs = music.fuzzy_songs(query) - print "Results" - print "=======" - for song in songs: - print "Title: %s Artist: %s" % (song.title, song.artist) - music.play(songs=songs) diff --git a/client/musicmode.py b/client/musicmode.py deleted file mode 100644 index 900c4f1..0000000 --- a/client/musicmode.py +++ /dev/null @@ -1,183 +0,0 @@ -# -*- coding: utf-8-*- -""" - Manages the conversation -""" - -import os -from mic import Mic -import g2p -from music import * -import stt - - -class MusicMode: - - def __init__(self, PERSONA, mic): - self.persona = PERSONA - # self.mic - we're actually going to ignore the mic they passed in - self.music = Music() - - # index spotify playlists into new dictionary and language models - original = self.music.get_soup_playlist( - ) + ["STOP", "CLOSE", "PLAY", "PAUSE", - "NEXT", "PREVIOUS", "LOUDER", "SOFTER", "LOWER", "HIGHER", "VOLUME", "PLAYLIST"] - pronounced = g2p.translateWords(original) - zipped = zip(original, pronounced) - lines = ["%s %s" % (x, y) for x, y in zipped] - - with open("dictionary_spotify.dic", "w") as f: - f.write("\n".join(lines) + "\n") - - with open("sentences_spotify.txt", "w") as f: - f.write("\n".join(original) + "\n") - f.write(" \n \n") - f.close() - - # make language model - os.system( - "text2idngram -vocab sentences_spotify.txt < sentences_spotify.txt -idngram spotify.idngram") - os.system( - "idngram2lm -idngram spotify.idngram -vocab sentences_spotify.txt -arpa languagemodel_spotify.lm") - - # create a new mic with the new music models - self.mic = Mic( - mic.speaker, - stt.PocketSphinxSTT(lmd_music="languagemodel_spotify.lm", dictd_music="dictionary_spotify.dic"), - stt.PocketSphinxSTT(lmd_music="languagemodel_spotify.lm", dictd_music="dictionary_spotify.dic") - ) - - def delegateInput(self, input): - - command = input.upper() - - # check if input is meant to start the music module - if "PLAYLIST" in command: - command = command.replace("PLAYLIST", "") - elif "STOP" in command: - self.mic.say("Stopping music") - self.music.stop() - return - elif "PLAY" in command: - self.mic.say("Playing %s" % self.music.current_song()) - self.music.play() - return - elif "PAUSE" in command: - self.mic.say("Pausing music") - # not pause because would need a way to keep track of pause/play - # state - self.music.stop() - return - elif any(ext in command for ext in ["LOUDER", "HIGHER"]): - self.mic.say("Louder") - self.music.volume(interval=10) - self.music.play() - return - elif any(ext in command for ext in ["SOFTER", "LOWER"]): - self.mic.say("Softer") - self.music.volume(interval=-10) - self.music.play() - return - elif "NEXT" in command: - self.mic.say("Next song") - self.music.play() # backwards necessary to get mopidy to work - self.music.next() - self.mic.say("Playing %s" % self.music.current_song()) - return - elif "PREVIOUS" in command: - self.mic.say("Previous song") - self.music.play() # backwards necessary to get mopidy to work - self.music.previous() - self.mic.say("Playing %s" % self.music.current_song()) - return - - # SONG SELECTION... requires long-loading dictionary and language model - # songs = self.music.fuzzy_songs(query = command.replace("PLAY", "")) - # if songs: - # self.mic.say("Found songs") - # self.music.play(songs = songs) - - # print "SONG RESULTS" - # print "============" - # for song in songs: - # print "Song: %s Artist: %s" % (song.title, song.artist) - - # self.mic.say("Playing %s" % self.music.current_song()) - - # else: - # self.mic.say("No songs found. Resuming current song.") - # self.music.play() - - # PLAYLIST SELECTION - playlists = self.music.fuzzy_playlists(query=command) - if playlists: - self.mic.say("Loading playlist %s" % playlists[0]) - self.music.play(playlist_name=playlists[0]) - self.mic.say("Playing %s" % self.music.current_song()) - else: - self.mic.say("No playlists found. Resuming current song.") - self.music.play() - - return - - def handleForever(self): - - self.music.play() - self.mic.say("Playing %s" % self.music.current_song()) - - while True: - - try: - threshold, transcribed = self.mic.passiveListen(self.persona) - except: - continue - - if threshold: - - self.music.pause() - - input = self.mic.activeListen(MUSIC=True) - - if "close" in input.lower(): - self.mic.say("Closing Spotify") - return - - if input: - self.delegateInput(input) - else: - self.mic.say("Pardon?") - self.music.play() - -if __name__ == "__main__": - """ - Indexes the Spotify music library to dictionary_spotify.dic and languagemodel_spotify.lm - """ - - musicmode = MusicMode("JASPER", None) - music = musicmode.music - - original = music.get_soup() + ["STOP", "CLOSE", "PLAY", - "PAUSE", "NEXT", "PREVIOUS", "LOUDER", "SOFTER"] - pronounced = g2p.translateWords(original) - zipped = zip(original, pronounced) - lines = ["%s %s" % (x, y) for x, y in zipped] - - with open("dictionary_spotify.dic", "w") as f: - f.write("\n".join(lines) + "\n") - - with open("sentences_spotify.txt", "w") as f: - f.write("\n".join(original) + "\n") - f.write(" \n \n") - f.close() - - with open("sentences_spotify_separated.txt", "w") as f: - f.write("\n".join(music.get_soup_separated()) + "\n") - f.write(" \n \n") - f.close() - - # make language model - os.system( - "text2idngram -vocab sentences_spotify.txt < sentences_spotify_separated.txt -idngram spotify.idngram") - os.system( - "idngram2lm -idngram spotify.idngram -vocab sentences_spotify.txt -arpa languagemodel_spotify.lm") - - print "Language Model and Dictionary Done" diff --git a/client/vocabcompiler.py b/client/vocabcompiler.py index aba85ce..1ca0d26 100644 --- a/client/vocabcompiler.py +++ b/client/vocabcompiler.py @@ -35,8 +35,6 @@ def compile(sentences, dictionary, languagemodel): for module in modules: words.extend(module.WORDS) - # for spotify module - words.extend(["MUSIC", "SPOTIFY"]) words = list(set(words)) # create the dictionary -- cgit v1.3.1 From 1a833f30fe98acc4692b4f8684a6d1f9baa99d82 Mon Sep 17 00:00:00 2001 From: schneefux Date: Wed, 1 Oct 2014 14:32:11 +0200 Subject: Readd MusicMode as dedicated module --- client/modules/MPDControl.py | 428 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 client/modules/MPDControl.py diff --git a/client/modules/MPDControl.py b/client/modules/MPDControl.py new file mode 100644 index 0000000..ecf857e --- /dev/null +++ b/client/modules/MPDControl.py @@ -0,0 +1,428 @@ +# -*- coding: utf-8-*- +import os +import re +import logging +import difflib +import mpd +import g2p +import stt +from mic import Mic + +# Standard module stuff +WORDS = ["MUSIC", "SPOTIFY"] + +def handle(text, mic, profile): + """ + Responds to user-input, typically speech text, by telling a joke. + + Arguments: + text -- user-input, typically transcribed speech + mic -- used to interact with the user (for both input and output) + profile -- contains information related to the user (e.g., phone number) + """ + logger = logging.getLogger(__name__) + + kwargs = {} + if 'mpdclient' in profile: + if 'server' in profile['mpdclient']: + kwargs['server'] = profile['mpdclient']['server'] + if 'port' in profile['mpdclient']: + kwargs['port'] = int(profile['mpdclient']['port']) + + logger.debug("Preparing to start music module") + try: + mpdwrapper = MPDWrapper(**kwargs) + except: + logger.error("Couldn't connect to MPD server", exc_info=True) + mic.say("I'm sorry. It seems that Spotify is not enabled. Please read the documentation to learn how to configure Spotify.") + return + + mic.say("Please give me a moment, I'm loading your Spotify playlists.") + + # FIXME: Make this configurable + persona = 'JASPER' + + logger.debug("Starting music mode") + music_mode = MusicMode(persona, mic, mpdwrapper) + music_mode.handleForever() + logger.debug("Exiting music mode") + + return + +def isValid(text): + """ + Returns True if the input is related to jokes/humor. + + Arguments: + text -- user-input, typically transcribed speech + """ + return any(word in text.upper() for word in WORDS) + +# The interesting part +class MusicMode(object): + + def __init__(self, PERSONA, mic, mpdwrapper): + self.persona = PERSONA + # self.mic - we're actually going to ignore the mic they passed in + self.music = mpdwrapper + + # index spotify playlists into new dictionary and language models + original = self.music.get_soup_playlist( + ) + ["STOP", "CLOSE", "PLAY", "PAUSE", + "NEXT", "PREVIOUS", "LOUDER", "SOFTER", "LOWER", "HIGHER", "VOLUME", "PLAYLIST"] + pronounced = g2p.translateWords(original) + zipped = zip(original, pronounced) + lines = ["%s %s" % (x, y) for x, y in zipped] + + with open("dictionary_spotify.dic", "w") as f: + f.write("\n".join(lines) + "\n") + + with open("sentences_spotify.txt", "w") as f: + f.write("\n".join(original) + "\n") + f.write(" \n \n") + f.close() + + # make language model + os.system( + "text2idngram -vocab sentences_spotify.txt < sentences_spotify.txt -idngram spotify.idngram") + os.system( + "idngram2lm -idngram spotify.idngram -vocab sentences_spotify.txt -arpa languagemodel_spotify.lm") + + # create a new mic with the new music models + self.mic = Mic( + mic.speaker, + mic.passive_stt_engine, + stt.PocketSphinxSTT(lmd_music="languagemodel_spotify.lm", dictd_music="dictionary_spotify.dic") + ) + + def delegateInput(self, input): + + command = input.upper() + + # check if input is meant to start the music module + if "PLAYLIST" in command: + command = command.replace("PLAYLIST", "") + elif "STOP" in command: + self.mic.say("Stopping music") + self.music.stop() + return + elif "PLAY" in command: + self.mic.say("Playing %s" % self.music.current_song()) + self.music.play() + return + elif "PAUSE" in command: + self.mic.say("Pausing music") + # not pause because would need a way to keep track of pause/play + # state + self.music.stop() + return + elif any(ext in command for ext in ["LOUDER", "HIGHER"]): + self.mic.say("Louder") + self.music.volume(interval=10) + self.music.play() + return + elif any(ext in command for ext in ["SOFTER", "LOWER"]): + self.mic.say("Softer") + self.music.volume(interval=-10) + self.music.play() + return + elif "NEXT" in command: + self.mic.say("Next song") + self.music.play() # backwards necessary to get mopidy to work + self.music.next() + self.mic.say("Playing %s" % self.music.current_song()) + return + elif "PREVIOUS" in command: + self.mic.say("Previous song") + self.music.play() # backwards necessary to get mopidy to work + self.music.previous() + self.mic.say("Playing %s" % self.music.current_song()) + return + + # SONG SELECTION... requires long-loading dictionary and language model + # songs = self.music.fuzzy_songs(query = command.replace("PLAY", "")) + # if songs: + # self.mic.say("Found songs") + # self.music.play(songs = songs) + + # print "SONG RESULTS" + # print "============" + # for song in songs: + # print "Song: %s Artist: %s" % (song.title, song.artist) + + # self.mic.say("Playing %s" % self.music.current_song()) + + # else: + # self.mic.say("No songs found. Resuming current song.") + # self.music.play() + + # PLAYLIST SELECTION + playlists = self.music.fuzzy_playlists(query=command) + if playlists: + self.mic.say("Loading playlist %s" % playlists[0]) + self.music.play(playlist_name=playlists[0]) + self.mic.say("Playing %s" % self.music.current_song()) + else: + self.mic.say("No playlists found. Resuming current song.") + self.music.play() + + return + + def handleForever(self): + + self.music.play() + self.mic.say("Playing %s" % self.music.current_song()) + + while True: + + try: + threshold, transcribed = self.mic.passiveListen(self.persona) + except: + continue + + if threshold: + + self.music.pause() + + input = self.mic.activeListen(MUSIC=True) + + if "close" in input.lower(): + self.mic.say("Closing Spotify") + return + + if input: + self.delegateInput(input) + else: + self.mic.say("Pardon?") + self.music.play() + +def reconnect(func, *default_args, **default_kwargs): + """ + Reconnects before running + """ + + def wrap(self, *default_args, **default_kwargs): + try: + self.client.connect(self.server, self.port) + except: + pass + + # sometimes not enough to just connect + try: + return func(self, *default_args, **default_kwargs) + except: + self.client = mpd.MPDClient() + self.client.timeout = None + self.client.idletimeout = None + self.client.connect(self.server, self.port) + + return func(self, *default_args, **default_kwargs) + + return wrap + + +class Song(object): + def __init__(self, id, title, artist, album): + + self.id = id + self.title = title + self.artist = artist + self.album = album + +class MPDWrapper(object): + + client = None + songs = [] # may have duplicates + playlists = [] + + # capitalized strings + song_titles = [] + song_artists = [] + + def __init__(self, server="localhost", port=6600): + """ + Prepare the client and music variables + """ + self.server = server + self.port = port + + # prepare client + self.client = mpd.MPDClient() + self.client.timeout = None + self.client.idletimeout = None + self.client.connect(self.server, self.port) + + # gather playlists + self.playlists = [x["playlist"] for x in self.client.listplaylists()] + + # gather songs + self.client.clear() + for playlist in self.playlists: + self.client.load(playlist) + + soup = self.client.playlist() + for i in range(0, len(soup) / 10): + index = i * 10 + id = soup[index].strip() + title = soup[index + 3].strip().upper() + artist = soup[index + 2].strip().upper() + album = soup[index + 4].strip().upper() + + self.songs.append(Song(id, title, artist, album)) + + self.song_titles.append(title) + self.song_artists.append(artist) + + @reconnect + def play(self, songs=False, playlist_name=False): + """ + Plays the current song or accepts a song to play. + + Arguments: + songs -- a list of song objects + playlist_name -- user-defined, something like "Love Song Playlist" + """ + if songs: + self.client.clear() + for song in songs: + try: # for some reason, certain ids don't work + self.client.add(song.id) + except: + pass + + if playlist_name: + self.client.clear() + self.client.load(playlist_name) + + self.client.play() + + @reconnect + def current_song(self): + item = self.client.playlistinfo(int(self.client.status()["song"]))[0] + result = "%s by %s" % (item["title"], item["artist"]) + return result + + @reconnect + def volume(self, level=None, interval=None): + + if level: + self.client.setvol(int(level)) + return + + if interval: + level = int(self.client.status()['volume']) + int(interval) + self.client.setvol(int(level)) + return + + @reconnect + def pause(self): + self.client.pause() + + @reconnect + def stop(self): + self.client.stop() + + @reconnect + def next(self): + self.client.next() + return + + @reconnect + def previous(self): + self.client.previous() + return + + def get_soup(self): + """ + returns the list of unique words that comprise song and artist titles + """ + + soup = [] + + for song in self.songs: + song_words = song.title.split(" ") + artist_words = song.artist.split(" ") + soup.extend(song_words) + soup.extend(artist_words) + + title_trans = ''.join( + chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) + soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", "") + for x in soup] + soup = [x for x in soup if x != ""] + + return list(set(soup)) + + def get_soup_playlist(self): + """ + returns the list of unique words that comprise playlist names + """ + + soup = [] + + for name in self.playlists: + soup.extend(name.split(" ")) + + title_trans = ''.join( + chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) + soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", "") + for x in soup] + soup = [x for x in soup if x != ""] + + return list(set(soup)) + + def get_soup_separated(self): + """ + returns the list of PHRASES that comprise song and artist titles + """ + + title_soup = [song.title for song in self.songs] + artist_soup = [song.artist for song in self.songs] + + soup = list(set(title_soup + artist_soup)) + + title_trans = ''.join( + chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256)) + soup = [x.decode('utf-8').encode("ascii", "ignore").upper().translate(title_trans).replace("_", " ") + for x in soup] + soup = [re.sub(' +', ' ', x) for x in soup if x != ""] + + return soup + + def fuzzy_songs(self, query): + """ + Returns songs matching a query best as possible on either artist field, etc + """ + + query = query.upper() + + matched_song_titles = difflib.get_close_matches(query, self.song_titles) + matched_song_artists = difflib.get_close_matches(query, self.song_artists) + + # if query is beautifully matched, then forget about everything else + strict_priority_title = [x for x in matched_song_titles if x == query] + strict_priority_artists = [ + x for x in matched_song_artists if x == query] + + if strict_priority_title: + matched_song_titles = strict_priority_title + if strict_priority_artists: + matched_song_artists = strict_priority_artists + + matched_songs_bytitle = [ + song for song in self.songs if song.title in matched_song_titles] + matched_songs_byartist = [ + song for song in self.songs if song.artist in matched_song_artists] + + matches = list(set(matched_songs_bytitle + matched_songs_byartist)) + + return matches + + def fuzzy_playlists(self, query): + """ + returns playlist names that match query best as possible + """ + query = query.upper() + lookup = {n.upper(): n for n in self.playlists} + results = [lookup[r] for r in difflib.get_close_matches(query, lookup)] + return results \ No newline at end of file -- cgit v1.3.1 From a9b51e5a39f3375947204215c50ac70c86a176c7 Mon Sep 17 00:00:00 2001 From: schneefux Date: Wed, 1 Oct 2014 14:40:32 +0200 Subject: Use instance attributes in MPDWrapper --- client/modules/MPDControl.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/client/modules/MPDControl.py b/client/modules/MPDControl.py index ecf857e..778fe5c 100644 --- a/client/modules/MPDControl.py +++ b/client/modules/MPDControl.py @@ -230,15 +230,6 @@ class Song(object): self.album = album class MPDWrapper(object): - - client = None - songs = [] # may have duplicates - playlists = [] - - # capitalized strings - song_titles = [] - song_artists = [] - def __init__(self, server="localhost", port=6600): """ Prepare the client and music variables @@ -260,6 +251,11 @@ class MPDWrapper(object): for playlist in self.playlists: self.client.load(playlist) + self.songs = [] # may have duplicates + # capitalized strings + self.song_titles = [] + self.song_artists = [] + soup = self.client.playlist() for i in range(0, len(soup) / 10): index = i * 10 -- cgit v1.3.1 From fe42407497f4f3dcc1388f2e9da53dd64ccf6382 Mon Sep 17 00:00:00 2001 From: schneefux Date: Wed, 1 Oct 2014 14:47:29 +0200 Subject: Apply fix from PR jasperproject/jasper-client#173 to MusicMode --- client/modules/MPDControl.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/modules/MPDControl.py b/client/modules/MPDControl.py index 778fe5c..7d79174 100644 --- a/client/modules/MPDControl.py +++ b/client/modules/MPDControl.py @@ -62,6 +62,7 @@ def isValid(text): class MusicMode(object): def __init__(self, PERSONA, mic, mpdwrapper): + self._logger = logging.getLogger(__name__) self.persona = PERSONA # self.mic - we're actually going to ignore the mic they passed in self.music = mpdwrapper @@ -175,26 +176,25 @@ class MusicMode(object): while True: - try: - threshold, transcribed = self.mic.passiveListen(self.persona) - except: - continue + threshold, transcribed = self.mic.passiveListen(self.persona) - if threshold: + if not transcribed or not threshold: + self._logger.info("Nothing has been said or transcribed.") + continue - self.music.pause() + self.music.pause() - input = self.mic.activeListen(MUSIC=True) + input = self.mic.activeListen(MUSIC=True) - if "close" in input.lower(): - self.mic.say("Closing Spotify") - return + if "close" in input.lower(): + self.mic.say("Closing Spotify") + return - if input: - self.delegateInput(input) - else: - self.mic.say("Pardon?") - self.music.play() + if input: + self.delegateInput(input) + else: + self.mic.say("Pardon?") + self.music.play() def reconnect(func, *default_args, **default_kwargs): """ -- cgit v1.3.1 From 32388e79b28f4f0c929bbf9200d4ba96b23526ff Mon Sep 17 00:00:00 2001 From: schneefux Date: Wed, 1 Oct 2014 14:57:40 +0200 Subject: Only look for 'close' if activeListen returned something --- client/modules/MPDControl.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/modules/MPDControl.py b/client/modules/MPDControl.py index 7d79174..6e8e438 100644 --- a/client/modules/MPDControl.py +++ b/client/modules/MPDControl.py @@ -186,11 +186,10 @@ class MusicMode(object): input = self.mic.activeListen(MUSIC=True) - if "close" in input.lower(): - self.mic.say("Closing Spotify") - return - if input: + if "close" in input.lower(): + self.mic.say("Closing Spotify") + return self.delegateInput(input) else: self.mic.say("Pardon?") -- cgit v1.3.1 From 66264fa47e264e2518abaaad5f44424c1c2e0864 Mon Sep 17 00:00:00 2001 From: schneefux Date: Wed, 1 Oct 2014 15:01:25 +0200 Subject: Fix VocabCompiler testcase because MUSIC/SPOTIFY are not hardcoded anymore --- client/test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/test.py b/client/test.py index 501fe6f..fd74571 100644 --- a/client/test.py +++ b/client/test.py @@ -35,9 +35,7 @@ class TestVocabCompiler(unittest.TestCase): dictionary = "temp_dictionary.dic" languagemodel = "temp_languagemodel.lm" - words = [ - 'MUSIC', 'SPOTIFY' - ] + words = [] mock_module = Mock() mock_module.WORDS = [ -- cgit v1.3.1