Compare commits

...

24 Commits
data ... master

Author SHA1 Message Date
d4100eb063 Prześlij pliki do '' 2023-05-10 19:10:15 +02:00
s444510
777e6fa497 fixes 2023-05-05 00:42:26 +02:00
s444510
de703d016c add basic main, dp, dst, nlg 2023-05-05 00:07:47 +02:00
s444510
22b61e0dd7 comment examples in nlu.py 2023-05-05 00:06:58 +02:00
s444510
d63f926b49 change act types from enums to dicts 2023-05-05 00:06:09 +02:00
s444510
5bf25d0b2b update gitignore 2023-05-05 00:05:17 +02:00
s444510
cdd9ce17e9 add user and system act types 2023-05-04 19:11:19 +02:00
s444510
18858dddc8 add system act type enum 2023-05-04 17:20:11 +02:00
s444510
283f26a164 add DST backbone 2023-05-04 16:27:18 +02:00
s444510
be761cfb54 add .gitignore 2023-05-04 16:26:42 +02:00
6cd5dcad5c Prześlij pliki do 'gramatyki' 2023-04-21 03:23:11 +02:00
e9e8eae277 Dodanie 'gramatyki/delivery.jsgf' 2023-04-21 02:41:45 +02:00
60dbfcd478 Usuń 'gramatyki/delivery.jsgf' 2023-04-21 02:41:33 +02:00
258d8b3be0 Zaktualizuj 'gramatyki/delivery.jsgf' 2023-04-21 02:41:15 +02:00
b0e4a5bb2e Zaktualizuj 'mockup.py' 2023-04-21 02:23:54 +02:00
1cce41a8c6 Dodanie 'evaluate.py' 2023-04-20 23:33:43 +02:00
0595bba4d8 Update 'nlu.py' 2023-04-20 22:38:00 +02:00
2f0d3350e9 Delete 'order.jsgf' 2023-04-20 22:37:32 +02:00
e3cfaf2573 Add 'gramatyki/order.jsgf' 2023-04-20 22:37:23 +02:00
00c4ee5c5f add grammatic 2023-04-20 22:36:48 +02:00
240ba12397 Zaktualizuj 'nlu.py' 2023-04-20 21:25:55 +02:00
b6411ae7d0 Add 'nlu.py' 2023-04-20 21:24:58 +02:00
c11e6ea284 Dodanie 'mockup' 2023-04-20 21:24:36 +02:00
1b2f1f6dc3 Add 'order.jsgf' 2023-04-20 21:24:31 +02:00
16 changed files with 400 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/
__pycache__/

18
SystemActType.py Normal file
View File

@ -0,0 +1,18 @@
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'
)

23
UserActType.py Normal file
View File

@ -0,0 +1,23 @@
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'
)

27
dp.py Normal file
View File

@ -0,0 +1,27 @@
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 Normal file
View File

@ -0,0 +1,51 @@
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 Normal file
View File

@ -0,0 +1,66 @@
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)}%')

8
evaluation.md Normal file
View File

@ -0,0 +1,8 @@
## 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.

8
gramatyki/delivery.jsgf Normal file
View File

@ -0,0 +1,8 @@
#JSGF V1.0 UTF-8 pl;
grammar delivery;
<deliverys> = <droga> ;
public <droga> = (na | <NULL>) (dowoz | miejscu | wynos);

8
gramatyki/hello.jsgf Normal file
View File

@ -0,0 +1,8 @@
#JSGF V1.0 UTF-8 pl;
grammar hello;
<hello> = <greeting> ;
public <greeting> = (dzień dobry | cześć | siema | witam);

13
gramatyki/order.jsgf Normal file
View File

@ -0,0 +1,13 @@
#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);

8
gramatyki/payment.jsgf Normal file
View File

@ -0,0 +1,8 @@
#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);

9
gramatyki/price.jsgf Normal file
View File

@ -0,0 +1,9 @@
#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 Normal file
View File

@ -0,0 +1,38 @@
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 Normal file
View File

@ -0,0 +1,51 @@
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 Normal file
View File

@ -0,0 +1,21 @@
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 Normal file
View File

@ -0,0 +1,49 @@
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'))