Build a Meal Prep AI Chatbot

Build an AI chatbot that generates personalized meal prep plans in Python.

Introduction

30 Second Summary

Meal prepping saves time and money, but the planning part is exhausting. Figuring out what to cook, balancing nutrition, staying on budget, and writing a grocery list takes longer than the actual cooking.

In this project, you will build a Meal Prep AI chatbot that generates personalised weekly meal plans, grocery lists, and prep instructions on demand. You'll connect Python to the OpenAI API and wrap it in a polished chat interface using Streamlit.

What You'll Build

A locally-running AI chatbot that takes your dietary preferences, budget, and schedule, then responds with structured meal plans and follow-up conversation support.

By the end of this project, you'll have:

  • A Python app that connects to the OpenAI API with a custom system prompt turning a general-purpose LLM into a meal prep specialist.
  • A polished Streamlit chat interface with chat bubbles, streaming responses, and conversation memory.
  • Hands-on experience with chat completions, message history, and real-time streaming using the modern OpenAI Python SDK.
  • Secret Mission: Add a sidebar with diet type, budget slider, and household size controls that automatically shape every response.

Are there any prerequisites?

None. This guide walks you through installing Python, setting up your project, and creating an OpenAI account from scratch. All you need is a computer and an internet connection.

Set Up Your Environment

Before you can build your chatbot, you need a few tools in place. Python runs your code, VS Code gives you a code editor, and the OpenAI API connects your app to a language model.

In this step, you will install Python, set up a project folder with an isolated environment, install the packages your chatbot needs, and store your API key securely.

In this step, get ready to:
  • Install Python and VS Code.
  • Create a project folder with a virtual environment and install packages.
  • Generate an OpenAI API key and store it in a secrets file.
Install Python, create your project folder, and set up a virtual environment

The OpenAI Python SDK requires Python 3.9 or higher. Let's confirm you have it installed.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Check your Python version by running this command:
python3 --version

✔️ I see version 3.9 or higher

You're all set. Move on to the VS Code step below.

ⓧ I see an older version

You have Python installed, but the version is too old for this project.

  • Visit python.org/downloads and download the latest Python 3 installer for your operating system.
  • Run the installer. On Windows, check the box that says Add Python to PATH before clicking Install Now.
  • Close and reopen your terminal, then run the version check again to confirm you see 3.9 or higher.

macOS users seeing an old system Python

macOS sometimes ships an older Python. After installing a newer version from python.org, you may need to restart your terminal or use the full version binary (e.g. python3.12) for the new version to take effect.

ⓧ Command not found

Python is not installed yet.

  • Visit python.org/downloads and download the latest Python 3 installer for your operating system.
  • Run the installer. On Windows, check the box that says Add Python to PATH before clicking Install Now.
  • Close and reopen your terminal, then run the version check again to confirm you see 3.9 or higher.

Windows users

On Windows, the command may be python instead of python3. Try both and use whichever returns a version number.

Next, open VS Code.

  • If you don't have VS Code installed, download it from code.visualstudio.com and install it.
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.

