SystemyDialogowe-ProjektMag.../lab/09-zarzadzanie-dialogiem-reguly.ipynb
2022-05-27 18:01:18 +02:00

66 KiB
Raw Permalink Blame History

Logo 1

Systemy Dialogowe

9. Zarządzanie dialogiem z wykorzystaniem reguł [laboratoria]

Marek Kubis (2021)

Logo 2

Zarządzanie dialogiem z wykorzystaniem reguł

Agent dialogowy wykorzystuje do zarządzanie dialogiem dwa moduły:

  • monitor stanu dialogu (dialogue state tracker, DST) — moduł odpowiedzialny za śledzenie stanu dialogu.

  • taktykę prowadzenia dialogu (dialogue policy) — moduł, który na podstawie stanu dialogu podejmuje decyzję o tym jaką akcję (akt systemu) agent ma podjąć w kolejnej turze.

Oba moduły mogą być realizowane zarówno z wykorzystaniem reguł jak i uczenia maszynowego. Mogą one zostać również połączone w pojedynczy moduł zwany wówczas _menedżerem dialogu.

Przykład

Zaimplementujemy regułowe moduły monitora stanu dialogu oraz taktyki dialogowej a następnie osadzimy je w środowisku _ConvLab-2, które służy do ewaluacji systemów dialogowych.

Uwaga: Niektóre moduły środowiska _ConvLab-2 nie są zgodne z najnowszymi wersjami Pythona, dlatego przed uruchomieniem poniższych przykładów należy się upewnić, że mają Państwo interpreter Pythona w wersji 3.7. W przypadku nowszych wersji Ubuntu Pythona 3.7 można zainstalować z repozytorium deadsnakes, wykonując polecenia przedstawione poniżej.

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.7 python3.7-dev python3.7-venv

W przypadku innych systemów można skorzystać np. z narzędzia pyenv lub środowiska conda.

Ze względu na to, że _ConvLab-2 ma wiele zależności zachęcam również do skorzystania ze środowiska wirtualnego venv, w którym moduły zależne mogą zostać zainstalowane. W tym celu należy wykonać następujące polecenia

python3.7 -m venv convenv                     # utworzenie nowego środowiska o nazwie convenv
source convenv/bin/activate                   # aktywacja środowiska w bieżącej powłoce
pip install --ignore-installed jupyter        # instalacja jupytera w środowisku convenv

Po skonfigurowaniu środowiska można przystąpić do instalacji _ConvLab-2, korzystając z następujących poleceń

mkdir -p l08
cd l08
git clone https://github.com/thu-coai/ConvLab-2.git
cd ConvLab-2
pip install -e .
python -m spacy download en_core_web_sm
cd ../..

Po zakończeniu instalacji należy ponownie uruchomić notatnik w powłoce, w której aktywne jest środowisko wirtualne _convenv.

jupyter notebook 08-zarzadzanie-dialogiem-reguly.ipynb

Działanie zaimplementowanych modułów zilustrujemy, korzystając ze zbioru danych MultiWOZ (Budzianowski i in., 2018), który zawiera wypowiedzi dotyczące m.in. rezerwacji pokoi hotelowych, zamawiania biletów kolejowych oraz rezerwacji stolików w restauracji.

Monitor Stanu Dialogu

Do reprezentowania stanu dialogu użyjemy struktury danych wykorzystywanej w _ConvLab-2.

