A customer support chatbot for a coffee store running locally with FastAPI + Ollama. This project uses a RAG-first architecture (Retrieval-Augmented Generation) where it looks up the database first before refining the answer with the LLM.
- Python 3.11 (recommended) and virtual environment
- macOS/Linux:
python -m venv .venv && source .venv/bin/activate - Windows (PowerShell):
python -m venv .venv; .\\.venv\\Scripts\\Activate.ps1
- macOS/Linux:
- Clone repository
git clone https://github.com/hidatara-ds/Customer-Support-Chatbot-Project.git cd Customer-Support-Chatbot-Project - Install dependencies
pip install -r requirements.txt # Or use make make install - Configure environment
# Copy example env file cp .env.example .env # Edit .env with your configuration
- Install Ollama and local LLM model
- Install Ollama: see official documentation (
https://ollama.com) - Run server:
ollama serve - Pull model:
ollama pull llama3.2:3b
- Install Ollama: see official documentation (
- Setup database
- Default: SQLite (automatically created and seeded on first run)
- Optional: MySQL (set ENV
DATABASE_URL, examplemysql+pymysql://root:root@127.0.0.1:3306/shoe_support)
- Run application (REST API on localhost)
uvicorn app.main:app --reload # Or use make make dev # API : http://localhost:8000 # Docs : http://localhost:8000/docs (Swagger UI for API testing) # OpenAPI : http://localhost:8000/openapi.json (JSON spec for BE/FE) # Web UI : http://localhost:8000/web
- Optional (bonus): Docker
docker compose up --build # Or use make make docker-up # Services: api + db (MySQL 8) + ollama
graph TD
A[User] -->|Message| B(Intent Detection)
B -->|Match| C{DB Lookup}
B -->|No Match| D[LLM]
C -->|Data Found| E[Tool Context]
C -->|No Data| D
E --> D
D -->|Refined Response| F[Response to User]
Purpose: store chat history so conversation context can be reused by the LLM.
- Challenge-required table:
chat_history- Columns:
id(primary key),user_message,bot_response,timestamp
- Columns:
Example SQL schema:
CREATE TABLE IF NOT EXISTS chat_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_message TEXT NOT NULL,
bot_response TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);Note: This repository implementation already stores conversations in the conversations table (with user/assistant roles) and also has catalog tables (products, product_sizes) and orders (orders).
- FastAPI: REST API framework
- Uvicorn: ASGI server
- SQLAlchemy: ORM/database access
- PyMySQL: MySQL driver (optional)
- Pydantic: request/response schema validation
- Requests: HTTP client (calling Ollama API)
- python-dotenv: load environment variables
- Ollama: local LLM runtime
- pytest: testing framework
- pytest-cov: test coverage reporting
(See requirements.txt for complete list.)
- Llama 3.2 (3B) via Ollama (running locally)
- Reason: lightweight, open-source, and meets challenge requirements for local LLM
- Order status
- Examples: "Where is my order?", "status of sela's order", "check order #12"
- Product information
- Examples: "What are the advantages of Air Max 90?", "details of Ultraboost 22"
- Size availability & stock per size
- Examples: "How much stock for Ultraboost 22 size 42?", "what sizes are available?"
- Warranty policy
- Examples: "How do I claim warranty?"
- Note: can be expanded for other questions as needed.
Demo users (seed) for order checking: alice, bob, carol. When testing order status/delivery, set the user field in the payload to match these names.
- Order Status Lookup
- Chatbot calls external function to check order status based on intent (regex) and/or
order_idextracted from message. Iforder_idis not available, system uses the last order belonging touserin the payload. - Standard status output:
processing,shipped,delivered, along with product name. - Example payload:
{ "user": "alice", "message": "order status" }
- Chatbot calls external function to check order status based on intent (regex) and/or
- Catalog Lookup (expandable)
- Product details, available sizes, stock per size.
- Warranty Info (expandable)
- Returns fixed warranty policy text.
Additional: Swagger docs at http://localhost:8000/docs can be used for interactive endpoint testing, and OpenAPI JSON specification is available at http://localhost:8000/openapi.json for BE/FE integration needs (generate client or import to Postman/Insomnia).
- Endpoints:
GET /health,GET /products,GET /orders/{user},POST /chat - Docs:
http://localhost:8000/docs(interactive testing), OpenAPI:/openapi.json - UI:
http://localhost:8000/web
- RAG focus: catalog data from DB, LLM as complement
- Simple web UI at
/web, configuration via ENV - Ready-to-use intents: order status, product info, size/stock, warranty
- Comprehensive error handling and logging
- Input validation and security
- Health check endpoint with database status
- Test suite with pytest
app/ # Main application code
├── main.py # FastAPI app and routes
├── db.py # Database operations
├── models.py # SQLAlchemy models
├── schemas.py # Pydantic schemas
├── utils.py # Utility functions
├── config.py # Configuration
└── llm.py # LLM integration
tests/ # Test suite
├── test_api.py # API endpoint tests
└── test_utils.py # Utility function tests
frontend/ # Web UI
└── index.html
data/ # Database files
└── database.mysql.sql
.env.example # Environment variables template
docker-compose.yml # Docker services configuration
Dockerfile # Container image definition
Makefile # Common commands
pytest.ini # Test configuration
requirements.txt # Python dependencies
CONTRIBUTING.md # Contribution guidelines- Python 3.11+, Ollama (model
llama3.2:3b), SQLite (default) / MySQL (optional) - Main ENV variables:
DATABASE_URL: Database connection stringOLLAMA_HOST: Ollama server URLOLLAMA_MODEL: LLM model nameMAX_HISTORY_MESSAGES: Number of messages to keep in contextLOG_LEVEL: Logging level (INFO, DEBUG, etc.)
- Copy
.env.exampleto.envand configure as needed
# Install dependencies
make install
# Run development server with auto-reload
make dev
# Or manually
uvicorn app.main:app --reload# Start all services (API, MySQL, Ollama)
make docker-up
# Or manually
docker compose up --build
# Stop services
make docker-down- API: http://localhost:8000
- Swagger UI: http://localhost:8000/docs
- Web UI: http://localhost:8000/web
- OpenAPI Spec: http://localhost:8000/openapi.json
Run tests with:
# Run all tests
pytest tests/ -v
# Or use make command
make test
# Run with coverage report
make test-covTest coverage includes:
- API endpoint validation
- Input validation
- Tool function logic
- Error handling
make install # Install dependencies
make dev # Run development server
make test # Run tests
make test-cov # Run tests with coverage
make clean # Clean cache files
make run # Run production server
make docker-up # Start Docker containers
make docker-down # Stop Docker containersGET /healthReturns application health status and database connectivity.
GET /productsReturns list of all available products.
GET /orders/{user}Returns latest order for specified user.
POST /chatMain chat endpoint for customer support interactions.
Request:
{
"user": "alice",
"message": "How much stock for size 42 Ultraboost 22?"
}Response:
{
"answer": "Ultraboost 22 size 42 stock: 4 pairs."
}Example cURL:
curl -s http://localhost:8000/chat \
-H 'Content-Type: application/json' \
-d '{"user":"alice","message":"What types of shoes are available?"}'- Open
http://localhost:8000/docsto try endpoints interactively (Swagger UI) - OpenAPI specification available at
http://localhost:8000/openapi.json - Useful for:
- BE/FE integration (generate client with tools like
openapi-generator) - Import to Postman/Insomnia for automatic request collection
- BE/FE integration (generate client with tools like
Example fetching OpenAPI JSON:
curl -s http://localhost:8000/openapi.json | jq '.info, .paths["/chat"]'- Access
http://localhost:8000/web - Input stays at bottom of screen, suitable for mobile
- Quick prompt examples available below input
- Main tables:
products,product_sizes(stock per size),orders,conversations - Seed automatically creates 16+ products from various categories/brands, stock per size, and sample orders for users like
alice,bob
- Intent and extraction (regex/heuristic) in
app/utils.py - Catalog/stock queries in
app/db.py(SQLAlchemy) - Tool answers (database) are formatted and prioritized
- If not answered by tool, combined prompt (history + tool context) is sent to Ollama via
app/llm.py - Conversation history stored in
conversationstable; number sent to LLM limited byMAX_HISTORY_MESSAGES - Comprehensive logging throughout the application
- Error handling with graceful fallbacks
- Order Status Lookup: check status based on
order_idor user's last order - Catalog Lookup: product details, available sizes, stock per size
- Warranty Info: fixed warranty policy text
Example order status test payload:
{ "user": "alice", "message": "order status" }Demo users: alice, bob, carol
- Questions requiring precise data: order status, stock per size, size availability, price list, category/brand/size filter → tool is called
- General questions (how to choose size, care tips, casual model suggestions) → answered directly by LLM (concise, empathetic), without fabricating numbers
Available sample users: alice, bob, carol. To check order status/delivery, set the user column in payload to match these user names.
Examples:
curl -s http://localhost:8000/chat \
-H 'Content-Type: application/json' \
-d '{"user":"alice","message":"check my order"}'
curl -s http://localhost:8000/chat \
-H 'Content-Type: application/json' \
-d '{"user":"bob","message":"order status"}'Helper endpoint:
GET /orders/{user}→ get last order foralice|bob|carol
POST /chat
{
"user": "alice",
"message": "How much stock for Ultraboost 22 size 42?"
}
Response:
{
"answer": "Ultraboost 22 size 42 stock: 4 pairs. Need help checking colors or similar alternatives?"
}- API version: see
app/main.py→FastAPI(..., version="1.5.0") - Static UI mounted at
/webwithStaticFiles - Logging configured via
LOG_LEVELenvironment variable - All database operations include error handling
- Ensure Ollama is running and model is available (
OLLAMA_HOSTis correct). In Docker,ollamaservice automatically exposes11434 - For local MySQL, ensure DSN
mysql+pymysql://...is valid and user has rights to create tables - If seed doesn't appear, delete SQLite file
data/shoe_support.dband restart, or ensure DB is empty - Check logs for detailed error messages (set
LOG_LEVEL=DEBUGfor verbose output) - Use health check endpoint
/healthto verify database connectivity
See CONTRIBUTING.md for guidelines on how to contribute to this project.
See LICENSE file.
- Environment Configuration: Added
.env.examplefor easy setup - Enhanced Error Handling: Comprehensive error handling throughout the application
- Logging: Structured logging with configurable log levels
- Input Validation: Improved validation with Pydantic schemas
- Health Checks: Enhanced health endpoint with database status
- Testing: Added pytest test suite with coverage reporting
- Docker: Added docker-compose.yml for easy deployment
- Documentation: Added CONTRIBUTING.md and improved README
- Developer Tools: Added Makefile for common commands
- Code Quality: Better code organization and documentation
.env.example- Environment configuration templatedocker-compose.yml- Multi-service Docker setuptests/- Test suite with pytestMakefile- Common development commandsCONTRIBUTING.md- Contribution guidelinespytest.ini- Test configuration- Enhanced logging throughout the application
- Better error messages and handling
- Improved code documentation
