Coffee Bot Project

Hello!

I’m having some problems with my code for this project: https://www.codecademy.com/paths/build-chatbots-with-python/tracks/introduction-to-python-and-chatbots/modules/chatbot-evolution-and-dialog-trees/projects/coffee-chatbot

It has checked all the functions required. The code also succeeded in prompting user for additional orders. I am stuck with implementing the extra order function as marked with # on the code below:

def coffee_bot():
    welcome_message()
    order_taking()

    name = input("\nCan I get your name please? ")

    print("\nThanks, {}! Your order will be ready shortly.".format(name))
    print("\nYour receipt is: \n" + receipt())

def welcome_message():
    print("Welcome to the Starbucks! \n\nToday's specials are Cherry Blossom Frappuccino and Nitro Cold Brew.")

#stuck here
def receipt():

Under the function for order_taking(), I’m not sure on how to append each new drink order to the orders list. Because I call the addon_prompt at the end of the function, the orders list start afresh.

Although I know that the exercise is supposed to flex knowledge on Control Flow, somehow I feel that incorporating lists may help me to find a way out. I read through the existing forum threads on this project too, but no one seems to have a similar problem. I was hoping to find a way on:

  1. How to ensure the orders list appends new orders.
  2. How to use the full orders list in the receipt function.

Thank you so much to our helpful moderators!!

#and stuck here too
def order_taking():
    orders = []
    size = get_size()
    drink_type = get_drink_type()
    temp_type = hot_or_iced()
    cup_type = cup_options()
    orders.append([size, drink_type, temp_type, cup_type])
    print("\n" + str(orders))
    print("\nAlright, that\'s a {} {} {} {}!".format(temp_type, size, drink_type, cup_type))
    addon_prompt()

def addon_prompt():
    res = input("\nDo you wish to add another order? \n[a] Yes \n[b] No \n> ")
    res = res.lower()
    if res == "a":
        print("\nAlright, taking your new order!")
        return order_taking()
    else:
        print("\nAlright, processing your orders now!")

def error_message():
    print("\nI'm sorry, I did not understand your selection.\n\nPlease enter the corresponding letter for your response.")

def get_size():
    res = input('\nWhat size drink can I get for you? \n[a] Small \n[b] Medium \n[c] Large \n> ')
    res = res.lower()
    if res == "a":
        return "Small"
    elif res == "b":
        return "Medium"
    elif res == "c":
        return "Large"
    else:
        error_message()
        return get_size()

def get_drink_type():
    res = input("\nWhat type of drink would you like?\n[a] Brewed Coffee \n[b] Mocha \n[c] Latte \n> ")
    res = res.lower()
    if res == "a":
        return "Brewed Coffee"
    elif res == "b":
        return "Mocha"
    elif res == "c":
        return order_latte()
    else:
        error_message()
        return get_drink_type()

def order_latte():
    res = input("\nAnd what kind of milk for your latte? \n[a] 2% milk \n[b] Non-fat milk \n[c] Soy milk \n> ")
    res = res.lower()
    if res == "a":
        return "Latte"
    elif res == "b":
        return "Non-fat Latte"
    elif res == "c":
        return "Soy Latte"
    else:
        error_message()
        return order_latte()

def hot_or_iced():
    res = input("\nHow would you like your drink? \n[a] Hot \n[b] Iced \n> ")
    res = res.lower()
    if res == "a":
        return "hot"
    elif res == "b":
        return "iced"
    else:
        error_message()
        return hot_or_iced()

def cup_options():
    res = input("\nWhat type of cup would you like to use?\n[a] Dine-in Cup \n[b] Takeaway Cup \n[c] Your own Reusable Cup \n> ")
    res = res.lower()
    if res == "a":
        return "in a dine-in cup"
    elif res == "b":
        return "in a takeaway cup."
    elif res == "c":
        return "in your reusable cup."
    else:
        error_message()
        return cup_options()

coffee_bot()

One thing that might help is to define the list ‘orders’ outside of the order taking function. That way you can append to it in the taking order function and use it in the receipt function.

remember that you can set default parameters to functions:

so if you don’t want orders = [] every time you call order_taking you can try

