Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
7e50c44b15 | |||
8e16848dcd | |||
259680b3b7 | |||
8cb6526c2b | |||
![]() |
a51b1b14ad |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
.idea/
|
|
||||||
__pycache__/
|
|
@ -1,18 +0,0 @@
|
|||||||
SystemActType = dict(
|
|
||||||
affirm='affirm',
|
|
||||||
bye='bye',
|
|
||||||
canthear='canthear',
|
|
||||||
confirm_domain='confirm-domain',
|
|
||||||
negate='negate',
|
|
||||||
repeat='repeat',
|
|
||||||
reqmore='reqmore',
|
|
||||||
welcomemsg='welcomemsg',
|
|
||||||
canthelp='canthelp',
|
|
||||||
canthelp_missing_slot_value='canthelp.missing_slot_value',
|
|
||||||
expl_conf='expl-conf',
|
|
||||||
impl_conf='inform-conf',
|
|
||||||
inform='infomr',
|
|
||||||
offer='offer',
|
|
||||||
request='request',
|
|
||||||
select='select'
|
|
||||||
)
|
|
@ -1,23 +0,0 @@
|
|||||||
UserActType = dict(
|
|
||||||
ack='ack',
|
|
||||||
affirm='affirm',
|
|
||||||
bye='bye',
|
|
||||||
hello='hello',
|
|
||||||
help='help',
|
|
||||||
negate='negate',
|
|
||||||
null='null',
|
|
||||||
repeat='repeat',
|
|
||||||
requalts='requalts',
|
|
||||||
reqmore='reqmore',
|
|
||||||
restart='restart',
|
|
||||||
silence='silence',
|
|
||||||
thankyou='thankyou',
|
|
||||||
confirm='confirm',
|
|
||||||
deny='deny',
|
|
||||||
inform='inform',
|
|
||||||
request='request',
|
|
||||||
order='order',
|
|
||||||
delivery='delivery',
|
|
||||||
payment='payment',
|
|
||||||
price='price'
|
|
||||||
)
|
|
39
chatbot.py
Normal file
39
chatbot.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from nltk.chat.util import Chat
|
||||||
|
|
||||||
|
reflections = {"": ""}
|
||||||
|
quit_msg = "do widzenia"
|
||||||
|
pairs = [
|
||||||
|
[r"mam na imię (.*)", ["cześć %1.",],],
|
||||||
|
[r"co tam u ciebie?", ["dobrze, rozmawiam z ciekawą osobą.","źle, serwer nie wyrabia","może być."]],
|
||||||
|
[r"chcesz coś powiedzieć?", ["mam sekret... lubię rozmawiać :).","dobrze mi się rozmawia."]],
|
||||||
|
[r"jesteś (.*)", ["Dlaczego uważasz, że jestem %1?", "Uważam, że ty też jesteś %1"]],
|
||||||
|
[r"nie jestem (.*)", ["Dlaczego nie jesteś %1?", "Na pewno nie jesteś %1?"]],
|
||||||
|
[r'jestem (.*)', ["Jak długo byłeś %1?", "Jak się czujesz będąc %1?", "Dlaczego twierdzisz, że jesteś %1?"]],
|
||||||
|
[r"czy potrafisz (.*)\?", ["Czemu pytasz czy potrafię %1?", "A co jeśli bym potrafiła?"]],
|
||||||
|
[r"potrzebuję (.*)", ["Czy na pewno tego właśnie potrzebujesz?", "Na pewno by Ci to pomogło?"]],
|
||||||
|
[r"(.*)\?", ["Czemu o to pytasz?", "Co masz na myśli?", "Chyba nie jestem w stanie na to odpowiedzieć."]],
|
||||||
|
[f"{quit_msg}", ["żegnaj.", "Dziękuję, to będzie 150 złotych. Miłego dnia!",],],
|
||||||
|
[r'mój (.*)', [ "Twój %1, rozumiem.", "Dlaczego twierdzisz, że twój %1?"]],
|
||||||
|
[r'jak (.*)', [ "Dlaczego pytasz?", "W jaki sposób odpowiedź na to pomoże?", "Co myślisz?"]],
|
||||||
|
[r'ponieważ (.*)', [ "Czy to jest prawdziwy powód?", "Jakie inne powody przychodzą Ci do głowy?", "Czy ten powód dotyczy czegoś innego?"]],
|
||||||
|
[r'myślę (.*)', [ "Czy wątpisz %1?", "Czy naprawdę tak sądzisz?", "Ale nie jesteś pewny %1?"]],
|
||||||
|
[r'tak', [ "Wydajesz się być całkiem pewny.", "Czy mógłbyś powiedzieć coś więcej?"]],
|
||||||
|
[r'czy to (.*)', [ "Czy myślisz, że to %1?", "Może to %1 - co myślisz?", "Gdyby to było %1, co byś zrobił?"]],
|
||||||
|
[r'czy możesz (.*)', [ "Co sprawia, że myślisz, że nie mogę %1?", "Gdybym mogła %1, co wtedy?", "Dlaczego pytasz czy mogę %1?"]],
|
||||||
|
[r'czy mogę*)', [ "Być może nie chcesz %1.", "Czy chcesz móc %1?", "Gdybyś mógł %1, zrobiłbyś to?"]],
|
||||||
|
[r'czuję (.*)', [ "Dobrze, opowiedz mi więcej o tych uczuciach.", "Czy często czujesz %1?", "Kiedy zwykle czujesz %1?", "Kiedy czujesz %1, co robisz?"]],
|
||||||
|
[r'mam (.*)',[ "Dlaczego mi mówisz, że masz %1?", "Teraz, gdy masz %1, co zrobisz dalej?"]],
|
||||||
|
[r'nie dostałem(.*)',[ "Przykro nam, że w Twoim zamówieniu zabrakło %1", "Podaj numer reklamowanego zamówienia z brakuącym %1"]],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def grazyna_chat():
|
||||||
|
print(f' cześć!\n',
|
||||||
|
f'mam na imię Grażyna. Jestem botem zaprogramowanym do rozmowy w języku polskim.\n',
|
||||||
|
f'w trakcie rozmowy proszę używaj polskich znaków.')
|
||||||
|
chat = Chat(pairs=pairs, reflections=reflections)
|
||||||
|
chat.converse(quit=quit_msg)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
grazyna_chat()
|
27
dp.py
27
dp.py
@ -1,27 +0,0 @@
|
|||||||
from SystemActType import SystemActType
|
|
||||||
from UserActType import UserActType
|
|
||||||
|
|
||||||
|
|
||||||
class DP:
|
|
||||||
def update_system_action(self, state, last_user_act, last_system_act, slots):
|
|
||||||
if state == UserActType['order']:
|
|
||||||
if 'kind' not in slots[state]:
|
|
||||||
return {'act': SystemActType['request'], 'slot': 'kind'}
|
|
||||||
elif 'size' not in slots[state]:
|
|
||||||
return {'act': SystemActType['request'], 'slot': 'size'}
|
|
||||||
elif 'plates' not in slots[state]:
|
|
||||||
return {'act': SystemActType['request'], 'slot': 'plates'}
|
|
||||||
else:
|
|
||||||
return {'act': SystemActType['confirm_domain']}
|
|
||||||
|
|
||||||
else:
|
|
||||||
if last_user_act == UserActType['hello']:
|
|
||||||
return {'act': SystemActType['welcomemsg']}
|
|
||||||
elif last_user_act == UserActType['bye']:
|
|
||||||
return {'act': SystemActType['bye']}
|
|
||||||
else:
|
|
||||||
return {'act': SystemActType['canthelp']}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
51
dst.py
51
dst.py
@ -1,51 +0,0 @@
|
|||||||
from UserActType import UserActType
|
|
||||||
|
|
||||||
class DST:
|
|
||||||
def __init__(self):
|
|
||||||
self.state = None
|
|
||||||
self.last_user_act = None
|
|
||||||
self.last_system_act = None
|
|
||||||
self.slots = self.init_slots()
|
|
||||||
|
|
||||||
def update(self, user_act=None):
|
|
||||||
act = user_act['act']
|
|
||||||
self.last_user_act = act
|
|
||||||
if not self.state:
|
|
||||||
if act in [UserActType['order'],
|
|
||||||
UserActType['delivery'],
|
|
||||||
UserActType['payment'],
|
|
||||||
UserActType['price']]:
|
|
||||||
self.state = act
|
|
||||||
|
|
||||||
for slot, value in user_act['slots']:
|
|
||||||
slot = slot.lower()
|
|
||||||
value = value.lower()
|
|
||||||
|
|
||||||
self.slots[act][slot] = value
|
|
||||||
|
|
||||||
return self.state
|
|
||||||
|
|
||||||
def get_dialogue_state_tracker_state(self):
|
|
||||||
return self.state, self.last_user_act, self.last_system_act, self.slots
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return self.state
|
|
||||||
|
|
||||||
def get_last_user_act(self):
|
|
||||||
return self.last_user_act
|
|
||||||
|
|
||||||
def get_last_system_act(self):
|
|
||||||
return self.last_system_act
|
|
||||||
|
|
||||||
def get_slots(self):
|
|
||||||
return self.slots
|
|
||||||
|
|
||||||
def update_last_user_act(self, new_user_act):
|
|
||||||
self.last_user_act = new_user_act
|
|
||||||
|
|
||||||
def update_last_system_act(self, new_system_act):
|
|
||||||
self.last_system_act = new_system_act
|
|
||||||
|
|
||||||
def init_slots(self):
|
|
||||||
return dict(order={}, delivery={}, payment={}, price={})
|
|
||||||
|
|
66
evaluate.py
66
evaluate.py
@ -1,66 +0,0 @@
|
|||||||
import jsgf
|
|
||||||
from os import listdir
|
|
||||||
from os.path import isfile, join
|
|
||||||
|
|
||||||
|
|
||||||
gram_dir = './gramatyki/'
|
|
||||||
grammar_files = [file for file in listdir(gram_dir) if isfile(join(gram_dir, file))]
|
|
||||||
|
|
||||||
grammars = []
|
|
||||||
|
|
||||||
for grammarFile in grammar_files:
|
|
||||||
grammar = jsgf.parse_grammar_file(gram_dir + grammarFile)
|
|
||||||
grammars.append(grammar)
|
|
||||||
|
|
||||||
lines = []
|
|
||||||
|
|
||||||
data_dir = './data/'
|
|
||||||
data_files = [file for file in listdir(data_dir) if isfile(join(data_dir, file))]
|
|
||||||
|
|
||||||
detected = 0
|
|
||||||
|
|
||||||
for file in data_files:
|
|
||||||
f = open(f'{data_dir}{file}', "r")
|
|
||||||
for line in f:
|
|
||||||
sep = line.split('\t')
|
|
||||||
if sep[0] == 'user':
|
|
||||||
lines.append([sep[1], sep[2]])
|
|
||||||
|
|
||||||
|
|
||||||
def get_dialog_act(rule):
|
|
||||||
slots = []
|
|
||||||
get_slots(rule.expansion, slots)
|
|
||||||
global detected
|
|
||||||
detected = detected + 1
|
|
||||||
return {'act': rule.grammar.name, 'slots': slots}
|
|
||||||
|
|
||||||
|
|
||||||
def get_slots(expansion, slots):
|
|
||||||
if expansion.tag != '':
|
|
||||||
slots.append((expansion.tag, expansion.current_match))
|
|
||||||
return
|
|
||||||
|
|
||||||
for child in expansion.children:
|
|
||||||
get_slots(child, slots)
|
|
||||||
|
|
||||||
if not expansion.children and isinstance(expansion, jsgf.NamedRuleRef):
|
|
||||||
get_slots(expansion.referenced_rule.expansion, slots)
|
|
||||||
|
|
||||||
|
|
||||||
def nlu(utterance):
|
|
||||||
matched = None
|
|
||||||
for _grammar in grammars:
|
|
||||||
matched = _grammar.find_matching_rules(utterance)
|
|
||||||
if matched:
|
|
||||||
break
|
|
||||||
|
|
||||||
if matched:
|
|
||||||
return get_dialog_act(matched[0])
|
|
||||||
else:
|
|
||||||
return {'act': 'null', 'slots': []}
|
|
||||||
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
nlu(line[0])
|
|
||||||
|
|
||||||
print(f'{round((detected/len(lines)*100),2)}%')
|
|
@ -1,8 +0,0 @@
|
|||||||
## WNIOSKI
|
|
||||||
|
|
||||||
- System był zrozumiały dla większości użytkowników
|
|
||||||
- Tempo reakcji było bardziej niż zadowalające według większości badanych
|
|
||||||
- Trzeba rozszerzyć system gramatyk, gdyż nie rozpoznaje on dostatecznie często wypowiedzi użytkowników
|
|
||||||
- Wśród badanych panuje duża niezgoda, czy system zachowuje się tak, jak oczekiwano, warto przeredagować odpowiedzi systemu by były bardziej zrozumiałe dla użytkownika
|
|
||||||
- Część użytkowników nie wiedziała co powiedzieć na każdym etapie dialogu, ponownie należy rozwinąć system gramatyk oraz przeredagować wypowiedzi systemu by bardziej nakierowywały użytkowników.
|
|
||||||
- Wśród badanych zauważalny był odzew negatywny, należy wprowadzić wspomniane poprawki do systemu i ponownie przeprowadzić ewaluację by zobaczyć nowy stan odczuć użytkowników w stosunku do chęci korzystania z systemu.
|
|
@ -1,8 +0,0 @@
|
|||||||
#JSGF V1.0 UTF-8 pl;
|
|
||||||
|
|
||||||
grammar delivery;
|
|
||||||
|
|
||||||
|
|
||||||
<deliverys> = <droga> ;
|
|
||||||
|
|
||||||
public <droga> = (na | <NULL>) (dowoz | miejscu | wynos);
|
|
@ -1,8 +0,0 @@
|
|||||||
#JSGF V1.0 UTF-8 pl;
|
|
||||||
|
|
||||||
grammar hello;
|
|
||||||
|
|
||||||
|
|
||||||
<hello> = <greeting> ;
|
|
||||||
|
|
||||||
public <greeting> = (dzień dobry | cześć | siema | witam);
|
|
@ -1,13 +0,0 @@
|
|||||||
#JSGF V1.0 UTF-8 pl;
|
|
||||||
|
|
||||||
grammar order;
|
|
||||||
|
|
||||||
public <zamow> = chciałbym zamowic <rodzaj> <rozmiar> <liczba_osob> ;
|
|
||||||
|
|
||||||
<rodzaj> = (pizze | <NULL>) (vesuvio | hawajska | amerykanska | grecka) {kind};
|
|
||||||
|
|
||||||
<rozmiar> = (mala | srednia | duza | XXL) {size};
|
|
||||||
|
|
||||||
<liczba_osob> = (na | dla) <liczba> {plates} (osób | osoby);
|
|
||||||
|
|
||||||
<liczba> = (dwie | dwóch | trzy | trzech | cztery | czterech | pięć | pieciu);
|
|
@ -1,8 +0,0 @@
|
|||||||
#JSGF V1.0 UTF-8 pl;
|
|
||||||
|
|
||||||
grammar payment;
|
|
||||||
|
|
||||||
|
|
||||||
<payment> = <platnosc> ;
|
|
||||||
|
|
||||||
public <platnosc> = (płacę | zapłacę | płatność | <NULL>) (kartą | gotówką | online | przy odbiorze);
|
|
@ -1,9 +0,0 @@
|
|||||||
#JSGF V1.0 UTF-8 pl;
|
|
||||||
|
|
||||||
grammar price;
|
|
||||||
|
|
||||||
|
|
||||||
<price> = <cena> ;
|
|
||||||
|
|
||||||
public <cena> = (ile | jaki jest | jaka jest | w jakiej jest | <NULL>) (całkowity | <NULL>)
|
|
||||||
(koszt | kosztuje | cena | cenie) (pizza | pizze | pizzy | zamówienia | <NULL>);
|
|
38
main.py
38
main.py
@ -1,38 +0,0 @@
|
|||||||
from UserActType import UserActType
|
|
||||||
from nlu import nlu
|
|
||||||
from dst import DST
|
|
||||||
from dp import DP
|
|
||||||
from nlg import NLG
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
dst = DST()
|
|
||||||
dp = DP()
|
|
||||||
nlg = NLG()
|
|
||||||
|
|
||||||
print("Witamy w restauracji πzza. W czym mogę pomóc?")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
user_input = input("$")
|
|
||||||
# get user act frame from user input with Natural Language Understanding
|
|
||||||
user_act_frame = nlu(user_input)
|
|
||||||
# print('NLU', user_act_frame)
|
|
||||||
# update Dialogue State Tracker with new user act frame
|
|
||||||
dst.update(user_act_frame)
|
|
||||||
state, last_user_act, last_system_act, slots = dst.get_dialogue_state_tracker_state()
|
|
||||||
# print('state', state)
|
|
||||||
# print('last_user_act', last_user_act)
|
|
||||||
# print('last_system_act', last_system_act)
|
|
||||||
# print('slots', slots)
|
|
||||||
|
|
||||||
# get system act frame which decides what's next from Dialogue Policy
|
|
||||||
system_act_frame = dp.update_system_action(state, last_user_act, last_system_act, slots)
|
|
||||||
dst.update_last_system_act(system_act_frame)
|
|
||||||
# print('system_act_frame', system_act_frame)
|
|
||||||
|
|
||||||
# generate response based on system act frame
|
|
||||||
system_response = nlg.generate_response(state, last_user_act, last_system_act, slots, system_act_frame)
|
|
||||||
print('BOT:', system_response)
|
|
||||||
|
|
||||||
if user_act_frame['act'] == UserActType['bye']:
|
|
||||||
break
|
|
51
mockup.py
51
mockup.py
@ -1,51 +0,0 @@
|
|||||||
acts_list = {'hello': 'welcomemsg',
|
|
||||||
'null': 'canthear'}
|
|
||||||
|
|
||||||
|
|
||||||
class Act_frame:
|
|
||||||
text = ''
|
|
||||||
act = []
|
|
||||||
|
|
||||||
|
|
||||||
class Dialogue_state_frame:
|
|
||||||
state_frame = []
|
|
||||||
|
|
||||||
|
|
||||||
def NLU(text):
|
|
||||||
user_frame = Act_frame()
|
|
||||||
user_frame.text = text
|
|
||||||
if text == 'Cześć, jak masz na imię?':
|
|
||||||
user_frame.act = 'hello'
|
|
||||||
print(user_frame.act)
|
|
||||||
else:
|
|
||||||
user_frame.act = 'null'
|
|
||||||
print(user_frame.act)
|
|
||||||
return user_frame
|
|
||||||
|
|
||||||
|
|
||||||
def DST(user_frame):
|
|
||||||
dialogue_frame = Dialogue_state_frame()
|
|
||||||
dialogue_frame.state_frame.append((user_frame.text, user_frame.act))
|
|
||||||
print(dialogue_frame.state_frame)
|
|
||||||
return dialogue_frame
|
|
||||||
|
|
||||||
|
|
||||||
def DP(dialogue_frame):
|
|
||||||
system_frame = Act_frame()
|
|
||||||
system_frame.act = acts_list[dialogue_frame.state_frame[-1][1]]
|
|
||||||
print(system_frame.act)
|
|
||||||
return system_frame
|
|
||||||
|
|
||||||
|
|
||||||
def NLG(system_frame):
|
|
||||||
answer = ''
|
|
||||||
if system_frame.act == 'welcomemsg':
|
|
||||||
answer = 'Witaj, nazywam się Igrek Iksiński.'
|
|
||||||
elif system_frame.act == 'canthear':
|
|
||||||
answer = 'Nie zrozumiałem.'
|
|
||||||
return answer
|
|
||||||
|
|
||||||
|
|
||||||
text = 'Cześć, jak masz na imię?'
|
|
||||||
#text = 'Niezrozumiałe'
|
|
||||||
print(NLG(DP(DST(NLU(text)))))
|
|
21
nlg.py
21
nlg.py
@ -1,21 +0,0 @@
|
|||||||
from SystemActType import SystemActType
|
|
||||||
from UserActType import UserActType
|
|
||||||
|
|
||||||
|
|
||||||
class NLG:
|
|
||||||
def generate_response(self, state, last_user_act, last_system_act, slots, system_act):
|
|
||||||
if state == UserActType['order']:
|
|
||||||
if system_act['act'] == SystemActType['request']:
|
|
||||||
if system_act['slot'] == 'kind':
|
|
||||||
return 'Jaką pizzę chcesz zamówić?'
|
|
||||||
elif system_act['slot'] == 'size':
|
|
||||||
return 'Jakiego rozmiaru chcesz pizzę?'
|
|
||||||
elif system_act['slot'] == 'plates':
|
|
||||||
return 'Dla ilu osób ma to być?'
|
|
||||||
elif system_act['act'] == SystemActType['confirm_domain']:
|
|
||||||
return 'Czy mam dodać tę pizzę do zamówienia?\nPizza: {}\nRozmiar: {}\nIlość osób: {}'.\
|
|
||||||
format(slots['order']['kind'], slots['order']['size'], slots['order']['plates'])
|
|
||||||
elif last_user_act == UserActType['hello']:
|
|
||||||
return 'Dzień dobry, w czym mogę pomóc?'
|
|
||||||
else:
|
|
||||||
return 'Przepraszam. Zdanie nie jest mi zrozumiałe. Spróbuj je sformułować w inny sposób.'
|
|
49
nlu.py
49
nlu.py
@ -1,49 +0,0 @@
|
|||||||
import jsgf
|
|
||||||
from os import listdir
|
|
||||||
from os.path import isfile, join
|
|
||||||
|
|
||||||
|
|
||||||
gram_dir = './gramatyki/'
|
|
||||||
grammar_files = [file for file in listdir(gram_dir) if isfile(join(gram_dir, file))]
|
|
||||||
|
|
||||||
grammars = []
|
|
||||||
|
|
||||||
for grammarFile in grammar_files:
|
|
||||||
grammar = jsgf.parse_grammar_file(gram_dir + grammarFile)
|
|
||||||
grammars.append(grammar)
|
|
||||||
|
|
||||||
|
|
||||||
def get_dialog_act(rule):
|
|
||||||
slots = []
|
|
||||||
get_slots(rule.expansion, slots)
|
|
||||||
return {'act': rule.grammar.name, 'slots': slots}
|
|
||||||
|
|
||||||
|
|
||||||
def get_slots(expansion, slots):
|
|
||||||
if expansion.tag != '':
|
|
||||||
slots.append((expansion.tag, expansion.current_match))
|
|
||||||
return
|
|
||||||
|
|
||||||
for child in expansion.children:
|
|
||||||
get_slots(child, slots)
|
|
||||||
|
|
||||||
if not expansion.children and isinstance(expansion, jsgf.NamedRuleRef):
|
|
||||||
get_slots(expansion.referenced_rule.expansion, slots)
|
|
||||||
|
|
||||||
|
|
||||||
def nlu(utterance):
|
|
||||||
matched = None
|
|
||||||
for _grammar in grammars:
|
|
||||||
matched = _grammar.find_matching_rules(utterance)
|
|
||||||
if matched:
|
|
||||||
break
|
|
||||||
|
|
||||||
if matched:
|
|
||||||
return get_dialog_act(matched[0])
|
|
||||||
else:
|
|
||||||
return {'act': 'null', 'slots': []}
|
|
||||||
|
|
||||||
|
|
||||||
# print(nlu('chciałbym zamowic pizze vesuvio XXL na dwie osoby'))
|
|
||||||
# print(nlu('na dowoz'))
|
|
||||||
# print(nlu('dowoz'))
|
|
Loading…
Reference in New Issue
Block a user