from convlab2.util.multiwoz.state import default_state
default_state()
{'user_action': [],
 'system_action': [],
 'belief_state': {'police': {'book': {'booked': []}, 'semi': {}},
  'hotel': {'book': {'booked': [], 'people': '', 'day': '', 'stay': ''},
   'semi': {'name': '',
    'area': '',
    'parking': '',
    'pricerange': '',
    'stars': '',
    'internet': '',
    'type': ''}},
  'attraction': {'book': {'booked': []},
   'semi': {'type': '', 'name': '', 'area': ''}},
  'restaurant': {'book': {'booked': [], 'people': '', 'day': '', 'time': ''},
   'semi': {'food': '', 'pricerange': '', 'name': '', 'area': ''}},
  'hospital': {'book': {'booked': []}, 'semi': {'department': ''}},
  'taxi': {'book': {'booked': []},
   'semi': {'leaveAt': '',
    'destination': '',
    'departure': '',
    'arriveBy': ''}},
  'train': {'book': {'booked': [], 'people': ''},
   'semi': {'leaveAt': '',
    'destination': '',
    'day': '',
    'arriveBy': '',
    'departure': ''}}},
 'request_state': {},
 'terminated': False,
 'history': []}

Metoda update naszego monitora stanu dialogu będzie przyjmować akty użytkownika i odpowiednio modyfikować stan dialogu. W przypadku aktów typu inform wartości slotów zostaną zapamiętane w słownikach odpowiadających poszczególnym dziedzinom pod kluczem belief_state. W przypadku aktów typu request sloty, o które pyta użytkownik zostaną zapisane pod kluczem request_state.

import json
import os
from convlab2.dst.dst import DST
from convlab2.dst.rule.multiwoz.dst_util import normalize_value
from convlab2.util.multiwoz.multiwoz_slot_trans import REF_SYS_DA


class SimpleRuleDST(DST):
    def __init__(self):
        DST.__init__(self)
        self.state = default_state()
        self.value_dict = json.load(open('ConvLab-2/data/multiwoz/value_dict.json'))

    def update(self, user_act=None):
        for intent, domain, slot, value in user_act:
            domain = domain.lower()
            intent = intent.lower()

            if domain in ['unk', 'general', 'booking']:
                continue

            if intent == 'inform':
                k = REF_SYS_DA[domain.capitalize()].get(slot, slot)

                if k is None:
                    continue

                domain_dic = self.state['belief_state'][domain]

                if k in domain_dic['semi']:
                    nvalue = normalize_value(self.value_dict, domain, k, value)
                    self.state['belief_state'][domain]['semi'][k] = nvalue
                elif k in domain_dic['book']:
                    self.state['belief_state'][domain]['book'][k] = value
                elif k.lower() in domain_dic['book']:
                    self.state['belief_state'][domain]['book'][k.lower()] = value
            elif intent == 'request':
                k = REF_SYS_DA[domain.capitalize()].get(slot, slot)

                if domain not in self.state['request_state']:
                    self.state['request_state'][domain] = {}
                if k not in self.state['request_state'][domain]:
                    self.state['request_state'][domain][k] = 0

        return self.state

    def init_session(self):
        self.state = default_state()

W definicji metody update zakładamy, że akty dialogowe przekazywane do monitora stanu dialogu z modułu NLU są czteroelementowymi listami złożonymi z:

  • nazwy aktu użytkownika,
  • nazwy dziedziny, której dotyczy wypowiedź,
  • nazwy slotu,
  • wartości slotu.

Zobaczmy na kilku prostych przykładach jak stan dialogu zmienia się pod wpływem przekazanych aktów użytkownika.

dst = SimpleRuleDST()
dst.state
{'user_action': [],
 'system_action': [],
 'belief_state': {'police': {'book': {'booked': []}, 'semi': {}},
  'hotel': {'book': {'booked': [], 'people': '', 'day': '', 'stay': ''},
   'semi': {'name': '',
    'area': '',
    'parking': '',
    'pricerange': '',
    'stars': '',
    'internet': '',
    'type': ''}},
  'attraction': {'book': {'booked': []},
   'semi': {'type': '', 'name': '', 'area': ''}},
  'restaurant': {'book': {'booked': [], 'people': '', 'day': '', 'time': ''},
   'semi': {'food': '', 'pricerange': '', 'name': '', 'area': ''}},
  'hospital': {'book': {'booked': []}, 'semi': {'department': ''}},
  'taxi': {'book': {'booked': []},
   'semi': {'leaveAt': '',
    'destination': '',
    'departure': '',
    'arriveBy': ''}},
  'train': {'book': {'booked': [], 'people': ''},
   'semi': {'leaveAt': '',
    'destination': '',
    'day': '',
    'arriveBy': '',
    'departure': ''}}},
 'request_state': {},
 'terminated': False,
 'history': []}