def order_taking(orders = [])
    # orders = [] the first time
    # orders = ['bananas'] the second
    # then when you call recursively you can update orders as you see fit
    order_taking(orders=['bananas'])

@frantz60 This worked, my additional orders are appending to the list!
Thank you for looking through my code, I was so blind due to an experience from a prev project, it affected my logic for this one as well.

Everything is working well, I furnished the Receipt Function and added Quantity enquiry for my bot. Small win for the day!

My code is now printing:

def receipt():
    print("\nYou have placed " + str((len(orders))) + " orders. Your orders are: ")
    for order in orders:
        print(*order)

You have placed 2 orders. Your orders are:
10 Small Hot Brewed Coffee in a dine-in cup
3 Medium Iced Mocha in a takeaway cup.

Would you be able to provide some advice on how I can improve and transform the output to this, where I can put the order sequence before the order:

You have placed 2 orders. Your orders are:
1 ) 10 Small Hot Brewed Coffee in a dine-in cup
2 ) 3 Medium Iced Mocha in a takeaway cup.

orders = [[10, 'Small', 'Hot', 'Brewed Coffee', 'in a dine-in cup'], [3, 'Medium', 'Iced', 'Mocha', 'in a takeaway cup.']]
total_orders = total_orders = range(1, (len(orders)+1))
#printed [1, 2]

seq_orders = list(zip(total_orders, orders))
#printed [(1, [10, 'Small', 'Hot', 'Brewed Coffee', 'in a dine-in cup']), (2, [3, 'Medium', 'Iced', 'Mocha', 'in a takeaway cup.'])]

print("\n")
for section in seq_orders:
    print(str(section[0]) + ". " + str(item))

I tried multiple variations. The closest I got was this.
Where #1’s order is incorrect, and the items are still in list format.

1 . [3, ‘Medium’, ‘Iced’, ‘Mocha’, ‘in a takeaway cup.’]
2 . [3, ‘Medium’, ‘Iced’, ‘Mocha’, ‘in a takeaway cup.’]

Cheers, stay safe!

1 Like

@toastedpitabread Right! It didn’t cross my mind to use a list as a parameter this way.

It works equally as well to store my orders! But when it got to another function that pulls data from orders, I ran into an error. Should be due to the fact that the orders list is available to the order_taking function? Do correct me if I’m wrong.

Thanks for taking the time to look through my code and reply so quickly!

def coffee_bot():
    welcome_message()
    order_taking()
    receipt()

    name = input("\nCan I get your name please? ")

    print("\nThanks, {}! Please proceed to the pick up counter for your order!".format(name))

def welcome_message():
    print("Welcome to the Starbucks! \n\nToday's specials are Cherry Blossom Frappuccino and Nitro Cold Brew.")

def receipt():
    total_orders = range(1, (len(orders)+1))
    print("\nYou have placed " + str((len(orders))) + " orders. Your orders are: ")
    for order in orders:
        print(*order)

def order_taking(orders = []):
    size = get_size()
    temp_type = hot_or_iced()
    drink_type = get_drink_type()
    cup_type = cup_options()
    quantity = get_quantity()
    orders.append([quantity, size, temp_type, drink_type, cup_type])
    
    print("\n" + str(orders))
    print("\nAlright, that\'s {} {} {} {} {}!".format(quantity, size, temp_type, drink_type, cup_type))
    addon_prompt()
    
def addon_prompt():
    res = input("\nDo you wish to add another order? \n[a] Yes \n[b] No \n> ")
    res = res.lower()
    if res == "a":
        print("\nAlright, taking your new order!")
        return order_taking()
    else:
        print("\nAlright, processing your orders now!")

def error_message():
    print("\nI'm sorry, I did not understand your selection.\n\nPlease enter the corresponding letter for your response.")

def get_size():
    res = input('\nWhat size drink can I get for you? \n[a] Small \n[b] Medium \n[c] Large \n> ')
    res = res.lower()
    if res == "a":
        return "Small"
    elif res == "b":
        return "Medium"
    elif res == "c":
        return "Large"
    else:
        error_message()
        return get_size()

