Beispiel #1
0
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.')
Beispiel #4
0
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()):
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #8
0
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
Beispiel #9
0
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")
Beispiel #10
0
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