Compare commits

..

5 Commits

Author SHA1 Message Date
7e50c44b15 fix formatting 2023-03-24 17:30:40 +01:00
8e16848dcd New conversations 2023-03-24 14:07:45 +01:00
259680b3b7 add more responses 2023-03-24 12:06:32 +01:00
8cb6526c2b add more chatbot responses 2023-03-23 22:49:45 +01:00
Bombo
a51b1b14ad initialize chatbot 2023-03-17 15:50:15 +01:00
17 changed files with 39 additions and 400 deletions

2
.gitignore vendored
View File

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

View File

@ -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'
)

View File

@ -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
View 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
View File

@ -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
View File

@ -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={})

View File

@ -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)}%')

View File

@ -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.

View File

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

View File

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

View File

@ -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);

View File

@ -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);

View File

@ -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
View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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'))