def get_drink_type():
    res = input("\nWhat type of drink would you like?\n[a] Brewed Coffee \n[b] Mocha \n[c] Latte \n> ")
    res = res.lower()
    if res == "a":
        return "Brewed Coffee"
    elif res == "b":
        return "Mocha"
    elif res == "c":
        return order_latte()
    else:
        error_message()
        return get_drink_type()

def order_latte():
    res = input("\nAnd what kind of milk for your latte? \n[a] 2% milk \n[b] Non-fat milk \n[c] Soy milk \n> ")
    res = res.lower()
    if res == "a":
        return "Latte"
    elif res == "b":
        return "Non-fat Latte"
    elif res == "c":
        return "Soy Latte"
    else:
        error_message()
        return order_latte()

def hot_or_iced():
    res = input("\nHow would you like your drink? \n[a] Hot \n[b] Iced \n> ")
    res = res.lower()
    if res == "a":
        return "Hot"
    elif res == "b":
        return "Iced"
    else:
        error_message()
        return hot_or_iced()

def cup_options():
    res = input("\nWhat type of cup would you like to use?\n[a] Dine-in Cup \n[b] Takeaway Cup \n[c] Your own Reusable Cup \n> ")
    res = res.lower()
    if res == "a":
        return "in a dine-in cup"
    elif res == "b":
        return "in a takeaway cup."
    elif res == "c":
        return "in your reusable cup."
    else:
        error_message()
        return cup_options()

def get_quantity():
    res = input("\nWhat is quantity for this order? > ")
    try:
        res = int(res)
        return res
    except ValueError:
        print("\nInvalid input. Please enter a value quantity.")
        return get_quantity()

coffee_bot()

Hm, I’m not sure from which other function you are referring to, or what the type of error is (there is often a huge clue in the error message itself).

I suspect your order_taking doesn’t have a final return value in all instances, so that would probably return None (when it calls addon_prompt(), there’s no return value for the else statement, so does that mean the whole function runs without returning anything? but without seeing the error msg I’m not sure…).

This is a side suggestion: Without really knowing your code, the question is how clear is the image you have of your structure. It helps to draw out the structure to spot inconsistencies or points of improvement. I find it helpful to just comment structural points and group all like functions in section (even when working alone) just so that it makes it easier to navigate (especially if I come back to the code after a long time). Additionally, commenting the functions they inter-depend on is crucial as trouble shooting becomes easier. (For example, I took 3 minutes to look over to interpret the code, with good comments, that could have been 30 seconds, multiply that every time you have to fix anything!!).

Thanks for the suggestion! I will improve upon the commenting of my code now that I’m aware of the heaps time it saves for others looking through it.

This is my code below in entirety, I’ve input the (orders = ) as a parameter for order_taking function.

Traceback (most recent call last):
File “/coffeebot_atom.py”, line 126, in
coffee_bot()
File “/coffeebot_atom.py”, line 5, in coffee_bot
receipt()
File “/coffeebot_atom.py”, line 43, in receipt
total_orders = range(1, (len(orders)+1))
NameError: name ‘orders’ is not defined

But I got this error message. I understand how your suggestion works when it’s used solely in the order taking function. However, when incorporated with the entire code, I’m not too sure.

What I gather from the Error Message is that (orders = ) cannot be called upon in the Receipt function.

#Main Coffee Bot function
def coffee_bot():
    welcome_message()
    order_taking()
    receipt()

    name = input("\nCan I get your name please? ")

    print("\nThanks, {}! Please proceed to the pick up counter for your order!".format(name))

#Welcome Message, called in main function
def welcome_message():
    print("Welcome to the Starbucks! \n\nToday's specials are Cherry Blossom Frappuccino and Nitro Cold Brew.")

#Order Taking, called in main function
def order_taking(order=[]):
    size = get_size()
    temp_type = get_temp()
    drink_type = get_drink_type()
    cup_type = get_cup()
    quantity = get_quantity()
    orders.append([quantity, size, temp_type, drink_type, cup_type])
    print("\n" + str(orders))
    print("\nAlright, that\'s {} {} {} {} {}!".format(quantity, size, temp_type, drink_type, cup_type))
    addon_prompt()

