예제 #1
0
    def cancel(self, schedule_id):
        """
        Cancel event scheduled with schedule
        :param schedule_id: id returned by schedule
        """
        spinner = SpinnerThread('Cancelling', 0.15)
        spinner.start()

        self.scheduler.cancel(schedule_id)

        spinner.stop()
        self.say('Cancellation successful', Fore.GREEN)
예제 #2
0
class JarvisAPI:
    """
    Jarvis interface for plugins.

    Plugins will receive a instance of this as the second (non-self) parameter
    of the exec()-method.

    Everything Jarvis-related that can't be implemented as a stateless-function
    in the utilities-package should be implemented here.
    """

    _CONNECTION_ERROR_MSG = "You are not connected to Internet"

    def __init__(self):
        self.spinner_running = False

        self.memory = Memory()
        self.scheduler = schedule.Scheduler()

        # Remember voice settings
        self.enable_voice = self.get_data('enable_voice')
        self.speech_rate = self.get_data('speech_rate')

        if not self.speech_rate:
            self.speech_rate = 120

        self.io = DummyIO()

        # what if the platform does not have any engines, travis doesn't have sapi5 acc to me
        try:
            gtts_status = self.get_data('gtts_status')
            self.speech = create_voice(self, gtts_status, rate=self.speech_rate)
        except Exception as e:
            self.say("Voice not supported", self, Fore.RED)
            self.say(str(e), self, Fore.RED)


    def say(self, text, color="", speak=True):
        """
        This method give the jarvis the ability to print a text
        and talk when sound is enable.
        :param text: the text to print (or talk)
        :param color: for text - use colorama (https://pypi.org/project/colorama/)
                      e.g. Fore.BLUE
        :param speak: False-, if text shouldn't be spoken even if speech is enabled
        """
        self.io.say(text, color)
        if speak:
            self._speak(text)

    def input(self, prompt="", color=""):
        """
        Get user input
        """
        self.io.input(prompt, color)

    def exit(self):
        """Immediately exit Jarvis"""
        self.io.exit()

    def _speak(self, text):
        if self.enable_voice:
            self.speech.text_to_speech(text)

    def input_number(self, prompt="", color="", rtype=float, rmin=None, rmax=None):
        """
        Get user input: As number.

        Guaranteed only returns number - ask user till correct number entered.

        :param prompt: Printed to console
        :param color: Color of prompot
        :param rtype: type of return value; e.g. float (default) or int
        :param rmin: Minum of values returned
        :param rmax: Maximum of values returned
        """
        while True:
            try:
                value = rtype(self.input(prompt, color).replace(',', '.'))
                if (rmin is not None and value < rmin) or (rmax is not None and value > rmax):
                    prompt = "Sorry, needs to be between {} and {}. Try again: ".format(rmin, rmax)
                else:
                    return value
            except ValueError:
                prompt = 'Sorry, needs to be a number. Try again: '
                continue

    def connection_error(self):
        """Print generic connection error"""

        if self.is_spinner_running():
            self.spinner_stop('')

        self.say(JarvisAPI._CONNECTION_ERROR_MSG)

    def notification(self, msg, time_seconds=0):
        """
        Sends notification msg in time_in milliseconds
        :param msg: Message. Either String (message body) or tuple (headline, message body)
        :param time_seconds: Time in seconds to wait before showing notification
        """
        if isinstance(msg, tuple):
            headline, message = msg
        elif isinstance(msg, str):
            headline = "Jarvis"
            message = msg
        else:
            raise ValueError("msg not a string or tuple")

        if time_seconds == 0:
            notify(headline, message)
        else:
            schedule(time_seconds, notify, headline, message)

    def schedule(self, time_seconds, function, *args):
        """
        Schedules function
        After time_seconds call function with these parameter:
           - reference to this JarvisAPI instance
           - schedule_id (return value of this function)
           - *args
        :return: integer, id - use with cancel
        """
        return self.scheduler.create_event(
            time_seconds, function, self, *args)

    def cancel(self, schedule_id):
        """
        Cancel event scheduled with schedule
        :param schedule_id: id returned by schedule
        """
        spinner = SpinnerThread('Cancelling', 0.15)
        spinner.start()

        self.scheduler.cancel(schedule_id)

        spinner.stop()
        self.say('Cancellation successful', Fore.GREEN)

    # Voice wrapper
    def enable_voice(self):
        """
        Use text to speech for every text passed to jarvis.say()
        """
        g = self.get_data('gtts_status')
        self.speech = create_voice(self, g, rate=120)
        self.enable_voice = True
        self.update_data('enable_voice', True)

    def disable_gtts(self):
        """
        Switch to default speech engine for every text passed to jarvis.say()
        """
        self.update_data('gtts_status', False)

    def enable_gtts(self):
        """
        Use google text to speech for every text passed to jarvis.say()
        """
        self.update_data('gtts_status', True)
        g = self.get_data('gtts_status')
        self.speech = create_voice(self, g, rate=120)

    def disable_voice(self):
        """
        Stop text to speech output & disable gtts for every text passed to jarvis.say()
        """
        self.disable_gtts()
        self.enable_voice = False
        self.update_data('enable_voice', False)

    def is_voice_enabled(self):
        """
        Returns True/False if voice is enabled/disabled with
        enable_voice or disable_voice
        Default: False (disabled)
        """
        return self.enable_voice

    def change_speech_rate(self, delta):
        """
        Alters the rate of the speech engine by a specified amount and remember
        the new speech rate.
        :param delta: Amount of change to apply to speech rate
        """
        self.speech.change_rate(delta)
        self.update_data('speech_rate', self.speech.rate)

    # MEMORY WRAPPER
    def get_data(self, key):
        """
        Get a specific key from memory
        """
        return self.memory.get_data(key)

    def add_data(self, key, value):
        """
        Add a key and value to memory
        """
        self.memory.add_data(key, value)
        self.memory.save()

    def update_data(self, key, value):
        """
        Updates a key with supplied value.
        """
        self.memory.update_data(key, value)
        self.memory.save()

    def del_data(self, key):
        """
        Delete a key from memory
        """
        self.memory.del_data(key)
        self.memory.save()

    def eval(self, s):
        """
        Simulates typing 's' in Jarvis prompt
        """
        line = self._jarvis.precmd(s)
        stop = self._jarvis.onecmd(line)
        stop = self._jarvis.postcmd(stop, line)
        # TODO

    def spinner_start(self, message="Starting "):
        """
        Function for starting a spinner when prompted from a plugin
        and a default message for performing the task
        """
        self.spinner_running = True
        self.spinner = SpinnerThread(message, 0.15)
        self.spinner.start()

    def spinner_stop(self, message="Task executed successfully! ", color=Fore.GREEN):
        """
        Function for stopping the spinner when prompted from a plugin
        and displaying the message after completing the task
        """
        self.spinner.stop()
        self.say(message, color)
        self.spinner_running = False

    def is_spinner_running(self):
        return self.spinner_running

    def get_server(self):
        return self.io.cmd_interpreter._jarvis.server