dst.update([['Inform', 'Hotel', 'Price', 'cheap'], ['Inform', 'Hotel', 'Parking', 'yes']])
dst.state['belief_state']['hotel']
{'book': {'booked': [], 'people': '', 'day': '', 'stay': ''},
 'semi': {'name': '',
  'area': '',
  'parking': 'yes',
  'pricerange': 'cheap',
  'stars': '',
  'internet': '',
  'type': ''}}
dst.update([['Inform', 'Hotel', 'Area', 'north']])
dst.state['belief_state']['hotel']
{'book': {'booked': [], 'people': '', 'day': '', 'stay': ''},
 'semi': {'name': '',
  'area': 'north',
  'parking': 'yes',
  'pricerange': 'cheap',
  'stars': '',
  'internet': '',
  'type': ''}}
dst.update([['Request', 'Hotel', 'Area', '?']])
dst.state['request_state']
{'hotel': {'area': 0}}
dst.update([['Inform', 'Hotel', 'Day', 'tuesday'], ['Inform', 'Hotel', 'People', '2'], ['Inform', 'Hotel', 'Stay', '4']])
dst.state['belief_state']['hotel']
{'book': {'booked': [], 'people': '2', 'day': 'tuesday', 'stay': '4'},
 'semi': {'name': '',
  'area': 'north',
  'parking': 'yes',
  'pricerange': 'cheap',
  'stars': '',
  'internet': '',
  'type': ''}}
dst.state
{'user_action': [],
 'system_action': [],
 'belief_state': {'police': {'book': {'booked': []}, 'semi': {}},
  'hotel': {'book': {'booked': [],
    'people': '2',
    'day': 'tuesday',
    'stay': '4'},
   'semi': {'name': '',
    'area': 'north',
    'parking': 'yes',
    'pricerange': 'cheap',
    'stars': '',
    'internet': '',
    'type': ''}},
  'attraction': {'book': {'booked': []},
   'semi': {'type': '', 'name': '', 'area': ''}},
  'restaurant': {'book': {'booked': [], 'people': '', 'day': '', 'time': ''},
   'semi': {'food': '', 'pricerange': '', 'name': '', 'area': ''}},
  'hospital': {'book': {'booked': []}, 'semi': {'department': ''}},
  'taxi': {'book': {'booked': []},
   'semi': {'leaveAt': '',
    'destination': '',
    'departure': '',
    'arriveBy': ''}},
  'train': {'book': {'booked': [], 'people': ''},
   'semi': {'leaveAt': '',
    'destination': '',
    'day': '',
    'arriveBy': '',
    'departure': ''}}},
 'request_state': {'hotel': {'area': 0}},
 'terminated': False,
 'history': []}

Taktyka Prowadzenia Dialogu

Prosta taktyka prowadzenia dialogu dla systemu rezerwacji pokoi hotelowych może składać się z następujących reguł:

  1. Jeżeli użytkownik przekazał w ostatniej turze akt typu Request, to udziel odpowiedzi na jego pytanie.

  2. Jeżeli użytkownik przekazał w ostatniej turze akt typu Inform, to zaproponuj mu hotel spełniający zdefiniowane przez niego kryteria.

  3. Jeżeli użytkownik przekazał w ostatniej turze akt typu Inform zawierający szczegóły rezerwacji, to zarezerwuj pokój.

Metoda predict taktyki SimpleRulePolicy realizuje reguły przedstawione powyżej.

from collections import defaultdict
import copy
import json
from copy import deepcopy

from convlab2.policy.policy import Policy
from convlab2.util.multiwoz.dbquery import Database
from convlab2.util.multiwoz.multiwoz_slot_trans import REF_SYS_DA, REF_USR_DA


