1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
# -*- coding: utf-8 -*-
from typing import Dict, Text, Any, List, Union, Optional
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import FormAction
class RestaurantForm(FormAction):
"""Example of a custom form action"""
def name(self) -> Text:
"""Unique identifier of the form"""
return "restaurant_form"
@staticmethod
def required_slots(tracker: Tracker) -> List[Text]:
"""A list of required slots that the form has to fill"""
# 和这个form相关的slot值
return ["cuisine", "num_people", "outdoor_seating", "preferences", "feedback"]
def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
"""A dictionary to map required slots to
- an extracted entity
- intent: value pairs
- a whole message
or a list of them, where a first match will be picked"""
# cuisine: 不是chitchat意图的消息中的cuisine实体
# num_people: inform或request_restaurant意图消息中的num_people实体,其他消息中的nunber实体
# 但在这个例子中并没有number实体
# outdoor_seating: 如果针对问题返回affirm的意图,那么值为True
# 如果针对问题返回deny的意图,那么值为False
# 提取到的seating值。
# preferences: 如果是拒绝意图,那么值是no additional preferences
# 否则从非affirm意图消息中获取文本
# feedback: feedback实体,或空
return {
"cuisine": self.from_entity(entity="cuisine", not_intent="chitchat"),
"num_people": [
self.from_entity(
entity="num_people", intent=["inform", "request_restaurant"]
),
self.from_entity(entity="number"),
],
"outdoor_seating": [
self.from_entity(entity="seating"),
self.from_intent(intent="affirm", value=True),
self.from_intent(intent="deny", value=False),
],
"preferences": [
self.from_intent(intent="deny", value="no additional preferences"),
self.from_text(not_intent="affirm"),
],
"feedback": [self.from_entity(entity="feedback"), self.from_text()],
}
# USED FOR DOCS: do not rename without updating in docs
@staticmethod
def cuisine_db() -> List[Text]:
"""Database of supported cuisines"""
return [
"caribbean",
"chinese",
"french",
"greek",
"indian",
"italian",
"mexican",
]
@staticmethod
def is_int(string: Text) -> bool:
"""Check if a string is an integer"""
try:
int(string)
return True
except ValueError:
return False
# USED FOR DOCS: do not rename without updating in docs
def validate_cuisine(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Validate cuisine value."""
if value.lower() in self.cuisine_db():
# validation succeeded, set the value of the "cuisine" slot to value
return {"cuisine": value}
else:
dispatcher.utter_template("utter_wrong_cuisine", tracker)
# validation failed, set this slot to None, meaning the
# user will be asked for the slot again
return {"cuisine": None}
def validate_num_people(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Validate num_people value."""
if self.is_int(value) and int(value) > 0:
return {"num_people": value}
else:
dispatcher.utter_template("utter_wrong_num_people", tracker)
# validation failed, set slot to None
return {"num_people": None}
def validate_outdoor_seating(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Validate outdoor_seating value."""
if isinstance(value, str):
if "out" in value:
# convert "out..." to True
return {"outdoor_seating": True}
elif "in" in value:
# convert "in..." to False
return {"outdoor_seating": False}
else:
dispatcher.utter_template("utter_wrong_outdoor_seating", tracker)
# validation failed, set slot to None
return {"outdoor_seating": None}
else:
# affirm/deny was picked up as T/F
return {"outdoor_seating": value}
def submit(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict]:
"""Define what the form has to do
after all required slots are filled"""
# utter submit template
dispatcher.utter_template("utter_submit", tracker)
return []
|