예제 #3
0
class JarvisAPI(object):
    """
    Jarvis interface for plugins.

    Plugins will receive a instance of this as the second (non-self) parameter
    of the exec()-method.

    Everything Jarvis-related that can't be implemented as a stateless-function
    in the utilities-package should be implemented here.
    """

    _CONNECTION_ERROR_MSG = "You are not connected to Internet"

    def __init__(self, jarvis):
        self._jarvis = jarvis
        self.spinner_running = False

    def say(self, text, color="", speak=True):
        """
        This method give the jarvis the ability to print a text
        and talk when sound is enable.
        :param text: the text to print (or talk)
        :param color: for text - use colorama (https://pypi.org/project/colorama/)
                      e.g. Fore.BLUE
        :param speak: False-, if text shouldn't be spoken even if speech is enabled
        """
        print(color + text + Fore.RESET, flush=True)

        if speak:
            self._jarvis.speak(text)

    def input(self, prompt="", color=""):
        """
        Get user input
        """
        # we can't use input because for some reason input() and color codes do not work on
        # windows cmd
        sys.stdout.write(color + prompt + Fore.RESET)
        sys.stdout.flush()
        text = sys.stdin.readline()
        # return without newline
        return text.rstrip()

    def input_number(self, prompt="", color="", rtype=float, rmin=None, rmax=None):
        """
        Get user input: As number.

        Guaranteed only returns number - ask user till correct number entered.

        :param prompt: Printed to console
        :param color: Color of prompot
        :param rtype: type of return value; e.g. float (default) or int
        :param rmin: Minum of values returned
        :param rmax: Maximum of values returned
        """
        while True:
            try:
                value = rtype(self.input(prompt, color).replace(',', '.'))
                if (rmin is not None and value < rmin) or (rmax is not None and value > rmax):
                    prompt = "Sorry, needs to be between {} and {}. Try again: ".format(
                        rmin, rmax)
                else:
                    return value
            except ValueError:
                prompt = 'Sorry, needs to be a number. Try again: '
                continue

    def connection_error(self):
        """Print generic connection error"""

        if self.is_spinner_running():
            self.spinner_stop('')

        self.say(JarvisAPI._CONNECTION_ERROR_MSG)

    def exit(self):
        """Immediately exit Jarvis"""
        self._jarvis.close()

    def notification(self, msg, time_seconds=0):
        """
        Sends notification msg in time_in milliseconds
        :param msg: Message. Either String (message body) or tuple (headline, message body)
        :param time_seconds: Time in seconds to wait before showing notification
        """
        if isinstance(msg, tuple):
            headline, message = msg
        elif isinstance(msg, str):
            headline = "Jarvis"
            message = msg
        else:
            raise ValueError("msg not a string or tuple")

        if time_seconds == 0:
            notify(headline, message)
        else:
            schedule(time_seconds, notify, headline, message)

    def schedule(self, time_seconds, function, *args):
        """
        Schedules function
        After time_seconds call function with these parameter:
           - reference to this JarvisAPI instance
           - schedule_id (return value of this function)
           - *args
        :return: integer, id - use with cancel
        """
        return self._jarvis.scheduler.create_event(
            time_seconds, function, self, *args)

    def cancel(self, schedule_id):
        """
        Cancel event scheduled with schedule
        :param schedule_id: id returned by schedule
        """
        spinner = SpinnerThread('Cancelling', 0.15)
        spinner.start()

        self._jarvis.scheduler.cancel(schedule_id)

        spinner.stop()
        self.say('Cancellation successful', Fore.GREEN)

    # Voice wrapper
    def enable_voice(self):
        """
        Use text to speech for every text passed to jarvis.say()
        """
        g = self.get_data('gtts_status')
        self._jarvis.speech = create_voice(self, g, rate=120)
        self._jarvis.enable_voice = True
        self.update_data('enable_voice', True)

    def disable_gtts(self):
        """
        Switch to default speech engine for every text passed to jarvis.say()
        """
        self.update_data('gtts_status', False)

    def enable_gtts(self):
        """
        Use google text to speech for every text passed to jarvis.say()
        """
        self.update_data('gtts_status', True)
        g = self.get_data('gtts_status')
        self._jarvis.speech = create_voice(self, g, rate=120)

    def disable_voice(self):
        """
        Stop text to speech output & disable gtts for every text passed to jarvis.say()
        """
        self.disable_gtts()
        self._jarvis.enable_voice = False
        self.update_data('enable_voice', False)

    def is_voice_enabled(self):
        """
        Returns True/False if voice is enabled/disabled with
        enable_voice or disable_voice
        Default: False (disabled)
        """
        return self._jarvis.enable_voice

    def change_speech_rate(self, delta):
        """
        Alters the rate of the speech engine by a specified amount and remember
        the new speech rate.
        :param delta: Amount of change to apply to speech rate
        """
        self._jarvis.speech.change_rate(delta)
        self.update_data('speech_rate', self._jarvis.speech.rate)

    # MEMORY WRAPPER
    def get_data(self, key):
        """
        Get a specific key from memory
        """
        return self._jarvis.memory.get_data(key)

    def add_data(self, key, value):
        """
        Add a key and value to memory
        """
        self._jarvis.memory.add_data(key, value)
        self._jarvis.memory.save()

    def update_data(self, key, value):
        """
        Updates a key with supplied value.
        """
        self._jarvis.memory.update_data(key, value)
        self._jarvis.memory.save()

    def del_data(self, key):
        """
        Delete a key from memory
        """
        self._jarvis.memory.del_data(key)
        self._jarvis.memory.save()

    def eval(self, s):
        """
        Simulates typing 's' in Jarvis prompt
        """
        line = self._jarvis.precmd(s)
        stop = self._jarvis.onecmd(line)
        stop = self._jarvis.postcmd(stop, line)

    def spinner_start(self, message="Starting "):
        """
        Function for starting a spinner when prompted from a plugin
        and a default message for performing the task
        """
        self.spinner_running = True
        self.spinner = SpinnerThread(message, 0.15)
        self.spinner.start()

    def spinner_stop(self, message="Task executed successfully! ", color=Fore.GREEN):
        """
        Function for stopping the spinner when prompted from a plugin
        and displaying the message after completing the task
        """
        self.spinner.stop()
        self.say(message, color)
        self.spinner_running = False

    def is_spinner_running(self):
        return self.spinner_running

    def get_saving_directory(self, path):
        """
        Returns the final directory where the files must be saved
        """
        while True:
            user_choice = self.input(
                'Would you like to save the file in the same folder?[y/n] ')
            user_choice = user_choice.lower()

            if user_choice == 'yes' or user_choice == 'y':
                destination = get_parent_directory(path)
                break

            elif user_choice == 'no' or user_choice == 'n':
                destination = self.input('Enter the folder destination: ')
                if not os.path.exists(destination):
                    os.makedirs(destination)
                break
            else:
                self.incorrect_option()

        os.chdir(destination)

        return destination

    def incorrect_option(self):
        """
        A function to notify the user that an incorrect option
        has been entered and prompting him to enter a correct one
        """
        self.say("Oops! Looks like you entered an incorrect option", Fore.RED)
        self.say("Look at the options once again:", Fore.GREEN)