chatbot #4

Merged
s464951 merged 11 commits from nlu-model into master 2024-06-14 11:55:59 +02:00
3 changed files with 106 additions and 23 deletions
Showing only changes of commit 1926681255 - Show all commits

View File

@ -1,5 +1,6 @@
from pathlib import Path from pathlib import Path
from modules.nlp import NaturalLanguageProcessor from modules.nlu import NLU, Slot, UserAct
from modules.state_monitor import DialogStateMonitor
from modules.generator import ResponseGenerator from modules.generator import ResponseGenerator
from modules.config import Config from modules.config import Config
import colorama import colorama
@ -13,7 +14,8 @@ def main():
config_path = base_path / 'config' / 'config.json' config_path = base_path / 'config' / 'config.json'
config = Config.load_config(config_path) config = Config.load_config(config_path)
nlp = NaturalLanguageProcessor(config) nlu = NLU()
dst = DialogStateMonitor()
generator = ResponseGenerator(config) generator = ResponseGenerator(config)
print(Fore.CYAN + "Witaj w chatbocie! Rozpocznij rozmowę.") print(Fore.CYAN + "Witaj w chatbocie! Rozpocznij rozmowę.")
@ -25,10 +27,14 @@ def main():
print(Fore.RED + "Zamykanie chatbota...") print(Fore.RED + "Zamykanie chatbota...")
break break
intent = nlp.analyze(user_input) user_act = nlu.analyze(user_input)
response = generator.generate(intent) # user_act = UserAct(intent='inform',
# slots=[Slot(name='item', value='laptop'), Slot(name='item', value='kot'),Slot(name='address', value='123 Main St')])
dst.update(user_act)
print(dst.state)
# response = generator.generate(intent)
print(Fore.CYAN + "Bot: " + response) # print(Fore.CYAN + "Bot: " + response)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,15 +1,39 @@
from flair.models import SequenceTagger from flair.models import SequenceTagger
import sys import sys
sys.path.append("..") sys.path.append("..")
from models.nlu_train2 import predict_frame, predict_slot from models.nlu_train2 import predict_frame, predict_slot
import logging import logging
logging.getLogger('flair').setLevel(logging.CRITICAL) logging.getLogger('flair').setLevel(logging.CRITICAL)
class Slot:
def __init__(self, name, value=None):
self.name = name
self.value = value
def __str__(self) -> str:
return f"Name: {self.name}, Value: {self.value}"
class UserAct:
def __init__(self, intent: str, slots: list[Slot] = []):
self.slots = slots
self.intent = intent
def __str__(self):
msg = f"Act: {self.intent}, Slots: ["
for slot in self.slots:
msg += f"({slot}), "
msg += "]"
return msg
class NLU: class NLU:
def __init__(self): def __init__(self):
self.frame_model = SequenceTagger.load('../models/frame-model/final-model.pt') self.frame_model = SequenceTagger.load('models/frame-model/final-model.pt')
self.slot_model = SequenceTagger.load('../models/slot-model/final-model.pt') self.slot_model = SequenceTagger.load('models/slot-model/final-model.pt')
def get_intent(self, text: str): def get_intent(self, text: str):
return predict_frame(self.frame_model, text.split(), 'frame') return predict_frame(self.frame_model, text.split(), 'frame')
@ -24,14 +48,14 @@ class NLU:
slot = frame["slot"] slot = frame["slot"]
if slot.startswith("B-"): if slot.startswith("B-"):
if current_slot: if current_slot:
slots.append({'name': current_slot, 'value': " ".join(current_slot_value)}) slots.append(Slot(name=current_slot, value=current_slot_value))
current_slot = slot[2:] current_slot = slot[2:]
current_slot_value = [frame["form"]] current_slot_value = [frame["form"]]
elif slot.startswith("I-"): elif slot.startswith("I-"):
current_slot_value.append(frame["form"]) current_slot_value.append(frame["form"])
if current_slot: if current_slot:
slots.append({'name': current_slot, 'value': " ".join(current_slot_value)}) slots.append(Slot(name=current_slot, value=current_slot_value))
return slots return slots
@ -39,12 +63,5 @@ class NLU:
intent = self.get_intent(text) intent = self.get_intent(text)
slots = self.get_slot(text) slots = self.get_slot(text)
print({'intent': intent, print({'intent': intent,
'slots': slots}) 'slots': slots})
return { return UserAct(intent=intent, slots=slots)
'intent': intent,
'slots': slots
}
nlu = NLU()
nlu.analyze("Chce kupic lakier do pazanokci")

View File

@ -1,6 +1,66 @@
class DialogueStateMonitor: import copy
def __init__(self) -> None: from modules.nlu import UserAct
self.state = {'last_intent': 'unknown'} import json
def update_state(self, intent: str) -> None:
self.state['last_intent'] = intent class DialogStateMonitor:
def __init__(self):
self.__initial_state = dict(
belief_state={
'item': {},
'address': {},
'card_nr': {},
'delivery_method': {},
'payment_method': {},
'email': {},
'order-complete': False,
},
act='',
slot_names=[])
self.state = copy.deepcopy(self.__initial_state)
def is_value_empty(self, d, key):
value = d.get(key, None)
if value in [None, '', [], {}]:
return True
return False
def update_act(self, intent):
self.state['act'] = intent
def update_slot_names(self, slots_names):
self.state['slot_names'] = slots_names
def check_order_complete(self):
all_filled = all(bool(self.state['belief_state'][key]) for key in
['item', 'address', 'card_nr', 'delivery_method', 'payment_method', 'email'])
self.state['belief_state']['order-complete'] = all_filled
def update(self, act: UserAct) -> None:
print(act)
if act.intent == 'inform':
self.update_act(act.intent)
slots_mapping = {
'item': [],
'address': [],
'card_nr': [],
'delivery_method': [],
'payment_method': [],
'email': []
}
for slot in act.slots:
if slot.name in slots_mapping and self.is_value_empty(self.state, slot.name):
slots_mapping[slot.name].append(slot.value) # To do: normalization
for slot_name, values in slots_mapping.items():
if values:
self.state['belief_state'][slot_name] = values
elif act.intent == 'request':
self.update_act(act.intent)
slots_names = [slot.name for slot in act.slots]
self.update_slot_names(slots_names)
elif act.intent == 'bye':
self.update_act(act.intent)
self.check_order_complete()