class SimpleRulePolicy(Policy):
    def __init__(self):
        Policy.__init__(self)
        self.db = Database()

    def predict(self, state):
        self.results = []
        system_action = defaultdict(list)
        user_action = defaultdict(list)

        for intent, domain, slot, value in state['user_action']:
            user_action[(domain, intent)].append((slot, value))

        for user_act in user_action:
            self.update_system_action(user_act, user_action, state, system_action)

        # Reguła 3
        if any(True for slots in user_action.values() for (slot, _) in slots if slot in ['Stay', 'Day', 'People']):
            if self.results:
                system_action = {('Booking', 'Book'): [["Ref", self.results[0].get('Ref', 'N/A')]]}

        system_acts = [[intent, domain, slot, value] for (domain, intent), slots in system_action.items() for slot, value in slots]
        state['system_action'] = system_acts
        return system_acts

    def update_system_action(self, user_act, user_action, state, system_action):
        domain, intent = user_act
        constraints = [(slot, value) for slot, value in state['belief_state'][domain.lower()]['semi'].items() if value != '']
        self.results = deepcopy(self.db.query(domain.lower(), constraints))

        # Reguła 1
        if intent == 'Request':
            if len(self.results) == 0:
                system_action[(domain, 'NoOffer')] = []
            else:
                for slot in user_action[user_act]:
                    kb_slot_name = REF_SYS_DA[domain].get(slot[0], slot[0])

                    if kb_slot_name in self.results[0]:
                        system_action[(domain, 'Inform')].append([slot[0], self.results[0].get(kb_slot_name, 'unknown')])

        # Reguła 2
        elif intent == 'Inform':
            if len(self.results) == 0:
                system_action[(domain, 'NoOffer')] = []
            else:
                system_action[(domain, 'Inform')].append(['Choice', str(len(self.results))])
                choice = self.results[0]

                if domain in ["Hotel", "Attraction", "Police", "Restaurant"]:
                    system_action[(domain, 'Recommend')].append(['Name', choice['name']])

Podobnie jak w przypadku aktów użytkownika akty systemowe przekazywane do modułu NLG są czteroelementowymi listami złożonymi z:

  • nazwy aktu systemowe,
  • nazwy dziedziny, której dotyczy wypowiedź,
  • nazwy slotu,
  • wartości slotu.

Sprawdźmy jakie akty systemowe zwraca taktyka SimpleRulePolicy w odpowiedzi na zmieniający się stan dialogu.

from convlab2.dialog_agent import PipelineAgent
dst.init_session()
policy = SimpleRulePolicy()
agent = PipelineAgent(nlu=None, dst=dst, policy=policy, nlg=None, name='sys')
agent.response([['Inform', 'Hotel', 'Price', 'cheap'], ['Inform', 'Hotel', 'Parking', 'yes']])
[['Inform', 'Hotel', 'Choice', '10'],
 ['Recommend', 'Hotel', 'Name', 'alexander bed and breakfast']]
agent.response([['Inform', 'Hotel', 'Area', 'north']])
[['Inform', 'Hotel', 'Choice', '2'],
 ['Recommend', 'Hotel', 'Name', 'city centre north b and b']]
agent.response([['Request', 'Hotel', 'Area', '?']])
[['Inform', 'Hotel', 'Area', 'north']]
agent.response([['Inform', 'Hotel', 'Day', 'tuesday'], ['Inform', 'Hotel', 'People', '2'], ['Inform', 'Hotel', 'Stay', '4']])
[['Book', 'Booking', 'Ref', '00000013']]

Testy End-to-End

Na koniec przeprowadźmy dialog łącząc w potok nasze moduły z modułami NLU i NLG dostępnymi dla MultiWOZ w środowisku ConvLab-2.

from convlab2.nlu.svm.multiwoz import SVMNLU
from convlab2.nlg.template.multiwoz import TemplateNLG

