Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event callbacks and example bot #27

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

flogiston
Copy link
Contributor

@flogiston flogiston commented May 22, 2016

Event callbacks

Enabling event-based handling of session state changes, instead of getting them and comparing after each reply.

def topic_cb(user, topic, redirect=None)
    ...

rive.on('topic', topic_cb)

def uservar_cb(user, name, value)
    ...

rive.on('uservar', uservar_cb)

Example bot - managing user session data using event callbacks

More info in eg/sessions/example.py.

NOTE: Maybe this could be added as a feature to RiveScript, but I've kept it separate for now as I'm not sure what's the status/roadmap for current multi-user functionality. I'm not using it in my bots which operate in multithreaded environment. I'm just keeping one RS instance per user and managing sessions outside. I think session management should be abstracted away and independent of scripting.

Additional public functions

get_topic(user), set_topic(user, topic), redirect(user, target)

Other changes

  • added readline config to rivescript.py so that all interactive prompts (including intaractive.py) are more terminal-friendly
  • cleaner history implementation based on collections.deque
  • minor cleanups


def redirect(self, user, target):
"""Redirect within current topic. Returns reply from the redirected trigger."""
return self._getreply(user, target)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this function here? To skip the processing of the >begin block? It doesn't seem to be called anywhere else internally except the unit tests. When redirects are actually processed it still goes straight for self._getreply().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main use case for this whole PR is being able to fully restore engine state, including setting last visited topic and replaying the last redirect if necessary. I'm actually using this in my bots. I think it's useful to add explicit API methods for setting topics and doing redirects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the documentation for this function and clarify its use case? I don't want users to accidentally start using this instead of reply() when they find out it kinda works the same way.

For example, things to highlight in the documentation:

  • The target parameter assumes that all message processing has already been done (e.g. substitutions, no punctuation, etc) - or just clarify that it must be formatted the same as how an @redirect would be in RiveScript source (also, maybe passing the target through check_syntax("@", target) internally would be a good idea to save users from themselves).
  • The begin block is not processed.
  • User input/reply history is not modified.
  • current_user() is not set nor cleared.

Or basically drive home the point that this function is for specific use cases and that most people probably don't need to worry about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirsle
Copy link
Member

kirsle commented May 31, 2016

What's the use case for the topic callback? Under the hood, topics are just user variables (e.g. <set topic=random> would do the same as {topic=random}, except the {} syntax has priority in begin blocks), or why is it useful to store the redirected trigger?

@flogiston
Copy link
Contributor Author

flogiston commented May 31, 2016

It's handy for tracking engine state (e.g. for persistence) - I attached an example bot. We might want to persist each topic change and in-topic redirects to be able to fully restore the session later. Of course you can get and store all engine state (vars, topic, etc.) after each reply, but I think the callback-based approach is much cleaner -- topic changes don't occur on every reply.

My first implementation of this behavior was via function calls, but it made the script a total mess and it was only time consuming and error-prone (adding a <call> in every topic and using an 'entry' redirect to trigger the call). With the optional callback it's easy and keeps the script clean.

from collections import deque

# Configure readline all interactive prompts
import readline
Copy link
Member

@kirsle kirsle May 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The readline module doesn't seem to be available on Win32. There is pyreadline which implements readline in pure Python which can work for Windows users.

This could maybe be replaced with some try/except logic to try the built-in readline first, then pyreadline for Windows, then give an error telling Windows users to pip install pyreadline (so that it doesn't have to go in the requirements.txt for users who don't need it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants