class Drowner: def __init__(self, db): self.db = db self.searcher = YouTubeSearcher() self.player = Player() self.speaker = Speaker() return def drown(self, keyword=None): if keyword: id = self.searcher.search(keyword) if id: print id self.db.register_music(keyword, id) self.player.play(id) else: row = self.db.fetch_music_randomly() id = row["url"] address = row["address"] self.speaker.speak(address + u"のトイレからです") self.player.play(id) return
class Interpreter: """ The interpreter recognises an input of spoken words and is able to process the correct answer which is defined in each of our recognizer classes. """ def __init__(self): self.spoken_words = None self.speaker = Speaker() self.doc = None self.recognizers = [] self.recognizers.append(RecognizerSimple()) self.recognizers.append(RecognizerSimpleMath()) self.recognizers.append(RecognizerNamedEntities()) self.recognizers.append(RecognizerTime()) self.nlp = spacy.load("en_core_web_sm") self.answer = utilities.DAVE_STANDARD_ANSWER def execute(self, spoken_words: str = None): if not spoken_words: spoken_words = self.spoken_words if not spoken_words: print("error: Missing spoken words") return self.spoken_words = spoken_words print(f"Hello Dave I understood: {self.spoken_words}") answer = "" doc = self.nlp(spoken_words) for recognizer in self.recognizers: if recognizer.recognize(doc): answer = recognizer.answer break if not answer: self.speaker.speak("Sorry Dave I did not understand you.") else: self.speaker.speak(answer)
def __init__(self): Follwer.__init__(self) self.state = State.NORMAL self.recognizer = SpeechRecognizer() self.follow(self.recognizer) self.answer = str() self.recommend_packages = [] self.interesting_package = None Speaker.speak('Please tell your phone number.') number = raw_input('Phone number : ') self.current_user = Database.find_one('customers', 'phone_number', number) self.user_account = Database.find_user_account(self.current_user.id) # If phone no is exist, Greeting if self.current_user is not None: Speaker.speak('Good morning mister %s. How can i help you.' % self.current_user.fullname()) self.recognizer.start() # Otherwise, Goodbye else: Speaker.speak('Sorry. Your number is not in our system.')
from recognizer import handleSpeech from weather import getLocation, getWeatherData, displayWeather from speaker import Speaker from browser import Browser from wikipedia import isQuestion, Wikipedia browser1 = Browser() speaker1 = Speaker() userCommand = "" while (True): speaker1.printAndSpeak("How may I help you, sir?") # userCommand = handleSpeech(userCommand) userCommand = input("Enter your command : ") print("Your command :", userCommand) if ("bye" in userCommand.lower()): speaker1.speak("Bye sir, see you next time") break elif (userCommand == ""): speaker1.printAndSpeak("Sorry sir, couldn't understand audio") elif (userCommand.lower() == "how are you doing"): speaker1.speak( random.choice( ["I am fine", "Incredible, Sir", "I am feeling great"])) elif ("open" in userCommand.lower()): browser1.open(userCommand) elif ("weather" in userCommand.lower()): displayWeather(userCommand) elif (isQuestion(userCommand)): wiki = Wikipedia(userCommand) wiki.findKeyword() if (wiki.doesPageExist()):
class ClockActivity(activity.Activity): """The clock activity displays a simple clock widget. """ def __init__(self, handle): """Create and initialize the clock activity. """ super(ClockActivity, self).__init__(handle) # TRANS: Title of the activity self.set_title(_('What Time Is It?')) # TRANS: The format used when writing the time in full # letters. You must take care to use a font size large enough # so that kids can read it easily, but also small enough so # that all times combination fit on the screen, even when the # screen is rotated. Pango markup: # http://www.pyGtk.org/docs/pyGtk/pango-markup-language.html self._TIME_LETTERS_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">%s</span></markup>') # TRANS: The format used to display the weekday and date # (example: Tuesday 10/21/2008) We recommend to use the same # font size as for the time display. See # http://docs.python.org/lib/module-time.html for available # strftime formats. xgettext:no-python-format self._DATE_SHORT_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">\ <span foreground="#B20008">%A</span>, \ <span foreground="#5E008C">%m</span>/\ <span foreground="#B20008">%d</span>/\ <span foreground="#9A5200">%Y</span></span></markup>') # Should we write the time in full letters? self._time_writer = None self._time_in_letters = self.get_title() self._time_letters = None self._date = None self._time_speaker = None if 'clock-mode' not in self.metadata.keys(): self.metadata['clock-mode'] = _MODE_SIMPLE_CLOCK else: self.metadata['clock-mode'] = int(self.metadata['clock-mode']) if 'write-time' in self.metadata.keys(): self._write_time = bool(self.metadata['write-time']) else: self._write_time = False if 'speak-time' in self.metadata.keys(): self._speak_time = bool(self.metadata['speak-time']) else: self._speak_time = False if 'write-date' in self.metadata.keys(): self._write_date = bool(self.metadata['write-date']) else: self._write_date = False self._make_display() self._make_toolbars() # Show the activity on the screen self.show_all() # We want to be notified when the minutes change self._clock.connect("time_minute", self._minutes_changed_cb) if not self.powerd_running(): try: bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.ohm', '/org/freedesktop/ohm/Keystore') self.ohm_keystore = dbus.Interface( proxy, 'org.freedesktop.ohm.Keystore') except dbus.DBusException: self.ohm_keystore = None def write_file(self, file_path): self.metadata['write-time'] = 'True' if self._write_time else '' self.metadata['write-date'] = 'True' if self._write_date else '' self.metadata['speak-time'] = 'True' if self._speak_time else '' self.metadata['clock-mode'] = str(self._clock._mode) def powerd_running(self): self.using_powerd = os.access(POWERD_INHIBIT_DIR, os.W_OK) return self.using_powerd def _inhibit_suspend(self): if self.using_powerd: fd = open(POWERD_INHIBIT_DIR + "/%u" % os.getpid(), 'w') fd.close() return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 1) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _allow_suspend(self): if self.using_powerd: os.unlink(POWERD_INHIBIT_DIR + "/%u" % os.getpid()) return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 0) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _make_toolbars(self): """Prepare and set the toolbars of the activity. Load and show icons. Associate them to the call back methods. """ self.max_participants = 1 toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_button.show() toolbar_box.toolbar.insert(activity_button, 0) self._add_clock_controls(toolbar_box.toolbar) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_size_request(0, -1) separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) toolbar_box.toolbar.insert(StopButton(self), -1) self.set_toolbar_box(toolbar_box) toolbar_box.show_all() return toolbar_box def _add_clock_controls(self, display_toolbar): # First group of radio button to select the type of clock to display button1 = RadioToolButton(icon_name="simple-clock") button1.set_tooltip(_('Simple Clock')) button1.connect("toggled", self._display_mode_changed_cb, _MODE_SIMPLE_CLOCK) display_toolbar.insert(button1, -1) button2 = RadioToolButton(icon_name="nice-clock", group=button1) button2.set_tooltip(_('Nice Clock')) button2.connect("toggled", self._display_mode_changed_cb, _MODE_NICE_CLOCK) display_toolbar.insert(button2, -1) button3 = RadioToolButton(icon_name="digital-clock", group=button1) button3.set_tooltip(_('Digital Clock')) button3.connect("toggled", self._display_mode_changed_cb, _MODE_DIGITAL_CLOCK) display_toolbar.insert(button3, -1) # A separator between the two groups of buttons separator = Gtk.SeparatorToolItem() separator.set_draw(True) display_toolbar.insert(separator, -1) # Now the options buttons to display other elements: date, day # of week... A button in the toolbar to write the time in # full letters button = ToggleToolButton("write-time") button.set_tooltip(_('Display time in full letters')) button.connect("toggled", self._write_time_clicked_cb) display_toolbar.insert(button, -1) # The button to display the weekday and date button = ToggleToolButton("write-date") button.set_tooltip(_('Display weekday and date')) button.connect("toggled", self._write_date_clicked_cb) display_toolbar.insert(button, -1) # Another button to speak aloud the time button = ToggleToolButton("microphone") button.set_tooltip(_('Talking clock')) button.connect("toggled", self._speak_time_clicked_cb) display_toolbar.insert(button, -1) # A separator between the two groups of buttons separator = Gtk.SeparatorToolItem() separator.set_draw(True) display_toolbar.insert(separator, -1) # And another button to toggle grabbing the hands self._grab_button = ToggleToolButton("grab") self._grab_button.set_tooltip(_('Grab the hands')) self._grab_button.connect("toggled", self._grab_clicked_cb) display_toolbar.insert(self._grab_button, -1) def _make_display(self): """Prepare the display of the clock. The display has two parts: the clock face at the top, and the time in full letters at the bottom, when the user selects to show it. """ # The clock face self._clock = ClockFace() # The label to print the time in full letters self._time_letters = Gtk.Label() self._time_letters.set_no_show_all(True) # Following line in ineffective! # self._time_letters.set_line_wrap(True) # Resize the invisible label so that Gtk will know in advance # the height when we show it. self._time_letters.set_markup( self._TIME_LETTERS_FORMAT % self._time_in_letters) # The label to write the date self._date = Gtk.Label() self._date.set_no_show_all(True) self._date.set_markup( self._clock.get_time().strftime(self._DATE_SHORT_FORMAT)) # Put all these widgets in a vertical box vbox = Gtk.VBox() vbox.pack_start(self._clock, True, True, 0) vbox.pack_start(self._time_letters, False, False, 0) vbox.pack_start(self._date, False, False, 0) # Attach the display to the activity self.set_canvas(vbox) def _write_date_clicked_cb(self, button): """The user clicked on the "write date" button to display the current weekday and date. """ if button.get_active(): self._date.show() else: self._date.hide() def _display_mode_changed_cb(self, radiobutton, display_mode): """The user selected a clock display mode (simple clock, nice or digital). """ self._clock.set_display_mode(display_mode) self._clock.queue_draw() is_digital = display_mode == _MODE_DIGITAL_CLOCK # Exit grab hands mode if the clock is digital if self._clock.grab_hands_mode and is_digital: self._grab_button.set_active(False) # The hands can't be grabbed in the digital clock mode self._grab_button.props.sensitive = not is_digital def _write_time_clicked_cb(self, button): """The user clicked on the "write time" button to print the current time. """ self._write_time = button.get_active() if self._write_time: self._time_letters.show() self._write_and_speak(False) else: self._time_letters.hide() def _speak_time_clicked_cb(self, button): """The user clicked on the "speak time" button to hear the talking clock. """ self._speak_time = button.get_active() if self._speak_time: self._write_and_speak(True) def _grab_clicked_cb(self, button): """The user clicked on the "grab hands" button to toggle grabbing the hands. """ self._clock.change_grab_hands_mode(button.get_active()) def _minutes_changed_cb(self, clock): """Minutes have changed on the clock face: we have to update the display of the time in full letters if the user has chosen to have it and eventually croak the time. """ # Change time display and talk, if necessary self._write_and_speak(True) # Update the weekday and date in case it was midnight self._date.set_markup( clock.get_time().strftime(self._DATE_SHORT_FORMAT)) def _notify_active_cb(self, widget, event): """Sugar notify us that the activity is becoming active or inactive. When we are inactive, we change the activity status of the clock face widget, so that it can stop updating every seconds. """ self._clock.active = self.props.active if self.props.active: self._inhibit_suspend() else: self._allow_suspend() def _write_and_speak(self, speak): """ Write and speak the time (called in another thread not to block the clock). """ # A helper function for the running thread def thread_write_and_speak(): # Only update the time in full letters when necessary if self._write_time or self._speak_time: self._do_write_time() # And if requested, say it aloud if self._speak_time and speak: self._do_speak_time() # Now detach a thread to do the big job thread = threading.Thread(target=thread_write_and_speak) thread.start() def _do_write_time(self): """Translate the time to full letters. """ if self._time_writer is None: self._time_writer = TimeWriter() hour = self._clock.get_time().hour minute = self._clock.get_time().minute self._time_in_letters = self._time_writer.write_time(hour, minute) self._time_letters.set_markup( self._TIME_LETTERS_FORMAT % self._time_in_letters) def _do_speak_time(self): """Speak aloud the current time. """ def gstmessage_cb(bus, message, pipe): if message.type in (Gst.MessageType.EOS, Gst.MessageType.ERROR): pipe.set_state(Gst.State.NULL) if self._time_speaker is None: self._time_speaker = Speaker() pipeline = 'espeak text="%(text)s" voice="%(voice)s" pitch="%(pitch)s" \ rate="%(rate)s" gap="%(gap)s" ! autoaudiosink' % { 'text': self._untag(self._time_in_letters), 'voice': self._time_speaker.VOICE, 'pitch': self._time_speaker.PITCH, 'rate': self._time_speaker.SPEED, 'gap': self._time_speaker.WORD_GAP} try: pipe = Gst.parse_launch(pipeline) bus = pipe.get_bus() bus.add_signal_watch() bus.connect('message', gstmessage_cb, pipe) pipe.set_state(Gst.State.PLAYING) except: self._time_speaker.speak(self._untag(self._time_in_letters)) def _untag(self, text): """Remove all the tags (pango markup) from a text. """ if text is False or "<" not in text: return text else: result = "" for s in re.findall(r"(<.*?>)|([^<>]+)", text): result += s[1] return result
class Bot: """ A class that represents the bot conducting the dialogue (SDS) Attributes ---------- _name: str the name of the bot _speaker: Speaker speaker object used for text to speech _listener: Listener listener object used for speech to perform Automatic Speech Recognition _prompt: str colored name of the bot to appear in the terminal _verbose: bool whether the bot should print info about the command it receives (dependency tree, lemmas info) _silent: bool whether the bot should only print replies (no text to speech) _frame_stack: list stack where the bot holds the frames it still has not finished to process _current_frame: Frame current frame the bot is processing _is_over: bool whether the interaction is over """ def __init__(self, name, color, verbose=True, silent=False, menu_path=None): """ Constructor :param name: the bot's name it will use in the dialogues :param color: the color the bot will use in the prompt :param verbose: whether the bot should print info about the command it receives (dependency tree, lemmas info) :param silent: if true, then only use print (no text to speech) :param menu_path: the path of the stored menu """ self._name = name self._speaker = Speaker(rate=150, volume=1) self._listener = Listener(mic_index=0) self._prompt = colored(f'{self._name}: ', color) self._verbose = verbose self._silent = silent self._frame_stack = [] self._current_frame = None self._is_over = False if menu_path is not None: self._load_menu(menu_path) else: self._menu = {"entries": []} # when finished setup, welcome user self._say(self._welcome()) def _say(self, sentence): """ Says the given sentence through the bot speaker object :param sentence: sentence :return: None """ print(f"{self._prompt} {sentence}") if not self._silent: self._speaker.speak(sentence) def listen(self): """ Tries to listen for commands. Loops until the sentence in understood properly or there is a connection error :return: transcribed sentence from voice """ if self._verbose: print(f'{self._prompt} * listening *') res = self._listen() while not res["success"]: err = res["error"] if isinstance(err, sr.UnknownValueError): self._say( "Sorry, I did not hear that, can you say that again?") elif isinstance(err, sr.RequestError): self._say("No connection with the server available") return None res = self._listen() return res["sentence"] def _listen(self): """ A simple proxy to access bot own listener object and obtain the transcription of the voice command issued by the user :return: a response object (see Listener docs) """ response = self._listener.listen() return response def process(self, command): """ Processes the given command :param command: command :return: a proper reply (None if interaction is over) """ # obtain spacy syntax dependency tree parsed = syntax_analysis(command) # if prompted to load last stored menu, or saved current one, do so if contains_text(parsed, "save"): self._save_menu() self._say("Menu saved") return if contains_text(parsed, "load"): self._load_menu() self._say("Menu loaded") return # print info if required if self._verbose: root = parsed.root.text.lower().strip() self._say(f"The root of the sentence is \'{root}\'") print(f"\n{'=' * 5} DEPENDENCIES OF SENTENCE {'=' * 5}") print_dependencies(parsed) print(f"\n{'=' * 5} TOKENS OF SENTENCE {'=' * 5}") print_tokens_info(parsed) # determine frame based on parsed command frame = self._determine_frame(parsed) # change current frame if necessary, storing old one if self._current_frame is None: self._current_frame = frame elif frame is not None and type(frame) != type(self._current_frame): self._frame_stack.insert(0, self._current_frame) # self._say("Ok we will come back to that later") self._current_frame = frame # obtain reply by handling parsed command based on the current frame if isinstance(self._current_frame, EndFrame): self._say(self._goodbye()) self._current_frame = None self._frame_stack = [] return elif isinstance(self._current_frame, AddInfoFrame): reply = self._handle_add_info_frame(parsed) elif isinstance(self._current_frame, AskInfoFrame): reply = self._handle_ask_info_frame(parsed) elif isinstance(self._current_frame, OrderFrame): reply = self._handle_order_frame(parsed) else: # if current frame is still None, could not determine user intention reply = "Sorry, I did not understand that, can you say that again?" self._say(reply) # if frame is not over yet, save current reply for later use if self._current_frame is not None: # self._current_frame.set_last_sentence(reply) self._set_last_sentence() # if older frame stored, restore it # and announce that bot is going back to older frame if self._current_frame is None and len(self._frame_stack) > 0: self._current_frame = self._frame_stack.pop(0) if isinstance(self._current_frame, AddInfoFrame): self._say("Ok now back to your statement") elif isinstance(self._current_frame, AskInfoFrame): self._say("Ok now back to your question") elif isinstance(self._current_frame, OrderFrame): self._say("Ok now back to your order") if self._current_frame.get_last_sentence() is not None: self._say(self._current_frame.get_last_sentence()) def _determine_frame(self, parsed): """ Determines the user intention based upon the parsed command and returns the appropriate frame to handle it :param parsed: parsed command (spacy tree) :return: appropriate frame """ # if command is a question, then user is asking info if is_question(parsed): return AskInfoFrame() # otherwise, count the number of frame triggers for each frame triggers_counts = self._count_frame_triggers(parsed) # could not determine frame if all([v == 0 for v in triggers_counts.values()]): return None # return the frame with the majority of triggers # MIGHT NOT BE THE BEST METHOD frame_name = max(triggers_counts, key=triggers_counts.get) if frame_name == "EndFrame": return EndFrame() elif frame_name == "OrderFrame": return OrderFrame() elif frame_name == "AddInfoFrame": return AddInfoFrame() elif frame_name == "AskInfoFrame": return AskInfoFrame() def _count_frame_triggers(self, parsed): """ Counts the number of keywords for each frame triggered by the given parsed command :param parsed: parsed command :return: a dictionary {frame_name: triggers_count} """ # setup return object res = { "EndFrame": 0, "OrderFrame": 0, "AddInfoFrame": 0, "AskInfoFrame": 0 } # visit tree breadth-first, adding up the triggers along the way nodes = [parsed.root] visited = [] while nodes: node = nodes.pop(0) visited.append(node) if EndFrame.is_trigger(node.lemma_, node.dep_): res["EndFrame"] += 1 if OrderFrame.is_trigger(node.lemma_, node.dep_): res["OrderFrame"] += 1 if AddInfoFrame.is_trigger(node.lemma_, node.dep_): res["AddInfoFrame"] += 1 if AskInfoFrame.is_trigger(node.lemma_, node.dep_): res["AskInfoFrame"] += 1 for child in node.children: if not child in visited: nodes.append(child) return res def _add_menu_entry(self, name, course=None): """ Adds an entry to the bot's menu to choose from :param name: name of the entry (e.g. hamburger) :param course: name of the course (optional, e.g. main course) :return: None """ # consistency checks if self._get_menu_entry(name) is not None: raise EntryAlreadyOnMenu() if course is not None and course not in courses_names: raise CourseNotValid() self._menu["entries"].append({"name": name, "course": course}) def _update_menu_entry(self, name, course=None): """ Updates a menu entry (mainly adding info about course, but can be extended later on if needed) :param name: entry name :param course: course of the entry (e.g. drink) :return: None """ # consistency checks if course is not None and course not in courses_names: raise CourseNotValid() entry = self._get_menu_entry(name) if entry is None: raise EntryNotOnMenu() if entry["course"] is not None: raise EntryAttributeAlreadySet() # update entry for i, entry in enumerate(self._menu["entries"]): if entry["name"] == name: self._menu["entries"][i].update({ "name": name, "course": course }) def _get_menu_entry(self, name): """ Searches the given entry in the bot menu :param name: entry name :return: entry, None if absent """ for i, entry in enumerate(self._menu["entries"]): if entry["name"] == name: return self._menu["entries"][i] return None def _handle_add_info_frame(self, parsed): """ Handles the current AddInfoFrame :param parsed: the parsed command :return: consistent reply """ # consistency check assert isinstance(self._current_frame, AddInfoFrame) # fill current frame slots based on the parsed command reply = "" self._fill_add_info_frame_slots(parsed) # based on the frame slots, handle command if self._current_frame.get_slot("subj") == "menu": # add entry to menu try: entry = self._current_frame.get_slot("obj") self._add_menu_entry(entry) if self._current_frame.get_slot("info") is None: reply = "Ok. What course is it?" self._current_frame.set_waiting_answer(True) else: course = self._current_frame.get_slot("info") self._update_menu_entry(entry, course) reply = "Ok" self._current_frame = None except EntryAlreadyOnMenu: reply = "This entry is already in the menu" self._current_frame = None elif self._current_frame.get_slot("subj") == "course": # add info about course entry = self._current_frame.get_slot("obj") course = self._current_frame.get_slot("info") try: self._update_menu_entry(entry, course) reply = "Ok" self._current_frame = None except EntryAttributeAlreadySet: # TODO: add option to modify entry reply = "{} is already a {}".format( entry, self._get_menu_entry(entry)["course"]) except EntryNotOnMenu: # TODO: add option to add entry reply = "I am sorry, {} is not on the menu".format(entry) except CourseNotValid: reply = "I am sorry, {} is not a course".format(course) return reply def _fill_add_info_frame_slots(self, parsed): """ Fills slots of the current AddInfoFrame based on the information contained in the given parsed command :param parsed: parsed command :return: None """ root_lemma = parsed.root.lemma_ pobj_lemma = obtain_lemma(find_dep(parsed, "pobj")) if root_lemma == "add" or pobj_lemma == "menu": # user wants to add entry to menu # TODO: allow to add entry and specify course at the same time self._current_frame.fill_slot("subj", "menu") entry = obtain_text(find_dep(parsed, "dobj")) self._current_frame.fill_slot("obj", entry) if pobj_lemma in courses_names: # user has also specified course self._current_frame.fill_slot("info", pobj_lemma) elif root_lemma == "is": # user wants to add info about course self._current_frame.fill_slot("subj", "course") entry = obtain_text(find_dep(parsed, "nsubj")) self._current_frame.fill_slot("obj", entry) course = obtain_lemma(find_dep(parsed, "attr")) self._current_frame.fill_slot("info", course) elif self._current_frame.is_waiting_answer(): # user has responded to a previous question from the bot # (up to now, that might be only to add info about course of added entry) root_lemma = obtain_lemma(find_dep(parsed, "ROOT")) attr = obtain_lemma(find_dep(parsed, "attr")) course = root_lemma if root_lemma in courses_names else attr self._current_frame.fill_slot("subj", "course") self._current_frame.fill_slot("info", course) def _handle_ask_info_frame(self, parsed): """ Handles the current AskInfoFrame :param parsed: the parsed command :return: consistent reply """ # consistency check assert isinstance(self._current_frame, AskInfoFrame) # if nothing to ask about... if len(self._menu["entries"]) == 0: reply = "I am sorry, there is nothing on menu today. " \ "Try and add something or load the stored menu first." self._current_frame = None return reply # perform slot filling of current frame self._fill_ask_info_frame_slots(parsed) subj = self._current_frame.get_slot("subj") if subj == "menu": # if asked to see the menu # tell menu (entry, course) for each entry in menu reply = "We have:" for course in courses_names: if len([ entry for entry in self._menu["entries"] if entry["course"] == course ]) == 0: continue for entry in self._menu["entries"]: if entry["course"] == course: reply = f"{reply} {entry['name']}," reply = reply[:-1] reply = f"{reply} for {course};" reply = reply[:-1] else: # if asked about a particular course # tell menu (entry, course) for each entry in menu if course == obj obj = self._current_frame.get_slot("obj") if obj in courses_names: reply = "" for entry in self._menu["entries"]: if entry["course"] == obj: reply = f"{reply} {entry['name']}," if len(reply) == "": reply = f"I'm sorry, we don't have anything for {obj}" else: reply = f"We have{reply[:-1]}" else: # the slot filling went wrong reply = "Sorry, I am not sure I understood your question" self._current_frame = None return reply def _fill_ask_info_frame_slots(self, parsed): """ Fills slots of the current AskInfoFrame based on the information contained in the given parsed command :param parsed: parsed command :return: None """ obj_lemma = obtain_lemma(find_dep(parsed, "dobj")) pobj_lemma = obtain_lemma(find_dep(parsed, "pobj")) if (obj_lemma is not None and obj_lemma == "menu") or \ (pobj_lemma is not None and pobj_lemma == "menu"): # user has asked to know the menu self._current_frame.fill_slot("subj", "menu") else: # user has asked to know a course in particular self._current_frame.fill_slot("subj", "course") # to handle different possible phrasings of the question if obj_lemma is not None and obj_lemma in courses_names: self._current_frame.fill_slot("obj", obj_lemma) elif pobj_lemma is not None and pobj_lemma in courses_names: self._current_frame.fill_slot("obj", pobj_lemma) def _handle_order_frame(self, parsed): """ Handles the current OrderFrame :param parsed: the parsed command :return: consistent reply """ # consistency check assert isinstance(self._current_frame, OrderFrame) # if nothing to order... if len(self._menu["entries"]) == 0: reply = "I am sorry, there is nothing on menu today. " \ "Try and add something or load the stored menu first." self._current_frame = None return reply # try to perform slot filling try: self._fill_order_frame_slots(parsed) except EntryNotOnMenu: reply = "I am sorry, that is not on the menu" return reply # if first interaction and user did not specified anything if len(self._current_frame.filled_slots()) == 0: # if user asked for order recap if self._current_frame.get_asked_recap(): reply = "You did not order anything yet, sir. " \ "I am ready to take your order" else: # user just said something like "i am ready to order" reply = "I am ready to take your order" else: # ongoing interaction if self._current_frame.get_asked_recap(): reply = self._recap_order() self._current_frame.set_asked_recap(False) reply = f"{reply}. Would you like to add something else?" self._current_frame.set_waiting_confirmation(True) elif self._current_frame.is_waiting_confirmation() and \ self._current_frame.get_user_answer() == "yes": # user said he wants something else reply = "Ok, please tell me" self._current_frame.set_waiting_confirmation(False) elif len(self._current_frame.unfilled_slots()) == 0 or \ (self._current_frame.is_waiting_confirmation() and self._current_frame.get_user_answer() == "no"): # user has made a full order or said he does not want anything else reply = "Ok. Your order is complete. It will come right away. Enjoy!" self._current_frame.set_waiting_confirmation(False) self._current_frame = None else: # user has added an entry to the order reply = "Ok. Do you want anything else?" self._current_frame.set_waiting_confirmation(True) return reply def _fill_order_frame_slots(self, parsed): """ Fills slots of the current OrderInfoFrame based on the information contained in the given parsed command :param parsed: parsed command :return: None """ # get needed sentence parts to determine user intention root_lemma = parsed.root.lemma_ xcomp_lemma = obtain_lemma(find_dep(parsed, "xcomp")) dobj_lemma = obtain_lemma(find_dep(parsed, "dobj")) dobj_text = obtain_text(find_dep(parsed, "dobj")) # need text for entry names advmod_lemma = obtain_lemma(find_dep(parsed, "advmod")) intj_lemma = obtain_lemma(find_dep(parsed, "intj")) det_lemma = obtain_lemma(find_dep(parsed, "det")) if self._current_frame.is_waiting_confirmation(): # if bot is waiting for a binary answer ("do you want anything else?") if (root_lemma == "no" or intj_lemma == "no" or det_lemma == "no") \ and \ (root_lemma != "have" and root_lemma != "like" and root_lemma != "take"): # user does not want anything else self._current_frame.set_user_answer("no") return elif (root_lemma == "yes" or intj_lemma == "yes") \ and \ (not OrderFrame.is_trigger(root_lemma, "ROOT")): # user wishes to keep on with his order self._current_frame.set_user_answer("yes") return else: # user did not give a straight answer self._current_frame.set_user_answer(None) elif xcomp_lemma is None and dobj_lemma is None: # user said gibberish (as far as the bot knows...) # best thing is to just say 'that is not on the menu' raise EntryNotOnMenu if dobj_lemma == "order" and advmod_lemma == "so far": # user has asked to recap his order so far self._current_frame.set_asked_recap(True) return if len(self._current_frame.filled_slots()) == 0 and \ xcomp_lemma == "order" and dobj_text is None: # user has just stated he is ready to order, # but has not ordered anything yet return if dobj_text is not None: # user has made an order for a menu entry, # add that to the current order if entry is on menu entry = self._get_menu_entry(dobj_text) if entry is None: raise EntryNotOnMenu() self._current_frame.fill_slot(entry["course"], entry["name"]) def _recap_order(self): """ Recaps the order made by the user so far :return: reply with the recap of the order """ # consistency check assert isinstance(self._current_frame, OrderFrame) reply = "You ordered:" for course in courses_names: order_entry = self._current_frame.get_slot(course) if order_entry is not None: reply = f"{reply} {order_entry} for {course}," reply = f"{reply[:-1]}" return reply def _set_last_sentence(self): if isinstance(self._current_frame, AskInfoFrame): return elif isinstance(self._current_frame, AddInfoFrame): return elif isinstance(self._current_frame, EndFrame): return elif isinstance(self._current_frame, OrderFrame): if len(self._current_frame.filled_slots()) == 0: self._current_frame.set_last_sentence( "I am ready to take your order") else: self._current_frame.set_last_sentence( "Would you like anything else?") self._current_frame.set_waiting_confirmation(True) def _welcome(self): """ Welcom message upon bot startup :return: welcome message """ self._is_over = False return "Hello, how may I help?" def _goodbye(self): """ Goodbye message upon bot termination :return: goodby message """ self._is_over = True return "Here's your bill. Goodbye!" def is_over(self): return self._is_over def _load_menu(self, path=None): """ Loads a menu :param path: menu path :return: None """ if path is None: menus = os.listdir("./menu") menus.sort() path = menus[-1] with open(f"./menu/{path}") as file: self._menu = json.load(file) def _save_menu(self): """ Saves the current menu on disk as a json file, at path timestamp_menu.json :return: None """ with open( f"./menu/{datetime.now().strftime('%Y%m%d-%H%M%S')}_menu.json", 'x') as f: json.dump(self._menu, f)
def receive(self, msg): self.recognizer.stop() # Pause Speech recognizer print('Callcenter receive msg : ' + msg) if KeywordProcessing.contains_keyword('exit', msg): self.answer = str('Do you want to exit.') self.state = State.EXIT_CONFIRM elif KeywordProcessing.contains_keyword('reset', msg): self.answer = str('How can i help you.') self.state = State.NORMAL elif KeywordProcessing.contains_keyword('operator', msg): self.answer = str('Do you want to talk to operator.') self.state = State.TALK_TO_OPERATOR elif self.state == State.NORMAL: # Package category if KeywordProcessing.contains_keyword('package', msg): # Recommend package if KeywordProcessing.contains_keyword('package_category', msg): package_category = [c for c in KeywordProcessing.keywords['package_category'] if c in msg][0] # Find interesting packages if self.user_account.package.payment == 'prepaid': self.recommend_packages = Database.find_list('prepaids', 'type', package_category) else: self.recommend_packages = Database.find_list('postpaids', 'type', package_category) # Generate answer self.answer = str('We recommend %d packages for you. ' % len(self.recommend_packages)) index = 1 for package in self.recommend_packages: self.answer += str('package number %d %s . ' % (index, package.name)) index += 1 self.answer += str('Which one you want to have a detail. Or you want to listen again.') self.state = State.SELECT_PACKAGE # Change state # Current package else: self.answer = str('Your current package is %s' % self.user_account.package.description()) self.state = State.REPEAT # Change state # How to elif KeywordProcessing.contains_keyword('how_to', msg): if KeywordProcessing.contains_keyword('topup', msg): self.answer = str('Please select your topup method. Online or phone.') self.state = State.SELECT_TOPUP_METHOD elif KeywordProcessing.contains_keyword('pay', msg): self.answer = str('Please select your payment method. Online or phone.') self.state = State.SELECT_PAYMENT_METHOD elif KeywordProcessing.contains_keyword('setup', msg): self.answer = str('What is your operating system.') self.state = State.SELECT_PHONE_OS # Bill category elif KeywordProcessing.contains_keyword('balance', msg) or KeywordProcessing.contains_keyword('expire', msg): if self.user_account.package.payment == 'postpaid': self.answer = str('Sorry, I don\'t understand your question') elif KeywordProcessing.contains_keyword('balance', msg): self.answer = self.user_account.report() self.state = State.REPEAT elif KeywordProcessing.contains_keyword('expire', msg): self.answer = str('Your account will expire on %s %s %s.' % (self.user_account.expiration_date.strftime('%d'), self.user_account.expiration_date.strftime('%B'), self.user_account.expiration_date.strftime('%Y'))) self.state = State.REPEAT elif KeywordProcessing.contains_keyword('bill', msg): if self.user_account.package.payment == 'postpaid': if KeywordProcessing.contains_keyword('unpaid', msg): all_bills = Database.find_list('bills', 'customer', ObjectId(self.current_user.id)) unpaid_bills = [bill for bill in all_bills if not bill.paid] if(len(unpaid_bills) > 0): self.answer = str('You have %d bills unpaid.' % len(unpaid_bills)) else: self.answer = str('You don\' have any unpaid bill.') elif KeywordProcessing.contains_keyword('how_to', msg) and KeywordProcessing.contains_keyword('pay', msg): self.answer = str('Please select your payment method. Online or phone.') self.state = State.SELECT_PAYMENT_METHOD elif KeywordProcessing.contains_keyword('when', msg): self.answer = str('Your bill is due on %d %s.' % (self.user_account.payment_date.strftime('%d'), self.user_account.payment_date.strftime('%B'))) else: self.answer = self.user_account.report() self.state = State.REPEAT else: self.answer = str('Sorry, I don\'t understand your question') # Troubleshooting elif KeywordProcessing.contains_keyword('cannot', msg): # Prepaid user if self.user_account.package.payment == 'prepaid': if KeywordProcessing.contains_keyword('internet', msg): if not self.user_account.package.is_internet_avail(): self.answer = str('Sorry, your current package is not support internet using.') else: self.answer = str('Sorry, i can\'t find any problem in your account. Do you want to talk to the operator.') self.state = State.TALK_TO_OPERATOR elif KeywordProcessing.contains_keyword('call', msg): if self.user_account.balance <= self.user_account.package.internal_calling_rate: self.answer = str('Sorry, your current balance is not enough.') else: self.answer = str('Sorry, i can\'t find any problem in your account. Do you want to talk to the operator.') self.state = State.TALK_TO_OPERATOR #Postpaid user else: if KeywordProcessing.contains_keyword('internet', msg): if not self.user_account.package.is_internet_avail(): self.answer = str('Sorry, your current package is not support internet using.') elif len([bill for bill in Database.find_list('bills', 'customer', self.current_user.id) if not bill.paid]) > 3: self.answer = str('Sorry, your account was suspended because you haven\'t pay monthly fee.') else: self.answer = str('Sorry, i can\'t find any problem in your account. Do you want to talk to the operator.') self.state = State.TALK_TO_OPERATOR elif KeywordProcessing.contains_keyword('call', msg): if self.user_account.package.payment == 'postpaid' and len([bill for bill in Database.find_list('bills', 'customer', self.current_user.id) if not bill.paid]) > 3: self.answer = str('Sorry, your account was suspended because you haven\'t pay monthly fee.') else: self.answer = str('Sorry, i can\'t find any problem in your account. Do you want to talk to the operator.') self.state = State.TALK_TO_OPERATOR elif self.state == State.REPEAT: # Repeat if KeywordProcessing.contains_keyword('confirm', msg): pass # Back to normal elif KeywordProcessing.contains_keyword('cancel', msg): self.answer = 'How can i help you.' self.state = State.NORMAL elif self.state == State.SELECT_PACKAGE: # Repeat if KeywordProcessing.contains_keyword('confirm', msg): pass elif KeywordProcessing.contains_keyword('cancel', msg): self.answer = 'How can i help you.' self.state = State.NORMAL # Explain user's interesting package detail elif KeywordProcessing.contains_keyword('ordinal', msg) and KeywordProcessing.get_index(msg) - 1 < len(self.recommend_packages): index = KeywordProcessing.get_index(msg) - 1 self.interesting_package = self.recommend_packages[index] self.answer = str(self.interesting_package.description()) self.answer += str(' Do you want to use this package.') self.state = State.CHANGE_PACKAGE else: self.answer = str('Sorry, i don\'t understand.') elif self.state == State.CHANGE_PACKAGE: if KeywordProcessing.contains_keyword('confirm', msg): if self.user_account.package.payment == 'prepaid': # Change package of account Database.update('accounts', 'customer', self.current_user.id, 'package', self.interesting_package.id) elif self.user_account.package.payment == 'postpaid': # Create new bill new_bill = Bill(self.current_user, self.interesting_package, 0, 0, 0, 0, datetime.datetime.now(), 0) Database.insert('bills', new_bill.tojson()) self.answer = 'package changing is complete.' # Get new user account self.user_account = Database.find_user_account(self.current_user.id) self.state = State.NORMAL elif KeywordProcessing.contains_keyword('cancel', msg): self.answer = 'How can i help you.' self.state = State.NORMAL else: self.answer = str('Sorry, i don\'t understand.') elif self.state == State.SELECT_PHONE_OS: if KeywordProcessing.contains_keyword('phone_os', msg): self.answer = Database.find_one('setups', 'os', msg).setup self.state = State.REPEAT else: self.answer = str('Sorry, we cannot find your operating system.') elif self.state == State.SELECT_PAYMENT_METHOD: if KeywordProcessing.contains_keyword('payment_method', msg): self.answer = Database.find_one('how_to_pays', 'method', msg).step self.state = State.REPEAT else: self.answer = str('Sorry, your payment method is not available.') elif self.state == State.SELECT_TOPUP_METHOD: if KeywordProcessing.contains_keyword('payment_method', msg): self.answer = Database.find_one('how_to_topups', 'method', msg).step self.state = State.REPEAT else: self.answer = str('Sorry, your payment method is not available.') elif self.state == State.TALK_TO_OPERATOR: if KeywordProcessing.contains_keyword('confirm', msg): self.answer = str('Transfer to operator. please wait for seconds.') elif KeywordProcessing.contains_keyword('cancel', msg): self.answer = str('How can i help you.') self.state = State.NORMAL elif self.state == State.EXIT_CONFIRM: if KeywordProcessing.contains_keyword('confirm', msg): self.answer = str('Thank you for using our service') self.state = State.EXIT self.recognizer.shutdown() elif KeywordProcessing.contains_keyword('cancel', msg): self.answer = str('How can i help you') self.state = State.NORMAL if self.answer is not None: Speaker.speak(self.answer) if self.state == State.REPEAT: Speaker.speak('Do you want to listen again.') self.recognizer.resume() # Resume Speech recognizer
class ClockActivity(activity.Activity): """The clock activity displays a simple clock widget. """ def __init__(self, handle): """Create and initialize the clock activity. """ super(ClockActivity, self).__init__(handle) # TRANS: Title of the activity self.set_title(_('What Time Is It?')) # TRANS: The format used when writing the time in full # letters. You must take care to use a font size large enough # so that kids can read it easily, but also small enough so # that all times combination fit on the screen, even when the # screen is rotated. Pango markup: # http://www.pygtk.org/docs/pygtk/pango-markup-language.html self._TIME_LETTERS_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">%s</span></markup>') # TRANS: The format used to display the weekday and date # (example: Tuesday 10/21/2008) We recommend to use the same # font size as for the time display. See # http://docs.python.org/lib/module-time.html for available # strftime formats. xgettext:no-python-format self._DATE_SHORT_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">\ <span foreground="#B20008">%A</span>, \ <span foreground="#5E008C">%m</span>/\ <span foreground="#B20008">%d</span>/\ <span foreground="#9A5200">%Y</span></span></markup>') # Should we write the time in full letters? self._time_writer = None self._time_in_letters = self.get_title() self._time_letters = None self._date = None self._time_speaker = None self._write_time = False self._speak_time = False self._write_date = False self._display_mode_buttons = [] self._ntp_process = None self._make_display() self._make_toolbars() # Show the activity on the screen self.show_all() # We want to be notified when the minutes change self._clock.connect("time_minute", self._minutes_changed_cb) if not self.powerd_running(): try: bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.ohm', '/org/freedesktop/ohm/Keystore') self.ohm_keystore = dbus.Interface( proxy, 'org.freedesktop.ohm.Keystore') except dbus.DBusException: self.ohm_keystore = None def write_file(self, file_path): self.metadata['write-time'] = str(self._write_time) self.metadata['write-date'] = str(self._write_date) self.metadata['speak-time'] = str(self._speak_time) self.metadata['clock-mode'] = str(self._clock._mode) logging.debug( 'Saving metadata %s', (self.metadata['write-time'], self.metadata['write-date'], self.metadata['speak-time'], self.metadata['clock-mode'])) # Need write a empty file or the read_file is not called with open(file_path, 'w') as data: data.write('') def read_file(self, file_path): logging.debug( 'Reading metadata %s', (self.metadata['write-time'], self.metadata['write-date'], self.metadata['speak-time'], self.metadata['clock-mode'])) if 'clock-mode' not in self.metadata.keys(): display_mode = _MODE_SIMPLE_CLOCK else: display_mode = int(self.metadata['clock-mode']) if 'write-time' in self.metadata.keys(): self._write_time = str(self.metadata['write-time']) == 'True' if 'speak-time' in self.metadata.keys(): self._speak_time = str(self.metadata['speak-time']) == 'True' if 'write-date' in self.metadata.keys(): self._write_date = str(self.metadata['write-date']) == 'True' logging.debug('Read values %s', (self._write_time, self._speak_time, self._write_date, display_mode)) # apply the changes in the UI self._display_mode_buttons[display_mode].set_active(True) self._write_time_btn.set_active(self._write_time) self._write_date_btn.set_active(self._write_date) self._speak_time_btn.set_active(self._speak_time) def powerd_running(self): self.using_powerd = os.access(POWERD_INHIBIT_DIR, os.W_OK) return self.using_powerd def _inhibit_suspend(self): if self.using_powerd: fd = open(POWERD_INHIBIT_DIR + "/%u" % os.getpid(), 'w') fd.close() return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 1) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _allow_suspend(self): if self.using_powerd: os.unlink(POWERD_INHIBIT_DIR + "/%u" % os.getpid()) return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 0) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _make_toolbars(self): """Prepare and set the toolbars of the activity. Load and show icons. Associate them to the call back methods. """ self.max_participants = 1 toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_button.show() toolbar_box.toolbar.insert(activity_button, 0) self._add_clock_controls(toolbar_box.toolbar) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_size_request(0, -1) separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) toolbar_box.toolbar.insert(StopButton(self), -1) self.set_toolbar_box(toolbar_box) toolbar_box.show_all() return toolbar_box def _add_clock_controls(self, display_toolbar): # First group of radio button to select the type of clock to display button1 = RadioToolButton(icon_name="simple-clock") button1.set_tooltip(_('Simple Clock')) button1.connect("toggled", self._display_mode_changed_cb, _MODE_SIMPLE_CLOCK) display_toolbar.insert(button1, -1) self._display_mode_buttons.append(button1) button2 = RadioToolButton(icon_name="nice-clock", group=button1) button2.set_tooltip(_('Nice Clock')) button2.connect("toggled", self._display_mode_changed_cb, _MODE_NICE_CLOCK) display_toolbar.insert(button2, -1) self._display_mode_buttons.append(button2) button3 = RadioToolButton(icon_name="digital-clock", group=button1) button3.set_tooltip(_('Digital Clock')) button3.connect("toggled", self._display_mode_changed_cb, _MODE_DIGITAL_CLOCK) display_toolbar.insert(button3, -1) self._display_mode_buttons.append(button3) # A separator between the two groups of buttons self._add_separator(display_toolbar) # Now the options buttons to display other elements: date, day # of week... A button in the toolbar to write the time in # full letters self._write_time_btn = ToggleToolButton("write-time") self._write_time_btn.set_tooltip(_('Display time in full letters')) self._write_time_btn.connect("toggled", self._write_time_clicked_cb) display_toolbar.insert(self._write_time_btn, -1) # The button to display the weekday and date self._write_date_btn = ToggleToolButton("write-date") self._write_date_btn.set_tooltip(_('Display weekday and date')) self._write_date_btn.connect("toggled", self._write_date_clicked_cb) display_toolbar.insert(self._write_date_btn, -1) # Another button to speak aloud the time self._speak_time_btn = ToggleToolButton("microphone") self._speak_time_btn.set_tooltip(_('Talking clock')) self._speak_time_btn.connect("toggled", self._speak_time_clicked_cb) display_toolbar.insert(self._speak_time_btn, -1) # A separator between the two groups of buttons self._add_separator(display_toolbar) # And another button to toggle grabbing the hands self._grab_button = ToggleToolButton("grab") self._grab_button.set_tooltip(_('Grab the hands')) self._grab_button.connect("toggled", self._grab_clicked_cb) display_toolbar.insert(self._grab_button, -1) if os.access('/boot/olpc_build', os.R_OK) and \ os.access('/usr/sbin/ntpdate', os.R_OK): self._add_separator(display_toolbar) self._ntp_button = ProgressToolButton("emblem-downloads", style.STANDARD_ICON_SIZE, 'vertical') self._ntp_button.set_tooltip(_('Download time')) self._ntp_button.connect("clicked", self._ntp_clicked_cb) self._ntp_button.update(0.05) display_toolbar.insert(self._ntp_button, -1) def _add_separator(self, display_toolbar): separator = Gtk.SeparatorToolItem() separator.set_draw(True) display_toolbar.insert(separator, -1) def _make_display(self): """Prepare the display of the clock. The display has two parts: the clock face at the top, and the time in full letters at the bottom, when the user selects to show it. """ # The clock face self._clock = ClockFace() # The label to print the time in full letters self._time_letters = Gtk.Label() self._time_letters.set_no_show_all(True) # Following line in ineffective! # self._time_letters.set_line_wrap(True) # Resize the invisible label so that Gtk will know in advance # the height when we show it. self._time_letters.set_markup(self._TIME_LETTERS_FORMAT % self._time_in_letters) # The label to write the date self._date = Gtk.Label() self._date.set_no_show_all(True) self._date.set_markup(self._clock.get_time().strftime( self._DATE_SHORT_FORMAT)) # Put all these widgets in a vertical box vbox = Gtk.VBox() vbox.pack_start(self._clock, True, True, 0) vbox.pack_start(self._time_letters, False, False, 0) vbox.pack_start(self._date, False, False, 0) # Attach the display to the activity self.set_canvas(vbox) self._clock.active = True def _write_date_clicked_cb(self, button): """The user clicked on the "write date" button to display the current weekday and date. """ self._write_date = button.get_active() if button.get_active(): self._date.show() else: self._date.hide() def _display_mode_changed_cb(self, radiobutton, display_mode): """The user selected a clock display mode (simple clock, nice or digital). """ self._clock.set_display_mode(display_mode) self._clock.queue_draw() is_digital = display_mode == _MODE_DIGITAL_CLOCK # Exit grab hands mode if the clock is digital if self._clock.grab_hands_mode and is_digital: self._grab_button.set_active(False) # The hands can't be grabbed in the digital clock mode self._grab_button.props.sensitive = not is_digital def _write_time_clicked_cb(self, button): """The user clicked on the "write time" button to print the current time. """ self._write_time = button.get_active() if self._write_time: self._time_letters.show() self._write_and_speak(False) else: self._time_letters.hide() def _speak_time_clicked_cb(self, button): """The user clicked on the "speak time" button to hear the talking clock. """ self._speak_time = button.get_active() self._write_and_speak(self._speak_time) def _grab_clicked_cb(self, button): """The user clicked on the "grab hands" button to toggle grabbing the hands. """ self._clock.change_grab_hands_mode(button.get_active()) def _minutes_changed_cb(self, clock): """Minutes have changed on the clock face: we have to update the display of the time in full letters if the user has chosen to have it and eventually croak the time. """ # Change time display and talk, if necessary self._write_and_speak(True) # Update the weekday and date in case it was midnight self._date.set_markup(clock.get_time().strftime( self._DATE_SHORT_FORMAT)) def _notify_active_cb(self, widget, event): """Sugar notify us that the activity is becoming active or inactive. When we are inactive, we change the activity status of the clock face widget, so that it can stop updating every seconds. """ self._clock.active = self.props.active if self.props.active: self._inhibit_suspend() else: self._allow_suspend() def _write_and_speak(self, speak): # Only update the time in full letters when necessary if self._write_time or self._speak_time: self._do_write_time() # And if requested, say it aloud if self._speak_time and speak: GObject.idle_add(self._do_speak_time) def _do_write_time(self): """Translate the time to full letters. """ if self._time_writer is None: self._time_writer = TimeWriter() hour = self._clock.get_time().hour minute = self._clock.get_time().minute self._time_in_letters = self._time_writer.write_time(hour, minute) self._time_letters.set_markup(self._TIME_LETTERS_FORMAT % self._time_in_letters) def _do_speak_time(self): """Speak aloud the current time. """ if self._time_speaker is None: self._time_speaker = Speaker() self._time_speaker.speak(self._untag(self._time_in_letters)) def _untag(self, text): """Remove all the tags (pango markup) from a text. """ if text is False or "<" not in text: return text else: result = "" for s in re.findall(r"(<.*?>)|([^<>]+)", text): result += s[1] return result def _ntp_clicked_cb(self, button): if self._ntp_process: return args = ["su", "-c", "/usr/sbin/ntpdate -u pool.ntp.org"] self._ntp_process = subprocess.Popen(args, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._ntp_counter = 0 GObject.timeout_add(100, self._ntpdate_poll_cb) button.update(0.1) button.set_tooltip(_('Download time began')) def _ntpdate_poll_cb(self): if self._ntp_process.poll() is None: self._ntp_counter += 1 self._ntp_button.update(0.1 + (self._ntp_counter / 90.0)) return True if self._ntp_process.returncode: data = self._ntp_process.communicate() logging.error('Download time failed (%d), %r', self._ntp_process.returncode, repr(data)) self._ntp_button.update(0.05) self._ntp_button.set_tooltip( _('Download time failed (%d)') % self._ntp_process.returncode) return False args = ["su", "-c", "/usr/sbin/hwclock --systohc"] self._ntp_process = subprocess.Popen(args, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._ntp_counter = 0 GObject.timeout_add(100, self._hwclock_poll_cb) return False def _hwclock_poll_cb(self): if self._ntp_process.poll() is None: self._ntp_counter += 1 self._ntp_button.update(0.1 + (self._ntp_counter / 20.0)) self._ntp_button.set_tooltip(_('Setting time in progress')) return True if self._ntp_process.returncode: data = self._ntp_process.communicate() logging.error('Setting time failed (%d), %r', self._ntp_process.returncode, repr(data)) self._ntp_button.update(1.0) self._ntp_button.set_tooltip(_('Download time done')) GObject.timeout_add(1000, self._ntp_disable_cb) return False def _ntp_disable_cb(self): self._ntp_button.update(0.0) self._ntp_button.set_sensitive(False) return False
from speaker import Speaker # This is just to test my custom class from speaker # I keep it because it's a milestone for me my_speak = Speaker() my_speak.speak('f yeah') my_speak.speak('I love this') my_speak.change_rate('175') my_speak.speak('f yeah') my_speak.speak('I love this') my_speak.change_voice('Fred') my_speak.speak('f yeah') my_speak.speak('I love this') my_speak.speak("I don't know")
class ClockActivity(activity.Activity): """The clock activity displays a simple clock widget. """ def __init__(self, handle): """Create and initialize the clock activity. """ super(ClockActivity, self).__init__(handle) # TRANS: Title of the activity self.set_title(_('What Time Is It?')) # TRANS: The format used when writing the time in full # letters. You must take care to use a font size large enough # so that kids can read it easily, but also small enough so # that all times combination fit on the screen, even when the # screen is rotated. Pango markup: # http://www.pygtk.org/docs/pygtk/pango-markup-language.html self._TIME_LETTERS_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">%s</span></markup>') # TRANS: The format used to display the weekday and date # (example: Tuesday 10/21/2008) We recommend to use the same # font size as for the time display. See # http://docs.python.org/lib/module-time.html for available # strftime formats. xgettext:no-python-format self._DATE_SHORT_FORMAT = _('<markup>\ <span lang="en" font_desc="Sans 20">\ <span foreground="#B20008">%A</span>, \ <span foreground="#5E008C">%m</span>/\ <span foreground="#B20008">%d</span>/\ <span foreground="#9A5200">%Y</span></span></markup>') # Should we write the time in full letters? self._time_writer = None self._time_in_letters = self.get_title() self._time_letters = None self._date = None self._time_speaker = None self._write_time = False self._speak_time = False self._write_date = False self._display_mode_buttons = [] self._make_display() self._make_toolbars() # Show the activity on the screen self.show_all() # We want to be notified when the minutes change self._clock.connect("time_minute", self._minutes_changed_cb) if not self.powerd_running(): try: bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.ohm', '/org/freedesktop/ohm/Keystore') self.ohm_keystore = dbus.Interface( proxy, 'org.freedesktop.ohm.Keystore') except dbus.DBusException: self.ohm_keystore = None def write_file(self, file_path): self.metadata['write-time'] = str(self._write_time) self.metadata['write-date'] = str(self._write_date) self.metadata['speak-time'] = str(self._speak_time) self.metadata['clock-mode'] = str(self._clock._mode) logging.debug('Saving metadata %s', (self.metadata['write-time'], self.metadata['write-date'], self.metadata['speak-time'], self.metadata['clock-mode'])) # Need write a empty file or the read_file is not called with open(file_path, 'w') as data: data.write('') def read_file(self, file_path): logging.debug('Reading metadata %s', (self.metadata['write-time'], self.metadata['write-date'], self.metadata['speak-time'], self.metadata['clock-mode'])) if 'clock-mode' not in self.metadata.keys(): display_mode = _MODE_SIMPLE_CLOCK else: display_mode = int(self.metadata['clock-mode']) if 'write-time' in self.metadata.keys(): self._write_time = str(self.metadata['write-time']) == 'True' if 'speak-time' in self.metadata.keys(): self._speak_time = str(self.metadata['speak-time']) == 'True' if 'write-date' in self.metadata.keys(): self._write_date = str(self.metadata['write-date']) == 'True' logging.debug('Read values %s', (self._write_time, self._speak_time, self._write_date, display_mode)) # apply the changes in the UI self._display_mode_buttons[display_mode].set_active(True) self._write_time_btn.set_active(self._write_time) self._write_date_btn.set_active(self._write_date) self._speak_time_btn.set_active(self._speak_time) def powerd_running(self): self.using_powerd = os.access(POWERD_INHIBIT_DIR, os.W_OK) return self.using_powerd def _inhibit_suspend(self): if self.using_powerd: fd = open(POWERD_INHIBIT_DIR + "/%u" % os.getpid(), 'w') fd.close() return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 1) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _allow_suspend(self): if self.using_powerd: os.unlink(POWERD_INHIBIT_DIR + "/%u" % os.getpid()) return True if self.ohm_keystore is not None: try: self.ohm_keystore.SetKey('suspend.inhibit', 0) return self.ohm_keystore.GetKey('suspend.inhibit') except dbus.exceptions.DBusException: return False else: return False def _make_toolbars(self): """Prepare and set the toolbars of the activity. Load and show icons. Associate them to the call back methods. """ self.max_participants = 1 toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_button.show() toolbar_box.toolbar.insert(activity_button, 0) self._add_clock_controls(toolbar_box.toolbar) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_size_request(0, -1) separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) toolbar_box.toolbar.insert(StopButton(self), -1) self.set_toolbar_box(toolbar_box) toolbar_box.show_all() return toolbar_box def _add_clock_controls(self, display_toolbar): # First group of radio button to select the type of clock to display button1 = RadioToolButton(icon_name="simple-clock") button1.set_tooltip(_('Simple Clock')) button1.connect("toggled", self._display_mode_changed_cb, _MODE_SIMPLE_CLOCK) display_toolbar.insert(button1, -1) self._display_mode_buttons.append(button1) button2 = RadioToolButton(icon_name="nice-clock", group=button1) button2.set_tooltip(_('Nice Clock')) button2.connect("toggled", self._display_mode_changed_cb, _MODE_NICE_CLOCK) display_toolbar.insert(button2, -1) self._display_mode_buttons.append(button2) button3 = RadioToolButton(icon_name="digital-clock", group=button1) button3.set_tooltip(_('Digital Clock')) button3.connect("toggled", self._display_mode_changed_cb, _MODE_DIGITAL_CLOCK) display_toolbar.insert(button3, -1) self._display_mode_buttons.append(button3) # A separator between the two groups of buttons separator = Gtk.SeparatorToolItem() separator.set_draw(True) display_toolbar.insert(separator, -1) # Now the options buttons to display other elements: date, day # of week... A button in the toolbar to write the time in # full letters self._write_time_btn = ToggleToolButton("write-time") self._write_time_btn.set_tooltip(_('Display time in full letters')) self._write_time_btn.connect("toggled", self._write_time_clicked_cb) display_toolbar.insert(self._write_time_btn, -1) # The button to display the weekday and date self._write_date_btn = ToggleToolButton("write-date") self._write_date_btn.set_tooltip(_('Display weekday and date')) self._write_date_btn.connect("toggled", self._write_date_clicked_cb) display_toolbar.insert(self._write_date_btn, -1) # Another button to speak aloud the time self._speak_time_btn = ToggleToolButton("microphone") self._speak_time_btn.set_tooltip(_('Talking clock')) self._speak_time_btn.connect("toggled", self._speak_time_clicked_cb) display_toolbar.insert(self._speak_time_btn, -1) # A separator between the two groups of buttons separator = Gtk.SeparatorToolItem() separator.set_draw(True) display_toolbar.insert(separator, -1) # And another button to toggle grabbing the hands self._grab_button = ToggleToolButton("grab") self._grab_button.set_tooltip(_('Grab the hands')) self._grab_button.connect("toggled", self._grab_clicked_cb) display_toolbar.insert(self._grab_button, -1) def _make_display(self): """Prepare the display of the clock. The display has two parts: the clock face at the top, and the time in full letters at the bottom, when the user selects to show it. """ # The clock face self._clock = ClockFace() # The label to print the time in full letters self._time_letters = Gtk.Label() self._time_letters.set_no_show_all(True) # Following line in ineffective! # self._time_letters.set_line_wrap(True) # Resize the invisible label so that Gtk will know in advance # the height when we show it. self._time_letters.set_markup( self._TIME_LETTERS_FORMAT % self._time_in_letters) # The label to write the date self._date = Gtk.Label() self._date.set_no_show_all(True) self._date.set_markup( self._clock.get_time().strftime(self._DATE_SHORT_FORMAT)) # Put all these widgets in a vertical box vbox = Gtk.VBox() vbox.pack_start(self._clock, True, True, 0) vbox.pack_start(self._time_letters, False, False, 0) vbox.pack_start(self._date, False, False, 0) # Attach the display to the activity self.set_canvas(vbox) self._clock.active = True def _write_date_clicked_cb(self, button): """The user clicked on the "write date" button to display the current weekday and date. """ self._write_date = button.get_active() if button.get_active(): self._date.show() else: self._date.hide() def _display_mode_changed_cb(self, radiobutton, display_mode): """The user selected a clock display mode (simple clock, nice or digital). """ self._clock.set_display_mode(display_mode) self._clock.queue_draw() is_digital = display_mode == _MODE_DIGITAL_CLOCK # Exit grab hands mode if the clock is digital if self._clock.grab_hands_mode and is_digital: self._grab_button.set_active(False) # The hands can't be grabbed in the digital clock mode self._grab_button.props.sensitive = not is_digital def _write_time_clicked_cb(self, button): """The user clicked on the "write time" button to print the current time. """ self._write_time = button.get_active() if self._write_time: self._time_letters.show() self._write_and_speak(False) else: self._time_letters.hide() def _speak_time_clicked_cb(self, button): """The user clicked on the "speak time" button to hear the talking clock. """ self._speak_time = button.get_active() self._write_and_speak(self._speak_time) def _grab_clicked_cb(self, button): """The user clicked on the "grab hands" button to toggle grabbing the hands. """ self._clock.change_grab_hands_mode(button.get_active()) def _minutes_changed_cb(self, clock): """Minutes have changed on the clock face: we have to update the display of the time in full letters if the user has chosen to have it and eventually croak the time. """ # Change time display and talk, if necessary self._write_and_speak(True) # Update the weekday and date in case it was midnight self._date.set_markup( clock.get_time().strftime(self._DATE_SHORT_FORMAT)) def _notify_active_cb(self, widget, event): """Sugar notify us that the activity is becoming active or inactive. When we are inactive, we change the activity status of the clock face widget, so that it can stop updating every seconds. """ self._clock.active = self.props.active if self.props.active: self._inhibit_suspend() else: self._allow_suspend() def _write_and_speak(self, speak): # Only update the time in full letters when necessary if self._write_time or self._speak_time: self._do_write_time() # And if requested, say it aloud if self._speak_time and speak: GObject.idle_add(self._do_speak_time) def _do_write_time(self): """Translate the time to full letters. """ if self._time_writer is None: self._time_writer = TimeWriter() hour = self._clock.get_time().hour minute = self._clock.get_time().minute self._time_in_letters = self._time_writer.write_time(hour, minute) self._time_letters.set_markup( self._TIME_LETTERS_FORMAT % self._time_in_letters) def _do_speak_time(self): """Speak aloud the current time. """ if self._time_speaker is None: self._time_speaker = Speaker() self._time_speaker.speak(self._untag(self._time_in_letters)) def _untag(self, text): """Remove all the tags (pango markup) from a text. """ if text is False or "<" not in text: return text else: result = "" for s in re.findall(r"(<.*?>)|([^<>]+)", text): result += s[1] return result