API Reference

Config

Holds functions related to Eva and plugins configuration.

eva.config.get_config(config_file=None, spec_file=None, **kwargs)

Function used to fetch Eva core and plugin configurations on startup. If config_file and spec_file are None, assumes the we’re looking for Eva’s config and spec file.

Warning

This function should not be used directly unless you know what you are doing. Use the singleton conf variable to access Eva and plugin configurations:

from eva import conf
plugin_directory = conf['eva']['plugin_directory']
fake_plugin_variable = conf['plugins']['fake_plugin']['config']['variable_name']
Parameters:
  • config_file (string) – The location of the configuration file to parse.
  • spec_file (string) – The location of the configuration specification file.
Returns:

The loaded configuration object.

Return type:

ConfigObj

eva.config.get_config_spec(spec_file=None)

Returns a configuration specification based on the spec file provided. Assumes the <eva_directory>/eva.conf.spec file if no spec file path specified.

Parameters:spec_file (string) – The path of the specification file to load.
Returns:The specification file object.
Return type:ConfigObj
eva.config.get_eva_config_file()

Function that attempts to determine where Eva’s main configuration file resides.

Looks for the following files:

  • ~/eva.conf
  • ~/.eva.conf
  • ~/eva/eva.conf
  • /etc/eva.conf
  • /etc/eva/eva.conf
Returns:Eva’s configuration file, if found.
Return type:string
eva.config.get_eva_directory()

Function used to get the directory of the current file. Effectively determining Eva’s source code directory.

Returns:Eva’s source code directory.
Return type:string
eva.config.get_plugin_config(plugin_id, config_dir)

Wrapper around get_config() to fetch a plugin’s configurations.

Warning

The same get_config() warning applies for this function. Stick with the conf singleton in order to retrieve plugin configurations.

Parameters:
  • plugin_id (string) – The plugin ID.
  • config_dir (string) – The directory where the plugin configuration file is found.
Returns:

The loaded configuration object.

Return type:

ConfigObj

eva.config.save_config(plugin_id=None, section=None)

Save current active plugin configuration to disk.

If plugin_id is not provided, then section_id MUST be provided. That is because without plugin_id, Eva assumes you’re trying to save it’s core configuration - which requires a section to save.

If Eva can’t find it’s core configuration object when saving, it will write out it’s current configurations to ~/eva/eva.conf.

Parameters:
  • plugin_id (string) – The plugin ID to have it’s configurations preserved. If None, assumes Eva’s core configurations - in which case section is required.
  • section (string) – If plugin_id is None, section must be provided to determine which section of the Eva configuration file should be saved.

Context

Holds the EvaContext class - an integral part of every Eva interaction.

class eva.context.EvaContext(data=None)

An EvaContext object is passed along to plugins (via gossip triggers) during an Eva interaction with the user. The object contains all the information required for the plugin to determine whether or not it should act on the current interaction.

Plugin developers should always interact with Eva (and back out to the user) through the context object. This is important as the context object fires various triggers that enable other plugins to hook into ongoing interactions.

__init__(data=None)

The data attribute is typically a dict with the following structure:

dict {
    'input_text': The text/query provided by the client
    'input_audio': dict {
        'audio': The binary audio data of the query (optional)
        'content_type': The content type of the audio binary data (optional)
    }
    'output_text': The text of the response from Eva
    'output_audio': dict {
        'audio': The binary audio data of the response(optional)
        'content_type': The content type of the audio binary data (optional)
    }
}

It may also contain output_text and output_audio with the same format as it’s input counterpart, but that is unlikely on initial creation of the context object (unless a plugin is doing something unorthodox on a trigger that’s fired before interaction begins).

Input in this case refers to text or audio that a client has sent Eva. Output refers to the resulting response from Eva that gets sent back.

Parameters:data (dict) – The data received from an Eva client.
contains(keyword)

Simple helper method to determine if a keyword appears in a client’s input text (query or command).

Parameters:keyword – The keyword to check for in the input text.
Returns:True if the keyword is found, False otherwise.
Return type:boolean
get_input_audio()

Method used to get the input audio data that was sent by the client for this interaction.

Returns:The audio binary data received from an Eva client this interaction.
Return type:binary string
get_input_audio_content_type()

Method that returns the content type of the audio binary data received during this interaction.

Typically something like ‘audio/mpeg’ or ‘audio/wave’.

Returns:The content type of the audio binary data received this interaction.
Return type:string
get_input_text()

Method used by plugins to get the input text (query or command) from the Eva client for this interaction.

Returns:The input text from the Eva client this interaction.
Return type:string
get_output_audio()

Method that returns the resulting output audio binary data that the Eva client will play to the user.

Returns:The output audio binary data that Eva will send back to the client.
Return type:binary string
get_output_audio_content_type()

Method that returns the output audio content type that will be sent back to the Eva client.

Returns:The content type of the audio binary data returned to the Eva client.
Return type:string
get_output_text()

Method used by plugins to get the output text (response) that has been generated so far by plugins in this interaction.

The string returned from this method may not always end up being the string returned to the Eva clients. A plugin may end up modifying the output text at any point in the interaction (even right before sending the response to the client).

Returns:The output text for the Eva client so far in this interaction.
Return type:string
input_audio = None

The input audio binary data from an Eva client.

input_audio_content_type = None

The content type of the input audio binary data.

input_text = None

The input text (query or command) from an Eva client.

output_audio = None

The output audio binary data from Eva.

output_audio_content_type = None

The content type of the output audio binary data.

output_text = None

The output text (response) from Eva.

responded = None

True if a plugin has already handled the response, False otherwise.

response_ready()

Method used by plugins to determine whether or not they should take part in this current interaction.

A response being ready means that another plugin has already set some output text that should be sent back to the Eva client.

Returns:True if a response has already been generated, False otherwise.
Return type:boolean
set_input_audio(audio, content_type)

Same as set_input_text() except it works for the input audio and content type. Not very many plugins will end up using this as it involves modifying the audio query or command that was sent by the Eva client.

This method fires the eva.pre_set_input_audio and eva.post_set_input_audio triggers.

Parameters:
  • audio (binary string) – The audio to be set as the input audio for this interaction.
  • content_type (string) – The content type of this binary audio data.
set_input_text(text)

Method used to set the input text of the current interaction.

This function is primarily used by voice recognition plugins to convert input audio into input text when clients don’t provide any.

This method fires the eva.pre_set_input_text and eva.post_set_input_text triggers.

Parameters:text (string) – The text that will now become the input text from the client.
set_output_audio(audio, content_type)

Similar to set_output_text() except for the audio data and content type. This method will be used primarily by the text-to-speech plugins.

Parameters:
  • audio (binary string) – The audio binary data to send back to the client.
  • content_type (string) – The content type of the binary audio data.
set_output_text(text, responding=True)

The bread and butter method of the context object.

This method is used by nearly every plugin as it’s used to tell Eva what the response to the client should be.

This method fires the eva.pre_set_output_text and eva.post_set_output_text triggers.

Parameters:
  • text (string) – The text to be set as output for the client.
  • responding (boolean) –

    True if the text provided is a response to the client. False if you’re simply modifying the output text without claiming to be the primary plugin to respond to the query or command.

    Leaving this as True means other plugins will be able to tell that the client’s query has already been answered (by checking the boolean variable returned by response_ready()).

    If a plugin is simply prepending/appending text or making slight modifications to the output, it should use responding=False so as to allow follow-up questions to be routed to the appropriate plugin.

Director

This is where the magic begins. The director has functions to fire up Eva, load all the plugins, and begin interactions with the clients.

eva.director.boot()

The function that runs the Eva boot sequence and loads all the plugins.

Fires the eva.pre_boot and eva.post_boot triggers.

eva.director.get_return_data(context)

This function is used to extract appropriate data from the context object before sending it to the Eva clients.

It will check the context object for a text response and an audio response, and return a dict containing this information.

Parameters:context (eva.context.EvaContext) – The context object used for this interaction.
Returns:A dict that may contain the key output_text, output_audio, or both. It should be identical to the return value of the interact() function barring any changes during the eva.pre_return_data trigger.
Return type:dict
eva.director.handle_data_from_client(pubsub, data)

Helper function to fire off an interaction with Eva based on client data received, and then send off the response back to the clients.

Parameters:
eva.director.interact(data)

Eva’s bread and butter function. Feeding data from the clients directly to this function will return a response dict, ready to be consumed by the clients as a response. This takes care of firing all the necessary triggers so that the plugins get a say in the responding text and/or audio.

Fires the following triggers:
  • eva.voice_recognition
  • eva.pre_interaction_context
  • eva.pre_interaction
  • eva.interaction
  • eva.post_interaction
  • eva.text_to_speech
  • eva.pre_return_data
