A Retrieval-Augmented Generation (RAG) chatbot built for Asia Motors Auto Garage. It answers customer questions (services offered, pricing, hours, brands serviced, common car issues, etc.) using information extracted from a business PDF, and responds in a warm, reassuring, garage-front-desk tone powered by an LLM.
The backend is a FastAPI service that embeds and indexes a business PDF into a vector store, retrieves relevant context for each incoming question, and generates a friendly, on-brand answer using Groq's Llama 3.3 70B model. Conversation history is persisted per session in PostgreSQL, and a minimal HTML widget (ask.html) is included as an embeddable chat frontend.
- Features
- Architecture
- Tech Stack
- Project Structure
- Prerequisites
- Setup & Installation
- Environment Variables
- Running Locally
- Running with Docker
- API Reference
- Deployment
- 📄 PDF-based answers — loads
data/business.pdfon startup, extracts both text and tables (viapdfplumber), and answers only from that context. - 🧠 Semantic search — chunks the PDF with
langchain-text-splittersand stores embeddings in a local Chroma vector store. - 🌐 Jina AI embeddings — text is embedded using the
jina-embeddings-v3model via the Jina Embeddings API. - ⚡ Fast LLM responses — uses Groq's hosted
llama-3.3-70b-versatilemodel for low-latency chat completions. - 💬 Conversation memory — chat turns are stored per
session_idin PostgreSQL so the bot has short-term memory across a session (last 10 messages). - 🎭 On-brand persona — a carefully crafted system prompt gives the bot a casual, reassuring "garage front desk" tone, with rules for when to use a reassuring opener vs. a plain informational answer.
- 🔌 REST API — a single
POST /askendpoint that any frontend (web widget, WhatsApp bot, etc.) can call. - 🖥️ Drop-in chat widget —
ask.htmlis a minimal, dependency-free HTML/JS snippet that can be embedded on any website. - 🐳 Containerized — ships with a
Dockerfilefor easy deployment.
| Layer | Technology |
|---|---|
| API framework | FastAPI + Uvicorn |
| LLM inference | Groq — llama-3.3-70b-versatile |
| Embeddings | Jina AI — jina-embeddings-v3 |
| Vector store | Chroma (via LangChain) |
| PDF parsing | pdfplumber |
| Text chunking | LangChain RecursiveCharacterTextSplitter |
| Chat history storage | PostgreSQL via SQLAlchemy |
| Frontend widget | Vanilla HTML/JS (ask.html) |
| Containerization | Docker (python:3.11-slim) |
asiamotors-chatbot/
├── app.py # FastAPI app: PDF ingestion, embeddings, /ask endpoint
├── ask.html # Minimal embeddable chat widget (frontend)
├── data/
│ └── business.pdf # Source document the bot answers from (not committed by default)
├── requirements.txt # Python dependencies
├── Dockerfile # Container build definition
└── .env # Local environment variables (not committed — see below)
- Python 3.11+
- A PostgreSQL database (local or hosted, e.g. Render/Supabase/Neon)
- A Groq API key (for LLM chat completions)
- A Jina AI API key (for text embeddings)
- Docker (optional, for containerized runs)
-
Clone the repository
git clone https://github.com/Krupa-Srinivasan/asiamotors-chatbot.git cd asiamotors-chatbot -
Create a virtual environment
python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate
-
Install dependencies
pip install -r requirements.txt
-
Add your source document Place the garage's business/FAQ document at:
data/business.pdfThis PDF is the sole source of truth the bot uses to answer questions.
-
Configure environment variables (see below).
Create a .env file in the project root:
JINA_API_KEY=your_jina_api_key_here
GROQ_API_KEY=your_groq_api_key_here
DATABASE_URL=postgresql://user:password@host:5432/garagedb| Variable | Description |
|---|---|
JINA_API_KEY |
API key for Jina AI's embeddings endpoint |
GROQ_API_KEY |
API key for Groq's chat completions API |
DATABASE_URL |
PostgreSQL connection string used to store chat history |
uvicorn app:app --host 0.0.0.0 --port 8000 --reloadOn startup, the app will:
- Connect to PostgreSQL and create the
chat_messagestable if it doesn't exist. - Load and parse
data/business.pdf. - Chunk the content, generate embeddings, and build the Chroma vector store.
Once running, the API is available at http://localhost:8000, with interactive docs at http://localhost:8000/docs.
docker build -t asiamotors-chatbot .
docker run -p 8000:8000 \
-e JINA_API_KEY=your_jina_api_key \
-e GROQ_API_KEY=your_groq_api_key \
-e DATABASE_URL=postgresql://user:password@host:5432/garagedb \
asiamotors-chatbotThe container installs dependencies from requirements.txt, copies the app, and starts Uvicorn on port 8000.
Ask the chatbot a question within a given session.
Request body
{
"session_id": "website_user_123",
"question": "My brakes are squeaking, can you fix it?"
}| Field | Type | Description |
|---|---|---|
session_id |
string | Unique identifier for the conversation (used to fetch/store chat history) |
question |
string | The customer's question |
Response
{
"question": "My brakes are squeaking, can you fix it?",
"answer": "No worries, we can sort that — brake repairs are a piece of cake for us. Bring it by Asia Motors Auto Garage, Padi."
}Error response (vector store not yet initialized)
{ "error": "Chatbot not ready." }A minimal, framework-free chat widget that can be dropped into any webpage. It posts questions to a deployed instance of the API and appends the conversation to the page.
<div id="chat"></div>
<input id="question" placeholder="Ask a question">
<button onclick="askQuestion()">Send</button>By default, it points to a deployed Render URL. Update the fetch() URL inside ask.html to match your own deployment before using it in production:
const response = await fetch("https://<your-deployment-url>/ask", { ... });- Ingestion (startup):
load_pdf()readsdata/business.pdfpage by page usingpdfplumber, extracting both prose text and any tables (converted to pipe-delimited rows). Each page/table becomes a LangChainDocument. - Chunking: Documents are split into ~1000-character chunks with 200-character overlap for better retrieval granularity.
- Embedding & indexing: Each chunk is embedded via the Jina Embeddings API and stored in a local Chroma vector database (
./chroma_data). - Retrieval: On each
/askrequest, the top 3 most similar chunks to the user's question are retrieved. - Persona-driven prompting: A detailed system prompt instructs the model to act as a friendly Asia Motors front-desk assistant — using a reassuring tone for problem reports, a plain/direct tone for informational questions (hours, brands, pricing), asking at most one clarifying question when needed, and always staying concise (2–4 sentences).
- Generation: The retrieved context, recent chat history (last 10 messages), and the new question are sent to Groq's
llama-3.3-70b-versatilemodel to generate the reply. - Persistence: Both the user's question and the bot's answer are saved to the
chat_messagestable, keyed bysession_id, so future turns in the same session retain context.
The project is set up to deploy easily as a container-based web service (e.g. Render, Railway, Fly.io, or any Docker-compatible host):
- Push the repo to your host of choice.
- Set the environment variables (
JINA_API_KEY,GROQ_API_KEY,DATABASE_URL) in the host's dashboard. - Ensure the host builds from the included
Dockerfile(or runsuvicorn app:app --host 0.0.0.0 --port $PORT). - Update
ask.htmlto point at your deployed URL.