nlu = SVMNLU()
nlg = TemplateNLG(is_user=False)
agent = PipelineAgent(nlu=nlu, dst=dst, policy=policy, nlg=nlg, name='sys')
[<convlab2.nlu.svm.Features.nbest object at 0x0000028BDD2032C8>]
loading saved Classifier
loaded.
agent.response("I need a cheap hotel with free parking .")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_13500\3260802613.py in <module>
----> 1 agent.response("I need a cheap hotel with free parking .")

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\dialog_agent\agent.py in response(self, observation)
    120         # get dialog act
    121         if self.nlu is not None:
--> 122             self.input_action = self.nlu.predict(observation, context=[x[1] for x in self.history[:-1]])
    123         else:
    124             self.input_action = observation

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\multiwoz\nlu.py in predict(self, utterance, context)
     74                 ]
     75             }
---> 76         slu_hyps = self.c.decode_sent(sentinfo, self.config.get("decode", "output"))
     77         act_list = []
     78         for hyp in slu_hyps:

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode_sent(self, sentinfo, output_fname, config)
    320 
    321         self.extractFeatures2(sentinfo,log_input_key=log_input_key)
--> 322         decode_results = self.decode()
    323         counter = defaultdict(int)
    324 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode(self)
    258             baseXs = [self.baseXs[index] for index in self.baseX_pointers[this_tuple]]
    259             X = toSparse(baseXs, self.X[this_tuple], self.dictionary)
--> 260             results[this_tuple] = self.classifiers[this_tuple].predict(X)
    261         return results
    262 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in predict(self, X)
    496 
    497     def predict(self, X):
--> 498         y = self.model.predict_proba(X)
    499         return y[:,1]
    500 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in predict_proba(self)
    588         datasets.
    589         """
--> 590         self._check_proba()
    591         return self._predict_proba
    592 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in _check_proba(self)
    557             raise AttributeError("predict_proba is not available when "
    558                                  " probability=False")
--> 559         if self._impl not in ('c_svc', 'nu_svc'):
    560             raise AttributeError("predict_proba only implemented for SVC"
    561                                  " and NuSVC")

AttributeError: 'SVC' object has no attribute '_impl'
agent.response("Where it is located ?")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_13500\2723043776.py in <module>
----> 1 agent.response("Where it is located ?")

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\dialog_agent\agent.py in response(self, observation)
    120         # get dialog act
    121         if self.nlu is not None:
--> 122             self.input_action = self.nlu.predict(observation, context=[x[1] for x in self.history[:-1]])
    123         else:
    124             self.input_action = observation

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\multiwoz\nlu.py in predict(self, utterance, context)
     74                 ]
     75             }
---> 76         slu_hyps = self.c.decode_sent(sentinfo, self.config.get("decode", "output"))
     77         act_list = []
     78         for hyp in slu_hyps:

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode_sent(self, sentinfo, output_fname, config)
    320 
    321         self.extractFeatures2(sentinfo,log_input_key=log_input_key)
--> 322         decode_results = self.decode()
    323         counter = defaultdict(int)
    324 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode(self)
    258             baseXs = [self.baseXs[index] for index in self.baseX_pointers[this_tuple]]
    259             X = toSparse(baseXs, self.X[this_tuple], self.dictionary)
--> 260             results[this_tuple] = self.classifiers[this_tuple].predict(X)
    261         return results
    262 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in predict(self, X)
    496 
    497     def predict(self, X):
--> 498         y = self.model.predict_proba(X)
    499         return y[:,1]
    500 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in predict_proba(self)
    588         datasets.
    589         """
--> 590         self._check_proba()
    591         return self._predict_proba
    592 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in _check_proba(self)
    557             raise AttributeError("predict_proba is not available when "
    558                                  " probability=False")
--> 559         if self._impl not in ('c_svc', 'nu_svc'):
    560             raise AttributeError("predict_proba only implemented for SVC"
    561                                  " and NuSVC")

