diff --git a/chatbot/modules/nlu.py b/chatbot/modules/nlu.py new file mode 100644 index 0000000..6e387ba --- /dev/null +++ b/chatbot/modules/nlu.py @@ -0,0 +1,42 @@ +import copy +from copy import deepcopy +import json +import os +import jsgf + + +class NLU: + def __init__(self): + self.grammars = [ + jsgf.parse_grammar_file(f"grammars/{file_name}") + for file_name in os.listdir("grammars") + ] + + def get_dialog_act(self, rule): + slots = [] + self.get_slots(rule.expansion, slots) + return {"act": rule.grammar.name, "slots": slots} + + def get_slots(self, expansion, slots): + if expansion.tag != "": + slots.append((expansion.tag, expansion.current_match)) + return + + for child in expansion.children: + self.get_slots(child, slots) + + if not expansion.children and isinstance(expansion, jsgf.NamedRuleRef): + self.get_slots(expansion.referenced_rule.expansion, slots) + + def match(self, utterance): + list_of_illegal_character = [",", ".", "'", "?", "!", ":", "-", "/"] + for illegal_character in list_of_illegal_character[:-2]: + utterance = utterance.replace(f"{illegal_character}", "") + for illegal_character in list_of_illegal_character[-2:]: + utterance = utterance.replace(f"{illegal_character}", " ") + + for grammar in self.grammars: + matched = grammar.find_matching_rules(utterance.lower()) + if matched: + return self.get_dialog_act(matched[0]) + return {"act": "null", "slots": []} diff --git a/data/02-01-01.tsv b/data/02-01-01.tsv index 1739641..96f49d4 100644 --- a/data/02-01-01.tsv +++ b/data/02-01-01.tsv @@ -1,5 +1,5 @@ system Witamy w sklepie internetowym XYZ. W czym mogę pomóc? welcomemsg() -user Potrzbuje nowego biurka, czy jest cos specjalnego w ofercie, oczekuje biurka 3 metry na 1 metr request(items=biurka, size=3m x 1m) +user Potrzebuje nowego biurka, czy jest cos specjalnego w ofercie, oczekuje biurka 3 metry na 1 metr request(items=biurka, size=3m x 1m) system Obecne modele biurek o długości 3m: Biurko WMI 3m x 1m; Biurko ABCD 3m x 70cm. Uprzejmie informujemy, iż dodatkowo na promocji znajduje się obecnie biurko Ania 2.70m x 1m inform(models=[Biurko WMI 3m x 1m, Biurko ABCD 3m x 70cm])&offer(promotion=Biurko Ania 2.70m x 1m) user Z czego wykonane są te biurka i jakie są ceny request(material, price) system Biurko WMI - 2000ZL, drewno debowe premium; Biurko ABCD - 1000ZL sklejka; BIurko Ania - 900ZL z 1200ZL, metal; inform(items= {model= Biurko WMI, material=drewno debowe premium, price=2000ZL}, {model=Biurko ABCD, material=sklejka, price=1000ZL}, {model=Biurko Ania, material=metal, price=900ZL (z 1200ZL)}) diff --git a/evaluate.py b/evaluate.py new file mode 100644 index 0000000..e53292c --- /dev/null +++ b/evaluate.py @@ -0,0 +1,26 @@ +import os +import re +import pandas as pd +import numpy as np +from chatbot.modules.nlu import NLU + +rows = 0 +hits = 0 + +nlu = NLU() + +for file_name in os.listdir("data"): + df = pd.read_csv(f"data/{file_name}", sep="\t", names=["user", "sentence", "acts"]) + df = df[df.user == "user"] + data = np.array(df) + + for row in data: + rows += 1 + sentence = row[1] + cleaned_text = re.sub(r'\([^)]*\)', '', row[2]) + user_acts = cleaned_text.split("&") + nlu_match = nlu.match(sentence) + if nlu_match["act"] in user_acts: + hits += 1 + +print(f"Accuracy: {(hits / rows) * 100}") diff --git a/grammars/affirm.jsgf b/grammars/affirm.jsgf new file mode 100644 index 0000000..7109a0b --- /dev/null +++ b/grammars/affirm.jsgf @@ -0,0 +1,7 @@ +#JSGF V1.0 UTF-8 pl; + +grammar affirm; + +public = ; + + = Tak zdecydowanie | Tak | Tak to brzmi świetnie | Potwierdzam; diff --git a/grammars/bye.jsgf b/grammars/bye.jsgf new file mode 100644 index 0000000..c7c88f3 --- /dev/null +++ b/grammars/bye.jsgf @@ -0,0 +1,7 @@ +#JSGF V1.0 UTF-8 pl; + +grammar bye; + +public = ; + + = Do widzenia | (Nie | Tak) to wszystko Dziękuję | Dziękujemy za zakupy Miłego dnia | Dziekujemy za zakupy w sklepie XYZ Milego dnia | Dziękuję Życzę miłego dnia | To wszystko; diff --git a/grammars/inform.jsgf b/grammars/inform.jsgf new file mode 100644 index 0000000..68bc7c6 --- /dev/null +++ b/grammars/inform.jsgf @@ -0,0 +1,26 @@ +#JSGF V1.0 UTF-8 pl; + +grammar inform; + +public = Jaka jest cena produktu {produkt}*; +public = Jaki jest adres dostawy; +public = Jakie są dostępne metody płatności; + +public = dostępne | niedostępne; + +public = Cena produktu {produkt}* wynosi *; +public = Adres dostawy to ; +public = Dostępne metody płatności to *; + +public = zł; +public = jeden | dwie | trzy | cztery | pięć | sześć | siedem | osiem | dziewięć | dziesięć; + +public = ulica miasto kod pocztowy ; +public = ul ; +public = ; +public = -; + +public = XYZ; +public = XYZ; +public = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0; +public = karta kredytowa | przelew bankowy | płatność przy odbiorze; diff --git a/grammars/request.jsgf b/grammars/request.jsgf new file mode 100644 index 0000000..ba0fac9 --- /dev/null +++ b/grammars/request.jsgf @@ -0,0 +1,29 @@ +#JSGF V1.0 UTF-8 pl; + +grammar request; + +public = kosmetyki | leżaki ogrodowe | artykuły spożywcze; + +public = szminka | krem do twarzy | szampon | balsam do ciała | maskara | leżak plażowy | leżak ogrodowy | parasol ogrodowy | grill | owoce | warzywa | mleko | jajka | pieczywo | ryby | mięso | woda mineralna | przekąski; + +public = Czy macie w ofercie {produkt}*; +public = Interesuje mnie zakup {produkt}*; +public = Interesuje mnie zakup {produkt} {kategorie}*; +public = Chciałbym kupić {produkt}*; +public = Chciałbym kupić {produkt} {kategorie}*; +public = Chciałabym kupić {produkt}*; +public = Chciałabym kupić {produkt} {kategorie}*; +public = Czy w sklepie dostępne są {produkt}*; +public = Czy w sklepie dostępne są {produkt} {kategorie}*; + +public = dostępne | niedostępne; + +public = Tak mamy {produkt}*; +public = Tak mamy {produkt} {kategorie}*; +public = Niestety aktualnie nie mamy {produkt}*; +public = Niestety aktualnie nie mamy {produkt} {kategorie}*; + +public = Tak w sklepie są {produkt}*; +public = Tak w sklepie są {produkt} {kategorie}*; +public = Niestety aktualnie nie ma {produkt}*; +public = Niestety aktualnie nie ma {produkt} {kategorie}*; diff --git a/grammars/welcomemsg.jsgf b/grammars/welcomemsg.jsgf new file mode 100644 index 0000000..063f7b8 --- /dev/null +++ b/grammars/welcomemsg.jsgf @@ -0,0 +1,6 @@ +#JSGF V1.0 UTF-8 pl; + +grammar welcomemsg; + +public = ; + = Witamy w sklepie internetowym XYZ W czym mogę pomóc | Witaj W czym mogę Ci dzisiaj pomóc | Witamy w sklepie internetowym XYZ W swojej ofercie mamy artykuły ogrodowe meblowe oraz kosmetyki | Witam tutaj sklep wielobranzowy w czym moge pomoc | cześć chciałbym kupić {product}; \ No newline at end of file diff --git a/main.py b/main.py index a53c62e..9dc34fe 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,12 @@ +import jsgf + +request_grammar = jsgf.parse_grammar_file('./grammars/request.jsgf') + + def main(): - pass + utterance = 'Czy macie w ofercie balsam do ciała' + matched = request_grammar.find_matching_rules(utterance) + print(matched) if __name__ == '__main__':