Quicky is a conversational food-ordering assistant for a fictional restaurant, Quant Eatery. It handles placing new orders (add/remove items, complete order) and tracking existing orders by order ID, entirely through natural language.
Stack: Dialogflow ES (NLU) → FastAPI (Python backend) → SQLite → HTML/CSS/JS website
(walkthrough: placing an order and tracking it)
- New Order : add multiple food items with quantities in one sentence ("2 pizzas and 1 mango lassi")
- Modify Order : add or remove items mid-conversation before checkout
- Complete Order : order is saved to the database and an order ID is returned
- Track Order : check delivery status using an order ID
- Session-aware conversation using Dialogflow contexts + a server-side in-progress order buffer
Why Dialogflow ES over Rasa/a raw LLM? This is a structured-action problem (order food, track order), not an open-ended generation problem, Dialogflow's intent/entity model plus built-in hosting and integrations got this to a working demo faster than self-hosting an NLU pipeline or wiring up an LLM for something it isn't needed for.
quant-eatery-chatbot/
├── main.py # FastAPI app, webhook entrypoint, intent router
├── db/
│ ├── create_db.py # schema + seed data
│ └── db_helper.py # DB read/write helpers
├── utils/
│ └── helper.py # session ID extraction, formatting helpers
├── frontend/ # website + chat widget embed
├── scripts/
│ └── view_db.py # dev utility to inspect DB contents
├── docs/ # demo gif, diagrams
├── .env.example
└── requirements.txt
git clone https://github.com/<your-username>/quant-eatery-chatbot.git
cd quant-eatery-chatbot
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txtCopy .env.example to .env and fill in:
DB_NAME=quant_eatery.db
NGROK_AUTH_TOKEN=your_ngrok_auth_token
python main.pyThis initializes the SQLite database (first run only) and opens an ngrok tunnel, printing a public HTTPS URL.
You have two options here, pick whichever suits you:
A ready-to-import agent export is included at dialogflow_agent/QuantEateryAgent.zip, with all intents, entities, and contexts already configured.
- Go to the Dialogflow ES Console → create a new agent.
- Open Settings (⚙️) → Export and Import → Import From Zip.
- Upload
QuantEateryAgent.zipand confirm (this overwrites the new agent with the imported one). - Enable webhook fulfillment under Fulfillment and paste in the ngrok URL printed when you run
main.py.
(Settings → Export and Import → Import From Zip)
If you'd rather build the agent yourself (recommended if you're learning Dialogflow, since this is what I did first):
- Create a Dialogflow ES agent and define the intents:
Default Welcome Intent,Default Fallback Intent,new.order - context: ongoing-order,order.add - context: ongoing-order,order.remove - context: ongoing-order,order.complete - context: ongoing-order,track.order,track.order - context: ongoing-tracking. - Add the
food-itemcustom entity (with synonyms) and use the system entity@sys.numberfor both thenumberparameter (quantities inorder.add) and theorder_idparameter (intrack.order - context: ongoing-tracking). - Set up all the settings for each intent, entity, and webhook exactly as described in
docs/dialogflow-agent-summary.txt— see the clip below for how input/output contexts and other params are saved per intent. - Enable webhook fulfillment for each intent and paste the ngrok URL printed when you run
main.pyinto Fulfillment → Webhook.
(Example: Sample order.add - context: ongoing-order intent with input, output context ongoing-order and required parameters)
Either way, once the agent is connected, test it in the Dialogflow console's built-in simulator, then embed the Web Demo <iframe> in frontend/index.html to use it on the website.
User: hi
Bot: Welcome! You can say New Order or Track Order.
User: new order
Bot: Starting a new order! Tell me items with quantity.
User: 2 pizzas and 1 mango lassi
Bot: So far you have: 2 pizza, 1 mango lassi. Anything else?
User: that's it
Bot: Awesome. We have placed your order. Here is your order id # 260710143210.
Your order total is 500 which you can pay at the time of delivery!
User: track order
Bot: Please enter your order ID.
User: 260710143210
Bot: The order status for order id: 260710143210 is: in transit
- In-progress orders are stored in an in-memory Python dict, so state is lost on server restart and won't scale across multiple backend instances.
- ngrok's free tier URL changes on every restart, requiring the Dialogflow webhook URL to be updated manually.
- No payment integration, order total is quoted for pay-on-delivery only.
order_idis generated from a timestamp (second precision), so two orders placed in the same second could theoretically collide.
- Add a "Store Hours" intent (static response, no webhook)
- Persist in-progress orders to a lightweight store (e.g. Redis) instead of an in-memory dict
- Swap timestamp-based order IDs for DB auto-increment or UUID
- Deploy backend somewhere persistent (Render/Railway) to drop the ngrok dependency
This project was built to learn Dialogflow ES end-to-end: intents, entities, contexts, and webhook fulfillment, paired with a FastAPI backend and SQLite storage.
MIT : see LICENSE for details.