Пример #1
0
 def update_tasks(self, new_tasks):
     m = Memory("tasks.json")
     if m.get_data("tasks_list") is None:
         m.add_data("tasks_list", new_tasks)
     else:
         m.update_data("tasks_list", new_tasks)
     m.save()
     self.tasks = new_tasks
Пример #2
0
 def remove_task_from_memory(self, task_name):
     m = Memory("tasks.json")
     task_list = m.get_data("tasks_list")
     if task_list is None:
         return
     old_task = filter(lambda x: x["name"] != task_name, task_list)
     m.update_data("tasks_list", list(old_task))
     m.save()
Пример #3
0
 def update_api_key(
     self,
     jarvis,
 ):
     user_api_key = jarvis.input("Enter New Api-BasketBall.com API_KEY: ",
                                 Fore.GREEN)
     m = Memory("basketball.json")
     m.update_data("API_KEY", user_api_key)
     m.save()
     self.key = user_api_key
Пример #4
0
 def get_api_key(self, jarvis):
     m = Memory("basketball.json")
     if m.get_data("API_KEY") is None:
         user_api_key = jarvis.input("Enter Api-BasketBall.com API_KEY: ",
                                     Fore.GREEN)
         m.add_data("API_KEY", user_api_key)
         m.save()
         self.key = user_api_key
     else:
         self.key = m.get_data("API_KEY")
