working chatbot
This commit is contained in:
parent
253320ce1d
commit
abdfe9d1b3
@ -1,7 +1,8 @@
|
||||
from pathlib import Path
|
||||
from modules.nlu import NLU, Slot, UserAct
|
||||
from modules.nlu import NLU, Slot, Act
|
||||
from modules.state_monitor import DialogStateMonitor
|
||||
from modules.generator import ResponseGenerator
|
||||
from modules.strategy import DialoguePolicy
|
||||
from modules.config import Config
|
||||
import colorama
|
||||
from colorama import Fore, Style
|
||||
@ -10,13 +11,15 @@ colorama.init(autoreset=True)
|
||||
|
||||
|
||||
def main():
|
||||
print(Fore.CYAN + "Starting chatbot. Please wait...")
|
||||
base_path = Path(__file__).resolve().parent
|
||||
config_path = base_path / 'config' / 'config.json'
|
||||
config = Config.load_config(config_path)
|
||||
|
||||
nlu = NLU()
|
||||
dst = DialogStateMonitor()
|
||||
generator = ResponseGenerator(config)
|
||||
dp = DialoguePolicy()
|
||||
generator = ResponseGenerator()
|
||||
|
||||
print(Fore.CYAN + "Witaj w chatbocie! Rozpocznij rozmowę.")
|
||||
print(Fore.YELLOW + "Wpisz 'quit' aby zakończyć program.\n")
|
||||
@ -28,13 +31,12 @@ def main():
|
||||
break
|
||||
|
||||
user_act = nlu.analyze(user_input)
|
||||
# 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)
|
||||
dst.update(user_act)
|
||||
system_action = dp.next_action(dst)
|
||||
response = generator.nlg(system_action)
|
||||
|
||||
print(Fore.CYAN + "Bot: " + response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -70,6 +70,8 @@ def conllu2flair_slot(sentences, label=None):
|
||||
|
||||
|
||||
def predict_frame(model, sentence, label_type):
|
||||
if not sentence:
|
||||
return 'unknown'
|
||||
csentence = [{'form': word, 'slot': 'O'} for word in sentence]
|
||||
fsentence = conllu2flair([csentence])[0]
|
||||
model.predict(fsentence)
|
||||
@ -84,6 +86,8 @@ def predict_frame(model, sentence, label_type):
|
||||
|
||||
|
||||
def predict_slot(model, sentence, label_type):
|
||||
if not sentence:
|
||||
return {'form': '', 'slot': 'unknown'},
|
||||
csentence = [{'form': word, 'slot': 'O'} for word in sentence]
|
||||
fsentence = conllu2flair([csentence])[0]
|
||||
model.predict(fsentence)
|
||||
@ -112,10 +116,9 @@ class Model:
|
||||
trainset = list(parse_incr(f, fields=['id', 'form', 'frame', 'slot'], field_parsers=field_parsers))
|
||||
with open(self.test_dataset, encoding='utf-8') as f:
|
||||
testset = list(parse_incr(f, fields=['id', 'form', 'frame', 'slot'], field_parsers=field_parsers))
|
||||
print('TRAINSET:', trainset)
|
||||
|
||||
corpus = Corpus(train=conllu2flair(trainset, label_type), test=conllu2flair(testset, label_type))
|
||||
label_dictionary = corpus.make_label_dictionary(label_type=label_type)
|
||||
print('LABEL:' ,label_dictionary)
|
||||
embedding_types = [
|
||||
WordEmbeddings('pl'),
|
||||
FlairEmbeddings('pl-forward'),
|
||||
|
@ -8,11 +8,41 @@ class ResponseGenerator:
|
||||
def __init__(self, config: Config):
|
||||
with config.responses_path.open('r', encoding='utf-8') as file:
|
||||
self.responses: Dict[str, list] = json.load(file)
|
||||
self.intent_to_response_key = {
|
||||
"ask_name": "name_response",
|
||||
"unknown": "unknown"
|
||||
|
||||
def nlg(self, system_act):
|
||||
intent = system_act.intent
|
||||
slot = system_act.slots[0].name if system_act.slots else None
|
||||
|
||||
responses = {
|
||||
"inform": {
|
||||
"item": "Nasz sklep oferuje szeroki wybór artykułów, takich jak\n artykuły spożywcze,\n ogrodowe\n oraz kosmetyki. Proszę podaj produkt.",
|
||||
"address": "Nasz sklep nie ma fizycznego adresu. To sklep internetowy.",
|
||||
"delivery_method": "Dostępne formy dostawy: INPOST, DPD, DHL.",
|
||||
"payment_method": "Dostępne formy płatności: Karta, przy odbiorze",
|
||||
"email": "Obsługa klienta: cs2137@gmail.com",
|
||||
"card_nr": random.choice([
|
||||
"Dzięki karcie rabatowej zbierasz punkty, które poźniej przekładają się na rabat.",
|
||||
"Dzisiaj z kartą rabatową meble ogrodowe 200zł taniej!",
|
||||
"Dzisiaj z kartą rabatową szampony 2 w cenie 1!"
|
||||
])
|
||||
},
|
||||
"canthelp": {
|
||||
"unknown": random.choice([
|
||||
"Przepraszam, nie rozumiem polecenia...",
|
||||
"Możesz powtórzyć?",
|
||||
"Powiedz proszę jeszcze raz.."
|
||||
])
|
||||
},
|
||||
"request": {
|
||||
"card_nr": "Podaj proszę numer karty rabatowej",
|
||||
"address": "Podaj proszę adres do wysyłki",
|
||||
"item": "Jaki produkt chcesz kupić?",
|
||||
"email": "Podaj proszę email.",
|
||||
"delivery_method": "Jaką formą dostawy jesteś zainteresowany?",
|
||||
"payment_method": "Jaką formą płatności jesteś zainteresowany?"
|
||||
},
|
||||
"bye": "Miłego dnia!",
|
||||
"confirmation": "Zamówienie zostało złożone!"
|
||||
}
|
||||
|
||||
def generate(self, response_key: str) -> str:
|
||||
response_key = self.intent_to_response_key.get(response_key, "unknown")
|
||||
return random.choice(self.responses.get(response_key, ["Przepraszam, nie rozumiem. Możesz to powtórzyć?"]))
|
||||
return responses.get(intent, {}).get(slot, "Nieznane zapytanie.")
|
||||
|
@ -17,7 +17,7 @@ class Slot:
|
||||
return f"Name: {self.name}, Value: {self.value}"
|
||||
|
||||
|
||||
class UserAct:
|
||||
class Act:
|
||||
def __init__(self, intent: str, slots: list[Slot] = []):
|
||||
self.slots = slots
|
||||
self.intent = intent
|
||||
@ -62,6 +62,4 @@ class NLU:
|
||||
def analyze(self, text: str):
|
||||
intent = self.get_intent(text)
|
||||
slots = self.get_slot(text)
|
||||
print({'intent': intent,
|
||||
'slots': slots})
|
||||
return UserAct(intent=intent, slots=slots)
|
||||
return Act(intent=intent, slots=slots)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import copy
|
||||
from modules.nlu import UserAct
|
||||
from modules.nlu import Act
|
||||
import json
|
||||
|
||||
|
||||
@ -39,11 +39,10 @@ class DialogStateMonitor:
|
||||
|
||||
def find_first_empty_slot(self):
|
||||
for slot_name, slot_value in self.state['belief_state'].items():
|
||||
if slot_name != 'order-completed' and self.is_value_empty(slot_value):
|
||||
if slot_name != 'order-completed' and slot_value in [None, '', [], {}]:
|
||||
return slot_name
|
||||
|
||||
def update(self, act: UserAct) -> None:
|
||||
print(act)
|
||||
def update(self, act: Act) -> None:
|
||||
if act.intent == 'inform':
|
||||
self.update_act(act.intent)
|
||||
slots_mapping = {
|
||||
@ -55,7 +54,7 @@ class DialogStateMonitor:
|
||||
'email': []
|
||||
}
|
||||
for slot in act.slots:
|
||||
if slot.name in slots_mapping and self.is_value_empty(self.state, slot.name):
|
||||
if slot.name in slots_mapping and self.is_value_empty(self.state['belief_state'], slot.name):
|
||||
slots_mapping[slot.name].append(slot.value) # To do: normalization
|
||||
|
||||
for slot_name, values in slots_mapping.items():
|
||||
@ -67,5 +66,7 @@ class DialogStateMonitor:
|
||||
self.update_slot_names(slots_names)
|
||||
elif act.intent == 'bye':
|
||||
self.update_act(act.intent)
|
||||
elif act.intent == 'unknown':
|
||||
self.update_act(act.intent)
|
||||
|
||||
self.check_order_complete()
|
||||
|
@ -1,24 +1,24 @@
|
||||
from modules.nlu import UserAct, Slot
|
||||
from numpy.random.mtrand import random
|
||||
from modules.nlu import Act, Slot
|
||||
import random
|
||||
|
||||
|
||||
class DialoguePolicy:
|
||||
def __init__(self, dst):
|
||||
self.dialogue_state = dst.state
|
||||
|
||||
def next_action(self):
|
||||
if not self.dialogue_state['belief_state']['order-complete']:
|
||||
user_intent = self.dialogue_state['act']
|
||||
def next_action(self, dst):
|
||||
if not dst.state['belief_state']['order-complete']:
|
||||
user_intent = dst.state['act']
|
||||
if user_intent == "inform":
|
||||
empty_slot = dst.find_first_empty_slot()
|
||||
return UserAct(intent="request", slots=[Slot(name=empty_slot, value='')])
|
||||
if user_intent == "request":
|
||||
if self.dialogue_state['slot_names']:
|
||||
slot = random.choice(self.state['slot_names'])
|
||||
return UserAct(intent="inform", slots=[Slot(name=slot, value='')])
|
||||
return Act(intent="request", slots=[Slot(name=empty_slot, value='')])
|
||||
elif user_intent == "request":
|
||||
if dst.state['slot_names']:
|
||||
slot = random.choice(dst.state['slot_names'])
|
||||
return Act(intent="inform", slots=[Slot(name=slot, value='')])
|
||||
else:
|
||||
return UserAct(intent="inform", slots=[Slot(name='unknown', value='')])
|
||||
if user_intent == "bye":
|
||||
return UserAct(intent="bye", slots=[Slot(name='', value='')])
|
||||
return Act(intent="canthelp", slots=[Slot(name='unknown', value='')])
|
||||
elif user_intent == "bye":
|
||||
return Act(intent="bye", slots=[Slot(name='', value='')])
|
||||
else:
|
||||
return Act(intent="canthelp", slots=[Slot(name='unknown', value='')])
|
||||
else:
|
||||
return UserAct(intent= "inform", slots=[Slot(name='confirmation', value='Zamówienie złożono poprawnie.')])
|
||||
return Act(intent="inform", slots=[Slot(name='confirmation', value='Zamówienie złożono poprawnie.')])
|
Loading…
Reference in New Issue
Block a user