Skip to content

Commit

Permalink
Merge pull request #10 from RasaHQ/forms_v2
Browse files Browse the repository at this point in the history
Forms v2
  • Loading branch information
Ghostvv authored Nov 8, 2018
2 parents d5772cd + 9d77b9e commit f4764bc
Show file tree
Hide file tree
Showing 7 changed files with 930 additions and 152 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,9 @@ venv.bak/
# mypy
.mypy_cache/
.idea/
examples/moodbot/models/
examples/moodbot/models/

# emacs
*~

*.DS_Store
12 changes: 12 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@ This project adheres to `Semantic Versioning`_ starting with version 0.11.0.
Added
-----
- added Dockerfile for rasa_core_sdk
- add ``active_form`` and ``latest_action_name`` properties to ``Tracker``
- add ``FormAction.slot_mapping()`` method to specify the mapping between user input and requested slot in the form
- add helper methods ``FormAction.from_entity(...)``, ``FormAction.from_intent(...)`` and ``FormAction.from_text(...)``
- add ``FormAction.validate(...)`` method to validate user input

Changed
-------

- ``FormAction`` class was completely refactored
- ``required_fields()`` is changed to ``required_slots(tracker)``
- moved ``FormAction.get_other_slots(...)`` functionality to ``FormAction.extract_other_slots(...)``
- moved ``FormAction.get_requested_slot(...)`` functionality to ``FormAction.extract_requested_slot(...)``
- logic of requesting next slot can be customized in ``FormAction.request_next_slot(...)`` method

Removed
-------

- ``FormField`` class and its subclasses

Fixed
-----

Expand Down
39 changes: 30 additions & 9 deletions rasa_core_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
import logging

import typing
from typing import Dict, Text, Any, Optional, Iterator
from typing import List

from typing import Dict, Text, Any, Optional, Iterator, List

logger = logging.getLogger(__name__)

Expand All @@ -30,10 +28,13 @@ def from_dict(cls, state):
state.get("latest_message", {}),
state.get("events"),
state.get("paused"),
state.get("followup_action"))
state.get("followup_action"),
state.get("active_form", {}),
state.get("latest_action_name"))

def __init__(self, sender_id, slots,
latest_message, events, paused, followup_action):
latest_message, events, paused, followup_action,
active_form, latest_action_name):
"""Initialize the tracker."""

# list of previously seen events
Expand All @@ -52,6 +53,8 @@ def __init__(self, sender_id, slots,
# "entities": UserUttered.entities,
# "text": text}
self.latest_message = latest_message if latest_message else {}
self.active_form = active_form
self.latest_action_name = latest_action_name

def current_state(self):
# type: () -> Dict[Text, Any]
Expand All @@ -68,7 +71,9 @@ def current_state(self):
"latest_message": self.latest_message,
"latest_event_time": latest_event_time,
"paused": self.is_paused(),
"events": self.events
"events": self.events,
"active_form": self.active_form,
"latest_action_name": self.latest_action_name
}

def current_slot_values(self):
Expand Down Expand Up @@ -137,7 +142,9 @@ def copy(self):
copy.deepcopy(self.latest_message),
copy.deepcopy(self.events),
self._paused,
self.followup_action)
self.followup_action,
self.active_form,
self.latest_action_name)


class Action(object):
Expand All @@ -147,7 +154,7 @@ def name(self):
# type: () -> Text
"""Unique identifier of this simple action."""

raise NotImplementedError
raise NotImplementedError("An action must implement a name")

def run(self, dispatcher, tracker, domain):
# type: (CollectingDispatcher, Tracker, Dict[Text, Any]) -> List[dict]
Expand All @@ -170,7 +177,21 @@ def run(self, dispatcher, tracker, domain):
instances that is returned through the endpoint
"""

raise NotImplementedError
raise NotImplementedError("An action must implement its run method")

def __str__(self):
return "Action('{}')".format(self.name())


class ActionExecutionRejection(Exception):
"""Raising this exception will allow other policies
to predict another action"""

def __init__(self, action_name, message=None):
self.action_name = action_name
self.message = (message or
"Custom action '{}' rejected execution of"
"".format(action_name))

def __str__(self):
return self.message
13 changes: 11 additions & 2 deletions rasa_core_sdk/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
from __future__ import print_function
from __future__ import unicode_literals

from builtins import str

import argparse
import logging

from flask import Flask, jsonify, request
from flask_cors import CORS, cross_origin
from gevent.pywsgi import WSGIServer
from rasa_core_sdk.executor import ActionExecutor
from rasa_core_sdk import ActionExecutionRejection

DEFAULT_SERVER_PORT = 5055

Expand Down Expand Up @@ -47,7 +50,6 @@ def create_argument_parser():
default=None,
help="name of action package to be loaded"
)

return parser


Expand Down Expand Up @@ -77,7 +79,14 @@ def health():
def webhook():
"""Webhook to retrieve action calls."""
action_call = request.json
response = executor.run(action_call)
try:
response = executor.run(action_call)
except ActionExecutionRejection as e:
logger.error(str(e))
result = {"error": str(e), "action_name": e.action_name}
response = jsonify(result)
response.status_code = 400
return response

return jsonify(response)

Expand Down
34 changes: 33 additions & 1 deletion rasa_core_sdk/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,12 @@ def ConversationResumed(timestamp=None):


# noinspection PyPep8Naming
def ActionExecuted(action_name, timestamp=None):
def ActionExecuted(action_name, policy=None, confidence=None, timestamp=None):
return {
"event": "action",
"name": action_name,
"policy": policy,
"confidence": confidence,
"timestamp": timestamp,
}

Expand All @@ -139,3 +141,33 @@ def AgentUttered(text=None, data=None, timestamp=None):
"data": data,
"timestamp": timestamp,
}


# noinspection PyPep8Naming
def Form(name, timestamp=None):
return {
"event": "form",
"name": name,
"timestamp": timestamp,
}


# noinspection PyPep8Naming
def FormValidation(validate, timestamp=None):
return {
"event": "form_validation",
"validate": validate,
"timestamp": timestamp,
}


# noinspection PyPep8Naming
def ActionExecutionRejected(action_name, policy=None, confidence=None,
timestamp=None):
return {
"event": "action_execution_rejected",
"name": action_name,
"policy": policy,
"confidence": confidence,
"timestamp": timestamp,
}
Loading

0 comments on commit f4764bc

Please sign in to comment.