From 8c77ac443990337e6f668a572a2b502ae3485ca8 Mon Sep 17 00:00:00 2001 From: Joseph Birkner Date: Wed, 15 May 2019 15:06:17 +0200 Subject: [PATCH] Updated docs. --- docs/index.html | 21 +++++++++++++++++++-- docs/search/search_index.json | 2 +- docs/sitemap.xml.gz | Bin 201 -> 201 bytes 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/index.html b/docs/index.html index bdc3349..4d3382e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -245,6 +245,13 @@ Initial configuration and setup + + +
  • + + Running your Telegram bot + +
  • @@ -599,6 +606,13 @@ Initial configuration and setup +
  • + +
  • + + Running your Telegram bot + +
  • @@ -732,7 +746,7 @@

    Home

    -

    Release +

    Release Build Status codecov

    About

    @@ -837,7 +851,10 @@

    Initial configuration and setup

    After the conversation, check the Neo4j interface under localhost:7474. It should now contain some nodes!

    -

    Reminder: Whenever you use ravestate from the command line, activate the virtual environment first!

    +

    Reminder: Whenever you use ravestate from the command line, source the virtual environment first!

    +

    Running your Telegram bot

    +

    To test your telegram bot with a custom bot token in your keys.yml, +just run telegram_test.yml instead of generic.yml. This will load the ravestate_telegramio module.

    Setting up PyCharm

    1. Open your local ravestate clone as a project in pycharm.
    2. diff --git a/docs/search/search_index.json b/docs/search/search_index.json index 4de78bd..ff47059 100644 --- a/docs/search/search_index.json +++ b/docs/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"About ____ __ __ _____ _____ / _ \\____ __ ______ ______/ /_____/ /___ /_ _\\ /_ _\\ / /_/ / __ \\/ / / / __ \\/ ___\\, / __ \\, / __ \\ 0> 0> <0 <0 / ,\\ ,/ /_/ /\\ \\/ / /_/ /\\__, / / /_/ / / /_/ / \\__\u22bd__/ \\__\u22bd__/ \\/ \\/\\__/\\/ \\__/ ,___/\\____/\\/\\__/\\/\\/ ,___/ \u22c2 - Hey! \u22c2 \\____/ \\____/ Ol\u00e0! - Ravestate is a reactive library for real-time natural language dialog systems. It combines elements from event-based and reactive programming into an API, where application states are defined as functions that are run when a certain boolean set of criteria (signals) in the current application context is satisfied. It is the first reactive API to allow for boolean combinations of events. You may find a short introductory video here . Reactive Hello World import ravestate as rs # We want to write some text output, so we # need the raw:out context property from ravestate_rawio. import ravestate_rawio as rawio # Make sure that we use some i/o implementation, # so we can actually see stuff that is written to rawio:out. import ravestate_conio # Ravestate applications should always be wrapped in a Module. # This allows easier scoping, and enables separation of concerns # beyond states. with rs.Module(name=\"hi!\"): # Create an application state which reacts to the `:startup` signal, # and writes a string to raw:out. Note: State functions are # always run asynchronously! @rs.state(cond=rs.sig_startup, write=rawio.prop_out) def hello_world(context): context[rawio.prop_out] = \"Waddup waddup waddup!\" # Run context with console input/output and our 'hi!' module. rs.Context(\"conio\", \"hi!\").run() Visualization Ravestate has a d3.js -based visualization. When using ravestate_ui.UIContext instead of Context , or python3 -m ravestate_ui instead of python3 -m ravestate , a real-time visualization of all states/properties/signals in the state machine will be hosted on port 5001. Here is the view of http://localhost:5001 after launching python3 ravestate_ui -f generic.yml : Installation Via PIP The easiest way to install ravestate is through pip: pip install ravestate Note: Ravestate requires Python 3.6 or higher. It is tested on Ubuntu 16.04 and 18.04, as well as macOS > High Sierra. It is currently not tested on Windows. For reliability, we recommend using an environment virtualization tool, like virtualenv or conda . For developers Initial configuration and setup Clone the repository and install dependencies: # Create a virtual python environment to not pollute the global setup python3 -m virtualenv python-ravestate # Source the virtual environment . python-ravestate/bin/activate # Clone the repo git clone git@github.com:roboy/ravestate && cd ravestate # Install normal requirements pip install -r requirements.txt # To run tests & build docs, install pytest, mocking, fixtures, pydoc, ... pip install -r requirements-dev.txt # Link your local ravestate clone into your virtualenv pip install -e . Now, launch a Neo4j docker instance to serve Scientio , so the dialog system has a memory: docker run \\ --publish=7474:7474 --publish=7687:7687 \\ --volume=$HOME/neo4j/data:/data \\ --volume=$HOME/neo4j/logs:/logs \\ neo4j:latest # Open the address localhost:7474 in a browser, and enter the # credentials `neo4j`/`neo4j`. You will then be prompted to enter # your own password. Remember this password. In the config folder, create a file called keys.yml . It should have the following content: module: telegramio config: telegram-token: # This is where your own telegram bot token # will go later --- module: ontology config: neo4j_address: bolt://localhost:7687 # Your neo4j server uri here neo4j_username: neo4j # Your neo4j user here neo4j_pw: test # Your neo4j pw here You may now conduct your first conversation with ravestate: python3 -m ravestate -f config/generic.yml -f config/keys.yml After the conversation, check the Neo4j interface under localhost:7474 . It should now contain some nodes! Reminder: Whenever you use ravestate from the command line, activate the virtual environment first! Setting up PyCharm Open your local ravestate clone as a project in pycharm. Mark the modules folder as sources root via the right-click context menu. Create a run config al\u00e0 the \"Edit configurations menu\": \u2022 Create a new Python configuration. \u2022 Set modules/ravestate/__main__.py as the script to execute \u2022 Set the working directory to the git clone directory. \u2022 Set parameters to -f config/generic.yml -f config/keys.yml . You should now be able to run the generic ravestate config from pycharm. Running Hello World Ravestate applications are defined by a configuration, which specifies the ravestate modules that should be loaded. To run the basic hello world application, run ravestate with a config file or command line arguments: Running with command line spec You can easily run a combination of ravestate modules in a shared context, by listing them as arguments to python3 -m ravestate : python3 -m ravestate \\ ravestate_wildtalk \\ ravestate_conio \\ ravestate_hibye \\ ravestate_persqa Run python3 -m ravestate -h to see more options! Running with config file(s) You may specify a series of config files to configure ravestate context, when specifying everything through the command line becomes too laborious: # In file hello_world.yml module: core config: import: - ravestate_wildtalk - ravestate_conio - ravestate_hibye - ravestate_persqa Then, run ravestate with this config file: python3 -m ravestate -f hello_world.yml Module overview Ravestate offers a landscape of fine-grained modules for different aspects of dialog application tasks, which may be seen in the following dependency diagram. Broadly, the modules are categorized into Core (Blue), I/O (Yellow), External (Red) and Skills (Green): Core Modules Module name Description ravestate Core ravestate library. ravestate_rawio Provides raw_in , raw_out , pic_in properties, which are served by the IO modules. ravestate_ontology Connects to scientio to serve a built-in ontology. ravestate_interloc Provides the all_interlocutors property, where present interlocutors are registered by the IO modules. ravestate_idle Provides bored and impatient signals, as specified here . ravestate_verbaliser Utilities for easy management of conversational text, documented here . ravestate_nlp Spacy-based NLP properties and signals, documented here . ravestate_ros2 Provides specific Ros2PubProperty , Ros2SubProperty and Ros2CallProperty context props., which greatly simplify working with ROS2 in ravestate. IO Modules Module name Description ravestate_conio Simple command-line based IO for development purposes. ravestate_telegramio Single- or Multi-process Telegram server module, documented here . ravestate_roboyio PyroBoy -based STT/TTS with ROS2. Skill Modules Module name Description ravestate_wildtalk ParlAI -based generative conversational module. ravestate_hibye Simply voices Hi! (or the likes thereof) when an interlocutor is added, and Bye when one is removed. ravestate_persqa Conducts personalized smalltalk with interlocutors, interacts with Scientio to persist trivia. ravestate_genqa DrQA -based general question answering module. ravestate_roboyqa QA module which provides answers to questions about Roboy, such as Who is your dad? ravestate_akinator Enables dialog-based play of Akinator! ravestate_sendpics Uses face recognition to extract facial features and an assiciated Person with pic_in and ontology, which are then persisted in Redis and Scientio. ravestate_stalker Uses facial feature <-> person tuples generated by sendpics, to surprise people in front of a camera with knowledge of their names. Running tests If you have installed the dependencies from requirements-dev.txt you may run the ravestate test suite as follows: ./run_tests.sh Docker for ROS and ROS2 There is a Dockerfile for ROS and ROS2 support which can be built with docker build -t ravestate-ros2-image . The image contains ROS, ROS2 and a ROS Bridge to connect ROS with ROS2. Furthermore the roboy_communication message and service types are installed. A container can then be created with the docker-compose.yml: docker-compose up --detach ravestate The container is now running and a connection into the container can be established with: docker exec -it ravestate-ros2-container bash Inside the container, first source the ROS2 setups and then ravestate can be run with ROS2 and rclpy available. source ~/ros2_ws/install/setup.sh python3 -m ravestate [...] Start ROS Bridge In order to start ROS Bridge, the image and container have to be set up as above. After connecting into the container run from inside the container: export ROS_IP=192.168.0.105 source ~/melodic_ws/devel/setup.sh source ~/ros2_ws/install/setup.sh source ~/ros1_bridge_ws/install/setup.sh ros2 run ros1_bridge dynamic_bridge Building/maintaining the docs If you have installed the dependencies from requirements-dev.txt , generate the docs by running this command at project root: export PYTHONPATH=$PYTHONPATH:$(pwd)/modules git rm -rf docs rm -rf _build docs pydocmd build mkdir -p docs/resources/docs && cp resources/docs/*.png docs/resources/docs && cp resources/docs/*.gif docs/resources/docs git add docs/* # For inspection: python3 -m http.server --directory docs The structure and content of the docs are defined in the file pydocmd.yml .","title":"Home"},{"location":"#about","text":"____ __ __ _____ _____ / _ \\____ __ ______ ______/ /_____/ /___ /_ _\\ /_ _\\ / /_/ / __ \\/ / / / __ \\/ ___\\, / __ \\, / __ \\ 0> 0> <0 <0 / ,\\ ,/ /_/ /\\ \\/ / /_/ /\\__, / / /_/ / / /_/ / \\__\u22bd__/ \\__\u22bd__/ \\/ \\/\\__/\\/ \\__/ ,___/\\____/\\/\\__/\\/\\/ ,___/ \u22c2 - Hey! \u22c2 \\____/ \\____/ Ol\u00e0! - Ravestate is a reactive library for real-time natural language dialog systems. It combines elements from event-based and reactive programming into an API, where application states are defined as functions that are run when a certain boolean set of criteria (signals) in the current application context is satisfied. It is the first reactive API to allow for boolean combinations of events. You may find a short introductory video here .","title":"About"},{"location":"#reactive-hello-world","text":"import ravestate as rs # We want to write some text output, so we # need the raw:out context property from ravestate_rawio. import ravestate_rawio as rawio # Make sure that we use some i/o implementation, # so we can actually see stuff that is written to rawio:out. import ravestate_conio # Ravestate applications should always be wrapped in a Module. # This allows easier scoping, and enables separation of concerns # beyond states. with rs.Module(name=\"hi!\"): # Create an application state which reacts to the `:startup` signal, # and writes a string to raw:out. Note: State functions are # always run asynchronously! @rs.state(cond=rs.sig_startup, write=rawio.prop_out) def hello_world(context): context[rawio.prop_out] = \"Waddup waddup waddup!\" # Run context with console input/output and our 'hi!' module. rs.Context(\"conio\", \"hi!\").run()","title":"Reactive Hello World"},{"location":"#visualization","text":"Ravestate has a d3.js -based visualization. When using ravestate_ui.UIContext instead of Context , or python3 -m ravestate_ui instead of python3 -m ravestate , a real-time visualization of all states/properties/signals in the state machine will be hosted on port 5001. Here is the view of http://localhost:5001 after launching python3 ravestate_ui -f generic.yml :","title":"Visualization"},{"location":"#installation","text":"","title":"Installation"},{"location":"#via-pip","text":"The easiest way to install ravestate is through pip: pip install ravestate Note: Ravestate requires Python 3.6 or higher. It is tested on Ubuntu 16.04 and 18.04, as well as macOS > High Sierra. It is currently not tested on Windows. For reliability, we recommend using an environment virtualization tool, like virtualenv or conda .","title":"Via PIP"},{"location":"#for-developers","text":"","title":"For developers"},{"location":"#initial-configuration-and-setup","text":"Clone the repository and install dependencies: # Create a virtual python environment to not pollute the global setup python3 -m virtualenv python-ravestate # Source the virtual environment . python-ravestate/bin/activate # Clone the repo git clone git@github.com:roboy/ravestate && cd ravestate # Install normal requirements pip install -r requirements.txt # To run tests & build docs, install pytest, mocking, fixtures, pydoc, ... pip install -r requirements-dev.txt # Link your local ravestate clone into your virtualenv pip install -e . Now, launch a Neo4j docker instance to serve Scientio , so the dialog system has a memory: docker run \\ --publish=7474:7474 --publish=7687:7687 \\ --volume=$HOME/neo4j/data:/data \\ --volume=$HOME/neo4j/logs:/logs \\ neo4j:latest # Open the address localhost:7474 in a browser, and enter the # credentials `neo4j`/`neo4j`. You will then be prompted to enter # your own password. Remember this password. In the config folder, create a file called keys.yml . It should have the following content: module: telegramio config: telegram-token: # This is where your own telegram bot token # will go later --- module: ontology config: neo4j_address: bolt://localhost:7687 # Your neo4j server uri here neo4j_username: neo4j # Your neo4j user here neo4j_pw: test # Your neo4j pw here You may now conduct your first conversation with ravestate: python3 -m ravestate -f config/generic.yml -f config/keys.yml After the conversation, check the Neo4j interface under localhost:7474 . It should now contain some nodes! Reminder: Whenever you use ravestate from the command line, activate the virtual environment first!","title":"Initial configuration and setup"},{"location":"#setting-up-pycharm","text":"Open your local ravestate clone as a project in pycharm. Mark the modules folder as sources root via the right-click context menu. Create a run config al\u00e0 the \"Edit configurations menu\": \u2022 Create a new Python configuration. \u2022 Set modules/ravestate/__main__.py as the script to execute \u2022 Set the working directory to the git clone directory. \u2022 Set parameters to -f config/generic.yml -f config/keys.yml . You should now be able to run the generic ravestate config from pycharm.","title":"Setting up PyCharm"},{"location":"#running-hello-world","text":"Ravestate applications are defined by a configuration, which specifies the ravestate modules that should be loaded. To run the basic hello world application, run ravestate with a config file or command line arguments:","title":"Running Hello World"},{"location":"#running-with-command-line-spec","text":"You can easily run a combination of ravestate modules in a shared context, by listing them as arguments to python3 -m ravestate : python3 -m ravestate \\ ravestate_wildtalk \\ ravestate_conio \\ ravestate_hibye \\ ravestate_persqa Run python3 -m ravestate -h to see more options!","title":"Running with command line spec"},{"location":"#running-with-config-files","text":"You may specify a series of config files to configure ravestate context, when specifying everything through the command line becomes too laborious: # In file hello_world.yml module: core config: import: - ravestate_wildtalk - ravestate_conio - ravestate_hibye - ravestate_persqa Then, run ravestate with this config file: python3 -m ravestate -f hello_world.yml","title":"Running with config file(s)"},{"location":"#module-overview","text":"Ravestate offers a landscape of fine-grained modules for different aspects of dialog application tasks, which may be seen in the following dependency diagram. Broadly, the modules are categorized into Core (Blue), I/O (Yellow), External (Red) and Skills (Green):","title":"Module overview"},{"location":"#core-modules","text":"Module name Description ravestate Core ravestate library. ravestate_rawio Provides raw_in , raw_out , pic_in properties, which are served by the IO modules. ravestate_ontology Connects to scientio to serve a built-in ontology. ravestate_interloc Provides the all_interlocutors property, where present interlocutors are registered by the IO modules. ravestate_idle Provides bored and impatient signals, as specified here . ravestate_verbaliser Utilities for easy management of conversational text, documented here . ravestate_nlp Spacy-based NLP properties and signals, documented here . ravestate_ros2 Provides specific Ros2PubProperty , Ros2SubProperty and Ros2CallProperty context props., which greatly simplify working with ROS2 in ravestate.","title":"Core Modules"},{"location":"#io-modules","text":"Module name Description ravestate_conio Simple command-line based IO for development purposes. ravestate_telegramio Single- or Multi-process Telegram server module, documented here . ravestate_roboyio PyroBoy -based STT/TTS with ROS2.","title":"IO Modules"},{"location":"#skill-modules","text":"Module name Description ravestate_wildtalk ParlAI -based generative conversational module. ravestate_hibye Simply voices Hi! (or the likes thereof) when an interlocutor is added, and Bye when one is removed. ravestate_persqa Conducts personalized smalltalk with interlocutors, interacts with Scientio to persist trivia. ravestate_genqa DrQA -based general question answering module. ravestate_roboyqa QA module which provides answers to questions about Roboy, such as Who is your dad? ravestate_akinator Enables dialog-based play of Akinator! ravestate_sendpics Uses face recognition to extract facial features and an assiciated Person with pic_in and ontology, which are then persisted in Redis and Scientio. ravestate_stalker Uses facial feature <-> person tuples generated by sendpics, to surprise people in front of a camera with knowledge of their names.","title":"Skill Modules"},{"location":"#running-tests","text":"If you have installed the dependencies from requirements-dev.txt you may run the ravestate test suite as follows: ./run_tests.sh","title":"Running tests"},{"location":"#docker-for-ros-and-ros2","text":"There is a Dockerfile for ROS and ROS2 support which can be built with docker build -t ravestate-ros2-image . The image contains ROS, ROS2 and a ROS Bridge to connect ROS with ROS2. Furthermore the roboy_communication message and service types are installed. A container can then be created with the docker-compose.yml: docker-compose up --detach ravestate The container is now running and a connection into the container can be established with: docker exec -it ravestate-ros2-container bash Inside the container, first source the ROS2 setups and then ravestate can be run with ROS2 and rclpy available. source ~/ros2_ws/install/setup.sh python3 -m ravestate [...]","title":"Docker for ROS and ROS2"},{"location":"#start-ros-bridge","text":"In order to start ROS Bridge, the image and container have to be set up as above. After connecting into the container run from inside the container: export ROS_IP=192.168.0.105 source ~/melodic_ws/devel/setup.sh source ~/ros2_ws/install/setup.sh source ~/ros1_bridge_ws/install/setup.sh ros2 run ros1_bridge dynamic_bridge","title":"Start ROS Bridge"},{"location":"#buildingmaintaining-the-docs","text":"If you have installed the dependencies from requirements-dev.txt , generate the docs by running this command at project root: export PYTHONPATH=$PYTHONPATH:$(pwd)/modules git rm -rf docs rm -rf _build docs pydocmd build mkdir -p docs/resources/docs && cp resources/docs/*.png docs/resources/docs && cp resources/docs/*.gif docs/resources/docs git add docs/* # For inspection: python3 -m http.server --directory docs The structure and content of the docs are defined in the file pydocmd.yml .","title":"Building/maintaining the docs"},{"location":"config/","text":"ravestate.argparser handle_args handle_args(*args) -> Tuple[List[str], List[Tuple[str, str, Any]], List[str]] Runs an argument parser for the given args. Returns modules-to-load, config value-overrides and config file-pathes. Note: If the arguments are ill-formatted, or the -h argument is passed, help will be printed to the console and the program will abort. args : Argument list which will be fed into argparse.parse_args. Returns: A Tuple with three items: 1.) A list of module names which should be imported. 2.) A list of tuples, where each tuple is a module name, a config key name, and a value. 3.) A list of yaml file paths. ravestate.config Configuration Configuration(self, paths: List[str]) The Configuration class maintains a dictionary of key-value stores, which represent configuration entries for specific named modules. The key-value stores may be successively updated with consecutive yaml files, where each yaml document has the following content: module: module-name config: key-a: value-a key-b: value-b # etc add_conf Configuration.add_conf(self, mod: ravestate.module.Module) Register a set of allowed config entries for a specific module. Correctly typed values for allowed keys, that were previously parsed during construction from the yaml files, will be applied immediately. mod : A module object with a name and a conf dict. get_conf Configuration.get_conf(self, module_name: str) Retrieve updated config values for a module that was previously registered with add_conf. module_name : The module name for which configuration should be retrieved. Returns: A dictionary which contains exactly the keys that were contained in the module configuration dictionary during add_conf, or an empty dictionary if the module name is unknown. get Configuration.get(self, module_name: str, key: str) -> Any Get the current value of a config entry. module_name : The module that provides the config entry. key : A config key for the module that was previously added through add_conf. Returns: The current value, or None, if the entry does not exist. set Configuration.set(self, module_name: str, key: str, value: Any) Set the current value of a config entry. module_name : The module of the config entry. key : A config key for the module that was previously added through add_conf. value : The new value for the config entry. An error will be raised, if the type of the new value does not match the type of the old value. write Configuration.write(self, path: str) Write all current config entries to a yaml file. path : The file path to write. Will be overwritten! read Configuration.read(self, path: str) Loads all documents from a yaml file and tries to interpret them as configuration objects as described above. path : The yaml file path from which to load config documents.","title":"Configuration"},{"location":"context/","text":"ravestate.context create_and_run_context create_and_run_context(*args, runtime_overrides=None) Creates a new Context with the given parameters and runs it Context Context(self, *arguments, runtime_overrides: List[Tuple[str, str, Any]] = None) emit Context.emit(self, signal: ravestate.constraint.Signal, parents: Set[ravestate.spike.Spike] = None, wipe: bool = False, payload: Any = None) -> None Emit a signal to the signal processing loop. Note: The signal will only be processed if run() has been called! signal : The signal to be emitted. parents : The signal's parents, if it is supposed to be integrated into a causal group. wipe : Boolean to control, whether wipe (signal) should be called before the new spike is created. payload : Value that should be embedded in the new spike. wipe Context.wipe(self, signal: ravestate.constraint.Signal) Delete all spikes for the given signal. Partially fulfilled states that have acquired an affected spike will be forced to reject it. Wiping a parent spike will also wipe all child spikes. signal : The signal for which all existing spikes (and their children) should be invalidated and forgotten. run Context.run(self) -> None Creates a signal processing thread, starts it, and emits the core:startup signal. shutting_down Context.shutting_down(self) -> bool Retrieve the shutdown flag value, which indicates whether shutdown() has been called. shutdown Context.shutdown(self) -> None Sets the shutdown flag and waits for the signal processing thread to join. add_module Context.add_module(self, module_name: str) -> None Add a module by python module folder name, or by ravestate module name. module_name : The name of the module to be added. If it is the name of a python module that has not been imported yet, the python module will be imported, and any ravestate modules registered during the python import will also be added to this context. add_state Context.add_state(self, *, st: ravestate.state.State) -> None Add a state to this context. It will be indexed wrt/ the properties/signals it depends on. Error messages will be generated for unknown signals/properties. st : The state which should be added to this context. rm_state Context.rm_state(self, *, st: ravestate.state.State) -> None Remove a state from this context. Note, that any state which is constrained on the signal that is emitted by the deleted state will also be deleted. st : The state to remove. An error message will be generated, if the state was not previously added to this context with add_state(). add_prop Context.add_prop(self, *, prop: ravestate.property.Property) -> None Add a copy of a property to this context. An error message will be generated, if a property with the same name has already been added previously. Note: Context will adopt a copy of the given property, the actual property will not be changed. prop : The property object that should be added. rm_prop Context.rm_prop(self, *, prop: ravestate.property.Property) -> None Remove a property from this context. Generates error message, if the property was not added with add_prop() to the context previously prop : The property to remove.object conf Context.conf(self, *, mod: str, key: Union[str, NoneType] = None) -> Any Get a single config value, or all config values for a particular module. mod : The module whose configuration should be retrieved. key : A specific config key of the given module, if only a single config value should be retrieved. Returns: The value of a single config entry if key and module are both specified and valid, or a dictionary of config entries if only the module name is specified (and valid). signal_specificity Context.signal_specificity(self, sig: ravestate.constraint.Signal) -> float Called by state activation to determine it's constraint's specificity. sig : The signal whose specificity should be returned. Returns: The given signal's specificity. reacquire Context.reacquire(self, act: ravestate.iactivation.IActivation, sig: ravestate.constraint.Signal) Called by activation, to indicate, that it needs a new Spike for the specified signal, and should for this purpose be referenced by context. Note: Not thread-safe, sync must be guaranteed by caller. act : The activation that needs a new spike of the specified nature. sig : Signal type for which a new spike is needed. withdraw Context.withdraw(self, act: ravestate.iactivation.IActivation, sig: ravestate.constraint.Signal) Called by activation to make sure that it isn't referenced anymore as looking for the specified signal. This might be, because the activation chose to eliminate itself due to activation pressure, or because one of the activations conjunctions was fulfilled, so it is no longer looking for signals to fulfill the remaining conjunctions. Note: Not thread-safe, sync must be guaranteed by caller. act : The activation that has lost interest in the specified signal. sig : Signal type for which interest is lost. secs_to_ticks Context.secs_to_ticks(self, seconds: float) -> int Convert seconds to an equivalent integer number of ticks, given this context's tick rate. seconds : Seconds to convert to ticks. Returns: An integer tick count. possible_signals Context.possible_signals(self, state: ravestate.state.State) -> Generator[ravestate.constraint.Signal, NoneType, NoneType] Yields all signals, for which spikes may be created if the given state is executed. state : The state, which should be analyzed for it's possibly generated signals (declared signal + property-changed signals). run_once Context.run_once(self, seconds_passed=1.0, debug=False) -> None Run a single update for this context, which will ... (0) progress cooled down state weights. (1) reduce redundant candidate activations. (2) associate new spikes with state activations. (3) update state activations. (4) forget spikes which have no suitors in their causal groups. (5) age spikes. (6) invoke garbage collection. (7) update the core:activity and core:pressure variables. seconds_passed : Seconds, as floatiing point, since the last update. Will be used to determine the number of ticks to add/subtract to/from spike/activation age/cooldown/deathclock. test Context.test(self) -> bool Execute internal integrity checks. ravestate.spike Spike Spike(self, *, sig: str, parents: Set[ForwardRef('Spike')] = None, consumable_resources: Set[str] = None, payload: Any = None) This class encapsulates a single spike, to track ... ... it's consumption for different output properties (through CausalGroup ). ... it's offspring instances (causal group -> spikes caused by this spike) causal_group Spike.causal_group(self) -> ravestate.causal.CausalGroup Get this spike's causal group. Returns: This instances causal group. Should never be None. adopt Spike.adopt(self, child: 'Spike') -> None Called in spike constructor, for instances which claim to be caused by this spike. child : The child to add to this spike's causal group. wiped Spike.wiped(self, child: 'ISpike') -> None Called by an offspring signal, to notify the spike that it was wiped, and should therefore be removed from the children set. child : The child to be forgotten. wipe Spike.wipe(self, already_wiped_in_causal_group: bool = False) -> None Called either in Context run loop when the spike is found to be stale (with wiped_in_causal_group=True), or in Context.wipe(spike), or by parent (recursively). After this function is called, the spike should be cleaned up by GC. already_wiped_in_causal_group : Boolean which indicates, whether wiped(spike) must still be called on the group to make sure sure that no dangling references to the spike are maintained by any state activations. has_offspring Spike.has_offspring(self) Called by CausalGroup.stale(spike). Returns: True if the spike has active offspring, false otherwise. tick Spike.tick(self) -> None Increment this spike's age by 1. age Spike.age(self) -> int Obtain this spike's age (in ticks). offspring Spike.offspring(self) -> Generator[ForwardRef('Spike'), NoneType, NoneType] Recursively yields this spike's offspring and it's children's offspring. Returns: All of this spike's offspring spikes. is_wiped Spike.is_wiped(self) Check, whether this spike has been wiped, and should therefore not be acquired anymore. payload Spike.payload(self) -> Any Get payload for this spike. The payload is an arbitrary value passed in Context.emit() . ravestate.activation Activation Activation(self, st: ravestate.state.State, ctx: ravestate.icontext.IContext) Encapsulates the potential activation of a state. Tracks the collection of Spikes to fulfill of the state-defined activation constraints. resources Activation.resources(self) -> Set[str] Return's the set of the activation's write-access property names. specificity Activation.specificity(self) -> float Returns the lowest specificity among the specificity values of the activation's conjunct constraints. The specificity for a single conjunction is calculated as the sum of it's component signal's specificities, which in turn is calculated as one over the signal's subscriber count. dereference Activation.dereference(self, *, spike: Union[ravestate.iactivation.ISpike, NoneType] = None, reacquire: bool = False, reject: bool = False, pressured: bool = False) -> None Notify the activation, that a single or all spike(s) are not available anymore, and should therefore not be referenced anymore by the activation. This is called by ... ... context when a state is deleted. ... causal group, when a referenced signal was consumed for a required property. ... causal group, when a referenced signal was wiped. ... this activation (with reacquire=True and pressured=True), if it gives in to activation pressure. spike : The spike that should be forgotten by the activation, or none, if all referenced spikes should be forgotten. reacquire : Flag which tells the function, whether for every rejected spike, the activation should hook into context for reacquisition of a replacement spike. reject : Flag which controls, whether de-referenced spikes should be explicitely rejected through their causal groups. pressured : Flag which controls, whether de-referencing should only occur for spikes of causal groups in the pressuring_causal_groups set. acquire Activation.acquire(self, spike: ravestate.spike.Spike) -> bool Let the activation acquire a signal it is registered to be interested in. spike : The signal which should fulfill at least one of this activation's signal constraints. Returns: True if the spike was acquired by at least one signal, false if acquisition failed: This may happen for multiple reasons: (1) Acquisition failed, because the spike is too old (2) Acquisition failed, because the spike's causal group does not match it's completions. (3) Acquisition failed, because the spike's causal group does not offer all of this activation's state's write-props. secs_to_ticks Activation.secs_to_ticks(self, seconds: float) -> int Convert seconds to an equivalent integer number of ticks, given this activation's tick rate. seconds : Seconds to convert to ticks. Returns: An integer tick count. pressure Activation.pressure(self, give_me_up: ravestate.iactivation.ICausalGroup) Called by CausalGroup, to pressure the activation to make a decision on whether it is going to retain a reference to the given spike, given that there is a lower- specificity activation which is ready to run. give_me_up : Causal group that wishes to be de-referenced by this activation. is_pressured Activation.is_pressured(self) Called by context, to figure out whether the activation is pressured, and therefore the idle:bored signal should be emitted. spiky Activation.spiky(self) -> bool Returns true, if the activation has acquired any spikes at all. Returns: True, if any of this activation's constraint's signal is referencing a spike. spikes Activation.spikes(self) -> Generator[ravestate.spike.Spike, NoneType, NoneType] Returns iterable for all the spikes currently acquired by the activation. possible_signals Activation.possible_signals(self) -> Generator[ForwardRef('Signal'), NoneType, NoneType] Yields all signals, for which spikes may be created if this activation's state is executed. effect_not_caused Activation.effect_not_caused(self, group: ravestate.iactivation.ICausalGroup, effect: str) -> None Notify the activation, that a follow-up signal will not be produced by the given causal group. The activation will go through it's constraint, and reject all completion spikes for signals of name effect , if the completion spikes are from the given causal group. group : The causal group which will not contain a spike for signal effect . effect : Name of the signal for which no spike will be produced. update Activation.update(self) -> bool Called once per tick on this activation, to give it a chance to activate itself, or auto-eliminate, or reject spikes which have become too old. Returns: True, if the target state is activated and teh activation be forgotten, false if needs further attention in the form of updates() by context in the future. ravestate.causal CausalGroup CausalGroup(self, resources: Set[str]) Class which represents a causal group graph of spike parent/offspring spikes (a \"superspike\"). These must synchronize wrt/ their (un)written properties and state activation candidates, such that they don't cause output races. Note: Always use a with ... construct to interact with a causal group. Otherwise, undefined behavior may occur due to race conditions. merge CausalGroup.merge(self, other: 'CausalGroup') Merge this causal group with another. Unwritten props will become the set intersection of this group's unwritten props and other's unwritten props. consumed() will be called with all properties that are consumed by other, but not this. Afterwards, other's member objects will be set to this's. acquired CausalGroup.acquired(self, spike: 'ISpike', acquired_by: ravestate.iactivation.IActivation, detached: bool) -> bool Called by Activation to notify the causal group, that it is being referenced by an activation constraint for a certain member spike. spike : State activation instance, which is now being referenced by the specified causal group. acquired_by : State activation instance, which is interested in this property. detached : Tells the causal group, whether the reference is detached, and should therefore receive special treatment. Returns: Returns True if all of the acquiring's write-props are free, and the group now refs. the activation, False otherwise. rejected CausalGroup.rejected(self, spike: 'ISpike', rejected_by: ravestate.iactivation.IActivation, reason: int) -> None Called by a state activation, to notify the group that a member spike is no longer being referenced for the given state's write props. This may be because ... ... the activation's dereference function was called. (reason=0) ... the spike got too old. (reason=1) ... the activation happened and is dereferencing it's spikes. (reason=2) spike : The member spike whose ref-set should be reduced. rejected_by : State activation instance, which is no longer interested in this property. reason : See about. consent CausalGroup.consent(self, ready_suitor: ravestate.iactivation.IActivation) -> bool Called by constraint, to inquire whether this causal group would happily be consumed for the given state activation's properties. This will be called periodically on the group by state activations that are ready to go. Therefore, a False return value from this function is never a final judgement (more like a \"maybe later\"). ready_suitor : The state activation which would like to consume this instance for it's write props. Returns: True if this instance agrees to proceeding with the given consumer for the consumer's write props, False otherwise. activated CausalGroup.activated(self, act: ravestate.iactivation.IActivation) Called by activation which previously received a go-ahead from consent(), when it is truly proceeding with running (after it got the go-ahead from all it's depended=on causal groups). act : The activation that is now running. resigned CausalGroup.resigned(self, act: ravestate.iactivation.IActivation) -> None Called by activation, to let the causal group know that it failed, and a less specific activation may now be considered for the resigned state's write props. act : The activation that is unexpectedly not consuming it's resources, because it's state resigned/failed. consumed CausalGroup.consumed(self, resources: Set[str]) -> None Called by activation to notify the group, that it has been consumed for the given set of properties. resources : The properties which have been consumed. wiped CausalGroup.wiped(self, spike: 'ISpike') -> None Called by a spike, to notify the causal group that the instance was wiped and should no longer be remembered. spike : The instance that should be henceforth forgotten. stale CausalGroup.stale(self, spike: 'ISpike') -> bool Determine, whether a spike is stale (has no remaining interested activations and no children). Returns: True, if no activations reference the given spike for any unwritten property. False otherwise. check_reference_sanity CausalGroup.check_reference_sanity(self) -> bool Make sure, that the refcount-per-act-per-spike-per-resource value sum is equal to the number of spikes from this causal group acquired per activation for each activation in the index. :return: True if the criterion is fulfilled, False otherwise.","title":"Context"},{"location":"modules/","text":"ravestate.module Module Module(self, *, name: str, config: Dict[str, Any] = None) Atomic class, which encapsulates a named set of states, properties and config entries, which form a coherent bundle. Example: with Module(name=\"my_module\", config={\"paramA\": 42}): # define properties # define states registered_modules dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2) import_module import_module(*, module_name: str, callback) Called by context to import a particular ravestate python module. module_name : The name of the python module to be imported (must be in pythonpath). callback : A callback which should be called when a module calls register() while it is being imported. has_module has_module(module_name: str) Check whether a module with a particular name has been registered. module_name : The name which should be checked for beign registered. Returns: True if a module with the given name has been registered, false otherwise. get_module get_module(module_name: str) Get a registered module with a particular name module_name : The name of the moduke which should be retrieved. Returns: The module with the given name if it was registered, false if otherwise.","title":"Modules"},{"location":"properties/","text":"ravestate.property Property Property(self, *, name='', allow_read=True, allow_write=True, allow_push=True, allow_pop=True, default_value=None, always_signal_changed=False, is_flag_property=False, wipe_on_changed=True) Base class for context properties. Controls read/write/push/pop/delete permissions, property name basic impls. for the property value, parent/child mechanism. Example (Creating a module containing a property named my_property): with Module(name=\"my_module\"): my_property = Property(name=\"my_property\") set_parent_path Property.set_parent_path(self, path) Set the ancestors (including modulename) for a property path : ancestry in the form of modulename:parent_prop_name (or simply modulename) gather_children Property.gather_children(self) -> List[ForwardRef('Property')] Collect this property, and all of it's children. read Property.read(self) Read the current property value write Property.write(self, value) Write a new value to the property value : The new value. Returns: True if the value has changed and :changed should be signaled, false otherwise. push Property.push(self, child: 'Property') Add a child to the property child : The child object Returns: True if the child was added successfully, false otherwise. pop Property.pop(self, child_name: str) Remove a child from the property by it's name. child_name : Name of the child to be removed. Returns: True if the pop was successful, False otherwise changed Property.changed(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when write() returns True. pushed Property.pushed(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when push() returns True. popped Property.popped(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when pop() returns True. true Property.true(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when it is a flag-property and self.value is set to True. false Property.false(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when it is a flag-property and self.value is set to False. signals Property.signals(self) -> Generator[ravestate.constraint.Signal, NoneType, NoneType] Yields all signals that may be emitted because of this property, given it's write/push/pop permissions.","title":"Properties"},{"location":"states/","text":"state state(*, signal: Union[ravestate.constraint.Signal, NoneType] = '', write: Tuple[ravestate.property.Property] = (), read: Tuple[ravestate.property.Property] = (), cond: ravestate.constraint.Constraint = None, emit_detached: bool = False, weight: float = 1.0, cooldown: float = 0.0) Decorator to declare a new state, which may emit a certain signal, write to a certain set of properties (calling write, push, pop), and read from certain properties (calling read). Example (Module that outputs \"Don't Panic\" after startup): with Module(name=\"my_module\"): @state(cond=startup()) def after_startup(context, write=OUTPUT_PROPERTY): context[OUTPUT_PROPERTY] = \"Don't Panic\" ravestate.constraint ConfigurableAge ConfigurableAge(self, key: str) Class for having min/max_age parameters for Constraints configurable with a config key key str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object. str () (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'. Constraint Constraint(self, /, *args, **kwargs) Superclass for Signal, Conjunct and Disjunct Signal Signal(self, name: str, *, min_age=0.0, max_age=5.0, detached=False, _skip_module_context=False) Class that represents a Signal. Should be constructed in a with Module(..) context, such that it's module scope is set automatically. SignalRef SignalRef(self, name: str, *, min_age=0.0, max_age=5.0, detached=False) Signal reference. Almost the same as a signal, except that it will not try to auto-discover it's module out of thread-local context (module_name will stay unfilled). Needed, because sometimes you need to reference a singal within a module scope without assigning that signal to the contextual module. Conjunct Conjunct(self, *args) Class that represents a Conjunction of Signals. Can be constructed using an overloaded & operator. Example: signal_A & signal_B Disjunct Disjunct(self, *args) Class that represents a Disjunction of Conjunctions Can be constructed using an overloaded | operator. Examples: conjunction_A | conjunction_B (signal_A & signal_B) | (signal_C & signal_D) receptor receptor(*, ctx_wrap: Union[ravestate.wrappers.ContextWrapper, ravestate.context.Context], write: Union[str, ravestate.property.Property, Tuple[Union[str, ravestate.property.Property]]]) A receptor is a special state which can be invoked from outside, to push values into the context. ctx_wrap : A context wrapper as is always given into the state functions as their first argument. write : The property, or tuple of properties, which are going to be written. Example: # Module that outputs \"Don't Panic\" one minute after startup # Because a receptor is used, the OUTPUT_PROPERTY is not blocked the whole time with Module(name=\"my_module\"): @state(cond=startup()) def after_startup(context): @receptor(ctx_wrap=context, write=OUTPUT_PROPERTY) def dont_panic(ctx_write): ctx_write[OUTPUT_PROPERTY] = \"Don't Panic\" sleep(60) dont_panic()","title":"States"},{"location":"modules/ravestate_akinator/","text":"_ _ | | (_) _ _____| | _ _ ____ _____ _| |_ ___ ____ (____ | |_/ ) | _ \\(____ (_ _) _ \\ / ___) / ___ | _ (| | | | / ___ | | || |_| | | \\_____|_| \\_)_|_| |_\\_____| \\__)___/|_| 20 Questions with Akinator The Ravestate Akinator module offers an implementation of the 20 questions game. It consists of a wrapper for the API calls to the Akinator web game and several states to handle the game flow with the interlocutor. Architecture This is an overview of the dialog flow for the 20 questions game. Starting the Game There are two possibilities to trigger the game: 1. Interlocutor input: \"I want to play\", \"I like games\" or something similar 2. Automatically through Ravestate: When the system gets bored (no dialog states are active but an interlocutor is present) then Akinator is one of the possible modules that will be triggered. The API Wrapper api.py handles the requests to the online Akinator game. There are three different types of get requests to handle the game: 1. Question asking phase: post the answer to the previous question and retrieve the next question 2. Guessing phase: retrieve the guess 3. Game finishing phase: give Akinator feedback on his guess","title":"Akinator"},{"location":"modules/ravestate_akinator/#20-questions-with-akinator","text":"The Ravestate Akinator module offers an implementation of the 20 questions game. It consists of a wrapper for the API calls to the Akinator web game and several states to handle the game flow with the interlocutor.","title":"20 Questions with Akinator"},{"location":"modules/ravestate_akinator/#architecture","text":"This is an overview of the dialog flow for the 20 questions game.","title":"Architecture"},{"location":"modules/ravestate_akinator/#starting-the-game","text":"There are two possibilities to trigger the game: 1. Interlocutor input: \"I want to play\", \"I like games\" or something similar 2. Automatically through Ravestate: When the system gets bored (no dialog states are active but an interlocutor is present) then Akinator is one of the possible modules that will be triggered.","title":"Starting the Game"},{"location":"modules/ravestate_akinator/#the-api-wrapper","text":"api.py handles the requests to the online Akinator game. There are three different types of get requests to handle the game: 1. Question asking phase: post the answer to the previous question and retrieve the next question 2. Guessing phase: retrieve the guess 3. Game finishing phase: give Akinator feedback on his guess","title":"The API Wrapper"},{"location":"modules/ravestate_nlp/","text":"_ | | ____ | | ____ | _ \\| || _ \\ | | | | || |_| | |_| |_|\\_) __/ |_| NLP The natural language processing (NLP) module enables Roboy to process and understand the human language. That way he can interpret the meaning of the detected sentences. We use a free, open-source NLP library for advanced NLP in Python: spaCy Extracted Features Feature Ravestate Properties/Signals Description Example Sentence: 'Revolutions need six fancy chickens!' Tokenization nlp.prop_tokens Segmenting text into words, punctuation marks etc. 'Revolutions', 'need', 'six', 'fancy', 'chickens', '!' Part-of-Speech (POS) Tagging nlp.prop_postags Assigning word types to tokens 'NOUN', 'VERB', 'NUM', 'ADJ', 'NOUN', 'PUNCT' Detailed POS Tag nlp.prop_tags Fine-grained part-of-speech 'Revolutions' has the tag: 'NNS', which stand for: noun, plural 'need' has the tag: 'VBP', which stands for: verb, non-3rd person singular present List of POS tags Lemmatization nlp.prop_lemmas Assigning the base forms of words 'Revolutions' has the lemma: 'revolution' 'was' would have the lemma: 'be' Named Entity Recognition (NER) nlp.prop_ner Labelling \"real-world\" objects (\"NE\"=Named Entity) 'six' has the NE: 'CARDINAL', which are numerals that do not fall under another type List of NEs Triple Extraction nlp.prop_triples A triple consists of subject, predicate, object of sentence Triple: subject: 'Revolutions', predicate: 'need', object: 'chickens' About Roboy nlp.prop_roboy Detecting whether sentence is about Roboy 'you', 'roboy', 'robot', 'roboboy', ... Yes-No nlp.prop_yesno Detecting answers to yes-no questions Checking for 'yes', 'no', 'i don't know', 'probably', 'probably not' and synonyms of these Sentence Type: Question nlp.sig_is_question Emitted if the input sentence is a question Play Game nlp.sig_intent_play Emitted when the interlocutor wants to play a game input: \"I want to play\", \"I like games\" or something similar Additional features can be added and published to the system. All existing features can be found here . Using the Features React to Property Change Each feature is stored in a ravestate property. A state which wants to access a property needs read permissions for that property. Example: State that reads the \"yesno\" property import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_yesno.changed(), # state reacts to a change in the 'yesno' property read=nlp.prop_yesno, # state is allowed to read the 'yesno' property write=rawio.prop_out) # state is allowed to write to the output property def postive_chicken(ctx: ContextWrapper): if ctx[nlp.prop_yesno] == \"yes\": ctx[rawio.prop_out] = \"You seem to be a positive chicken!\" React to Signals For 'Sentence Type: Question' a signal is emitted. Example: State that reacts to the \"is-question\" signal import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.sig_is_question, # state reacts to the is-question signal write=rawio.prop_out) # state is allowed to write to the output property def curious_chicken(ctx: ContextWrapper): ctx[nlp.prop_out] = \"You seem to ask a lot of questions, chicken!\" Using the Triples for Sentence Analysis The triple extraction is done in extract_triples.py by using the dependency tree of the sentence. A dependency tree shows the relation between the words of a sentence. The finite verb (predicate) is the structural center of the sentence and therefor of the tree. So starting with the predicate the algorithm searches through the dependency tree to find subject and object. Analyzing a Sentence Example: 'Chickens like revolutions' reaction state Triple: subject: 'Chickens', predicate: 'like', object: 'revolutions' import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_triples.changed(), # state reacts to a change in the 'triples' property read=nlp.prop_triples, # state is allowed to read the 'triples' property write=rawio.prop_out) # state is allowed to write to the output chanel def postive_chicken(ctx: ContextWrapper): triple = ctx[nlp.prop_triples][0] # gives you the first Triple object # check predicate and object correspondingly # match_either_lemma() is a method in the Triple class if triple.match_either_lemma(subj={\"chicken\", \"dinosaur\"}): # returns true when subj, pred or obj have the desired value ctx[rawio.prop_out] = \"You said something about a chicken, i like chickens!\" Happy language processing to all chickens out there!","title":"NLP"},{"location":"modules/ravestate_nlp/#nlp","text":"The natural language processing (NLP) module enables Roboy to process and understand the human language. That way he can interpret the meaning of the detected sentences. We use a free, open-source NLP library for advanced NLP in Python: spaCy","title":"NLP"},{"location":"modules/ravestate_nlp/#extracted-features","text":"Feature Ravestate Properties/Signals Description Example Sentence: 'Revolutions need six fancy chickens!' Tokenization nlp.prop_tokens Segmenting text into words, punctuation marks etc. 'Revolutions', 'need', 'six', 'fancy', 'chickens', '!' Part-of-Speech (POS) Tagging nlp.prop_postags Assigning word types to tokens 'NOUN', 'VERB', 'NUM', 'ADJ', 'NOUN', 'PUNCT' Detailed POS Tag nlp.prop_tags Fine-grained part-of-speech 'Revolutions' has the tag: 'NNS', which stand for: noun, plural 'need' has the tag: 'VBP', which stands for: verb, non-3rd person singular present List of POS tags Lemmatization nlp.prop_lemmas Assigning the base forms of words 'Revolutions' has the lemma: 'revolution' 'was' would have the lemma: 'be' Named Entity Recognition (NER) nlp.prop_ner Labelling \"real-world\" objects (\"NE\"=Named Entity) 'six' has the NE: 'CARDINAL', which are numerals that do not fall under another type List of NEs Triple Extraction nlp.prop_triples A triple consists of subject, predicate, object of sentence Triple: subject: 'Revolutions', predicate: 'need', object: 'chickens' About Roboy nlp.prop_roboy Detecting whether sentence is about Roboy 'you', 'roboy', 'robot', 'roboboy', ... Yes-No nlp.prop_yesno Detecting answers to yes-no questions Checking for 'yes', 'no', 'i don't know', 'probably', 'probably not' and synonyms of these Sentence Type: Question nlp.sig_is_question Emitted if the input sentence is a question Play Game nlp.sig_intent_play Emitted when the interlocutor wants to play a game input: \"I want to play\", \"I like games\" or something similar Additional features can be added and published to the system. All existing features can be found here .","title":"Extracted Features"},{"location":"modules/ravestate_nlp/#using-the-features","text":"","title":"Using the Features"},{"location":"modules/ravestate_nlp/#react-to-property-change","text":"Each feature is stored in a ravestate property. A state which wants to access a property needs read permissions for that property. Example: State that reads the \"yesno\" property import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_yesno.changed(), # state reacts to a change in the 'yesno' property read=nlp.prop_yesno, # state is allowed to read the 'yesno' property write=rawio.prop_out) # state is allowed to write to the output property def postive_chicken(ctx: ContextWrapper): if ctx[nlp.prop_yesno] == \"yes\": ctx[rawio.prop_out] = \"You seem to be a positive chicken!\"","title":"React to Property Change"},{"location":"modules/ravestate_nlp/#react-to-signals","text":"For 'Sentence Type: Question' a signal is emitted. Example: State that reacts to the \"is-question\" signal import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.sig_is_question, # state reacts to the is-question signal write=rawio.prop_out) # state is allowed to write to the output property def curious_chicken(ctx: ContextWrapper): ctx[nlp.prop_out] = \"You seem to ask a lot of questions, chicken!\"","title":"React to Signals"},{"location":"modules/ravestate_nlp/#using-the-triples-for-sentence-analysis","text":"The triple extraction is done in extract_triples.py by using the dependency tree of the sentence. A dependency tree shows the relation between the words of a sentence. The finite verb (predicate) is the structural center of the sentence and therefor of the tree. So starting with the predicate the algorithm searches through the dependency tree to find subject and object.","title":"Using the Triples for Sentence Analysis"},{"location":"modules/ravestate_nlp/#analyzing-a-sentence","text":"Example: 'Chickens like revolutions' reaction state Triple: subject: 'Chickens', predicate: 'like', object: 'revolutions' import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_triples.changed(), # state reacts to a change in the 'triples' property read=nlp.prop_triples, # state is allowed to read the 'triples' property write=rawio.prop_out) # state is allowed to write to the output chanel def postive_chicken(ctx: ContextWrapper): triple = ctx[nlp.prop_triples][0] # gives you the first Triple object # check predicate and object correspondingly # match_either_lemma() is a method in the Triple class if triple.match_either_lemma(subj={\"chicken\", \"dinosaur\"}): # returns true when subj, pred or obj have the desired value ctx[rawio.prop_out] = \"You said something about a chicken, i like chickens!\"","title":"Analyzing a Sentence"},{"location":"modules/ravestate_nlp/#happy-language-processing-to-all-chickens-out-there","text":"","title":"Happy language processing to all chickens out there!"},{"location":"modules/ravestate_telegramio/","text":"_______ _ _____ ____ |__ __| | | |_ _/ __ \\ | | ___| | ___ __ _ _ __ __ _ _ __ ___ | || | | | | |/ _ \\ |/ _ \\/ _` | '__/ _` | '_ ` _ \\ | || | | | | | __/ | __/ (_| | | | (_| | | | | | |_| || |__| | |_|\\___|_|\\___|\\__, |_| \\__,_|_| |_| |_|_____\\____/ __/ | |___/ TelegramIO The TelegramIO module enables ravestate to connect to a Telegram-Bot and chat to people there. The connection to Telegram is managed with python-telegram-bot Architecture There are two main modes for this module: * Single-Process-Mode: All chats share the same context * Multiprocess-Mode: Every chat creates its own context in a separate process Single-Process-Mode In this mode the module handles incoming text messages and pictures from all chats. Outgoing messages are sent to every currently active chat. Multiprocess-Mode In this mode the \"Master\" part of the module is running in the main process of ravestate. Whenever there is a new chat, a new instance of ravestate is started in a new process and a bidirectional pipe is set up to enable communication between the main process and the new child process. Only the main process is connected to the Telegram-Bot and therefore any incoming messages get forwarded to the corresponding child process via the pipe. The main process also forwards any incoming messages it receives through the pipe to the corresponding telegram chat. In order to clean up unused child processes, the main process kills child processes after a configurable amount of inactivity. Child processes running the TelegramIO-Module listen for incoming text messages or pictures on the pipe and write output to the pipe. They only exchange messages with a single chat (indirectly via the pipe). Abilities The TelegramIO module is able to handle incoming text messages as well as incoming pictures. The module creates an interlocutor node for every user it is chatting with, containing the user's telegram-id, username and full name if it is set by the user. Incoming text messages are simply written into the RawIO Input property. For incoming pictures, the picture is saved locally as a file and the filepath is written to the RawIO Pic_In Context property. Messages in the RawIO Output are sent to the Telegram Chat(s). Configuration There are 5 configurable parameters (see init .py ): * telegram-token : Put the Token of your Telegram-Bot here * all_in_one_context : True if Single-Process-Mode should be used, False if Multiprocess-Mode should be used. * child_conn : Not to be set in a config file or via the command line. Will be set by master process as a runtime_override. * child_config_files : If in Multiprocess-Mode, the config-paths listed here will be used when creating a new context for a new chat. * chat_lifetime : The timespan in minutes in which a chat will be kept active after the last message","title":"TelegramIO"},{"location":"modules/ravestate_telegramio/#telegramio","text":"The TelegramIO module enables ravestate to connect to a Telegram-Bot and chat to people there. The connection to Telegram is managed with python-telegram-bot","title":"TelegramIO"},{"location":"modules/ravestate_telegramio/#architecture","text":"There are two main modes for this module: * Single-Process-Mode: All chats share the same context * Multiprocess-Mode: Every chat creates its own context in a separate process","title":"Architecture"},{"location":"modules/ravestate_telegramio/#single-process-mode","text":"In this mode the module handles incoming text messages and pictures from all chats. Outgoing messages are sent to every currently active chat.","title":"Single-Process-Mode"},{"location":"modules/ravestate_telegramio/#multiprocess-mode","text":"In this mode the \"Master\" part of the module is running in the main process of ravestate. Whenever there is a new chat, a new instance of ravestate is started in a new process and a bidirectional pipe is set up to enable communication between the main process and the new child process. Only the main process is connected to the Telegram-Bot and therefore any incoming messages get forwarded to the corresponding child process via the pipe. The main process also forwards any incoming messages it receives through the pipe to the corresponding telegram chat. In order to clean up unused child processes, the main process kills child processes after a configurable amount of inactivity. Child processes running the TelegramIO-Module listen for incoming text messages or pictures on the pipe and write output to the pipe. They only exchange messages with a single chat (indirectly via the pipe).","title":"Multiprocess-Mode"},{"location":"modules/ravestate_telegramio/#abilities","text":"The TelegramIO module is able to handle incoming text messages as well as incoming pictures. The module creates an interlocutor node for every user it is chatting with, containing the user's telegram-id, username and full name if it is set by the user. Incoming text messages are simply written into the RawIO Input property. For incoming pictures, the picture is saved locally as a file and the filepath is written to the RawIO Pic_In Context property. Messages in the RawIO Output are sent to the Telegram Chat(s).","title":"Abilities"},{"location":"modules/ravestate_telegramio/#configuration","text":"There are 5 configurable parameters (see init .py ): * telegram-token : Put the Token of your Telegram-Bot here * all_in_one_context : True if Single-Process-Mode should be used, False if Multiprocess-Mode should be used. * child_conn : Not to be set in a config file or via the command line. Will be set by master process as a runtime_override. * child_config_files : If in Multiprocess-Mode, the config-paths listed here will be used when creating a new context for a new chat. * chat_lifetime : The timespan in minutes in which a chat will be kept active after the last message","title":"Configuration"},{"location":"modules/ravestate_verbaliser/","text":"_ _ _ | | | |(_) _ _ _____ ____| |__ _____| | _ ___ _____ ____ | | | | ___ |/ ___) _ \\(____ | || |/___) ___ |/ ___) \\ V /| ____| | | |_) ) ___ | || |___ | ____| | \\_/ |_____)_| |____/\\_____|\\_)_(___/|_____)_| Verbaliser The Verbaliser produces Roboy's utterances. It diversifies the interactions with Roboy by randomizing the output given a specific intent. Using the Verbaliser Question-Answer Lists YAML files are used to define the actual utterances. In other words: they store everything Roboy can vocalise. To diversify his remarks the Verbaliser randomises similar outputs. The class QAPhrases retrieves the values from a YAML file and parses the containing phrases. Here is a template for such a YAML file: type: qa # remark types: question answering (qa), phrases name: \"INTENT\" # intent or topic Q: # possible questions - \"Question phrasing 1\" - \"Question phrasing 2\" - \"Question phrasing 3\" A: # answers SUCCESS: - \"Possible answer on success 1\" - \"Possible answer on success 2\" FAILURE: - \"Possible answer on failure\" FUP: # follow up questions (for interlocutors that are already known to Roboy) Q: - \"Possible follow up question\" A: - \"Possible follow up answer\" See more examples here . Example for Answering the Question: What happened to the Dinosaurs? Creating the YAML file: Fill in all the possible answers. type: qa name: \"DINO\" A: SUCCESS: - \"I am sure it was a mind-boggingly huge meteorite!\" - \"They smoked too much ash!\" - \"A vulcano had flatulences.\" - \"The chicken were stronger.\" FAILURE: - \"I have no idea what you just said.\" - \"Sorry, I am only interested in dinosaurs.\" Adding this file to the Verbaliser: In this case the file is going to be located in a folder of important facts. However, the single file can similarly be added by itself. The folder is in the same path as the python file adding it. from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_folder(join(dirname(realpath(__file__)), \"important_facts_folder\")) Using the Verbaliser for fancy outputs: This outputs an answer to the question. To understand how to analyse the context of the question have a look at the Natural Language Processing README if input_had_something_to_do_with_dinos and was_a_question: ctx[\"rawio:out\"] = verbaliser.get_random_successful_answer(\"DINO\") else: ctx[\"rawio:out\"] = verbaliser.get_random_failure_answer(\"DINO\") Possible conversation flow: Interlocutor: \"What happend to the Dinosaurs?\" Roboy: \"The chicken were stronger.\" Example for Extracting Phrase Lists The Verbaliser can also be used to get all the imported phrases for a specific intent as a list. Creating the phrases.yml: type: phrases name: \"dino\" opts: - \"Dinos can not scratch their backs.\" - \"Once upon a time these mind-bogglingly huge creatures wandered the earth.\" - \"The longest Dinosaur was the Argentiosaurus.\" --- type: phrases name: \"chicken\" opts: - \" Chickens are not completely flightless.\" - \" There are more chickens out there than programmers.\" - \" If I were a chicken for one day I would say: 'Puk Puk Pukaaak'. Adding the file to the Verbaliser: The YAML file is assumed to be located in the important_phrases folder. The folder is again in the same path as this python script: from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_file(join(dirname(realpath(__file__)), \"important_phrases\", \"phrases.yml\")) Using the Verbaliser to get a list of phrases: Given a specific intent the Verbaliser can be used to return a list of phrases. import ravestate_verbaliser dino_list = ravestate_verbaliser.verbaliser.get_phrase_list('dino') The verbaliser:intent Property The verbaliser:react_to_intent state produces a random phrase output for a given intent. All the possible intents are specified in YAML files that are located in the ravestate_phrases_basic_en folder . The state reads the verbaliser:intent property and outputs one random phrase in the list with that specific intent. It can therefor be triggered as follows: Let's assume that phrases.yml is now located in avestate_phrases_basic_en. @state(cond=s(\"triggered_by_some_signal\"), write=\"verbaliser:intent\") def say_some_nice_chicken_suff(ctx: ContextWrapper): ctx[\"verbaliser:intent\"] = \"chicken\"","title":"Verbaliser"},{"location":"modules/ravestate_verbaliser/#verbaliser","text":"The Verbaliser produces Roboy's utterances. It diversifies the interactions with Roboy by randomizing the output given a specific intent.","title":"Verbaliser"},{"location":"modules/ravestate_verbaliser/#using-the-verbaliser","text":"","title":"Using the Verbaliser"},{"location":"modules/ravestate_verbaliser/#question-answer-lists","text":"YAML files are used to define the actual utterances. In other words: they store everything Roboy can vocalise. To diversify his remarks the Verbaliser randomises similar outputs. The class QAPhrases retrieves the values from a YAML file and parses the containing phrases. Here is a template for such a YAML file: type: qa # remark types: question answering (qa), phrases name: \"INTENT\" # intent or topic Q: # possible questions - \"Question phrasing 1\" - \"Question phrasing 2\" - \"Question phrasing 3\" A: # answers SUCCESS: - \"Possible answer on success 1\" - \"Possible answer on success 2\" FAILURE: - \"Possible answer on failure\" FUP: # follow up questions (for interlocutors that are already known to Roboy) Q: - \"Possible follow up question\" A: - \"Possible follow up answer\" See more examples here .","title":"Question-Answer Lists"},{"location":"modules/ravestate_verbaliser/#example-for-answering-the-question-what-happened-to-the-dinosaurs","text":"Creating the YAML file: Fill in all the possible answers. type: qa name: \"DINO\" A: SUCCESS: - \"I am sure it was a mind-boggingly huge meteorite!\" - \"They smoked too much ash!\" - \"A vulcano had flatulences.\" - \"The chicken were stronger.\" FAILURE: - \"I have no idea what you just said.\" - \"Sorry, I am only interested in dinosaurs.\" Adding this file to the Verbaliser: In this case the file is going to be located in a folder of important facts. However, the single file can similarly be added by itself. The folder is in the same path as the python file adding it. from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_folder(join(dirname(realpath(__file__)), \"important_facts_folder\")) Using the Verbaliser for fancy outputs: This outputs an answer to the question. To understand how to analyse the context of the question have a look at the Natural Language Processing README if input_had_something_to_do_with_dinos and was_a_question: ctx[\"rawio:out\"] = verbaliser.get_random_successful_answer(\"DINO\") else: ctx[\"rawio:out\"] = verbaliser.get_random_failure_answer(\"DINO\") Possible conversation flow: Interlocutor: \"What happend to the Dinosaurs?\" Roboy: \"The chicken were stronger.\"","title":"Example for Answering the Question: What happened to the Dinosaurs?"},{"location":"modules/ravestate_verbaliser/#example-for-extracting-phrase-lists","text":"The Verbaliser can also be used to get all the imported phrases for a specific intent as a list. Creating the phrases.yml: type: phrases name: \"dino\" opts: - \"Dinos can not scratch their backs.\" - \"Once upon a time these mind-bogglingly huge creatures wandered the earth.\" - \"The longest Dinosaur was the Argentiosaurus.\" --- type: phrases name: \"chicken\" opts: - \" Chickens are not completely flightless.\" - \" There are more chickens out there than programmers.\" - \" If I were a chicken for one day I would say: 'Puk Puk Pukaaak'. Adding the file to the Verbaliser: The YAML file is assumed to be located in the important_phrases folder. The folder is again in the same path as this python script: from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_file(join(dirname(realpath(__file__)), \"important_phrases\", \"phrases.yml\")) Using the Verbaliser to get a list of phrases: Given a specific intent the Verbaliser can be used to return a list of phrases. import ravestate_verbaliser dino_list = ravestate_verbaliser.verbaliser.get_phrase_list('dino')","title":"Example for Extracting Phrase Lists"},{"location":"modules/ravestate_verbaliser/#the-verbaliserintent-property","text":"The verbaliser:react_to_intent state produces a random phrase output for a given intent. All the possible intents are specified in YAML files that are located in the ravestate_phrases_basic_en folder . The state reads the verbaliser:intent property and outputs one random phrase in the list with that specific intent. It can therefor be triggered as follows: Let's assume that phrases.yml is now located in avestate_phrases_basic_en. @state(cond=s(\"triggered_by_some_signal\"), write=\"verbaliser:intent\") def say_some_nice_chicken_suff(ctx: ContextWrapper): ctx[\"verbaliser:intent\"] = \"chicken\"","title":"The verbaliser:intent Property"}]} \ No newline at end of file +{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"About ____ __ __ _____ _____ / _ \\____ __ ______ ______/ /_____/ /___ /_ _\\ /_ _\\ / /_/ / __ \\/ / / / __ \\/ ___\\, / __ \\, / __ \\ 0> 0> <0 <0 / ,\\ ,/ /_/ /\\ \\/ / /_/ /\\__, / / /_/ / / /_/ / \\__\u22bd__/ \\__\u22bd__/ \\/ \\/\\__/\\/ \\__/ ,___/\\____/\\/\\__/\\/\\/ ,___/ \u22c2 - Hey! \u22c2 \\____/ \\____/ Ol\u00e0! - Ravestate is a reactive library for real-time natural language dialog systems. It combines elements from event-based and reactive programming into an API, where application states are defined as functions that are run when a certain boolean set of criteria (signals) in the current application context is satisfied. It is the first reactive API to allow for boolean combinations of events. You may find a short introductory video here . Reactive Hello World import ravestate as rs # We want to write some text output, so we # need the raw:out context property from ravestate_rawio. import ravestate_rawio as rawio # Make sure that we use some i/o implementation, # so we can actually see stuff that is written to rawio:out. import ravestate_conio # Ravestate applications should always be wrapped in a Module. # This allows easier scoping, and enables separation of concerns # beyond states. with rs.Module(name=\"hi!\"): # Create an application state which reacts to the `:startup` signal, # and writes a string to raw:out. Note: State functions are # always run asynchronously! @rs.state(cond=rs.sig_startup, write=rawio.prop_out) def hello_world(context): context[rawio.prop_out] = \"Waddup waddup waddup!\" # Run context with console input/output and our 'hi!' module. rs.Context(\"conio\", \"hi!\").run() Visualization Ravestate has a d3.js -based visualization. When using ravestate_ui.UIContext instead of Context , or python3 -m ravestate_ui instead of python3 -m ravestate , a real-time visualization of all states/properties/signals in the state machine will be hosted on port 5001. Here is the view of http://localhost:5001 after launching python3 ravestate_ui -f generic.yml : Installation Via PIP The easiest way to install ravestate is through pip: pip install ravestate Note: Ravestate requires Python 3.6 or higher. It is tested on Ubuntu 16.04 and 18.04, as well as macOS > High Sierra. It is currently not tested on Windows. For reliability, we recommend using an environment virtualization tool, like virtualenv or conda . For developers Initial configuration and setup Clone the repository and install dependencies: # Create a virtual python environment to not pollute the global setup python3 -m virtualenv python-ravestate # Source the virtual environment . python-ravestate/bin/activate # Clone the repo git clone git@github.com:roboy/ravestate && cd ravestate # Install normal requirements pip install -r requirements.txt # To run tests & build docs, install pytest, mocking, fixtures, pydoc, ... pip install -r requirements-dev.txt # Link your local ravestate clone into your virtualenv pip install -e . Now, launch a Neo4j docker instance to serve Scientio , so the dialog system has a memory: docker run \\ --publish=7474:7474 --publish=7687:7687 \\ --volume=$HOME/neo4j/data:/data \\ --volume=$HOME/neo4j/logs:/logs \\ neo4j:latest # Open the address localhost:7474 in a browser, and enter the # credentials `neo4j`/`neo4j`. You will then be prompted to enter # your own password. Remember this password. In the config folder, create a file called keys.yml . It should have the following content: module: telegramio config: telegram-token: # This is where your own telegram bot token # will go later --- module: ontology config: neo4j_address: bolt://localhost:7687 # Your neo4j server uri here neo4j_username: neo4j # Your neo4j user here neo4j_pw: test # Your neo4j pw here You may now conduct your first conversation with ravestate: python3 -m ravestate -f config/generic.yml -f config/keys.yml After the conversation, check the Neo4j interface under localhost:7474 . It should now contain some nodes! Reminder: Whenever you use ravestate from the command line, source the virtual environment first! Running your Telegram bot To test your telegram bot with a custom bot token in your keys.yml , just run telegram_test.yml instead of generic.yml . This will load the ravestate_telegramio module. Setting up PyCharm Open your local ravestate clone as a project in pycharm. Mark the modules folder as sources root via the right-click context menu. Create a run config al\u00e0 the \"Edit configurations menu\": \u2022 Create a new Python configuration. \u2022 Set modules/ravestate/__main__.py as the script to execute \u2022 Set the working directory to the git clone directory. \u2022 Set parameters to -f config/generic.yml -f config/keys.yml . You should now be able to run the generic ravestate config from pycharm. Running Hello World Ravestate applications are defined by a configuration, which specifies the ravestate modules that should be loaded. To run the basic hello world application, run ravestate with a config file or command line arguments: Running with command line spec You can easily run a combination of ravestate modules in a shared context, by listing them as arguments to python3 -m ravestate : python3 -m ravestate \\ ravestate_wildtalk \\ ravestate_conio \\ ravestate_hibye \\ ravestate_persqa Run python3 -m ravestate -h to see more options! Running with config file(s) You may specify a series of config files to configure ravestate context, when specifying everything through the command line becomes too laborious: # In file hello_world.yml module: core config: import: - ravestate_wildtalk - ravestate_conio - ravestate_hibye - ravestate_persqa Then, run ravestate with this config file: python3 -m ravestate -f hello_world.yml Module overview Ravestate offers a landscape of fine-grained modules for different aspects of dialog application tasks, which may be seen in the following dependency diagram. Broadly, the modules are categorized into Core (Blue), I/O (Yellow), External (Red) and Skills (Green): Core Modules Module name Description ravestate Core ravestate library. ravestate_rawio Provides raw_in , raw_out , pic_in properties, which are served by the IO modules. ravestate_ontology Connects to scientio to serve a built-in ontology. ravestate_interloc Provides the all_interlocutors property, where present interlocutors are registered by the IO modules. ravestate_idle Provides bored and impatient signals, as specified here . ravestate_verbaliser Utilities for easy management of conversational text, documented here . ravestate_nlp Spacy-based NLP properties and signals, documented here . ravestate_ros2 Provides specific Ros2PubProperty , Ros2SubProperty and Ros2CallProperty context props., which greatly simplify working with ROS2 in ravestate. IO Modules Module name Description ravestate_conio Simple command-line based IO for development purposes. ravestate_telegramio Single- or Multi-process Telegram server module, documented here . ravestate_roboyio PyroBoy -based STT/TTS with ROS2. Skill Modules Module name Description ravestate_wildtalk ParlAI -based generative conversational module. ravestate_hibye Simply voices Hi! (or the likes thereof) when an interlocutor is added, and Bye when one is removed. ravestate_persqa Conducts personalized smalltalk with interlocutors, interacts with Scientio to persist trivia. ravestate_genqa DrQA -based general question answering module. ravestate_roboyqa QA module which provides answers to questions about Roboy, such as Who is your dad? ravestate_akinator Enables dialog-based play of Akinator! ravestate_sendpics Uses face recognition to extract facial features and an assiciated Person with pic_in and ontology, which are then persisted in Redis and Scientio. ravestate_stalker Uses facial feature <-> person tuples generated by sendpics, to surprise people in front of a camera with knowledge of their names. Running tests If you have installed the dependencies from requirements-dev.txt you may run the ravestate test suite as follows: ./run_tests.sh Docker for ROS and ROS2 There is a Dockerfile for ROS and ROS2 support which can be built with docker build -t ravestate-ros2-image . The image contains ROS, ROS2 and a ROS Bridge to connect ROS with ROS2. Furthermore the roboy_communication message and service types are installed. A container can then be created with the docker-compose.yml: docker-compose up --detach ravestate The container is now running and a connection into the container can be established with: docker exec -it ravestate-ros2-container bash Inside the container, first source the ROS2 setups and then ravestate can be run with ROS2 and rclpy available. source ~/ros2_ws/install/setup.sh python3 -m ravestate [...] Start ROS Bridge In order to start ROS Bridge, the image and container have to be set up as above. After connecting into the container run from inside the container: export ROS_IP=192.168.0.105 source ~/melodic_ws/devel/setup.sh source ~/ros2_ws/install/setup.sh source ~/ros1_bridge_ws/install/setup.sh ros2 run ros1_bridge dynamic_bridge Building/maintaining the docs If you have installed the dependencies from requirements-dev.txt , generate the docs by running this command at project root: export PYTHONPATH=$PYTHONPATH:$(pwd)/modules git rm -rf docs rm -rf _build docs pydocmd build mkdir -p docs/resources/docs && cp resources/docs/*.png docs/resources/docs && cp resources/docs/*.gif docs/resources/docs git add docs/* # For inspection: python3 -m http.server --directory docs The structure and content of the docs are defined in the file pydocmd.yml .","title":"Home"},{"location":"#about","text":"____ __ __ _____ _____ / _ \\____ __ ______ ______/ /_____/ /___ /_ _\\ /_ _\\ / /_/ / __ \\/ / / / __ \\/ ___\\, / __ \\, / __ \\ 0> 0> <0 <0 / ,\\ ,/ /_/ /\\ \\/ / /_/ /\\__, / / /_/ / / /_/ / \\__\u22bd__/ \\__\u22bd__/ \\/ \\/\\__/\\/ \\__/ ,___/\\____/\\/\\__/\\/\\/ ,___/ \u22c2 - Hey! \u22c2 \\____/ \\____/ Ol\u00e0! - Ravestate is a reactive library for real-time natural language dialog systems. It combines elements from event-based and reactive programming into an API, where application states are defined as functions that are run when a certain boolean set of criteria (signals) in the current application context is satisfied. It is the first reactive API to allow for boolean combinations of events. You may find a short introductory video here .","title":"About"},{"location":"#reactive-hello-world","text":"import ravestate as rs # We want to write some text output, so we # need the raw:out context property from ravestate_rawio. import ravestate_rawio as rawio # Make sure that we use some i/o implementation, # so we can actually see stuff that is written to rawio:out. import ravestate_conio # Ravestate applications should always be wrapped in a Module. # This allows easier scoping, and enables separation of concerns # beyond states. with rs.Module(name=\"hi!\"): # Create an application state which reacts to the `:startup` signal, # and writes a string to raw:out. Note: State functions are # always run asynchronously! @rs.state(cond=rs.sig_startup, write=rawio.prop_out) def hello_world(context): context[rawio.prop_out] = \"Waddup waddup waddup!\" # Run context with console input/output and our 'hi!' module. rs.Context(\"conio\", \"hi!\").run()","title":"Reactive Hello World"},{"location":"#visualization","text":"Ravestate has a d3.js -based visualization. When using ravestate_ui.UIContext instead of Context , or python3 -m ravestate_ui instead of python3 -m ravestate , a real-time visualization of all states/properties/signals in the state machine will be hosted on port 5001. Here is the view of http://localhost:5001 after launching python3 ravestate_ui -f generic.yml :","title":"Visualization"},{"location":"#installation","text":"","title":"Installation"},{"location":"#via-pip","text":"The easiest way to install ravestate is through pip: pip install ravestate Note: Ravestate requires Python 3.6 or higher. It is tested on Ubuntu 16.04 and 18.04, as well as macOS > High Sierra. It is currently not tested on Windows. For reliability, we recommend using an environment virtualization tool, like virtualenv or conda .","title":"Via PIP"},{"location":"#for-developers","text":"","title":"For developers"},{"location":"#initial-configuration-and-setup","text":"Clone the repository and install dependencies: # Create a virtual python environment to not pollute the global setup python3 -m virtualenv python-ravestate # Source the virtual environment . python-ravestate/bin/activate # Clone the repo git clone git@github.com:roboy/ravestate && cd ravestate # Install normal requirements pip install -r requirements.txt # To run tests & build docs, install pytest, mocking, fixtures, pydoc, ... pip install -r requirements-dev.txt # Link your local ravestate clone into your virtualenv pip install -e . Now, launch a Neo4j docker instance to serve Scientio , so the dialog system has a memory: docker run \\ --publish=7474:7474 --publish=7687:7687 \\ --volume=$HOME/neo4j/data:/data \\ --volume=$HOME/neo4j/logs:/logs \\ neo4j:latest # Open the address localhost:7474 in a browser, and enter the # credentials `neo4j`/`neo4j`. You will then be prompted to enter # your own password. Remember this password. In the config folder, create a file called keys.yml . It should have the following content: module: telegramio config: telegram-token: # This is where your own telegram bot token # will go later --- module: ontology config: neo4j_address: bolt://localhost:7687 # Your neo4j server uri here neo4j_username: neo4j # Your neo4j user here neo4j_pw: test # Your neo4j pw here You may now conduct your first conversation with ravestate: python3 -m ravestate -f config/generic.yml -f config/keys.yml After the conversation, check the Neo4j interface under localhost:7474 . It should now contain some nodes! Reminder: Whenever you use ravestate from the command line, source the virtual environment first!","title":"Initial configuration and setup"},{"location":"#running-your-telegram-bot","text":"To test your telegram bot with a custom bot token in your keys.yml , just run telegram_test.yml instead of generic.yml . This will load the ravestate_telegramio module.","title":"Running your Telegram bot"},{"location":"#setting-up-pycharm","text":"Open your local ravestate clone as a project in pycharm. Mark the modules folder as sources root via the right-click context menu. Create a run config al\u00e0 the \"Edit configurations menu\": \u2022 Create a new Python configuration. \u2022 Set modules/ravestate/__main__.py as the script to execute \u2022 Set the working directory to the git clone directory. \u2022 Set parameters to -f config/generic.yml -f config/keys.yml . You should now be able to run the generic ravestate config from pycharm.","title":"Setting up PyCharm"},{"location":"#running-hello-world","text":"Ravestate applications are defined by a configuration, which specifies the ravestate modules that should be loaded. To run the basic hello world application, run ravestate with a config file or command line arguments:","title":"Running Hello World"},{"location":"#running-with-command-line-spec","text":"You can easily run a combination of ravestate modules in a shared context, by listing them as arguments to python3 -m ravestate : python3 -m ravestate \\ ravestate_wildtalk \\ ravestate_conio \\ ravestate_hibye \\ ravestate_persqa Run python3 -m ravestate -h to see more options!","title":"Running with command line spec"},{"location":"#running-with-config-files","text":"You may specify a series of config files to configure ravestate context, when specifying everything through the command line becomes too laborious: # In file hello_world.yml module: core config: import: - ravestate_wildtalk - ravestate_conio - ravestate_hibye - ravestate_persqa Then, run ravestate with this config file: python3 -m ravestate -f hello_world.yml","title":"Running with config file(s)"},{"location":"#module-overview","text":"Ravestate offers a landscape of fine-grained modules for different aspects of dialog application tasks, which may be seen in the following dependency diagram. Broadly, the modules are categorized into Core (Blue), I/O (Yellow), External (Red) and Skills (Green):","title":"Module overview"},{"location":"#core-modules","text":"Module name Description ravestate Core ravestate library. ravestate_rawio Provides raw_in , raw_out , pic_in properties, which are served by the IO modules. ravestate_ontology Connects to scientio to serve a built-in ontology. ravestate_interloc Provides the all_interlocutors property, where present interlocutors are registered by the IO modules. ravestate_idle Provides bored and impatient signals, as specified here . ravestate_verbaliser Utilities for easy management of conversational text, documented here . ravestate_nlp Spacy-based NLP properties and signals, documented here . ravestate_ros2 Provides specific Ros2PubProperty , Ros2SubProperty and Ros2CallProperty context props., which greatly simplify working with ROS2 in ravestate.","title":"Core Modules"},{"location":"#io-modules","text":"Module name Description ravestate_conio Simple command-line based IO for development purposes. ravestate_telegramio Single- or Multi-process Telegram server module, documented here . ravestate_roboyio PyroBoy -based STT/TTS with ROS2.","title":"IO Modules"},{"location":"#skill-modules","text":"Module name Description ravestate_wildtalk ParlAI -based generative conversational module. ravestate_hibye Simply voices Hi! (or the likes thereof) when an interlocutor is added, and Bye when one is removed. ravestate_persqa Conducts personalized smalltalk with interlocutors, interacts with Scientio to persist trivia. ravestate_genqa DrQA -based general question answering module. ravestate_roboyqa QA module which provides answers to questions about Roboy, such as Who is your dad? ravestate_akinator Enables dialog-based play of Akinator! ravestate_sendpics Uses face recognition to extract facial features and an assiciated Person with pic_in and ontology, which are then persisted in Redis and Scientio. ravestate_stalker Uses facial feature <-> person tuples generated by sendpics, to surprise people in front of a camera with knowledge of their names.","title":"Skill Modules"},{"location":"#running-tests","text":"If you have installed the dependencies from requirements-dev.txt you may run the ravestate test suite as follows: ./run_tests.sh","title":"Running tests"},{"location":"#docker-for-ros-and-ros2","text":"There is a Dockerfile for ROS and ROS2 support which can be built with docker build -t ravestate-ros2-image . The image contains ROS, ROS2 and a ROS Bridge to connect ROS with ROS2. Furthermore the roboy_communication message and service types are installed. A container can then be created with the docker-compose.yml: docker-compose up --detach ravestate The container is now running and a connection into the container can be established with: docker exec -it ravestate-ros2-container bash Inside the container, first source the ROS2 setups and then ravestate can be run with ROS2 and rclpy available. source ~/ros2_ws/install/setup.sh python3 -m ravestate [...]","title":"Docker for ROS and ROS2"},{"location":"#start-ros-bridge","text":"In order to start ROS Bridge, the image and container have to be set up as above. After connecting into the container run from inside the container: export ROS_IP=192.168.0.105 source ~/melodic_ws/devel/setup.sh source ~/ros2_ws/install/setup.sh source ~/ros1_bridge_ws/install/setup.sh ros2 run ros1_bridge dynamic_bridge","title":"Start ROS Bridge"},{"location":"#buildingmaintaining-the-docs","text":"If you have installed the dependencies from requirements-dev.txt , generate the docs by running this command at project root: export PYTHONPATH=$PYTHONPATH:$(pwd)/modules git rm -rf docs rm -rf _build docs pydocmd build mkdir -p docs/resources/docs && cp resources/docs/*.png docs/resources/docs && cp resources/docs/*.gif docs/resources/docs git add docs/* # For inspection: python3 -m http.server --directory docs The structure and content of the docs are defined in the file pydocmd.yml .","title":"Building/maintaining the docs"},{"location":"config/","text":"ravestate.argparser handle_args handle_args(*args) -> Tuple[List[str], List[Tuple[str, str, Any]], List[str]] Runs an argument parser for the given args. Returns modules-to-load, config value-overrides and config file-pathes. Note: If the arguments are ill-formatted, or the -h argument is passed, help will be printed to the console and the program will abort. args : Argument list which will be fed into argparse.parse_args. Returns: A Tuple with three items: 1.) A list of module names which should be imported. 2.) A list of tuples, where each tuple is a module name, a config key name, and a value. 3.) A list of yaml file paths. ravestate.config Configuration Configuration(self, paths: List[str]) The Configuration class maintains a dictionary of key-value stores, which represent configuration entries for specific named modules. The key-value stores may be successively updated with consecutive yaml files, where each yaml document has the following content: module: module-name config: key-a: value-a key-b: value-b # etc add_conf Configuration.add_conf(self, mod: ravestate.module.Module) Register a set of allowed config entries for a specific module. Correctly typed values for allowed keys, that were previously parsed during construction from the yaml files, will be applied immediately. mod : A module object with a name and a conf dict. get_conf Configuration.get_conf(self, module_name: str) Retrieve updated config values for a module that was previously registered with add_conf. module_name : The module name for which configuration should be retrieved. Returns: A dictionary which contains exactly the keys that were contained in the module configuration dictionary during add_conf, or an empty dictionary if the module name is unknown. get Configuration.get(self, module_name: str, key: str) -> Any Get the current value of a config entry. module_name : The module that provides the config entry. key : A config key for the module that was previously added through add_conf. Returns: The current value, or None, if the entry does not exist. set Configuration.set(self, module_name: str, key: str, value: Any) Set the current value of a config entry. module_name : The module of the config entry. key : A config key for the module that was previously added through add_conf. value : The new value for the config entry. An error will be raised, if the type of the new value does not match the type of the old value. write Configuration.write(self, path: str) Write all current config entries to a yaml file. path : The file path to write. Will be overwritten! read Configuration.read(self, path: str) Loads all documents from a yaml file and tries to interpret them as configuration objects as described above. path : The yaml file path from which to load config documents.","title":"Configuration"},{"location":"context/","text":"ravestate.context create_and_run_context create_and_run_context(*args, runtime_overrides=None) Creates a new Context with the given parameters and runs it Context Context(self, *arguments, runtime_overrides: List[Tuple[str, str, Any]] = None) emit Context.emit(self, signal: ravestate.constraint.Signal, parents: Set[ravestate.spike.Spike] = None, wipe: bool = False, payload: Any = None) -> None Emit a signal to the signal processing loop. Note: The signal will only be processed if run() has been called! signal : The signal to be emitted. parents : The signal's parents, if it is supposed to be integrated into a causal group. wipe : Boolean to control, whether wipe (signal) should be called before the new spike is created. payload : Value that should be embedded in the new spike. wipe Context.wipe(self, signal: ravestate.constraint.Signal) Delete all spikes for the given signal. Partially fulfilled states that have acquired an affected spike will be forced to reject it. Wiping a parent spike will also wipe all child spikes. signal : The signal for which all existing spikes (and their children) should be invalidated and forgotten. run Context.run(self) -> None Creates a signal processing thread, starts it, and emits the core:startup signal. shutting_down Context.shutting_down(self) -> bool Retrieve the shutdown flag value, which indicates whether shutdown() has been called. shutdown Context.shutdown(self) -> None Sets the shutdown flag and waits for the signal processing thread to join. add_module Context.add_module(self, module_name: str) -> None Add a module by python module folder name, or by ravestate module name. module_name : The name of the module to be added. If it is the name of a python module that has not been imported yet, the python module will be imported, and any ravestate modules registered during the python import will also be added to this context. add_state Context.add_state(self, *, st: ravestate.state.State) -> None Add a state to this context. It will be indexed wrt/ the properties/signals it depends on. Error messages will be generated for unknown signals/properties. st : The state which should be added to this context. rm_state Context.rm_state(self, *, st: ravestate.state.State) -> None Remove a state from this context. Note, that any state which is constrained on the signal that is emitted by the deleted state will also be deleted. st : The state to remove. An error message will be generated, if the state was not previously added to this context with add_state(). add_prop Context.add_prop(self, *, prop: ravestate.property.Property) -> None Add a copy of a property to this context. An error message will be generated, if a property with the same name has already been added previously. Note: Context will adopt a copy of the given property, the actual property will not be changed. prop : The property object that should be added. rm_prop Context.rm_prop(self, *, prop: ravestate.property.Property) -> None Remove a property from this context. Generates error message, if the property was not added with add_prop() to the context previously prop : The property to remove.object conf Context.conf(self, *, mod: str, key: Union[str, NoneType] = None) -> Any Get a single config value, or all config values for a particular module. mod : The module whose configuration should be retrieved. key : A specific config key of the given module, if only a single config value should be retrieved. Returns: The value of a single config entry if key and module are both specified and valid, or a dictionary of config entries if only the module name is specified (and valid). signal_specificity Context.signal_specificity(self, sig: ravestate.constraint.Signal) -> float Called by state activation to determine it's constraint's specificity. sig : The signal whose specificity should be returned. Returns: The given signal's specificity. reacquire Context.reacquire(self, act: ravestate.iactivation.IActivation, sig: ravestate.constraint.Signal) Called by activation, to indicate, that it needs a new Spike for the specified signal, and should for this purpose be referenced by context. Note: Not thread-safe, sync must be guaranteed by caller. act : The activation that needs a new spike of the specified nature. sig : Signal type for which a new spike is needed. withdraw Context.withdraw(self, act: ravestate.iactivation.IActivation, sig: ravestate.constraint.Signal) Called by activation to make sure that it isn't referenced anymore as looking for the specified signal. This might be, because the activation chose to eliminate itself due to activation pressure, or because one of the activations conjunctions was fulfilled, so it is no longer looking for signals to fulfill the remaining conjunctions. Note: Not thread-safe, sync must be guaranteed by caller. act : The activation that has lost interest in the specified signal. sig : Signal type for which interest is lost. secs_to_ticks Context.secs_to_ticks(self, seconds: float) -> int Convert seconds to an equivalent integer number of ticks, given this context's tick rate. seconds : Seconds to convert to ticks. Returns: An integer tick count. possible_signals Context.possible_signals(self, state: ravestate.state.State) -> Generator[ravestate.constraint.Signal, NoneType, NoneType] Yields all signals, for which spikes may be created if the given state is executed. state : The state, which should be analyzed for it's possibly generated signals (declared signal + property-changed signals). run_once Context.run_once(self, seconds_passed=1.0, debug=False) -> None Run a single update for this context, which will ... (0) progress cooled down state weights. (1) reduce redundant candidate activations. (2) associate new spikes with state activations. (3) update state activations. (4) forget spikes which have no suitors in their causal groups. (5) age spikes. (6) invoke garbage collection. (7) update the core:activity and core:pressure variables. seconds_passed : Seconds, as floatiing point, since the last update. Will be used to determine the number of ticks to add/subtract to/from spike/activation age/cooldown/deathclock. test Context.test(self) -> bool Execute internal integrity checks. ravestate.spike Spike Spike(self, *, sig: str, parents: Set[ForwardRef('Spike')] = None, consumable_resources: Set[str] = None, payload: Any = None) This class encapsulates a single spike, to track ... ... it's consumption for different output properties (through CausalGroup ). ... it's offspring instances (causal group -> spikes caused by this spike) causal_group Spike.causal_group(self) -> ravestate.causal.CausalGroup Get this spike's causal group. Returns: This instances causal group. Should never be None. adopt Spike.adopt(self, child: 'Spike') -> None Called in spike constructor, for instances which claim to be caused by this spike. child : The child to add to this spike's causal group. wiped Spike.wiped(self, child: 'ISpike') -> None Called by an offspring signal, to notify the spike that it was wiped, and should therefore be removed from the children set. child : The child to be forgotten. wipe Spike.wipe(self, already_wiped_in_causal_group: bool = False) -> None Called either in Context run loop when the spike is found to be stale (with wiped_in_causal_group=True), or in Context.wipe(spike), or by parent (recursively). After this function is called, the spike should be cleaned up by GC. already_wiped_in_causal_group : Boolean which indicates, whether wiped(spike) must still be called on the group to make sure sure that no dangling references to the spike are maintained by any state activations. has_offspring Spike.has_offspring(self) Called by CausalGroup.stale(spike). Returns: True if the spike has active offspring, false otherwise. tick Spike.tick(self) -> None Increment this spike's age by 1. age Spike.age(self) -> int Obtain this spike's age (in ticks). offspring Spike.offspring(self) -> Generator[ForwardRef('Spike'), NoneType, NoneType] Recursively yields this spike's offspring and it's children's offspring. Returns: All of this spike's offspring spikes. is_wiped Spike.is_wiped(self) Check, whether this spike has been wiped, and should therefore not be acquired anymore. payload Spike.payload(self) -> Any Get payload for this spike. The payload is an arbitrary value passed in Context.emit() . ravestate.activation Activation Activation(self, st: ravestate.state.State, ctx: ravestate.icontext.IContext) Encapsulates the potential activation of a state. Tracks the collection of Spikes to fulfill of the state-defined activation constraints. resources Activation.resources(self) -> Set[str] Return's the set of the activation's write-access property names. specificity Activation.specificity(self) -> float Returns the lowest specificity among the specificity values of the activation's conjunct constraints. The specificity for a single conjunction is calculated as the sum of it's component signal's specificities, which in turn is calculated as one over the signal's subscriber count. dereference Activation.dereference(self, *, spike: Union[ravestate.iactivation.ISpike, NoneType] = None, reacquire: bool = False, reject: bool = False, pressured: bool = False) -> None Notify the activation, that a single or all spike(s) are not available anymore, and should therefore not be referenced anymore by the activation. This is called by ... ... context when a state is deleted. ... causal group, when a referenced signal was consumed for a required property. ... causal group, when a referenced signal was wiped. ... this activation (with reacquire=True and pressured=True), if it gives in to activation pressure. spike : The spike that should be forgotten by the activation, or none, if all referenced spikes should be forgotten. reacquire : Flag which tells the function, whether for every rejected spike, the activation should hook into context for reacquisition of a replacement spike. reject : Flag which controls, whether de-referenced spikes should be explicitely rejected through their causal groups. pressured : Flag which controls, whether de-referencing should only occur for spikes of causal groups in the pressuring_causal_groups set. acquire Activation.acquire(self, spike: ravestate.spike.Spike) -> bool Let the activation acquire a signal it is registered to be interested in. spike : The signal which should fulfill at least one of this activation's signal constraints. Returns: True if the spike was acquired by at least one signal, false if acquisition failed: This may happen for multiple reasons: (1) Acquisition failed, because the spike is too old (2) Acquisition failed, because the spike's causal group does not match it's completions. (3) Acquisition failed, because the spike's causal group does not offer all of this activation's state's write-props. secs_to_ticks Activation.secs_to_ticks(self, seconds: float) -> int Convert seconds to an equivalent integer number of ticks, given this activation's tick rate. seconds : Seconds to convert to ticks. Returns: An integer tick count. pressure Activation.pressure(self, give_me_up: ravestate.iactivation.ICausalGroup) Called by CausalGroup, to pressure the activation to make a decision on whether it is going to retain a reference to the given spike, given that there is a lower- specificity activation which is ready to run. give_me_up : Causal group that wishes to be de-referenced by this activation. is_pressured Activation.is_pressured(self) Called by context, to figure out whether the activation is pressured, and therefore the idle:bored signal should be emitted. spiky Activation.spiky(self) -> bool Returns true, if the activation has acquired any spikes at all. Returns: True, if any of this activation's constraint's signal is referencing a spike. spikes Activation.spikes(self) -> Generator[ravestate.spike.Spike, NoneType, NoneType] Returns iterable for all the spikes currently acquired by the activation. possible_signals Activation.possible_signals(self) -> Generator[ForwardRef('Signal'), NoneType, NoneType] Yields all signals, for which spikes may be created if this activation's state is executed. effect_not_caused Activation.effect_not_caused(self, group: ravestate.iactivation.ICausalGroup, effect: str) -> None Notify the activation, that a follow-up signal will not be produced by the given causal group. The activation will go through it's constraint, and reject all completion spikes for signals of name effect , if the completion spikes are from the given causal group. group : The causal group which will not contain a spike for signal effect . effect : Name of the signal for which no spike will be produced. update Activation.update(self) -> bool Called once per tick on this activation, to give it a chance to activate itself, or auto-eliminate, or reject spikes which have become too old. Returns: True, if the target state is activated and teh activation be forgotten, false if needs further attention in the form of updates() by context in the future. ravestate.causal CausalGroup CausalGroup(self, resources: Set[str]) Class which represents a causal group graph of spike parent/offspring spikes (a \"superspike\"). These must synchronize wrt/ their (un)written properties and state activation candidates, such that they don't cause output races. Note: Always use a with ... construct to interact with a causal group. Otherwise, undefined behavior may occur due to race conditions. merge CausalGroup.merge(self, other: 'CausalGroup') Merge this causal group with another. Unwritten props will become the set intersection of this group's unwritten props and other's unwritten props. consumed() will be called with all properties that are consumed by other, but not this. Afterwards, other's member objects will be set to this's. acquired CausalGroup.acquired(self, spike: 'ISpike', acquired_by: ravestate.iactivation.IActivation, detached: bool) -> bool Called by Activation to notify the causal group, that it is being referenced by an activation constraint for a certain member spike. spike : State activation instance, which is now being referenced by the specified causal group. acquired_by : State activation instance, which is interested in this property. detached : Tells the causal group, whether the reference is detached, and should therefore receive special treatment. Returns: Returns True if all of the acquiring's write-props are free, and the group now refs. the activation, False otherwise. rejected CausalGroup.rejected(self, spike: 'ISpike', rejected_by: ravestate.iactivation.IActivation, reason: int) -> None Called by a state activation, to notify the group that a member spike is no longer being referenced for the given state's write props. This may be because ... ... the activation's dereference function was called. (reason=0) ... the spike got too old. (reason=1) ... the activation happened and is dereferencing it's spikes. (reason=2) spike : The member spike whose ref-set should be reduced. rejected_by : State activation instance, which is no longer interested in this property. reason : See about. consent CausalGroup.consent(self, ready_suitor: ravestate.iactivation.IActivation) -> bool Called by constraint, to inquire whether this causal group would happily be consumed for the given state activation's properties. This will be called periodically on the group by state activations that are ready to go. Therefore, a False return value from this function is never a final judgement (more like a \"maybe later\"). ready_suitor : The state activation which would like to consume this instance for it's write props. Returns: True if this instance agrees to proceeding with the given consumer for the consumer's write props, False otherwise. activated CausalGroup.activated(self, act: ravestate.iactivation.IActivation) Called by activation which previously received a go-ahead from consent(), when it is truly proceeding with running (after it got the go-ahead from all it's depended=on causal groups). act : The activation that is now running. resigned CausalGroup.resigned(self, act: ravestate.iactivation.IActivation) -> None Called by activation, to let the causal group know that it failed, and a less specific activation may now be considered for the resigned state's write props. act : The activation that is unexpectedly not consuming it's resources, because it's state resigned/failed. consumed CausalGroup.consumed(self, resources: Set[str]) -> None Called by activation to notify the group, that it has been consumed for the given set of properties. resources : The properties which have been consumed. wiped CausalGroup.wiped(self, spike: 'ISpike') -> None Called by a spike, to notify the causal group that the instance was wiped and should no longer be remembered. spike : The instance that should be henceforth forgotten. stale CausalGroup.stale(self, spike: 'ISpike') -> bool Determine, whether a spike is stale (has no remaining interested activations and no children). Returns: True, if no activations reference the given spike for any unwritten property. False otherwise. check_reference_sanity CausalGroup.check_reference_sanity(self) -> bool Make sure, that the refcount-per-act-per-spike-per-resource value sum is equal to the number of spikes from this causal group acquired per activation for each activation in the index. :return: True if the criterion is fulfilled, False otherwise.","title":"Context"},{"location":"modules/","text":"ravestate.module Module Module(self, *, name: str, config: Dict[str, Any] = None) Atomic class, which encapsulates a named set of states, properties and config entries, which form a coherent bundle. Example: with Module(name=\"my_module\", config={\"paramA\": 42}): # define properties # define states registered_modules dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2) import_module import_module(*, module_name: str, callback) Called by context to import a particular ravestate python module. module_name : The name of the python module to be imported (must be in pythonpath). callback : A callback which should be called when a module calls register() while it is being imported. has_module has_module(module_name: str) Check whether a module with a particular name has been registered. module_name : The name which should be checked for beign registered. Returns: True if a module with the given name has been registered, false otherwise. get_module get_module(module_name: str) Get a registered module with a particular name module_name : The name of the moduke which should be retrieved. Returns: The module with the given name if it was registered, false if otherwise.","title":"Modules"},{"location":"properties/","text":"ravestate.property Property Property(self, *, name='', allow_read=True, allow_write=True, allow_push=True, allow_pop=True, default_value=None, always_signal_changed=False, is_flag_property=False, wipe_on_changed=True) Base class for context properties. Controls read/write/push/pop/delete permissions, property name basic impls. for the property value, parent/child mechanism. Example (Creating a module containing a property named my_property): with Module(name=\"my_module\"): my_property = Property(name=\"my_property\") set_parent_path Property.set_parent_path(self, path) Set the ancestors (including modulename) for a property path : ancestry in the form of modulename:parent_prop_name (or simply modulename) gather_children Property.gather_children(self) -> List[ForwardRef('Property')] Collect this property, and all of it's children. read Property.read(self) Read the current property value write Property.write(self, value) Write a new value to the property value : The new value. Returns: True if the value has changed and :changed should be signaled, false otherwise. push Property.push(self, child: 'Property') Add a child to the property child : The child object Returns: True if the child was added successfully, false otherwise. pop Property.pop(self, child_name: str) Remove a child from the property by it's name. child_name : Name of the child to be removed. Returns: True if the pop was successful, False otherwise changed Property.changed(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when write() returns True. pushed Property.pushed(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when push() returns True. popped Property.popped(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when pop() returns True. true Property.true(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when it is a flag-property and self.value is set to True. false Property.false(self) -> ravestate.constraint.Signal Signal that is emitted by PropertyWrapper when it is a flag-property and self.value is set to False. signals Property.signals(self) -> Generator[ravestate.constraint.Signal, NoneType, NoneType] Yields all signals that may be emitted because of this property, given it's write/push/pop permissions.","title":"Properties"},{"location":"states/","text":"state state(*, signal: Union[ravestate.constraint.Signal, NoneType] = '', write: Tuple[ravestate.property.Property] = (), read: Tuple[ravestate.property.Property] = (), cond: ravestate.constraint.Constraint = None, emit_detached: bool = False, weight: float = 1.0, cooldown: float = 0.0) Decorator to declare a new state, which may emit a certain signal, write to a certain set of properties (calling write, push, pop), and read from certain properties (calling read). Example (Module that outputs \"Don't Panic\" after startup): with Module(name=\"my_module\"): @state(cond=startup()) def after_startup(context, write=OUTPUT_PROPERTY): context[OUTPUT_PROPERTY] = \"Don't Panic\" ravestate.constraint ConfigurableAge ConfigurableAge(self, key: str) Class for having min/max_age parameters for Constraints configurable with a config key key str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object. str () (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'. Constraint Constraint(self, /, *args, **kwargs) Superclass for Signal, Conjunct and Disjunct Signal Signal(self, name: str, *, min_age=0.0, max_age=5.0, detached=False, _skip_module_context=False) Class that represents a Signal. Should be constructed in a with Module(..) context, such that it's module scope is set automatically. SignalRef SignalRef(self, name: str, *, min_age=0.0, max_age=5.0, detached=False) Signal reference. Almost the same as a signal, except that it will not try to auto-discover it's module out of thread-local context (module_name will stay unfilled). Needed, because sometimes you need to reference a singal within a module scope without assigning that signal to the contextual module. Conjunct Conjunct(self, *args) Class that represents a Conjunction of Signals. Can be constructed using an overloaded & operator. Example: signal_A & signal_B Disjunct Disjunct(self, *args) Class that represents a Disjunction of Conjunctions Can be constructed using an overloaded | operator. Examples: conjunction_A | conjunction_B (signal_A & signal_B) | (signal_C & signal_D) receptor receptor(*, ctx_wrap: Union[ravestate.wrappers.ContextWrapper, ravestate.context.Context], write: Union[str, ravestate.property.Property, Tuple[Union[str, ravestate.property.Property]]]) A receptor is a special state which can be invoked from outside, to push values into the context. ctx_wrap : A context wrapper as is always given into the state functions as their first argument. write : The property, or tuple of properties, which are going to be written. Example: # Module that outputs \"Don't Panic\" one minute after startup # Because a receptor is used, the OUTPUT_PROPERTY is not blocked the whole time with Module(name=\"my_module\"): @state(cond=startup()) def after_startup(context): @receptor(ctx_wrap=context, write=OUTPUT_PROPERTY) def dont_panic(ctx_write): ctx_write[OUTPUT_PROPERTY] = \"Don't Panic\" sleep(60) dont_panic()","title":"States"},{"location":"modules/ravestate_akinator/","text":"_ _ | | (_) _ _____| | _ _ ____ _____ _| |_ ___ ____ (____ | |_/ ) | _ \\(____ (_ _) _ \\ / ___) / ___ | _ (| | | | / ___ | | || |_| | | \\_____|_| \\_)_|_| |_\\_____| \\__)___/|_| 20 Questions with Akinator The Ravestate Akinator module offers an implementation of the 20 questions game. It consists of a wrapper for the API calls to the Akinator web game and several states to handle the game flow with the interlocutor. Architecture This is an overview of the dialog flow for the 20 questions game. Starting the Game There are two possibilities to trigger the game: 1. Interlocutor input: \"I want to play\", \"I like games\" or something similar 2. Automatically through Ravestate: When the system gets bored (no dialog states are active but an interlocutor is present) then Akinator is one of the possible modules that will be triggered. The API Wrapper api.py handles the requests to the online Akinator game. There are three different types of get requests to handle the game: 1. Question asking phase: post the answer to the previous question and retrieve the next question 2. Guessing phase: retrieve the guess 3. Game finishing phase: give Akinator feedback on his guess","title":"Akinator"},{"location":"modules/ravestate_akinator/#20-questions-with-akinator","text":"The Ravestate Akinator module offers an implementation of the 20 questions game. It consists of a wrapper for the API calls to the Akinator web game and several states to handle the game flow with the interlocutor.","title":"20 Questions with Akinator"},{"location":"modules/ravestate_akinator/#architecture","text":"This is an overview of the dialog flow for the 20 questions game.","title":"Architecture"},{"location":"modules/ravestate_akinator/#starting-the-game","text":"There are two possibilities to trigger the game: 1. Interlocutor input: \"I want to play\", \"I like games\" or something similar 2. Automatically through Ravestate: When the system gets bored (no dialog states are active but an interlocutor is present) then Akinator is one of the possible modules that will be triggered.","title":"Starting the Game"},{"location":"modules/ravestate_akinator/#the-api-wrapper","text":"api.py handles the requests to the online Akinator game. There are three different types of get requests to handle the game: 1. Question asking phase: post the answer to the previous question and retrieve the next question 2. Guessing phase: retrieve the guess 3. Game finishing phase: give Akinator feedback on his guess","title":"The API Wrapper"},{"location":"modules/ravestate_nlp/","text":"_ | | ____ | | ____ | _ \\| || _ \\ | | | | || |_| | |_| |_|\\_) __/ |_| NLP The natural language processing (NLP) module enables Roboy to process and understand the human language. That way he can interpret the meaning of the detected sentences. We use a free, open-source NLP library for advanced NLP in Python: spaCy Extracted Features Feature Ravestate Properties/Signals Description Example Sentence: 'Revolutions need six fancy chickens!' Tokenization nlp.prop_tokens Segmenting text into words, punctuation marks etc. 'Revolutions', 'need', 'six', 'fancy', 'chickens', '!' Part-of-Speech (POS) Tagging nlp.prop_postags Assigning word types to tokens 'NOUN', 'VERB', 'NUM', 'ADJ', 'NOUN', 'PUNCT' Detailed POS Tag nlp.prop_tags Fine-grained part-of-speech 'Revolutions' has the tag: 'NNS', which stand for: noun, plural 'need' has the tag: 'VBP', which stands for: verb, non-3rd person singular present List of POS tags Lemmatization nlp.prop_lemmas Assigning the base forms of words 'Revolutions' has the lemma: 'revolution' 'was' would have the lemma: 'be' Named Entity Recognition (NER) nlp.prop_ner Labelling \"real-world\" objects (\"NE\"=Named Entity) 'six' has the NE: 'CARDINAL', which are numerals that do not fall under another type List of NEs Triple Extraction nlp.prop_triples A triple consists of subject, predicate, object of sentence Triple: subject: 'Revolutions', predicate: 'need', object: 'chickens' About Roboy nlp.prop_roboy Detecting whether sentence is about Roboy 'you', 'roboy', 'robot', 'roboboy', ... Yes-No nlp.prop_yesno Detecting answers to yes-no questions Checking for 'yes', 'no', 'i don't know', 'probably', 'probably not' and synonyms of these Sentence Type: Question nlp.sig_is_question Emitted if the input sentence is a question Play Game nlp.sig_intent_play Emitted when the interlocutor wants to play a game input: \"I want to play\", \"I like games\" or something similar Additional features can be added and published to the system. All existing features can be found here . Using the Features React to Property Change Each feature is stored in a ravestate property. A state which wants to access a property needs read permissions for that property. Example: State that reads the \"yesno\" property import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_yesno.changed(), # state reacts to a change in the 'yesno' property read=nlp.prop_yesno, # state is allowed to read the 'yesno' property write=rawio.prop_out) # state is allowed to write to the output property def postive_chicken(ctx: ContextWrapper): if ctx[nlp.prop_yesno] == \"yes\": ctx[rawio.prop_out] = \"You seem to be a positive chicken!\" React to Signals For 'Sentence Type: Question' a signal is emitted. Example: State that reacts to the \"is-question\" signal import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.sig_is_question, # state reacts to the is-question signal write=rawio.prop_out) # state is allowed to write to the output property def curious_chicken(ctx: ContextWrapper): ctx[nlp.prop_out] = \"You seem to ask a lot of questions, chicken!\" Using the Triples for Sentence Analysis The triple extraction is done in extract_triples.py by using the dependency tree of the sentence. A dependency tree shows the relation between the words of a sentence. The finite verb (predicate) is the structural center of the sentence and therefor of the tree. So starting with the predicate the algorithm searches through the dependency tree to find subject and object. Analyzing a Sentence Example: 'Chickens like revolutions' reaction state Triple: subject: 'Chickens', predicate: 'like', object: 'revolutions' import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_triples.changed(), # state reacts to a change in the 'triples' property read=nlp.prop_triples, # state is allowed to read the 'triples' property write=rawio.prop_out) # state is allowed to write to the output chanel def postive_chicken(ctx: ContextWrapper): triple = ctx[nlp.prop_triples][0] # gives you the first Triple object # check predicate and object correspondingly # match_either_lemma() is a method in the Triple class if triple.match_either_lemma(subj={\"chicken\", \"dinosaur\"}): # returns true when subj, pred or obj have the desired value ctx[rawio.prop_out] = \"You said something about a chicken, i like chickens!\" Happy language processing to all chickens out there!","title":"NLP"},{"location":"modules/ravestate_nlp/#nlp","text":"The natural language processing (NLP) module enables Roboy to process and understand the human language. That way he can interpret the meaning of the detected sentences. We use a free, open-source NLP library for advanced NLP in Python: spaCy","title":"NLP"},{"location":"modules/ravestate_nlp/#extracted-features","text":"Feature Ravestate Properties/Signals Description Example Sentence: 'Revolutions need six fancy chickens!' Tokenization nlp.prop_tokens Segmenting text into words, punctuation marks etc. 'Revolutions', 'need', 'six', 'fancy', 'chickens', '!' Part-of-Speech (POS) Tagging nlp.prop_postags Assigning word types to tokens 'NOUN', 'VERB', 'NUM', 'ADJ', 'NOUN', 'PUNCT' Detailed POS Tag nlp.prop_tags Fine-grained part-of-speech 'Revolutions' has the tag: 'NNS', which stand for: noun, plural 'need' has the tag: 'VBP', which stands for: verb, non-3rd person singular present List of POS tags Lemmatization nlp.prop_lemmas Assigning the base forms of words 'Revolutions' has the lemma: 'revolution' 'was' would have the lemma: 'be' Named Entity Recognition (NER) nlp.prop_ner Labelling \"real-world\" objects (\"NE\"=Named Entity) 'six' has the NE: 'CARDINAL', which are numerals that do not fall under another type List of NEs Triple Extraction nlp.prop_triples A triple consists of subject, predicate, object of sentence Triple: subject: 'Revolutions', predicate: 'need', object: 'chickens' About Roboy nlp.prop_roboy Detecting whether sentence is about Roboy 'you', 'roboy', 'robot', 'roboboy', ... Yes-No nlp.prop_yesno Detecting answers to yes-no questions Checking for 'yes', 'no', 'i don't know', 'probably', 'probably not' and synonyms of these Sentence Type: Question nlp.sig_is_question Emitted if the input sentence is a question Play Game nlp.sig_intent_play Emitted when the interlocutor wants to play a game input: \"I want to play\", \"I like games\" or something similar Additional features can be added and published to the system. All existing features can be found here .","title":"Extracted Features"},{"location":"modules/ravestate_nlp/#using-the-features","text":"","title":"Using the Features"},{"location":"modules/ravestate_nlp/#react-to-property-change","text":"Each feature is stored in a ravestate property. A state which wants to access a property needs read permissions for that property. Example: State that reads the \"yesno\" property import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_yesno.changed(), # state reacts to a change in the 'yesno' property read=nlp.prop_yesno, # state is allowed to read the 'yesno' property write=rawio.prop_out) # state is allowed to write to the output property def postive_chicken(ctx: ContextWrapper): if ctx[nlp.prop_yesno] == \"yes\": ctx[rawio.prop_out] = \"You seem to be a positive chicken!\"","title":"React to Property Change"},{"location":"modules/ravestate_nlp/#react-to-signals","text":"For 'Sentence Type: Question' a signal is emitted. Example: State that reacts to the \"is-question\" signal import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.sig_is_question, # state reacts to the is-question signal write=rawio.prop_out) # state is allowed to write to the output property def curious_chicken(ctx: ContextWrapper): ctx[nlp.prop_out] = \"You seem to ask a lot of questions, chicken!\"","title":"React to Signals"},{"location":"modules/ravestate_nlp/#using-the-triples-for-sentence-analysis","text":"The triple extraction is done in extract_triples.py by using the dependency tree of the sentence. A dependency tree shows the relation between the words of a sentence. The finite verb (predicate) is the structural center of the sentence and therefor of the tree. So starting with the predicate the algorithm searches through the dependency tree to find subject and object.","title":"Using the Triples for Sentence Analysis"},{"location":"modules/ravestate_nlp/#analyzing-a-sentence","text":"Example: 'Chickens like revolutions' reaction state Triple: subject: 'Chickens', predicate: 'like', object: 'revolutions' import ravestate as rs import ravestate_nlp as nlp import ravestate_rawio as rawio @rs.state( cond=nlp.prop_triples.changed(), # state reacts to a change in the 'triples' property read=nlp.prop_triples, # state is allowed to read the 'triples' property write=rawio.prop_out) # state is allowed to write to the output chanel def postive_chicken(ctx: ContextWrapper): triple = ctx[nlp.prop_triples][0] # gives you the first Triple object # check predicate and object correspondingly # match_either_lemma() is a method in the Triple class if triple.match_either_lemma(subj={\"chicken\", \"dinosaur\"}): # returns true when subj, pred or obj have the desired value ctx[rawio.prop_out] = \"You said something about a chicken, i like chickens!\"","title":"Analyzing a Sentence"},{"location":"modules/ravestate_nlp/#happy-language-processing-to-all-chickens-out-there","text":"","title":"Happy language processing to all chickens out there!"},{"location":"modules/ravestate_telegramio/","text":"_______ _ _____ ____ |__ __| | | |_ _/ __ \\ | | ___| | ___ __ _ _ __ __ _ _ __ ___ | || | | | | |/ _ \\ |/ _ \\/ _` | '__/ _` | '_ ` _ \\ | || | | | | | __/ | __/ (_| | | | (_| | | | | | |_| || |__| | |_|\\___|_|\\___|\\__, |_| \\__,_|_| |_| |_|_____\\____/ __/ | |___/ TelegramIO The TelegramIO module enables ravestate to connect to a Telegram-Bot and chat to people there. The connection to Telegram is managed with python-telegram-bot Architecture There are two main modes for this module: * Single-Process-Mode: All chats share the same context * Multiprocess-Mode: Every chat creates its own context in a separate process Single-Process-Mode In this mode the module handles incoming text messages and pictures from all chats. Outgoing messages are sent to every currently active chat. Multiprocess-Mode In this mode the \"Master\" part of the module is running in the main process of ravestate. Whenever there is a new chat, a new instance of ravestate is started in a new process and a bidirectional pipe is set up to enable communication between the main process and the new child process. Only the main process is connected to the Telegram-Bot and therefore any incoming messages get forwarded to the corresponding child process via the pipe. The main process also forwards any incoming messages it receives through the pipe to the corresponding telegram chat. In order to clean up unused child processes, the main process kills child processes after a configurable amount of inactivity. Child processes running the TelegramIO-Module listen for incoming text messages or pictures on the pipe and write output to the pipe. They only exchange messages with a single chat (indirectly via the pipe). Abilities The TelegramIO module is able to handle incoming text messages as well as incoming pictures. The module creates an interlocutor node for every user it is chatting with, containing the user's telegram-id, username and full name if it is set by the user. Incoming text messages are simply written into the RawIO Input property. For incoming pictures, the picture is saved locally as a file and the filepath is written to the RawIO Pic_In Context property. Messages in the RawIO Output are sent to the Telegram Chat(s). Configuration There are 5 configurable parameters (see init .py ): * telegram-token : Put the Token of your Telegram-Bot here * all_in_one_context : True if Single-Process-Mode should be used, False if Multiprocess-Mode should be used. * child_conn : Not to be set in a config file or via the command line. Will be set by master process as a runtime_override. * child_config_files : If in Multiprocess-Mode, the config-paths listed here will be used when creating a new context for a new chat. * chat_lifetime : The timespan in minutes in which a chat will be kept active after the last message","title":"TelegramIO"},{"location":"modules/ravestate_telegramio/#telegramio","text":"The TelegramIO module enables ravestate to connect to a Telegram-Bot and chat to people there. The connection to Telegram is managed with python-telegram-bot","title":"TelegramIO"},{"location":"modules/ravestate_telegramio/#architecture","text":"There are two main modes for this module: * Single-Process-Mode: All chats share the same context * Multiprocess-Mode: Every chat creates its own context in a separate process","title":"Architecture"},{"location":"modules/ravestate_telegramio/#single-process-mode","text":"In this mode the module handles incoming text messages and pictures from all chats. Outgoing messages are sent to every currently active chat.","title":"Single-Process-Mode"},{"location":"modules/ravestate_telegramio/#multiprocess-mode","text":"In this mode the \"Master\" part of the module is running in the main process of ravestate. Whenever there is a new chat, a new instance of ravestate is started in a new process and a bidirectional pipe is set up to enable communication between the main process and the new child process. Only the main process is connected to the Telegram-Bot and therefore any incoming messages get forwarded to the corresponding child process via the pipe. The main process also forwards any incoming messages it receives through the pipe to the corresponding telegram chat. In order to clean up unused child processes, the main process kills child processes after a configurable amount of inactivity. Child processes running the TelegramIO-Module listen for incoming text messages or pictures on the pipe and write output to the pipe. They only exchange messages with a single chat (indirectly via the pipe).","title":"Multiprocess-Mode"},{"location":"modules/ravestate_telegramio/#abilities","text":"The TelegramIO module is able to handle incoming text messages as well as incoming pictures. The module creates an interlocutor node for every user it is chatting with, containing the user's telegram-id, username and full name if it is set by the user. Incoming text messages are simply written into the RawIO Input property. For incoming pictures, the picture is saved locally as a file and the filepath is written to the RawIO Pic_In Context property. Messages in the RawIO Output are sent to the Telegram Chat(s).","title":"Abilities"},{"location":"modules/ravestate_telegramio/#configuration","text":"There are 5 configurable parameters (see init .py ): * telegram-token : Put the Token of your Telegram-Bot here * all_in_one_context : True if Single-Process-Mode should be used, False if Multiprocess-Mode should be used. * child_conn : Not to be set in a config file or via the command line. Will be set by master process as a runtime_override. * child_config_files : If in Multiprocess-Mode, the config-paths listed here will be used when creating a new context for a new chat. * chat_lifetime : The timespan in minutes in which a chat will be kept active after the last message","title":"Configuration"},{"location":"modules/ravestate_verbaliser/","text":"_ _ _ | | | |(_) _ _ _____ ____| |__ _____| | _ ___ _____ ____ | | | | ___ |/ ___) _ \\(____ | || |/___) ___ |/ ___) \\ V /| ____| | | |_) ) ___ | || |___ | ____| | \\_/ |_____)_| |____/\\_____|\\_)_(___/|_____)_| Verbaliser The Verbaliser produces Roboy's utterances. It diversifies the interactions with Roboy by randomizing the output given a specific intent. Using the Verbaliser Question-Answer Lists YAML files are used to define the actual utterances. In other words: they store everything Roboy can vocalise. To diversify his remarks the Verbaliser randomises similar outputs. The class QAPhrases retrieves the values from a YAML file and parses the containing phrases. Here is a template for such a YAML file: type: qa # remark types: question answering (qa), phrases name: \"INTENT\" # intent or topic Q: # possible questions - \"Question phrasing 1\" - \"Question phrasing 2\" - \"Question phrasing 3\" A: # answers SUCCESS: - \"Possible answer on success 1\" - \"Possible answer on success 2\" FAILURE: - \"Possible answer on failure\" FUP: # follow up questions (for interlocutors that are already known to Roboy) Q: - \"Possible follow up question\" A: - \"Possible follow up answer\" See more examples here . Example for Answering the Question: What happened to the Dinosaurs? Creating the YAML file: Fill in all the possible answers. type: qa name: \"DINO\" A: SUCCESS: - \"I am sure it was a mind-boggingly huge meteorite!\" - \"They smoked too much ash!\" - \"A vulcano had flatulences.\" - \"The chicken were stronger.\" FAILURE: - \"I have no idea what you just said.\" - \"Sorry, I am only interested in dinosaurs.\" Adding this file to the Verbaliser: In this case the file is going to be located in a folder of important facts. However, the single file can similarly be added by itself. The folder is in the same path as the python file adding it. from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_folder(join(dirname(realpath(__file__)), \"important_facts_folder\")) Using the Verbaliser for fancy outputs: This outputs an answer to the question. To understand how to analyse the context of the question have a look at the Natural Language Processing README if input_had_something_to_do_with_dinos and was_a_question: ctx[\"rawio:out\"] = verbaliser.get_random_successful_answer(\"DINO\") else: ctx[\"rawio:out\"] = verbaliser.get_random_failure_answer(\"DINO\") Possible conversation flow: Interlocutor: \"What happend to the Dinosaurs?\" Roboy: \"The chicken were stronger.\" Example for Extracting Phrase Lists The Verbaliser can also be used to get all the imported phrases for a specific intent as a list. Creating the phrases.yml: type: phrases name: \"dino\" opts: - \"Dinos can not scratch their backs.\" - \"Once upon a time these mind-bogglingly huge creatures wandered the earth.\" - \"The longest Dinosaur was the Argentiosaurus.\" --- type: phrases name: \"chicken\" opts: - \" Chickens are not completely flightless.\" - \" There are more chickens out there than programmers.\" - \" If I were a chicken for one day I would say: 'Puk Puk Pukaaak'. Adding the file to the Verbaliser: The YAML file is assumed to be located in the important_phrases folder. The folder is again in the same path as this python script: from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_file(join(dirname(realpath(__file__)), \"important_phrases\", \"phrases.yml\")) Using the Verbaliser to get a list of phrases: Given a specific intent the Verbaliser can be used to return a list of phrases. import ravestate_verbaliser dino_list = ravestate_verbaliser.verbaliser.get_phrase_list('dino') The verbaliser:intent Property The verbaliser:react_to_intent state produces a random phrase output for a given intent. All the possible intents are specified in YAML files that are located in the ravestate_phrases_basic_en folder . The state reads the verbaliser:intent property and outputs one random phrase in the list with that specific intent. It can therefor be triggered as follows: Let's assume that phrases.yml is now located in avestate_phrases_basic_en. @state(cond=s(\"triggered_by_some_signal\"), write=\"verbaliser:intent\") def say_some_nice_chicken_suff(ctx: ContextWrapper): ctx[\"verbaliser:intent\"] = \"chicken\"","title":"Verbaliser"},{"location":"modules/ravestate_verbaliser/#verbaliser","text":"The Verbaliser produces Roboy's utterances. It diversifies the interactions with Roboy by randomizing the output given a specific intent.","title":"Verbaliser"},{"location":"modules/ravestate_verbaliser/#using-the-verbaliser","text":"","title":"Using the Verbaliser"},{"location":"modules/ravestate_verbaliser/#question-answer-lists","text":"YAML files are used to define the actual utterances. In other words: they store everything Roboy can vocalise. To diversify his remarks the Verbaliser randomises similar outputs. The class QAPhrases retrieves the values from a YAML file and parses the containing phrases. Here is a template for such a YAML file: type: qa # remark types: question answering (qa), phrases name: \"INTENT\" # intent or topic Q: # possible questions - \"Question phrasing 1\" - \"Question phrasing 2\" - \"Question phrasing 3\" A: # answers SUCCESS: - \"Possible answer on success 1\" - \"Possible answer on success 2\" FAILURE: - \"Possible answer on failure\" FUP: # follow up questions (for interlocutors that are already known to Roboy) Q: - \"Possible follow up question\" A: - \"Possible follow up answer\" See more examples here .","title":"Question-Answer Lists"},{"location":"modules/ravestate_verbaliser/#example-for-answering-the-question-what-happened-to-the-dinosaurs","text":"Creating the YAML file: Fill in all the possible answers. type: qa name: \"DINO\" A: SUCCESS: - \"I am sure it was a mind-boggingly huge meteorite!\" - \"They smoked too much ash!\" - \"A vulcano had flatulences.\" - \"The chicken were stronger.\" FAILURE: - \"I have no idea what you just said.\" - \"Sorry, I am only interested in dinosaurs.\" Adding this file to the Verbaliser: In this case the file is going to be located in a folder of important facts. However, the single file can similarly be added by itself. The folder is in the same path as the python file adding it. from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_folder(join(dirname(realpath(__file__)), \"important_facts_folder\")) Using the Verbaliser for fancy outputs: This outputs an answer to the question. To understand how to analyse the context of the question have a look at the Natural Language Processing README if input_had_something_to_do_with_dinos and was_a_question: ctx[\"rawio:out\"] = verbaliser.get_random_successful_answer(\"DINO\") else: ctx[\"rawio:out\"] = verbaliser.get_random_failure_answer(\"DINO\") Possible conversation flow: Interlocutor: \"What happend to the Dinosaurs?\" Roboy: \"The chicken were stronger.\"","title":"Example for Answering the Question: What happened to the Dinosaurs?"},{"location":"modules/ravestate_verbaliser/#example-for-extracting-phrase-lists","text":"The Verbaliser can also be used to get all the imported phrases for a specific intent as a list. Creating the phrases.yml: type: phrases name: \"dino\" opts: - \"Dinos can not scratch their backs.\" - \"Once upon a time these mind-bogglingly huge creatures wandered the earth.\" - \"The longest Dinosaur was the Argentiosaurus.\" --- type: phrases name: \"chicken\" opts: - \" Chickens are not completely flightless.\" - \" There are more chickens out there than programmers.\" - \" If I were a chicken for one day I would say: 'Puk Puk Pukaaak'. Adding the file to the Verbaliser: The YAML file is assumed to be located in the important_phrases folder. The folder is again in the same path as this python script: from ravestate_verbaliser import verbaliser from os.path import realpath, dirname, join verbaliser.add_file(join(dirname(realpath(__file__)), \"important_phrases\", \"phrases.yml\")) Using the Verbaliser to get a list of phrases: Given a specific intent the Verbaliser can be used to return a list of phrases. import ravestate_verbaliser dino_list = ravestate_verbaliser.verbaliser.get_phrase_list('dino')","title":"Example for Extracting Phrase Lists"},{"location":"modules/ravestate_verbaliser/#the-verbaliserintent-property","text":"The verbaliser:react_to_intent state produces a random phrase output for a given intent. All the possible intents are specified in YAML files that are located in the ravestate_phrases_basic_en folder . The state reads the verbaliser:intent property and outputs one random phrase in the list with that specific intent. It can therefor be triggered as follows: Let's assume that phrases.yml is now located in avestate_phrases_basic_en. @state(cond=s(\"triggered_by_some_signal\"), write=\"verbaliser:intent\") def say_some_nice_chicken_suff(ctx: ContextWrapper): ctx[\"verbaliser:intent\"] = \"chicken\"","title":"The verbaliser:intent Property"}]} \ No newline at end of file diff --git a/docs/sitemap.xml.gz b/docs/sitemap.xml.gz index 670b34f2619bba2a4ba93ae9c854b2f2e728ab77..86cccab41858d57f7e5fde1405d423b80390b152 100644 GIT binary patch delta 15 WcmX@fc#@G_zMF&NAm5#d?1um+!UbCZ delta 15 WcmX@fc#@G_zMF%C@5k+l?1um-9tDvA