diff --git a/attributes.json b/attributes.json index 579faab..a4e6fe2 100644 --- a/attributes.json +++ b/attributes.json @@ -1,39 +1,40 @@ { + "size": ["M", "L", "XL"], "dough": [ "thick" ], "drink": { + "woda": { + "price": 5 + }, "pepsi": { - "price": 10 + "price": 7 }, "cola": { - "price": 10 - }, - "water": { - "price": 5 + "price": 8 } }, "food": [ "pizza" ], "meat": [ - "chicken", - "ham", + "kurczak", + "szynka", "tuna" ], "sauce": [ "garlic", "1000w" ], - "ingredient": { - "chicken": {}, + "ingredients": { + "kurczak": {}, "tuna": {}, - "pineapple": {}, - "onion": {}, - "cheese": {}, - "tomato": {}, - "ham": {}, - "pepper": {} + "ananas": {}, + "cebula": {}, + "ser": {}, + "pomidor": {}, + "szynka": {}, + "papryka": {} }, "menu": [ "capri", diff --git a/src/main.py b/src/main.py index 1a7aaad..db7b5ea 100644 --- a/src/main.py +++ b/src/main.py @@ -1,50 +1,56 @@ -from service.dialog_state_monitor import DialogStateMonitor -from service.dialog_policy import DialogPolicy -from service.natural_languag_understanding import NaturalLanguageUnderstanding -from service.natural_language_generation import NaturalLanguageGeneration, parse_frame -from service.templates import templates - -# initialize classes -nlu = NaturalLanguageUnderstanding(use_mocks=False) # NLU -monitor = DialogStateMonitor() # DSM -dialog_policy = DialogPolicy() # DP -language_generation = NaturalLanguageGeneration(templates) # NLG - -def frame_to_dict(frame): - return { - "act": frame.act, - "slots": [{"name": slot.name, "value": slot.value} for slot in frame.slots] - } - - -# Main loop -dial_num = 0 -print("CTRL+C aby zakończyć program.") -while True: - monitor.reset() - -# print(f"\n==== Rozpoczynasz rozmowę nr {dial_num} ====\n") - user_input = input("Witamy w naszej pizzerii. W czym mogę pomóc?\n") - - while True: - # NLU - frame = nlu.predict(user_input) - print("Frame: ", frame) - - # DSM - monitor.update(frame) - - # DP - system_action = dialog_policy.predict(monitor) - system_action = frame_to_dict(system_action) # Ensure system_action is a dictionary - print("System action: ", system_action) - - # NLG - response = language_generation.generate(frame, system_action) - print(response) - - if frame.act == "bye": - break - - user_input = input(">\n") -# dial_num += 1 \ No newline at end of file +from service.dialog_state_monitor import DialogStateMonitor +from service.dialog_policy import DialogPolicy +from service.natural_languag_understanding import NaturalLanguageUnderstanding +from service.natural_language_generation import NaturalLanguageGeneration, parse_frame +from service.templates import templates + +# initialize classes +nlu = NaturalLanguageUnderstanding(use_mocks=False) # NLU +monitor = DialogStateMonitor() # DSM +dialog_policy = DialogPolicy() # DP +language_generation = NaturalLanguageGeneration(templates) # NLG + +def frame_to_dict(frame): + return { + "act": frame.act, + "slots": [{"name": slot.name, "value": slot.value} for slot in frame.slots], + "act_understood": frame.act_understood, + } + + +# Main loop +dial_num = 0 +print("CTRL+C aby zakończyć program.") +while True: + monitor.reset() + + print(f"\n==== Rozpoczynasz rozmowę nr {dial_num} ====\n") + user_input = input("Witamy w naszej pizza-przez-internet. W czym mogę pomóc?\n") + + while True: + # NLU + frame = nlu.predict(user_input) + print("Frame: ", frame) + + # DSM + monitor.update(frame) + + # DP + system_action = dialog_policy.predict(monitor) + system_action_dict = frame_to_dict(system_action) # Ensure system_action is a dictionary + print("System action: ", system_action_dict) + + # NLG + response = language_generation.generate(frame, system_action_dict) + print(response) + + if system_action.act == "bye_and_thanks" or system_action.act == "bye": + print(monitor.print_order()) + break + + if frame.act == "bye": + print(monitor.print_order()) + break + + user_input = input(">\n") + dial_num += 1 \ No newline at end of file diff --git a/src/model/frame.py b/src/model/frame.py index caf874f..5d5861d 100644 --- a/src/model/frame.py +++ b/src/model/frame.py @@ -1,10 +1,11 @@ from .slot import Slot class Frame: - def __init__(self, source: str, act: str, slots: list[Slot] = []): + def __init__(self, source: str, act: str, slots: list[Slot] = [], act_understood = None): self.source = source self.slots = slots self.act = act + self.act_understood = act_understood def __str__(self): msg = f"Act: {self.act}, Slots: [" diff --git a/src/service/dialog_policy.py b/src/service/dialog_policy.py index a1d5d4f..133998a 100644 --- a/src/service/dialog_policy.py +++ b/src/service/dialog_policy.py @@ -3,26 +3,37 @@ from model.frame import Frame from model.slot import Slot class DialogPolicy: - - def predict(self, dsm): + def _predict(self, dsm): last_frame = dsm.state['history'][-1] + act_processed = dsm.state['was_system_act_processed'] if(dsm.state['was_previous_order_invalid'] == False): - if("inform" in last_frame.act): + if last_frame.act == "inform/order-complete": + act = last_frame.act + elif ("inform" in last_frame.act): act = last_frame.act.split('/')[0] else: act = last_frame.act match(act): + case "bye": + return Frame(source="system", act = "bye") + case "inform/order-complete": + return Frame(source="system", act = "bye_and_thanks") case "inform" | "affirm" | "negate": - current_active_status = dsm.get_current_active_stage() - match(current_active_status): + current_active_stage = dsm.get_current_active_stage() + if current_active_stage == None: + return Frame(source="system", act = "bye_and_thanks") + match(current_active_stage['name']): case "collect_food": - return Frame(source="system", act = "request/food") + # current_active_stage['confirmed'] = True + return Frame(source="system", act = "request/food", slots = [Slot("menu", dsm.state['constants']['menu'])], act_understood=act_processed) case "collect_drinks": - return Frame(source="system", act = "request/drinks") + return Frame(source="system", act = "request/drinks", slots = [Slot("drink", dsm.state['constants']['drink'])], act_understood=act_processed) case "collect_address": - return Frame(source="system", act = "request/address") - if(current_active_status == None): - return Frame(source="system", act = "end") + return Frame(source="system", act = "request/address", act_understood=act_processed) + case "collect_payment_method": + return Frame(source="system", act = "request/payment-method", act_understood=act_processed) + case "collect_phone": + return Frame(source="system", act = "request/phone", act_understood=act_processed) case "request/menu": return Frame(source="system", act = "inform", slots = [Slot("menu", dsm.state['constants']['menu'])]) case "request/price": @@ -41,7 +52,12 @@ class DialogPolicy: return Frame(source="system", act = "inform", slots = [Slot("drink", dsm.state['constants']['drink'])]) case "welcomemsg": return Frame(source="system", act = "inform", slots = [Slot("menu", dsm.state['constants']['menu'])]) - case "bye": - return Frame(source="system", act = "bye") + case "repeat": + return Frame(source="system", act = "repeat") - return Frame(source="system", act = "repeat") \ No newline at end of file + return Frame(source="system", act = "repeat") + + def predict(self, dsm): + frame = self._predict(dsm) + dsm.state["system_history"].append(frame) + return frame diff --git a/src/service/dialog_state_monitor.py b/src/service/dialog_state_monitor.py index 4d8e91c..a4601e7 100644 --- a/src/service/dialog_state_monitor.py +++ b/src/service/dialog_state_monitor.py @@ -1,11 +1,19 @@ -from src.model.frame import Frame +from model.frame import Frame import copy import json def normalize(value): value = value.lower() - # TODO: pomyslec nad odmianą slów + if value[-1] in [",", "!", "?" ,"." ,")" ,"(",")"]: + value = value[:-1] + if value[-2:] == "ie": + value = value[:-2] + "a" + if value[-1] in ["ę", "ą", "y"]: + value = value[:-1] + "a" + if value in ["pizz", "pizzy", "pizze", "picce"]: + value = "pizza" + return ' '.join(value.split()) @@ -13,37 +21,71 @@ class DialogStateMonitor: def __init__(self, initial_state_file: str = 'attributes.json'): with open(initial_state_file) as file: constants = json.load(file) - self.__initial_state = dict(belief_state={ - 'order': [], - 'address': {}, - 'order-complete': False, - 'phone': {}, - 'delivery': {}, - 'payment': {}, - 'time': {}, - 'name': {}, - }, + self.__initial_state = dict( + belief_state={ + 'order': [], + 'address': {}, + 'order-complete': False, + 'phone': {}, + 'delivery': {}, + 'payment': {}, + 'time': {}, + 'name': {}, + }, total_cost=0, stages=[ - {'completed': False, 'name': 'collect_food'}, - {'completed': False, 'name': 'collect_drinks'}, - {'completed': False, 'name': 'collect_address'}, + {'completed': False, 'name': 'collect_food', "confirmed": False}, + {'completed': False, 'name': 'collect_drinks', "confirmed": False}, + {'completed': False, 'name': 'collect_address', "confirmed": False}, + {'completed': False, 'name': 'collect_phone', "confirmed": False}, ], was_previous_order_invalid=False, + was_system_act_processed=False, constants=constants, - history=[]) + history=[], + system_history=[] + ) self.state = copy.deepcopy(self.__initial_state) def get_current_active_stage(self) -> str | None: for stage in self.state['stages']: if stage['completed'] is False: - return stage['name'] + print("Current stage: ", stage['name']) + return stage + self.state['belief_state']['order-complete'] = True def mark_current_stage_completed(self) -> None: for stage in self.state['stages']: - if stage['completed'] is False: + if stage['completed'] is False: # and stage['confirmed']: + print("Stage completed: ", stage['name']) stage['completed'] = True return + + def complete_stage_if_valid(self, stage_name): + for stage in self.state['stages']: + if stage['name'] != stage_name: + continue + + if stage['name'] == "collect_food": + for order in self.state['belief_state']['order']: + if order.get("pizza"): + stage['completed'] = True + return + elif stage["name"] == "collect_drinks": + for order in self.state['belief_state']['order']: + if order.get("drink"): + stage['completed'] = True + return + elif stage["name"] == "collect_address": + if not len(self.state['belief_state']['address']): + return + stage['completed'] = True + return + elif stage["name"] == "collect_phone": + if self.state['belief_state']["phone"].get("phone"): + stage['completed'] = True + return + pass def item_exists(self, type: str, name: str) -> bool: return normalize(name) in self.state['constants'][type] @@ -53,8 +95,30 @@ class DialogStateMonitor: def get_total_cost(self) -> int: return self.state['total_cost'] + + def slot_augmentation(self, slot, value): + drink_normalize = ["woda", "pepsi", "cola", "coca cola", "cole", "coca"] + if slot.name in ["food", "pizza", "ingredient"]: + if value in drink_normalize: + slot.name = 'drink' + return slot + + def slot_valid(self, slot, act): + if act == "inform/order": + if slot.name in ["address", "payment-method", 'delivery', 'phone', 'time', 'name']: + return False + + return True + + def value_valid(self, slot_name, value): + if slot_name == "food": + if value != "pizza": + return False + return True def update(self, frame: Frame) -> None: + self.state['was_system_act_processed'] = False + belief_state_copy = copy.deepcopy(self.state["belief_state"]) self.state['history'].append(frame) if frame.source != 'user': return @@ -62,27 +126,40 @@ class DialogStateMonitor: new_order = dict() for slot in frame.slots: value = normalize(slot.value) - if (slot.name == 'pizza' and self.get_current_active_stage() == 'collect_food') or (slot.name == 'drink' and self.get_current_active_stage() == 'collect_drinks'): + slot = self.slot_augmentation(slot, value) + if not self.slot_valid(slot, frame.act): + continue + if not self.value_valid(slot.name, value): + continue + + stage_name = self.get_current_active_stage()['name'] + is_collect_food = (slot.name == 'pizza' and stage_name == 'collect_food') + is_collect_drinks = (slot.name == 'drink' and stage_name == 'collect_drinks') + if is_collect_food or is_collect_drinks: if self.item_exists(slot.name, value) is False: self.state['was_previous_order_invalid'] = True return self.state['was_previous_order_invalid'] = False self.state['total_cost'] += self.state['constants'][slot.name][value]['price'] - self.mark_current_stage_completed() new_order[slot.name] = value - self.state['belief_state']['order'].append(new_order) - elif frame.act == 'inform/address' and self.get_current_active_stage() == 'collect_address': + if len(new_order) > 0: + self.state['belief_state']['order'].append(new_order) + self.complete_stage_if_valid('collect_food') + self.complete_stage_if_valid('collect_drinks') + elif frame.act == 'inform/address': for slot in frame.slots: self.state['belief_state']['address'][slot.name] = normalize(slot.value) - self.mark_current_stage_completed() + self.complete_stage_if_valid('collect_address') elif frame.act == 'inform/phone': for slot in frame.slots: self.state['belief_state']['phone'][slot.name] = normalize(slot.value) + self.complete_stage_if_valid('collect_phone') elif frame.act == 'inform/order-complete': self.state['belief_state']['order-complete'] = True elif frame.act == 'inform/delivery': for slot in frame.slots: self.state['belief_state']['delivery'][slot.name] = normalize(slot.value) + self.complete_stage_if_valid('collect_address') elif frame.act == 'inform/payment': for slot in frame.slots: self.state['belief_state']['payment'][slot.name] = normalize(slot.value) @@ -92,6 +169,16 @@ class DialogStateMonitor: elif frame.act == 'inform/name': for slot in frame.slots: self.state['belief_state']['name'][slot.name] = normalize(slot.value) + elif frame.act == 'negate': + if "request" in self.state["system_history"][-1].act: + self.mark_current_stage_completed() + self.state['was_system_act_processed'] = True + + if self.state["belief_state"] != belief_state_copy and frame.act not in ["repeat", 'affirm', 'negate']: + self.state['was_system_act_processed'] = True def reset(self) -> None: self.state = copy.deepcopy(self.__initial_state) + + def print_order(self) -> dict: + return json.dumps(self.state['belief_state']) \ No newline at end of file diff --git a/src/service/natural_languag_understanding.py b/src/service/natural_languag_understanding.py index facb98f..908a54a 100644 --- a/src/service/natural_languag_understanding.py +++ b/src/service/natural_languag_understanding.py @@ -91,10 +91,13 @@ class NaturalLanguageUnderstanding(): def predict(self, text: str): if not self.use_mocks: - act = self.__predict_intention(text) - slots = self.__predict_slot(text) - frame = Frame(source = 'user', act = act, slots = slots) - return frame + try: + act = self.__predict_intention(text) + slots = self.__predict_slot(text) + frame = Frame(source = 'user', act = act, slots = slots) + return frame + except: + return Frame(source="user", act = "repeat", slots=[]) else: frames = [ Frame(source="user", act = "inform/order", slots=[Slot(name="pizza", value="barcelona")]), diff --git a/src/service/natural_language_generation.py b/src/service/natural_language_generation.py index 42935bf..e2bc5da 100644 --- a/src/service/natural_language_generation.py +++ b/src/service/natural_language_generation.py @@ -27,6 +27,10 @@ class NaturalLanguageGeneration: slot_dict[slot['name']] = slot['value'] response = template.format(**slot_dict) + if system_action['act_understood'] == True: + response = f"Zrozumiałem. {response}" + elif system_action['act_understood'] == False: + response = f"Nie zrozumiałem. {response}" return response def parse_frame(frame): @@ -37,14 +41,3 @@ def parse_frame(frame): slots = [{"name": slot.name, "value": slot.value} for slot in frame.slots] return act, slots - - -class Slot: - def __init__(self, name, value): - self.name = name - self.value = value - -class Frame: - def __init__(self, act, slots): - self.act = act - self.slots = slots \ No newline at end of file diff --git a/src/service/template_selector.py b/src/service/template_selector.py index 4cf5a70..cc6c6ff 100644 --- a/src/service/template_selector.py +++ b/src/service/template_selector.py @@ -1,203 +1,208 @@ -import random -from service.templates import templates - -def generate_pizza_info(slots): - pizza_name = None - query_type = None - - for slot in slots: - if slot['name'] == 'pizza': - pizza_name = slot['value'].lower() - elif slot['name'] == 'ingredient': - query_type = 'ingredient' - elif slot['name'] == 'price': - query_type = 'price' - - if pizza_name not in pizza_data: - return f"Nie mamy w ofercie pizzy o nazwie {pizza_name}." - - if query_type == 'ingredient': - ingredients = pizza_data[pizza_name]['ingredient'] - return f"Składniki pizzy {pizza_name} to: {', '.join(ingredients)}." - elif query_type == 'price': - price = pizza_data[pizza_name]['price'] - return f"Cena pizzy {pizza_name} to {price} zł." - - return f"Informacje o pizzy {pizza_name}: składniki to {', '.join(pizza_data[pizza_name]['ingredient'])}, cena to {pizza_data[pizza_name]['price']} zł." - - -def generate_ingredients_response(slots): - ingredients = [slot['value'] for slot in slots if slot['name'] == 'ingredients'] - if ingredients: - ingredient_list = [] - for ingredient in ingredients: - ingredient_list.extend(ingredient.keys()) - response = f"Składniki to: {', '.join(ingredient_list)}." - return response - return "Nie podano składników." - - -def generate_drinks_response(slots): - drinks = [slot['value'] for slot in slots if slot['name'] == 'drink'] - if drinks: - drink_details = [] - for drink in drinks: - for name, details in drink.items(): - price = details.get('price', 'unknown') - drink_details.append(f"{name} w cenie {price} zł") - if len(drink_details) > 1: - response = f"Dostępne napoje to: {', '.join(drink_details[:-1])} oraz {drink_details[-1]}." - else: - response = f"Dostępne napoje to: {drink_details[0]}." - return response - return "Nie podano napojów." - -def generate_size_response(slots): - sizes = [slot['value'] for slot in slots if slot['name'] == 'size'] - if sizes: - size_details = [] - for size in sizes: - for name, details in size.items(): - rozmiar = details.get('rozmiar', 'unknown') - size_details.append(f"{name} o średnicy {rozmiar} cm") - if len(size_details) > 1: - response = f"Dostępne rozmiary to: {', '.join(size_details[:-1])} oraz {size_details[-1]}." - else: - response = f"Dostępne rozmiary to: {size_details[0]}." - return response - return "Nie podano rozmiarów." - -def generate_sauce_response(slots): - sauces = [slot['value'] for slot in slots if slot['name'] == 'sauce'] - if sauces: - sauce_list = [] - for sauce in sauces: - if isinstance(sauce, list): - sauce_list.extend(sauce) - else: - sauce_list.append(sauce) - return f"Dostępne sosy to: {', '.join(sauce_list)}." - return "Nie podano sosów." - - -def select_template(act, slots): - slot_names = {slot['name'] for slot in slots} - - if act == "welcomemsg": - return random.choice(templates["welcomemsg"]) - - if "ingredients" in slot_names: - return generate_ingredients_response(slots) - elif "drink" in slot_names: - return generate_drinks_response(slots) - elif "sauce" in slot_names: - return generate_sauce_response(slots) - elif "size" in slot_names: - return generate_size_response(slots) - elif "price" in slot_names: - return random.choice(templates["inform/price"]) - - if act == "inform": - if "menu" in slot_names: - return random.choice(templates["inform/menu"]) - elif "address" in slot_names: - return random.choice(templates["inform/address"]) - elif "phone" in slot_names: - return random.choice(templates["inform/phone"]) - elif "order-complete" in slot_names: - return random.choice(templates["inform/order-complete"]) - elif "delivery" in slot_names: - return random.choice(templates["inform/delivery"]) - elif "payment" in slot_names: - return random.choice(templates["inform/payment"]) - elif "time" in slot_names: - return random.choice(templates["inform/time"]) - elif "name" in slot_names: - return random.choice(templates["inform/name"]) - elif "price" in slot_names and "pizza" in slot_names: - return generate_pizza_info(slots) - elif act == "inform/order": - if "quantity" in slot_names and "pizza" in slot_names and "size" in slot_names: - return templates["inform/order"][1] - elif "quantity" in slot_names and "pizza" in slot_names: - return templates["inform/order"][2] - elif "quantity" in slot_names and "food" in slot_names: - return templates["inform/order"][0] - elif "food" in slot_names and "pizza" in slot_names and "price" in slot_names: - return templates["inform/order"][5] - elif "quantity" in slot_names: - return templates["inform/order"][3] - else: - return templates["inform/order"][4] - elif act == "request/menu": - return random.choice(templates["request/menu"]) - elif act == "inform/address": - return random.choice(templates["inform/address"]) - elif act == "request/price": - return random.choice(templates["request/price"]) - elif act == "inform/menu": - return random.choice(templates["inform/menu"]) - elif act == "request/ingredients": - return random.choice(templates["request/ingredients"]) - elif act == "request/sauce": - return random.choice(templates["request/sauce"]) - elif act == "inform/phone": - return random.choice(templates["inform/phone"]) - elif act == "inform/order-complete": - return random.choice(templates["inform/order-complete"]) - elif act == "request/time": - return random.choice(templates["request/time"]) - elif act == "request/size": - return random.choice(templates["request/size"]) - elif act == "inform/delivery": - return random.choice(templates["inform/delivery"]) - elif act == "inform/payment": - return random.choice(templates["inform/payment"]) - elif act == "request/delivery-price": - return random.choice(templates["request/delivery-price"]) - elif act == "inform/time": - return random.choice(templates["inform/time"]) - elif act == "request/drinks": - return random.choice(templates["request/drinks"]) - elif act == "request/food": - return random.choice(templates["request/food"]) - elif act == "inform/name": - return random.choice(templates["inform/name"]) - elif act == "bye": - return random.choice(templates["bye"]) - - return None - - -# def select_template(act, slots): -# slot_names = {slot['name'] for slot in slots} - -# if act == "welcomemsg": -# return random.choice(templates["welcomemsg"]) -# if act == "request/menu": -# return random.choice(templates["request/menu"]) -# if act == "inform/address": -# return random.choice(templates["inform/address"]) -# if act == "inform/delivery": -# return random.choice(templates["inform/delivery"]) -# if act == "inform/payment": -# return random.choice(templates["inform/payment"]) -# if act == "affirm": -# return random.choice(templates["affirm"]) -# if act == "request/drinks": -# return random.choice(templates["request/drinks"]) -# if act == "bye": -# return random.choice(templates["bye"]) -# if act == "inform/order": -# if "quantity" in slot_names and "food" in slot_names and "pizza" in slot_names: -# return templates["inform/order"][1] -# elif "quantity" in slot_names and "pizza" in slot_names: -# return templates["inform/order"][4] -# elif "food" in slot_names and "pizza" in slot_names: -# return templates["inform/order"][2] -# elif "quantity" in slot_names: -# return templates["inform/order"][3] -# else: -# return templates["inform/order"][4] - -# return "default/template" +import random +from service.templates import templates + +def generate_pizza_info(slots): + pizza_name = None + query_type = None + + for slot in slots: + if slot['name'] == 'pizza': + pizza_name = slot['value'].lower() + elif slot['name'] == 'ingredient': + query_type = 'ingredient' + elif slot['name'] == 'price': + query_type = 'price' + + if pizza_name not in pizza_data: + return f"Nie mamy w ofercie pizzy o nazwie {pizza_name}." + + if query_type == 'ingredient': + ingredients = pizza_data[pizza_name]['ingredient'] + return f"Składniki pizzy {pizza_name} to: {', '.join(ingredients)}." + elif query_type == 'price': + price = pizza_data[pizza_name]['price'] + return f"Cena pizzy {pizza_name} to {price} zł." + + return f"Informacje o pizzy {pizza_name}: składniki to {', '.join(pizza_data[pizza_name]['ingredient'])}, cena to {pizza_data[pizza_name]['price']} zł." + + +def generate_ingredients_response(slots): + ingredients = [slot['value'] for slot in slots if slot['name'] == 'ingredients'] + if ingredients: + ingredient_list = [] + for ingredient in ingredients: + ingredient_list.extend(ingredient.keys()) + response = f"Dostępne składniki to: {', '.join(ingredient_list)}." + return response + return "Nie podano składników." + + +def generate_drinks_response(slots): + drinks = [slot['value'] for slot in slots if slot['name'] == 'drink'] + print(slots) + print(drinks) + if drinks: + drink_details = [] + for drink in drinks: + for name, details in drink.items(): + # price = details.get('price', 'unknown') + drink_details.append(f"{name}") # w cenie {price} zł") + if len(drink_details) > 1: + response = f"Czy chcesz coś do picia? Dostępne napoje to: {', '.join(drink_details[:-1])} oraz {drink_details[-1]}." + else: + response = f"Czy chcesz coś do picia? Dostępne napoje to: {drink_details[0]}." + return response + return "Nie podano napojów." + +def generate_size_response(slots): + sizes = [slot['value'] for slot in slots if slot['name'] == 'size'][0] + if len(sizes) != 0: + return F"Dostępne rozmiary to: {', '.join(sizes)}" + return "Nie podano rozmiarów." + +def generate_sauce_response(slots): + sauces = [slot['value'] for slot in slots if slot['name'] == 'sauce'] + if sauces: + sauce_list = [] + for sauce in sauces: + if isinstance(sauce, list): + sauce_list.extend(sauce) + else: + sauce_list.append(sauce) + return f"Dostępne sosy to: {', '.join(sauce_list)}." + return "Nie podano sosów." + + +def select_template(act, slots): + slot_names = {slot['name'] for slot in slots} + + if act == "welcomemsg": + return random.choice(templates["welcomemsg"]) + + if "ingredients" in slot_names: + return generate_ingredients_response(slots) + elif "drink" in slot_names: + return generate_drinks_response(slots) + elif "sauce" in slot_names: + return generate_sauce_response(slots) + elif "size" in slot_names: + return generate_size_response(slots) + elif "price" in slot_names: + return random.choice(templates["inform/price"]) + elif "food" in slot_names: + return random.choice(templates["inform/menu"]) + + if act == "inform": + if "menu" in slot_names: + return random.choice(templates["inform/menu"]) + elif "address" in slot_names: + return random.choice(templates["inform/address"]) + elif "phone" in slot_names: + return random.choice(templates["inform/phone"]) + elif "order-complete" in slot_names: + return random.choice(templates["inform/order-complete"]) + elif "delivery" in slot_names: + return random.choice(templates["inform/delivery"]) + elif "payment" in slot_names: + return random.choice(templates["inform/payment"]) + elif "time" in slot_names: + return random.choice(templates["inform/time"]) + elif "name" in slot_names: + return random.choice(templates["inform/name"]) + elif "price" in slot_names and "pizza" in slot_names: + return generate_pizza_info(slots) + elif act == "inform/order": + if "quantity" in slot_names and "pizza" in slot_names and "size" in slot_names: + return templates["inform/order"][1] + elif "quantity" in slot_names and "pizza" in slot_names: + return templates["inform/order"][2] + elif "quantity" in slot_names and "food" in slot_names: + return templates["inform/order"][0] + elif "food" in slot_names and "pizza" in slot_names and "price" in slot_names: + return templates["inform/order"][5] + elif "quantity" in slot_names: + return templates["inform/order"][3] + else: + return templates["inform/order"][4] + elif act == "request/menu": + return random.choice(templates["request/menu"]) + elif act == "inform/address": + return random.choice(templates["inform/address"]) + elif act == "request/price": + return random.choice(templates["request/price"]) + elif act == "inform/menu": + return random.choice(templates["inform/menu"]) + elif act == "request/ingredients": + return random.choice(templates["request/ingredients"]) + elif act == "request/sauce": + return random.choice(templates["request/sauce"]) + elif act == "inform/phone": + return random.choice(templates["inform/phone"]) + elif act == "inform/order-complete": + return random.choice(templates["inform/order-complete"]) + elif act == "request/time": + return random.choice(templates["request/time"]) + elif act == "request/size": + return random.choice(templates["request/size"]) + elif act == "inform/delivery": + return random.choice(templates["inform/delivery"]) + elif act == "inform/payment": + return random.choice(templates["inform/payment"]) + elif act == "request/delivery-price": + return random.choice(templates["request/delivery-price"]) + elif act == "inform/time": + return random.choice(templates["inform/time"]) + elif act == "request/drinks": + return random.choice(templates["request/drinks"]) + elif act == "request/food": + return random.choice(templates["inform/menu"]) + elif act == "inform/name": + return random.choice(templates["inform/name"]) + elif act == "bye": + return random.choice(templates["bye"]) # TODO force end? + elif act == "bye_and_thanks": + return random.choice(templates["bye_and_thanks"]) + elif act == "repeat": + return random.choice(templates["repeat"]) + elif act == "request/address": + return random.choice(templates["request/address"]) + elif act == "request/payment-method": + return random.choice(templates["request/payment-method"]) + elif act == "request/phone": + return random.choice(templates["request/phone"]) + + return None + + +# def select_template(act, slots): +# slot_names = {slot['name'] for slot in slots} + +# if act == "welcomemsg": +# return random.choice(templates["welcomemsg"]) +# if act == "request/menu": +# return random.choice(templates["request/menu"]) +# if act == "inform/address": +# return random.choice(templates["inform/address"]) +# if act == "inform/delivery": +# return random.choice(templates["inform/delivery"]) +# if act == "inform/payment": +# return random.choice(templates["inform/payment"]) +# if act == "affirm": +# return random.choice(templates["affirm"]) +# if act == "request/drinks": +# return random.choice(templates["request/drinks"]) +# if act == "bye": +# return random.choice(templates["bye"]) +# if act == "inform/order": +# if "quantity" in slot_names and "food" in slot_names and "pizza" in slot_names: +# return templates["inform/order"][1] +# elif "quantity" in slot_names and "pizza" in slot_names: +# return templates["inform/order"][4] +# elif "food" in slot_names and "pizza" in slot_names: +# return templates["inform/order"][2] +# elif "quantity" in slot_names: +# return templates["inform/order"][3] +# else: +# return templates["inform/order"][4] + +# return "default/template" diff --git a/src/service/templates.py b/src/service/templates.py index b45590b..1917f64 100644 --- a/src/service/templates.py +++ b/src/service/templates.py @@ -1,180 +1,166 @@ -templates = { - "inform/order": [ - "Zamówiłeś {quantity} x {food}.", - "Twoje zamówienie to {quantity} x {food} {pizza}.", - "Mmmm... {food} {pizza} to rewelacyjny wybór. Czy chcesz coś do picia?", - "Dziękujemy za zamówienie {quantity} x {food}.", - "Na jaką pizzę masz ochotę?" - ], - "inform/menu": [ - "Oferujemy następujące pizze: {menu}.", - "Nasze pizze to: {menu}.", - "W naszym menu znajdziesz pizze: {menu}.", - "Dostępne pizze to: {menu}.", - "Proszę, oto lista dostępnych pizz: {menu}." - ], - "inform/name": [ - "Twoje imię to {name}.", - "Podane imię: {name}.", - "Twoje imię: {name}.", - "Masz na imię {name}.", - "Imię: {name}." - ], - "inform/price": [ - "Cena wybranej pizzy to {price} zł.", - "Koszt pizzy to {price} zł.", - "Wybrana pizza kosztuje {price} zł.", - "Cena pizzy wynosi {price} zł." - ], - "inform/address": [ - "Twój adres to: {address}.", - "Adres, który podałeś, to: {address}.", - "Dostawa na adres: {address}.", - "Dostarczymy na adres: {address}.", - "Twój podany adres to: {address}." - ], - "inform/sauce": [ - "Dostępne sosy to: {sauce}.", - "Możesz wybrać spośród następujących sosów: {sauce}.", - "Oferujemy następujące sosy: {sauce}." - ], - "inform/phone": [ - "Twój numer telefonu to: {phone}.", - "Podany numer telefonu: {phone}.", - "Numer telefonu, który podałeś, to: {phone}.", - "Twoje dane kontaktowe: {phone}.", - "Telefon kontaktowy: {phone}." - ], - "inform/order-complete": [ - "Twoje zamówienie zostało zrealizowane. Dziękujemy!", - "Zamówienie zakończone. Dziękujemy za zakupy!", - "Zamówienie zrealizowane. Czekaj na dostawę!", - "Twoje zamówienie jest gotowe. Dziękujemy!", - "Realizacja zamówienia zakończona. Dziękujemy!" - ], - "inform/delivery": [ - "Twoje zamówienie zostanie dostarczone na {address}.", - "Dostarczymy zamówienie na adres: {address}.", - "Dostawa na adres: {address}.", - "Twoje zamówienie jedzie na {address}.", - "Adres dostawy: {address}." - ], - "inform/address": [ - "Twoje zamówienie zostanie dostarczone na adres: {address}.", - "Dostawa będzie na adres: {address}.", - "Adres dostawy: {address}." - ], - "inform/payment": [ - "Metoda płatności to: {payment-method}.", - "Płatność realizujesz przez: {payment-method}.", - "Wybrałeś metodę płatności: {payment-method}.", - "Płatność: {payment-method}.", - "Możesz zapłacić kartą, gotówką lub blikiem" - ], - "affirm": [ - "Świetnie! Napisz co Ci chodzi po głowie.", - "Dobrze! Co dalej?", - "OK! Co chciałbyś zamówić?", - "Super! Co dalej?", - "Dobrze! Jakie dalsze zamówienia?" - ], - "request/delivery-price": [ - "Koszt dostawy wynosi {delivery-price} zł.", - "Cena dostawy to {delivery-price} zł.", - "Za dostawę zapłacisz {delivery-price} zł.", - "Dostawa kosztuje {delivery-price} zł.", - "Koszt dostawy: {delivery-price} zł." - ], - "request/menu": [ - "Oto nasze menu: {menu}.", - "Nasze menu obejmuje: {menu}.", - "Proszę, oto lista dostępnych dań: {menu}.", - "Dostępne dania to: {menu}.", - "W naszym menu znajdziesz: {menu}." - ], - "inform/time": [ - "Aktualny czas to {time}.", - "Jest teraz {time}.", - "Czas: {time}.", - "Godzina: {time}.", - "Obecny czas: {time}." - ], - "request/drinks": [ - "Jakie napoje chciałbyś zamówić?", - "Proszę wybrać napoje do zamówienia.", - "Jakie napoje dołączamy do zamówienia?", - "Co chciałbyś pić?", - "Proszę podać napoje do zamówienia." - ], - "welcomemsg": [ - "Witaj w naszej wspaniałej pizzerii. W czym mogę pomóc?", - "Halo, halo, tu najlepsza pizza w mieście. Masz głoda?", - "Dzieńdoberek, gdyby wszyscy jedli nasze pizze, na świecie nie byłoby wojen. Jaką pizzę sobie dziś gruchniesz?", - ], - "request/menu": [ - "W naszym menu znajdują się pizze, spaghetti, gnocci oraz aranchini. Polecam potrawkę śląską po grecku.", - "Smażymy, gotujemy, prażymy, ale najlepiej nam wychodzi pizza. Na co masz ochotę?", - ], - "request/drink": [ - "Oferujemy napoje zimne, ciepłe i letnie. Cola, fanta, woda mineralna, kawa, herbata lub frappe.", - "Może z alkoholem? Mamy świeżo warzone piwo", - ], - "request/price": [ - "Cena za {food} wynosi {price} zł.", - "Koszt {food} to {price} zł.", - "Cena {pizza} o rozmiarze {size} wynosi {price} zł.", - "Za {quantity} x {pizza} zapłacisz {price} zł.", - "Koszt {food} to {price} zł." - ], - "request/ingredients": [ - "Nasza {food} {pizza} składa się z ciasta, sosu pomidorowego, sera i innych dodatków.", - "W {pizza} znajdziesz: {ingredients}.", - "{pizza} zawiera: {ingredients}.", - "W skład {pizza} wchodzi: {ingredients}.", - "Na {pizza} składają się: {ingredients}." - ], - "request/sauce": [ - "Jakie sosy chciałbyś do {food}?", - "Proszę wybrać sosy do {food}.", - "Jakie sosy zamawiasz do {food}?", - "Które sosy mają być do {food}?", - "Wybierz sosy do {food}." - ], - "request/food": [ - "Co chciałbyś zamówić?", - "Proszę podać na jaką pizzę masz ochotę", - "Którą pizzę wybrałeś?" - ], - "request/time": [ - "Oczekiwany czas dostawy to {time} minut.", - "Dostawa zajmie około {time} minut.", - "Czas dostawy to około {time} minut.", - "Przewidywany czas dostawy to {time} minut.", - "Twoje zamówienie dotrze w {time} minut." - ], - "request/size": [ - "Jaką wielkość {pizza} preferujesz? Mamy {sizes}.", - "Dostępne rozmiary {pizza} to {sizes}.", - "Jaką wielkość {pizza} chciałbyś zamówić? {sizes}.", - "Proszę wybrać rozmiar {pizza}: {sizes}.", - "Mamy następujące rozmiary {pizza}: {sizes}." - ], - "bye": [ - "Dziękujemy i do zobaczenia wkrótce.", - "Polecamy się na przyszłość. Do zobaczenia!", - "Do widzenia.", - ], - "negate": [ - "Przepraszam, nie mamy {ingredient/neg} w ofercie.", - "Niestety, {ingredient/neg} jest niedostępne.", - "Nie posiadamy {ingredient/neg} w menu.", - "Brak {ingredient/neg} w naszej ofercie.", - "Niestety, nie mamy {ingredient/neg}." - ], - "default/template": [ - "Przepraszamy, ale nie rozumiemy Twojego zapytania.", - "Proszę spróbować ponownie później.", - "Nie rozpoznajemy Twojej prośby, spróbuj ponownie.", - "Strasznie szybko to napisałeś, nie zrozumiałem...." - ] -} +templates = { + "inform/order": [ + "Zamówiłeś {quantity} x {food}.", + "Twoje zamówienie to {quantity} x {food} {pizza}.", + "Mmmm... {food} {pizza} to rewelacyjny wybór. Czy chcesz coś do picia?", + "Dziękujemy za zamówienie {quantity} x {food}.", + "Na jaką pizzę masz ochotę?" + ], + "inform/menu": [ + "Oferujemy następujące pizze: {menu}.", + ], + "inform/name": [ + "Twoje imię to {name}.", + "Podane imię: {name}.", + "Twoje imię: {name}.", + "Masz na imię {name}.", + "Imię: {name}." + ], + "inform/price": [ + "Cena wybranej pizzy to {price} zł.", + "Koszt pizzy to {price} zł.", + "Wybrana pizza kosztuje {price} zł.", + "Cena pizzy wynosi {price} zł." + ], + "inform/address": [ + "Twój adres to: {address}.", + "Adres, który podałeś, to: {address}.", + "Dostawa na adres: {address}.", + "Dostarczymy na adres: {address}.", + "Twój podany adres to: {address}." + ], + "inform/sauce": [ + "Dostępne sosy to: {sauce}.", + "Możesz wybrać spośród następujących sosów: {sauce}.", + "Oferujemy następujące sosy: {sauce}." + ], + "inform/phone": [ + "Twój numer telefonu to: {phone}.", + "Podany numer telefonu: {phone}.", + "Numer telefonu, który podałeś, to: {phone}.", + "Twoje dane kontaktowe: {phone}.", + "Telefon kontaktowy: {phone}." + ], + "inform/order-complete": [ + "Twoje zamówienie zostało zrealizowane. Dziękujemy!", + "Zamówienie zakończone. Dziękujemy za zakupy!", + "Zamówienie zrealizowane. Czekaj na dostawę!", + "Twoje zamówienie jest gotowe. Dziękujemy!", + "Realizacja zamówienia zakończona. Dziękujemy!" + ], + "inform/delivery": [ + "Twoje zamówienie zostanie dostarczone na {address}.", + "Dostarczymy zamówienie na adres: {address}.", + "Dostawa na adres: {address}.", + "Twoje zamówienie jedzie na {address}.", + "Adres dostawy: {address}." + ], + "inform/address": [ + "Twoje zamówienie zostanie dostarczone na adres: {address}.", + "Dostawa będzie na adres: {address}.", + "Adres dostawy: {address}." + ], + "inform/payment": [ + "Metoda płatności to: {payment-method}.", + "Płatność realizujesz przez: {payment-method}.", + "Wybrałeś metodę płatności: {payment-method}.", + "Płatność: {payment-method}.", + "Możesz zapłacić kartą, gotówką lub blikiem" + ], + "affirm": [ + "Świetnie! Napisz co Ci chodzi po głowie.", + "Dobrze! Co dalej?", + "OK! Co chciałbyś zamówić?", + "Super! Co dalej?", + "Dobrze! Jakie dalsze zamówienia?" + ], + "request/delivery-price": [ + "Koszt dostawy wynosi {delivery-price} zł.", + "Cena dostawy to {delivery-price} zł.", + "Za dostawę zapłacisz {delivery-price} zł.", + "Dostawa kosztuje {delivery-price} zł.", + "Koszt dostawy: {delivery-price} zł." + ], + "request/menu": [ + "W naszym menu znajdziesz: {menu}." + ], + "inform/time": [ + "Aktualny czas to {time}.", + "Jest teraz {time}.", + "Czas: {time}.", + "Godzina: {time}.", + "Obecny czas: {time}." + ], + "welcomemsg": [ + "Witaj w naszej wspaniałej pizzerii. W czym mogę pomóc?", + "Halo, halo, tu najlepsza pizza w mieście. Masz głoda?", + "Dzieńdoberek, gdyby wszyscy jedli nasze pizze, na świecie nie byłoby wojen. Jaką pizzę sobie dziś gruchniesz?", + ], + "request/price": [ + "Cena za {food} wynosi {price} zł.", + "Koszt {food} to {price} zł.", + "Cena {pizza} o rozmiarze {size} wynosi {price} zł.", + "Za {quantity} x {pizza} zapłacisz {price} zł.", + "Koszt {food} to {price} zł." + ], + "request/ingredients": [ + "Nasza {food} {pizza} składa się z ciasta, sosu pomidorowego, sera i innych dodatków.", + "W {pizza} znajdziesz: {ingredients}.", + "{pizza} zawiera: {ingredients}.", + "W skład {pizza} wchodzi: {ingredients}.", + "Na {pizza} składają się: {ingredients}." + ], + "request/sauce": [ + "Jakie sosy chciałbyś do {food}?", + "Proszę wybrać sosy do {food}.", + "Jakie sosy zamawiasz do {food}?", + "Które sosy mają być do {food}?", + "Wybierz sosy do {food}." + ], + "request/food": [ + "Co chciałbyś zamówić?", + "Proszę podać na jaką pizzę masz ochotę", + "Którą pizzę wybrałeś?" + ], + "request/time": [ + "Oczekiwany czas dostawy to {time} minut.", + "Dostawa zajmie około {time} minut.", + "Czas dostawy to około {time} minut.", + "Przewidywany czas dostawy to {time} minut.", + "Twoje zamówienie dotrze w {time} minut." + ], + "request/size": [ + "Jaką wielkość {pizza} preferujesz? Mamy {sizes}.", + "Dostępne rozmiary {pizza} to {sizes}.", + "Jaką wielkość {pizza} chciałbyś zamówić? {sizes}.", + "Proszę wybrać rozmiar {pizza}: {sizes}.", + "Mamy następujące rozmiary {pizza}: {sizes}." + ], + "bye": [ + "Dziękujemy i do zobaczenia wkrótce.", + "Polecamy się na przyszłość. Do zobaczenia!", + "Do widzenia.", + ], + "negate": [ + "Przepraszam, nie mamy {ingredient/neg} w ofercie.", + "Niestety, {ingredient/neg} jest niedostępne.", + "Nie posiadamy {ingredient/neg} w menu.", + "Brak {ingredient/neg} w naszej ofercie.", + "Niestety, nie mamy {ingredient/neg}." + ], + "default/template": [ + "Nie zrozumiałem, spróbuj inaczej sformułować zdanie." + ], + "repeat": [ + "Nie zrozumiałem, spróbuj inaczej sformułować zdanie.", + ], + "request/address": [ + "Jaki adres dostawy?" + ], + "bye_and_thanks": [ + "Dziękujemy za zamówienie. Do zobaczenia!", + ], + "request/phone": [ + "Podaj proszę numer telefonu do kontaktu dla kuriera." + ] +}