Parameters:data (dict) – The data received from the clients on query/command. See eva.context.EvaContext.__init__() for more details.
Returns:A dictionary with all the information necessary for the clients to handle the response appropriately. Typically something like this:
dict {
    'output_text': The text of the response from Eva
    'output_audio': dict {
        'audio': The binary audio data of the response (optional)
        'content_type': The content type of the audio binary data (optional)
    }
}
Return type:dict
eva.director.serve()

This is the one function you need to execute to start Eva.

It begins the boot sequence, loads up all plugins, and starts listening for client interactions.

Logger

Contains all of Eva’s logging facilities.

class eva.logger.Logger

The Logger class is a very light wrapper around Python’s standard logging framework. It’s primary purpose is to wrap every logging message into a method that fires triggers on messages. This allows for plugins to act on certain log messages.

It should not be necessary to instantiate this class manually as this is already done in the __init__.py file. Use from eva import log to use a singleton instance of this class.

__init__()

Initializes the standard Python logging class at the appropriate level set in the Eva configuration file. Will also specify the appropriate logging format.

critical(message)

Simple wrapper around the standard Python logger’s critical method. Fires the eva.logger.critical trigger.

debug(message)

Simple wrapper around the standard Python logger’s debug method. Fires the eva.logger.debug trigger.

error(message)

Simple wrapper around the standard Python logger’s error method. Fires the eva.logger.error trigger.

info(message)

Simple wrapper around the standard Python logger’s info method. Fires the eva.logger.info trigger.

warning(message)

Simple wrapper around the standard Python logger’s warning method. Fires the eva.logger.warning trigger.

Plugin

All necessary helper functions to facilitate plugin management.

eva.plugin.download_plugin(plugin_id, destination)

Will download the specified plugin to the specified destination if it is found in the plugin repository.

Parameters:
  • plugin_id (string) – The plugin ID to download.
  • destination (string) – The destination to download the plugin on disk.
eva.plugin.enable_plugin(plugin_id, downloadable_plugins=None)

Enables a single plugin, which entails:

  • If already enabled, return
  • If plugin not found, search online repository
  • Download if found in repository, else log and return
  • Recusively enable dependencies if found, else log error and return
  • Run a pip install -r requirements.txt --user if requirements file found
  • Insert plugin directory in Python path and dynamically import module
  • Execute the <plugin>.on_enable() function if found
Todo:

Need to clean up, comment, and shorten this function.

Parameters:
  • plugin_id (string) – The plugin id to enable.
  • downloadable_plugins (dict) – A dict of plugins that are available for download from Eva’s repository. This is typically the return value of the get_downloadable_plugins() function.
eva.plugin.enable_plugins()

Function that enables all plugins specified in Eva configuration file. Will enable all available plugins if none is specified in the configs.

eva.plugin.get_downloadable_plugins(pull_latest=False)

Gets a dict of downloadable plugins from the plugin repository. The plugin repository is simply a git repo with a list of available plugins stored in a CSV file. The repository will be cloned locally if not found.

Parameters:pull_latest (boolean) – Whether or not to perform a git pull on the repository before parsing the plugins.
Returns:A dict of all available plugins for download. The format is:
{
    <plugin_id> {
        'id': <id>,
        'name': <name>,
        'description': <description>,
        'url': <url>
    }
    ...
}
Return type:dict
eva.plugin.get_plugin_directory()

Helper function to get Eva’s plugin directory specified in the config file.

Will automatically replace ~ with the user’s home directory.

eva.plugin.load_plugin_configs(config_dir)

Function that loops through all available plugins and loads their corresponding plugin configuration if found in the configuration directory provided.

The load_plugin_directory() function must be called before calling this function as it relies on the plugin info files having been loaded into the conf['plugins'] dict.

Parameters:config_dir (string) – The configuration directory that holds all Eva plugin configuration files.
eva.plugin.load_plugin_directory(plugin_dir)

Will crawl Eva’s plugin directory and load the plugin info files for all the valid plugins found. The info file information will eventually be used when enabling plugins and their dependencies.

This function does not return anything. It stores all plugin information in the conf['plugins'] dict. Every plugin should have the following accessible information once this function is run:

conf['plugins'][<plugin_id>] = {
    'info': 'Data from the info file for this plugin'
    'path': 'The path of the plugin on disk'
    'git': 'True if the plugin is a git repo (and can be updated)'
}

Use the following statement to access the conf dict: from eva import conf