Пример #5
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
Пример #6
0
class CmdInterpreter(Cmd):
    # We use this variable at Breakpoint #1.
    # We use this in order to allow Jarvis say "Hi", only at the first
    # interaction.

    # This can be used to store user specific data

    def __init__(self,
                 first_reaction_text,
                 prompt,
                 directories=[],
                 first_reaction=True,
                 enable_voice=False):
        """
        This constructor contains a dictionary with Jarvis Actions (what Jarvis can do).
        In alphabetically order.
        """
        Cmd.__init__(self)
        self.first_reaction = first_reaction
        self.first_reaction_text = first_reaction_text
        self.prompt = prompt
        self.enable_voice = enable_voice
        # Register do_quit() function to SIGINT signal (Ctrl-C)
        signal.signal(signal.SIGINT, self.interrupt_handler)

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

        self.actions = [
            {
                "check": ("ram", "weather", "time", "forecast")
            },
            "directions",
            "help",
            "how_are_you",
            "near",
            "pinpoint",
            "umbrella",
            {
                "update": ("location", "system")
            },
            "weather",
        ]

        self.fixed_responses = {
            "what time is it": "clock",
            "where am i": "pinpoint",
            "how are you": "how_are_you"
        }

        self._api = JarvisAPI(self)
        self._plugin_manager = PluginManager()

        for directory in directories:
            self._plugin_manager.add_directory(directory)

        self._activate_plugins()

    def _activate_plugins(self):
        """Generate do_XXX, help_XXX and (optionally) complete_XXX functions"""
        for (plugin_name, plugin) in self._plugin_manager.get_all().items():
            completions = self._plugin_update_action(plugin, plugin_name)
            if completions is not None:

                def complete(completions):
                    def _complete_impl(self, text, line, begidx, endidx):
                        return [i for i in completions if i.startswith(text)]

                    return _complete_impl

                setattr(CmdInterpreter, "complete_" + plugin_name,
                        complete(completions))
            setattr(CmdInterpreter, "do_" + plugin_name,
                    partial(plugin.run, self._api))
            setattr(CmdInterpreter, "help_" + plugin_name,
                    partial(self._api.say, plugin.get_doc()))

            if hasattr(plugin.__class__, "init") and callable(
                    getattr(plugin.__class__, "init")):
                plugin.init(self._api)

    def _plugin_update_action(self, plugin, plugin_name):
        """Return True if completion is available"""
        complete = plugin.complete()
        if complete is not None:
            # add plugin with completion
            # Dictionary:
            # { plugin_name : list of completions }
            complete = [x for x in complete]
            self.actions.append({plugin_name: complete})
            return complete
        else:
            # add plugin without completion
            # plugin name only
            self.actions.append(plugin_name)
            return None

    def close(self):
        """Closing Jarvis."""
        print_say("Goodbye, see you later!", self, Fore.RED)
        self.scheduler.stop_all()
        exit()

    def completedefault(self, text, line, begidx, endidx):
        """Default completion"""
        return [i for i in self.actions if i.startswith(text)]

    def error(self):
        """Jarvis let you know if an error has occurred."""
        print_say("I could not identify your command...", self, Fore.RED)

    def get_completions(self, command, text):
        """Returns a list with the completions of a command."""
        dict_target = [
            item for item in self.actions
            if type(item) == dict and command in item
        ][0]
        completions_list = dict_target[command]
        return [i for i in completions_list if i.startswith(text) and i != '']

    def interrupt_handler(self, signal, frame):
        """Closes Jarvis on SIGINT signal. (Ctrl-C)"""
        self.close()

    def do_calculate(self, s):
        """Jarvis will get your calculations done!"""
        tempt = s.replace(" ", "")
        if len(tempt) > 1:
            evaluator.calc(tempt, self)
        else:
            print_say("Error: Not in correct format", self, Fore.RED)

    def help_calculate(self):
        """Print help about calculate command."""
        print_say("Jarvis will get your calculations done!", self)
        print_say("-- Example:", self)
        print_say("\tcalculate 3 + 5", self)

    def do_check(self, s):
        """Checks your system's RAM stats."""
        # if s == "ram":
        if "ram" in s:
            system("free -lm")
        # if s == "time"
        elif "time" in s:
            timeIn.main(self, s)
        elif "forecast" in s:
            forecast.main(self, s)
        # if s == "weather"
        elif "weather" in s:
            try:
                weatherIn.main(self, s)
            except ConnectionError:
                print(CONNECTION_ERROR_MSG)

    def help_check(self):
        """Prints check command help."""
        print_say("ram: checks your system's RAM stats.", self)
        print_say("time: checks the current time in any part of the globe.",
                  self)
        print_say(
            "weather in *: checks the current weather in any part of the globe.",
            self)
        print_say("forecast: checks the weather forecast for the next 7 days.",
                  self)
        print_say("-- Examples:", self)
        print_say("\tcheck ram", self)
        print_say("\tcheck time in Manchester (UK)", self)
        print_say("\tcheck weather in Canada", self)
        print_say("\tcheck forecast", self)
        print_say("\tcheck forecast in Madrid", self)
        # add here more prints

    def complete_check(self, text, line, begidx, endidx):
        """Completions for check command"""
        return self.get_completions("check", text)

    def do_directions(self, data):
        """Get directions about a destination you are interested to."""
        try:
            directions_to.main(data)
        except ValueError:
            print("Please enter destination")
        except ConnectionError:
            print(CONNECTION_ERROR_MSG)

    def help_directions(self):
        """Prints help about directions command"""
        print_say("Get directions about a destination you are interested to.",
                  self)
        print_say("-- Example:", self)
        print_say("\tdirections to the Eiffel Tower", self)

    def do_how_are_you(self, s):
        """Jarvis will inform you about his status."""
        print_say("I am fine, How about you?", self, Fore.BLUE)

    def help_how_are_you(self):
        """Print info about how_are_you command"""
        print_say("Jarvis will inform you about his status.", self)

    def do_near(self, data):
        """Jarvis can find what is near you!"""
        near_me.main(data)

    def help_near(self):
        """Print help about near command."""
        print_say("Jarvis can find what is near you!", self)
        print_say("-- Examples:", self)
        print_say("\trestaurants near me", self)
        print_say("\tmuseums near the eiffel tower", self)

    def do_pinpoint(self, s):
        """Jarvis will pinpoint your location."""
        try:
            mapps.locate_me()
        except ConnectionError:
            print(CONNECTION_ERROR_MSG)

    def help_pinpoint(self):
        """Print help about pinpoint command."""
        print_say("Jarvis will pinpoint your location.", self)

    def do_umbrella(self, s):
        """If you're leaving your place, Jarvis will inform you if you might need an umbrella or not"""
        s = 'umbrella'
        try:
            weather_pinpoint.main(self.memory, self, s)
        except ConnectionError:
            print(CONNECTION_ERROR_MSG)

    def help_umbrella(self):
        """Print info about umbrella command."""
        print_say(
            "If you're leaving your place, Jarvis will inform you if you might need an umbrella or not.",
            self, Fore.BLUE)

    def do_update(self, s):
        """Updates location or system."""
        if "location" in s:
            location = self.memory.get_data('city')
            loc_str = str(location)
            print_say("Your current location is set to " + loc_str, self)
            print_say("What is your new location?", self)
            i = input()
            self.memory.update_data('city', i)
            self.memory.save()
        elif "system" in s:
            update_system()

    def help_update(self):
        """Prints help about update command"""
        print_say("location: Updates location.", self)
        print_say("system: Updates system.", self)

    def complete_update(self, text, line, begidx, endidx):
        """Completions for update command"""
        return self.get_completions("update", text)

    def do_weather(self, s):
        """Get information about today's weather."""
        try:
            word = s.strip()
            if (len(word) > 1):
                weatherIn.main(self, s)
            else:
                weather_pinpoint.main(self.memory, self, s)
        except ConnectionError:
            print(CONNECTION_ERROR_MSG)

    def help_weather(self):
        """Prints help about weather command."""
        print_say(
            "Get information about today's weather in your current location.",
            self)