#For Additional Orders, called in Order Taking function
def addon_prompt():
    res = input("\nDo you wish to add another order? \n[a] Yes \n[b] No \n> ")
    res = res.lower()
    if res == "a":
        print("\nAlright, taking your new order!")
        return order_taking()
    else:
        print("\nAlright, processing your orders now!")

#Error Message, used for invalid input
def error_message():
    print("\nI'm sorry, I did not understand your selection.\n\nPlease enter the corresponding letter for your response.")

#Order Summary, called in main function
def receipt():
    total_orders = range(1, (len(orders)+1))
    print("\nYou have placed " + str((len(orders))) + " orders. Your orders are: ")
    for order in orders:
        print(*order)

#Size Choice, called in Order Taking function
def get_size():
    res = input('\nWhat size drink can I get for you? \n[a] Small \n[b] Medium \n[c] Large \n> ')
    res = res.lower()
    if res == "a":
        return "Small"
    elif res == "b":
        return "Medium"
    elif res == "c":
        return "Large"
    else:
        error_message()
        return get_size()

#Drink Choice, called in Order Taking function
def get_drink_type():
    res = input("\nWhat type of drink would you like?\n[a] Brewed Coffee \n[b] Mocha \n[c] Latte \n> ")
    res = res.lower()
    if res == "a":
        return "Brewed Coffee"
    elif res == "b":
        return "Mocha"
    elif res == "c":
        return order_latte()
    else:
        error_message()
        return get_drink_type()

#Milk Component, called in Get_Drink_Type function
def order_latte():
    res = input("\nAnd what kind of milk for your latte? \n[a] 2% milk \n[b] Non-fat milk \n[c] Soy milk \n> ")
    res = res.lower()
    if res == "a":
        return "Latte"
    elif res == "b":
        return "Non-fat Latte"
    elif res == "c":
        return "Soy Latte"
    else:
        error_message()
        return order_latte()

#Temp Choice, called in Order Taking function
def get_temp():
    res = input("\nHow would you like your drink? \n[a] Hot \n[b] Iced \n> ")
    res = res.lower()
    if res == "a":
        return "Hot"
    elif res == "b":
        return "Iced"
    else:
        error_message()
        return get_temp()

#Cup choice, called in Order Taking function
def get_cup():
    res = input("\nWhat type of cup would you like to use?\n[a] Dine-in Cup \n[b] Takeaway Cup \n[c] Your own Reusable Cup \n> ")
    res = res.lower()
    if res == "a":
        return "in a dine-in cup"
    elif res == "b":
        return "in a takeaway cup."
    elif res == "c":
        return "in your reusable cup."
    else:
        error_message()
        return get_cup()

#Quantity choice, called in Order Taking function
def get_quantity():
    res = input("\nWhat is quantity for this order? > ")
    try:
        res = int(res)
        return res
    except ValueError:
        print("\nInvalid input. Please enter a value quantity.")
        return get_quantity()

coffee_bot()

No problem!

As the error message says, in the function receipt() orders is not defined :slight_smile: That should fix that one. You write len(orders) but orders wasn’t previously defined in the function or globally.

1 Like

@toastedpitabread I thought about your suggestion on implement orders globally and tried around 5 times work about each new error I was thrown. I’m super happy that it’s solved!

I defined the orders = [] variable globally. Then I proceed to insert the variable as a parameter to all functions that referenced the order_taking function. Last, I inserted the parameter into the receipt function as it used the variable to pull data from and the code worked! Thank you so much for this!

I have one last improvement I hope to make for this Coffee Bot Project.
If you have some time, could you have a look at this too? I appreciate all your help and effort! :smile:

Improved Code:

#Main Coffee Bot function
orders = []
def coffee_bot():
    welcome_message()
    order_taking(orders)
    receipt(orders)

    name = input("\nCan I get your name please? ")

    print("\nThanks, {}! Please proceed to the pick up counter for your order!".format(name))

#Welcome Message, called in main function
def welcome_message():
    print("Welcome to the Starbucks! \n\nToday's specials are Cherry Blossom Frappuccino and Nitro Cold Brew.")