Parameters:plugin_dir (string) – The directory containing available Eva plugins. Typically the return value of get_plugin_directory().
eva.plugin.load_plugin_info(plugin_path, plugin_id)

Given a plugin path and plugin name, this function will attempt to return a loaded plugin info file as a ConfigObj specification instance.

Parameters:
  • plugin_path (string) – The path of the plugin in question.
  • plugin_id (string) – The plugin ID.
Returns:

A ConfigObj specification instance.

Return type:

ConfigObj

eva.plugin.load_plugins()

The function that is called during Eva’s boot sequence. Will fetch the plugin directory , load all of the plugins’ info files, load all of the plugin’s configurations, and enable all the required plugins and their dependencies specified in Eva’s configuration file.

Fires the eva.plugins_loaded trigger.

eva.plugin.num_available_plugins()

Function used to get the number of available plugins. Will simply check the length of the conf['plugins'] dict.

Returns:The number of available plugins.
Return type:integer
eva.plugin.num_enabled_plugins()

Function used to determine the number of enabled plugins. Simply checks if the module key exists in the conf['plugins'][<plugin>] dict.

Returns:The number of enabled plugins.
Return type:integer
eva.plugin.plugin_enabled(plugin_id)

Function used to determine whether a plugin is enabled or not. Simply looks in the conf['plugins'] dict to see if the imported module is present.

Parameters:plugin_id (string) – The plugin name.
Returns:True if the plugin seems to be enabled, False otherwise.
Return type:boolean
eva.plugin.plugin_is_git_repo(plugin_path)

Will attempt to determine if the plugin_path specified is a git repo. Simply checks if the .git folder exists.

Todo:There’s probably a better way of doing this.
Parameters:plugin_path (string) – The path of the plugin to check.
eva.plugin.pull_repo(repo_path)

Helper function to perform the equivalent of a git pull origin master on a specified git repository on disk.

Parameters:repo_path (string) – The path of the git repository to pull.
eva.plugin.refresh_downloadable_plugins()

Will remove the entire local directory holding the plugin repository and re-clone the repo locally. This can be useful when changing plugin repositories.

Scheduler

Holds functions required to start and manage the Eva scheduler.

eva.scheduler.get_scheduler()

Function used to return the APScheduler instance that is used by Eva and plugins.

Warning

This function should only be used by Eva. Plugins should access the scheduler through Eva’s singleton object:

from eva import scheduler
# This will fire off the job immediately.
scheduler.add_job(func_name, id="eva_<plugin_id>_job")
Note:This function most likely needs to be revisited as it may not be thread-safe. Eva and plugins can modify the config singleon simultaneously inside and outside of jobs.
Returns:The scheduler object used by plugins to schedule long-running jobs.
Return type:apscheduler.schedulers.background.BackgroundScheduler
eva.scheduler.job_failed(event)

A callback function that gets called when an APScheduler job fails.

Currently will simply fire the eva.scheduler.job_failed trigger with the failed event object.

eva.scheduler.job_succeeded(event)

A callback function that gets called when an APScheduler job succeeds.

Currently will simply fire the eva.scheduler.job_succeeded trigger with the success event object.

Util

Any function that did not neatly fit in any other Eva python file.

eva.util.get_calling_plugin(depth=2)

This method will inspect the depth level of the call stack to find which python module is responsible for the current method invocation.

It is used when determining which plugin called the get/set output/input text/audio methods in the context object.

Parameters:depth (integer) – How deep to look down the call stack (2 for calling function).
eva.util.get_mongo_client()

A helper function to get a MongoDB client object with the credentials, host, and port specified in the Eva configuration file.

Returns:A MongoClient configured for a Eva MongoDB connection.
Return type:pymongo.MongoClient
eva.util.get_pubsub()

Helper function to get the pubsub client used to send and receive messages.

Returns:The pubsub object used to publish Eva messages to the clients.
Return type:anypubsub.interfaces.PubSub
eva.util.publish(message, channel='eva_messages')

A helper function used to broadcast messages to all available Eva clients.

Todo:

Needs to be thoroughly tested (especially with audio data).

Parameters:
  • message (string) – The message to send to clients.
  • channel (string) – The channel to publish in. The default channel that clients should be listening on is called ‘eva_messages’.
eva.util.restart(args=[])

Function used to restart Eva.

Warning

This will restart Eva immediately and kill all running scheduler jobs.

Parameters:args (list) – A list of arguments to feed Eva on restart.