AttributeError: 'SVC' object has no attribute '_impl'
agent.response("I would prefer the hotel be in the north part of town .")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_13500\871593950.py in <module>
----> 1 agent.response("I would prefer the hotel be in the north part of town .")

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\dialog_agent\agent.py in response(self, observation)
    120         # get dialog act
    121         if self.nlu is not None:
--> 122             self.input_action = self.nlu.predict(observation, context=[x[1] for x in self.history[:-1]])
    123         else:
    124             self.input_action = observation

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\multiwoz\nlu.py in predict(self, utterance, context)
     74                 ]
     75             }
---> 76         slu_hyps = self.c.decode_sent(sentinfo, self.config.get("decode", "output"))
     77         act_list = []
     78         for hyp in slu_hyps:

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode_sent(self, sentinfo, output_fname, config)
    320 
    321         self.extractFeatures2(sentinfo,log_input_key=log_input_key)
--> 322         decode_results = self.decode()
    323         counter = defaultdict(int)
    324 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in decode(self)
    258             baseXs = [self.baseXs[index] for index in self.baseX_pointers[this_tuple]]
    259             X = toSparse(baseXs, self.X[this_tuple], self.dictionary)
--> 260             results[this_tuple] = self.classifiers[this_tuple].predict(X)
    261         return results
    262 

c:\develop\wmi\aitech\sem1\systemy dialogowe\lab\convlab-2\convlab2\nlu\svm\Classifier.py in predict(self, X)
    496 
    497     def predict(self, X):
--> 498         y = self.model.predict_proba(X)
    499         return y[:,1]
    500 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in predict_proba(self)
    588         datasets.
    589         """
--> 590         self._check_proba()
    591         return self._predict_proba
    592 

c:\Develop\wmi\AITECH\sem1\Systemy dialogowe\lab\venv\lib\site-packages\sklearn\svm\base.py in _check_proba(self)
    557             raise AttributeError("predict_proba is not available when "
    558                                  " probability=False")
--> 559         if self._impl not in ('c_svc', 'nu_svc'):
    560             raise AttributeError("predict_proba only implemented for SVC"
    561                                  " and NuSVC")

AttributeError: 'SVC' object has no attribute '_impl'
agent.response("Yeah , could you book me a room for 2 people for 4 nights starting Tuesday ?")

Zauważmy, ze nasza prosta taktyka dialogowa zawiera wiele luk, do których należą m.in.:

  1. Niezdolność do udzielenia odpowiedzi na przywitanie, prośbę o pomoc lub restart.

  2. Brak reguł dopytujących użytkownika o szczegóły niezbędne do dokonania rezerwacji takie, jak długość pobytu czy liczba osób.

Bardziej zaawansowane moduły zarządzania dialogiem zbudowane z wykorzystaniem reguł można znaleźć w środowisku ConvLab-2. Należą do nich m.in. monitor RuleDST oraz taktyka RuleBasedMultiwozBot.

Zadania

  1. Zaimplementować w projekcie monitor stanu dialogu.

  2. Zaimplementować w projekcie taktykę prowadzenia dialogu.

Termin: 24.05.2021, godz. 23:59.

Literatura

  1. Pawel Budzianowski, Tsung-Hsien Wen, Bo-Hsiang Tseng, Iñigo Casanueva, Stefan Ultes, Osman Ramadan, Milica Gasic, MultiWOZ - A Large-Scale Multi-Domain Wizard-of-Oz Dataset for Task-Oriented Dialogue Modelling. EMNLP 2018, pp. 5016-5026
  2. Cathy Pearl, Basic principles for designing voice user interfaces, https://www.oreilly.com/content/basic-principles-for-designing-voice-user-interfaces/ data dostępu: 21 marca 2021
  3. Cathy Pearl, Designing Voice User Interfaces, Excerpts from Chapter 5: Advanced Voice User Interface Design, https://www.uxmatters.com/mt/archives/2018/01/designing-voice-user-interfaces.php data dostępu: 21 marca 2021