Now create your project folder. You'll use the terminal inside VS Code for the rest of this step.

  • Open the built-in terminal in VS Code by pressing Ctrl+` (backtick key, same shortcut on macOS and Windows).
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir meal-prep-chatbot
cd meal-prep-chatbot

Now set up a virtual environment so your project's packages stay isolated from the rest of your system.

  • Create a virtual environment by running:
python3 -m venv venv
  • Activate the virtual environment:

macOS

source venv/bin/activate

Windows

venv\Scripts\activate

You should see (venv) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.

Don't see (venv) in your prompt?

Make sure you ran the activate command for your operating system. On Windows, if you see an execution policy error, run this command first, then try activating again:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Help me activate my virtual environment

Install the required packages

Your chatbot needs two packages: the OpenAI SDK to talk to the language model, and Streamlit to build the chat interface.

  • Install both packages by running:
pip install openai streamlit

What does this install?

openai is the official Python SDK for calling OpenAI's language models. streamlit is a framework that turns Python scripts into interactive web apps with zero frontend code.

  • Confirm the install succeeded by running:
pip show openai streamlit

You should see version information for both packages printed in your terminal.

Seeing a pip not found error?

Make sure your virtual environment is active (you see (venv) in your prompt). If the error persists, try this instead:

pip3 install openai streamlit

Help me fix a pip installation error

Set up your OpenAI API key

Your chatbot needs an API key to authenticate with OpenAI's servers. You will create a free account, generate a key, and store it in a secrets file that Streamlit reads automatically.

  • Open platform.openai.com in your browser and sign up for a free account (or log in if you already have one).
  • Once logged in, navigate to the API Keys page from the left sidebar.
  • Click Create new secret key.
  • Give it a name like meal-prep-chatbot and click Create secret key.
  • Copy the key immediately. You won't be able to see it again after you close the dialog.

How much does this cost?

OpenAI's free tier gives you a usage allowance to experiment with. The model you will use in this project (gpt-4.1-nano) costs $0.10 per million input tokens. Testing your chatbot will cost fractions of a cent.

Now store the key in a Streamlit secrets file so your app can read it without hardcoding credentials.

  • In your terminal (still inside meal-prep-chatbot), create the secrets directory and file by running:

macOS

mkdir .streamlit
touch .streamlit/secrets.toml

Windows

mkdir .streamlit
New-Item .streamlit/secrets.toml
  • Open the file in VS Code by clicking File in the top menu bar, then Open File.
  • Navigate to your meal-prep-chatbot/.streamlit folder and select secrets.toml.
  • Paste the following into the file, replacing your-api-key-here with the key you just copied:
OPENAI_API_KEY = "your-api-key-here"

Why a secrets.toml file?

Streamlit has a built-in secrets management system. Any key you place in .streamlit/secrets.toml is accessible in your code via st.secrets["OPENAI_API_KEY"]. This keeps your key out of your source code.

  • Save the file with Cmd+S (macOS) or Ctrl+S (Windows).

Never commit this file

The .streamlit/secrets.toml file contains your API key. If you ever push this project to GitHub, add .streamlit/secrets.toml to your .gitignore file.

Finally, create the empty app file you will build in the next step.

  • Create app.py by running:
touch app.py
  • Confirm your project structure by running:
ls -a

You should see .streamlit, app.py, and venv in the output.

✔️ Awesome, I've got everything!

Great. Double check you've saved your secrets file.

ⓧ I'd like to double check the full code

Here's what your .streamlit/secrets.toml file should look like (with your own key in place of the placeholder):

OPENAI_API_KEY = "your-api-key-here"

Seeing a file or directory error?

Make sure you are inside the meal-prep-chatbot folder when running these commands. Check your current directory by running:

pwd

Help me fix a file creation error in my project folder

Your environment is ready. Next up, you'll build the core chat logic that sends messages to OpenAI and streams back responses.

Build the Core Chat Logic

Your environment is set up and ready to go. Now it's time to give your chatbot a brain.

You'll connect your app to OpenAI's language model and write a system prompt that shapes how the AI responds. By the end of this step, your chatbot will know it's a meal prep expert.

In this step, get ready to:
  • Set up the OpenAI client to connect your app to the API.
  • Write a system prompt that defines the chatbot's personality and expertise.
Set up the OpenAI client

The OpenAI client is the connection between your Python code and OpenAI's servers. It uses the API key you saved in secrets.toml to authenticate every request.

  • Open app.py in VS Code and add the following code:
import streamlit as st
from openai import OpenAI

client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

What does this code do?

  • import streamlit as st imports the Streamlit library, which you'll use to build the chat interface.
  • from openai import OpenAI imports the OpenAI class from the Python SDK.
  • client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"]) creates a client instance that reads your API key from Streamlit's built-in secrets manager.

Why st.secrets instead of a .env file?

Streamlit has its own built-in secrets management system via .streamlit/secrets.toml. This is simpler than using a separate library like python-dotenv because Streamlit already knows how to read the file. No extra setup needed.

You won't see a change yet. The next chunk adds the system prompt that gives your chatbot its personality.

Seeing ModuleNotFoundError?

  • Make sure your virtual environment is activated. You should see (venv) at the start of your terminal prompt.
  • If it's not activated, run the activation command from Step 1 again, then re-run pip install openai streamlit.

Help me fix a ModuleNotFoundError for openai in my Python project.

Write the system prompt

A system prompt is a set of instructions that tells the LLM how to behave before the user says anything. It defines the chatbot's personality, expertise, and response rules.

  • In app.py, add the following code below the client line:
SYSTEM_PROMPT = """You are a friendly and knowledgeable meal prep assistant. Your job is to help users plan their weekly meals, create grocery lists, and provide prep instructions.

Rules:
- Always ask clarifying questions if the user hasn't specified: number of people, budget, dietary restrictions, or how many days to prep for.
- Format meal plans clearly with days, meals (breakfast, lunch, dinner), and snacks.
- Include a consolidated grocery list at the end of each plan.
- Provide estimated costs when possible.
- Keep recipes simple and batch-cooking friendly.
- When suggesting changes, only modify what the user asked about and keep the rest of the plan intact.
- Use metric and imperial measurements.
"""

What does this system prompt do?

This prompt gives the AI a clear role (meal prep assistant) and a set of rules that shape every response. Without it, the model would give generic answers with no structure.

  • The first sentence sets the role and expertise area.
  • The rules list enforces specific behaviours. The AI will ask clarifying questions, format plans consistently, and include grocery lists automatically.
  • The "only modify what the user asked about" rule prevents the AI from rewriting an entire plan when you ask for one small change.
  • Save app.py.

You won't see any output yet. The system prompt is used when the chatbot sends messages to OpenAI, which you'll wire up in the next step.

Seeing a SyntaxError?

  • Check that your triple quotes match. The prompt starts and ends with """ (three double-quote characters).
  • Make sure there's no stray quote or backslash inside the prompt text that closes the string early.

Help me fix a SyntaxError in my Python multi-line string.

✔️ Awesome, I've got everything!

Great. Double check you've saved app.py and move on to the next step.

ⓧ I'd like to double check the full code

Here's the complete app.py so far. Compare it against your file:

import streamlit as st
from openai import OpenAI

client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

SYSTEM_PROMPT = """You are a friendly and knowledgeable meal prep assistant. Your job is to help users plan their weekly meals, create grocery lists, and provide prep instructions.

Rules:
- Always ask clarifying questions if the user hasn't specified: number of people, budget, dietary restrictions, or how many days to prep for.
- Format meal plans clearly with days, meals (breakfast, lunch, dinner), and snacks.
- Include a consolidated grocery list at the end of each plan.
- Provide estimated costs when possible.
- Keep recipes simple and batch-cooking friendly.
- When suggesting changes, only modify what the user asked about and keep the rest of the plan intact.
- Use metric and imperial measurements.
"""

Your chatbot now has its identity and rules. Next up, you'll build the chat interface so users can actually talk to it.

Create the Chat Interface

Your chatbot has a brain (the system prompt) and a connection to OpenAI, but no way for anyone to actually talk to it.

In this step, you'll build the user-facing chat interface using Streamlit's built-in chat components. These components give you message bubbles, a text input bar, and streaming responses with just a few lines of Python.

In this step, get ready to:
  • Configure your app's page title and layout.
  • Set up conversation memory with session state.
  • Build the chat loop that sends messages to OpenAI and streams responses back.
Add page config and title

Every Streamlit app needs a page configuration to set the browser tab title, favicon, and layout. This goes at the very top of your script, before any other Streamlit calls.

  • In app.py, find the blank line between your imports and the client = OpenAI(...) line.
  • Add the following code on that blank line, keeping a blank line between it and the client line below:
# Configure the browser tab title, favicon, and page layout
st.set_page_config(page_title="Meal Prep AI", page_icon="\ud83e\udd57", layout="centered")
st.title("\ud83e\udd57 Meal Prep AI Chatbot")

What does this code do?

st.set_page_config sets the browser tab title to "Meal Prep AI", adds a salad emoji as the favicon, and constrains the page content to a centered column.

st.title renders a large heading at the top of the app so users immediately know what the tool does.

Initialize session state and build the chat display

Streamlit reruns your entire script every time the user interacts with the app. Without session state, every message would disappear on the next interaction.

  • In app.py, scroll to the bottom of the file (below the closing """ of your SYSTEM_PROMPT).
  • Add the following code below SYSTEM_PROMPT:
# Initialize conversation history in session state
if "messages" not in st.session_state:
    st.session_state.messages = []

# Display all previous messages in the chat
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

What does this code do?

The if "messages" not in st.session_state check creates an empty list the first time the app loads. On every rerun, it skips creation because the list already exists.

The for loop iterates through all stored messages and renders each one inside a chat bubble using st.chat_message. The role value ("user" or "assistant") controls which side of the chat the bubble appears on.

  • Save app.py.

You won't see a change yet because the app isn't running. The next chunk completes the chat interface.

Add the chat input and connect it to OpenAI

This is the core interaction loop. When a user types a message, the app sends it (along with the full conversation history) to OpenAI and streams the response back in real time.

  • In app.py, add the following code directly below the display loop you just wrote:
# Accept user input and generate AI response
if prompt := st.chat_input("What meals would you like to prep?"):
    # Add user message to history and display it
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    # Generate and stream the assistant's response
    with st.chat_message("assistant"):
        stream = client.chat.completions.create(
            model="gpt-4.1-nano",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
            ] + [
                {"role": m["role"], "content": m["content"]}
                for m in st.session_state.messages
            ],
            stream=True,
        )
        response = st.write_stream(stream)

    # Save the assistant's response to history
    st.session_state.messages.append({"role": "assistant", "content": response})

What does this code do?

st.chat_input renders a text box at the bottom of the page. The walrus operator (:=) assigns the user's input to prompt and evaluates to True when the user submits something.

The app appends the user's message to st.session_state.messages, then passes the full conversation history (plus the system prompt) to client.chat.completions.create. Setting stream=True means the response arrives token by token instead of all at once.

st.write_stream renders those tokens with a typewriter effect and returns the complete text once streaming finishes. That final text gets saved to session state so it appears on the next rerun.

  • Save app.py.

Your file is now complete. You will run and test it in the next step.

Seeing a syntax error on the walrus operator?

The := operator requires Python 3.8 or higher. If you see a syntax error on that line, check your Python version with python3 --version. This project requires Python 3.9+.

Also make sure the indentation matches exactly. The with st.chat_message("assistant"): block must be inside the if prompt block (indented one level in).

help me debug a syntax error in my Streamlit chat app

✔️ Awesome, I've got everything!

Great. Double check you've saved app.py and move on to the next step where you'll run the chatbot.

ⓧ I'd like to double check the full code

Here is the complete app.py file at the end of this step:

import streamlit as st
from openai import OpenAI

st.set_page_config(page_title="Meal Prep AI", page_icon="🥗", layout="centered")
st.title("🥗 Meal Prep AI Chatbot")

client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

SYSTEM_PROMPT = """You are a friendly and knowledgeable meal prep assistant. Your job is to help users plan their weekly meals, create grocery lists, and provide prep instructions.

Rules:
- Always ask clarifying questions if the user hasn't specified: number of people, budget, dietary restrictions, or how many days to prep for.
- Format meal plans clearly with days, meals (breakfast, lunch, dinner), and snacks.
- Include a consolidated grocery list at the end of each plan.
- Provide estimated costs when possible.
- Keep recipes simple and batch-cooking friendly.
- When suggesting changes, only modify what the user asked about and keep the rest of the plan intact.
- Use metric and imperial measurements.
"""

if "messages" not in st.session_state:
    st.session_state.messages = []

for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

if prompt := st.chat_input("What meals would you like to prep?"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    with st.chat_message("assistant"):
        stream = client.chat.completions.create(
            model="gpt-4.1-nano",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
            ] + [
                {"role": m["role"], "content": m["content"]}
                for m in st.session_state.messages
            ],
            stream=True,
        )
        response = st.write_stream(stream)

    st.session_state.messages.append({"role": "assistant", "content": response})

Your chat interface is built and ready to go. Next up, you'll run the app and have your first conversation with your meal prep chatbot.

Test Your Chatbot

In the last step, you built the full chat interface with streaming responses and conversation history.

Now it's time to see your chatbot in action. You'll launch the Streamlit dev server, have a real conversation with your meal prep AI, and confirm that it remembers context across messages.

In this step, get ready to:
  • Run the Streamlit app locally in your browser.
  • Test a meal plan conversation with specific parameters.
  • Verify conversation memory with a follow-up question.
Run the Streamlit app

Streamlit includes a built-in development server that hosts your app locally and opens it in the browser.

  • Make sure your virtual environment is still active in the terminal (you should see (venv) at the start of your terminal prompt).
  • Start the app by running this command:
streamlit run app.py

Your default browser opens automatically to http://localhost:8501. You should see the page title "Meal Prep AI Chatbot" and a chat input field at the bottom.

What does the terminal show?

Your terminal displays a local URL and a network URL. The app stays running in the terminal until you stop it with Ctrl+C. Leave it running for the rest of this step.

Don't see the app open?

If the browser didn't open automatically, copy the Local URL shown in your terminal and paste it into your browser manually.

If you see a "command not found" error, your virtual environment may not be active. Run source venv/bin/activate (macOS) or venv\Scripts\activate (Windows) and try again.

If you see an API key error, double check that your .streamlit/secrets.toml file contains your actual OpenAI API key (not the placeholder text).

Help me troubleshoot why my Streamlit app isn't running

Ask for a meal plan

Your chatbot is designed to generate structured meal plans based on specific parameters like budget, number of people, and number of days.

  • Click the chat input field at the bottom of the page (it says "What meals would you like to prep?").
  • Type this message and press Enter:
Create a 5-day meal plan for two people on a $75 weekly grocery budget

You should see the AI response stream in word by word with a typewriter effect. The response includes days broken out by meal (breakfast, lunch, dinner), recipe suggestions, and a consolidated grocery list with estimated costs.

Why does the response stream in?

Your code uses stream=True in the API call, which tells OpenAI to send the response in small chunks as it generates them. st.write_stream() renders each chunk as it arrives. This makes the chatbot feel responsive instead of making you wait for the full response.

Getting an error instead of a response?

If you see an authentication error, your API key in .streamlit/secrets.toml may be incorrect. Copy a fresh key from your OpenAI dashboard, paste it between the quotes in the file, and refresh the browser page.

If you see a rate limit or quota error, your OpenAI account may not have credits available. Check your usage page at platform.openai.com.

Help me fix my OpenAI API error in Streamlit

Verify conversation memory

A chatbot without memory would treat every message as a brand new conversation. Your app passes the full message history to the API on every turn, so the AI can reference earlier messages.

  • In the same chat session, type a follow-up message that references the plan you just received:
Can you make the lunches cheaper and swap any chicken recipes for tofu?
  • Watch the response stream in.

The AI should modify only the lunches and chicken recipes from the previous plan, keeping everything else intact. This proves conversation memory is working.

How does conversation memory work here?

Every time you send a message, your code appends it to st.session_state.messages and sends the entire list to the OpenAI API. The AI sees the full history and can reference anything said earlier.

If you refresh the browser page, the conversation resets because session state is cleared. This is expected behaviour for a local Streamlit app.

AI ignoring the previous plan?

If the AI generates a completely new plan instead of modifying the previous one, you may have accidentally refreshed the page between messages. Refreshing clears the conversation history. Start a new conversation from the beginning.

Help me understand why my chatbot doesn't remember the conversation

Secret mission

Add Sidebar Preference Controls

Your chatbot works, but users have to type their dietary preferences every single conversation. What if the sidebar remembered their diet type, budget, and household size, and automatically shaped every AI response?

Clean Up Your Resources

Clean Up Your Resources

This project runs locally on your machine, so there are no ongoing cloud costs. The only potential cost comes from OpenAI API calls, which only happen when you actively run the chatbot.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • Your project folder on the Desktop (contains app.py, .streamlit/secrets.toml, and the venv virtual environment).
  • Your OpenAI API key (stored in your OpenAI account and referenced in your secrets file).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your chatbot or want to build on it further.

  • Your project files stay on your Desktop.
  • Your OpenAI API key remains active, but you are only charged when you make API calls by running the app.
  • No background processes are running. The Streamlit server only starts when you run streamlit run app.py.

Pause - I'll come back to this later

Stop any running processes to free up your terminal. Your files and API key stay intact for when you return.

  • If your Streamlit server is still running, press Ctrl+C in the terminal to stop it.
  • If your virtual environment is still active, deactivate it by running:
deactivate
  • Your project folder and API key remain ready for next time.

Delete - I don't want to use this again

Remove all project files and revoke your API key so nothing lingers on your machine or OpenAI account.

  • If your Streamlit server is still running, press Ctrl+C in the terminal to stop it.
  • Deactivate your virtual environment by running:
deactivate
  • Delete your project folder by running the appropriate command for your system.

macOS

rm -rf ~/Desktop/meal-prep-ai

Windows

rmdir /s /q %USERPROFILE%\Desktop\meal-prep-ai

Why revoke the key?

Deleting the key ensures no one can use it to make API calls on your account. If you created the key specifically for this project, revoking it is good security hygiene.

Nice Work!

Nice Work!

You did it. You built an AI-powered meal prep chatbot from scratch using Python, the OpenAI API, and Streamlit.

Here's what you accomplished:

  • Built a working Streamlit web app with a professional chat interface that streams responses in real time.
  • Connected to the OpenAI API using the modern Python SDK to generate meal plans on demand.
  • Crafted a custom system prompt that turns a general-purpose LLM into a meal prep specialist with conversation memory.
  • Secret Mission: Added sidebar controls for diet type, budget, and household size that automatically shape every response.

Ready to quiz yourself?