Source code for botiverse.bots.BasicTaskBot.BasicTaskBot
"""
This module contains the base code and interface of basic Taskbot.
"""
from botiverse.bots.BasicTaskBot.utils import RuleBasedNLU, MostRecentDST, RandomDP, TemplateBasedNLG
[docs]class BasicTaskBot:
"""
Instantiate a Task Oriented Dialogue System chat bot.
It aims to assist the user in completing certain tasks in specific domains.
The chat bot can use a fully Rule-Based approach which required no data for
training and can also include Deep learning and data can be then used to train
the chatbot model.
:param domains_slots: The slots of each domain in the system.
:type domains_slots: dict[str, list[str]]
:param templates: The predefined templates, where templates["domain"]["slot"] is
a list of questions asking about slot "slot" in domain "domain".
:type templates: dict[str, dict[str, list[str]]]
:param domains_pattern: Dictionary where the key is a name of a domain
and the value is a Regex that is used to capture that domain.
:type domains_pattern: dict[str, str]
:param slots_pattern: Dictionary where the key is a name of a domain
and the value is another dictionary where the key is a name of a slot
inside the domain and the value is a Regex that is used to capture that slot.
:type slots_pattern: dict[str, dict[str, str]]
:param verbose: Whether to print the internal state of the chatbot.
:type verbose: bool
:param append_state: Whether to append the internal state of the chatbot to the response.
:type append_state: bool
"""
def __init__(self, domains_slots, templates, domains_pattern, slots_pattern, verbose=False, append_state=False):
self.nlu = RuleBasedNLU(domains_pattern, slots_pattern)
self.dst = MostRecentDST(domains_slots)
self.dpo = RandomDP()
self.nlg = TemplateBasedNLG(templates)
self.verbose = verbose
self.current_domain = None
self.append_state = append_state
[docs] def read_data(self, data):
"""
Read the chatbot training data, redundant here as we are using a fully classical approach.
:param data: any
:type number: any
:return: None
:rtype: NoneType
"""
pass
[docs] def train(self):
"""
Train the chatbot model with the given data in read_data, redundant here as we are using a fully classical approach.
:param data: any
:type number: any
:return: None
:rtype: NoneType
"""
pass
[docs] def infer(self, prompt):
"""
Infer a suitable response to the given prompt.
:param promp: The user's prompt
:type number: str
:return: When all slots in the current domain are filled it returns empty string, otherwise it returns the response.
:rtype: str
"""
response = ""
status, self.current_domain = self.nlu.get_domain(self.current_domain, prompt)
# if no domain is detected or the domain is not supported return a default response
if status is False or self.current_domain is None:
response = "Sorry I don't know what domain are you talking about!"
else:
# get the slots and their values
status, slots, values = self.nlu.get_slot_fillers(self.current_domain, prompt)
# if no slots are detected or the slots are not supported return a default response
if status is False:
response = "Sorry I Couldn't catch that can you say it in a different way!"
else:
# update the dialogue state
self.dst.update_state(self.current_domain, slots, values)
# get the action to be taken
action = self.dpo.get_action(self.current_domain, self.dst.get_dialogue_state())
# if no action is detected return empty response
response = self.nlg.generate(self.current_domain, action)
if self.verbose == True:
print(f'State: {self.dst.get_dialogue_state()}')
if self.append_state and self.dst.is_all_slots_filled(self.current_domain):
response += str(self.dst.get_dialogue_state()[self.current_domain])
return response
[docs] def get_dialogue_state(self):
"""
Gets the dialogue state.
:return: The dialogue state, where state["domain"]["slot"] indicates
value of slot "slot" in domain "domain".
:rtype: dict[str, dict[str, str]]
"""
return self.dst.get_dialogue_state()
[docs] def reset(self, domain=None, slot=None):
"""
Reset the dialogue state.
Note: if the domain or the slot is equal to None all domains
or slots will be reset respectively.
:param domain: The domain to be reset, defaults to None.
:type domain: str
:param slot: The slot to be reset, defaults to None.
:type slot: str
"""
self.dst.reset(domain, slot)