#Order Taking, called in main function
def order_taking(orders):
    size = get_size()
    temp_type = get_temp()
    drink_type = get_drink_type()
    cup_type = get_cup()
    quantity = get_quantity()
    orders.append([quantity, size, temp_type, drink_type, cup_type])
    print("\n" + str(orders))
    print("\nAlright, that\'s {} {} {} {} {}!".format(quantity, size, temp_type, drink_type, cup_type))
    addon_prompt()

#For Additional Orders, called in Order Taking function
def addon_prompt():
    res = input("\nDo you wish to add another order? \n[a] Yes \n[b] No \n> ")
    res = res.lower()
    if res == "a":
        print("\nAlright, taking your new order!")
        return order_taking(orders)
    else:
        print("\nAlright, processing your orders now!")

#Error Message, used for invalid input
def error_message():
    print("\nI'm sorry, I did not understand your selection.\n\nPlease enter the corresponding letter for your response.")

#Order Summary, called in main function
def receipt(orders):
    total_orders = range(1, (len(orders)+1))
    print("\nYou have placed " + str((len(orders))) + " orders. Your orders are: ")
    for order in orders:
        print(*order)

#Size Choice, called in Order Taking function
def get_size():
    res = input('\nWhat size drink can I get for you? \n[a] Small \n[b] Medium \n[c] Large \n> ')
    res = res.lower()
    if res == "a":
        return "Small"
    elif res == "b":
        return "Medium"
    elif res == "c":
        return "Large"
    else:
        error_message()
        return get_size()

#Drink Choice, called in Order Taking function
def get_drink_type():
    res = input("\nWhat type of drink would you like?\n[a] Brewed Coffee \n[b] Mocha \n[c] Latte \n> ")
    res = res.lower()
    if res == "a":
        return "Brewed Coffee"
    elif res == "b":
        return "Mocha"
    elif res == "c":
        return order_latte()
    else:
        error_message()
        return get_drink_type()

#Milk Component, called in Get_Drink_Type function
def order_latte():
    res = input("\nAnd what kind of milk for your latte? \n[a] 2% milk \n[b] Non-fat milk \n[c] Soy milk \n> ")
    res = res.lower()
    if res == "a":
        return "Latte"
    elif res == "b":
        return "Non-fat Latte"
    elif res == "c":
        return "Soy Latte"
    else:
        error_message()
        return order_latte()

#Temp Choice, called in Order Taking function
def get_temp():
    res = input("\nHow would you like your drink? \n[a] Hot \n[b] Iced \n> ")
    res = res.lower()
    if res == "a":
        return "Hot"
    elif res == "b":
        return "Iced"
    else:
        error_message()
        return get_temp()

#Cup choice, called in Order Taking function
def get_cup():
    res = input("\nWhat type of cup would you like to use?\n[a] Dine-in Cup \n[b] Takeaway Cup \n[c] Your own Reusable Cup \n> ")
    res = res.lower()
    if res == "a":
        return "in a dine-in cup"
    elif res == "b":
        return "in a takeaway cup."
    elif res == "c":
        return "in your reusable cup."
    else:
        error_message()
        return get_cup()

#Quantity choice, called in Order Taking function
def get_quantity():
    res = input("\nWhat is quantity for this order? > ")
    try:
        res = int(res)
        return res
    except ValueError:
        print("\nInvalid input. Please enter a value quantity.")
        return get_quantity()

coffee_bot()

1 Like

Nice!

Ok, one last point: Global variables in python tend to be an tricky business (often avoided unless necessary). You should check for example, what happens if you call your coffee bot 3 times in a row at the end? Can it work 3 times in a row without letting the old orders spill over to the new calls (which is crucial if this is going to be a real app!)? If it doesn’t what are some ways to work around this?

I can think of 1 at least: structural (thinking beyond functions). (There might be more)

1 Like

Duly noted. At this point, I’m still not too familiar with the process of code transforming into an app. I will attempt more debugging thoughts for my code. If there’s a resource you would like to share on good examples of python run apps, please do share with me! Much appreciation for your time once again!

1 Like