A simple, complete Retrieval-Augmented Generation (RAG) project built with plain Python files (no notebooks), ChromaDB, sentence-transformers, and OpenRouter, wrapped in a Streamlit UI.
documents
-> preprocessing
-> chunking
-> vector representation
-> vector store
-> context retrieval
-> prompting
-> Streamlit UI
.
├── 01_documents.py # Stage 1: load raw documents (.txt, .md, .pdf)
├── 02_preprocessing.py # Stage 2: clean and normalize text
├── 03_chunking.py # Stage 3: split text into overlapping chunks
├── 04_vector_representation.py # Stage 4: embed chunks (sentence-transformers)
├── 05_create_chroma_store.py # Stage 5: build/persist the ChromaDB vector store
├── 06_retrieve_context.py # Stage 6: retrieve relevant chunks for a question
├── 07_prompting.py # Stage 7: build prompt + call OpenRouter (LLM)
├── streamlit_app.py # Streamlit UI wiring every stage together
├── requirements.txt
├── .gitignore
├── .env.example # Template only — never commit your real .env
├── data/
│ └── sample_document.txt # Example source document
└── README.md
Each numbered file can also be run directly (e.g. python 03_chunking.py) to see
that pipeline stage working in isolation — useful for debugging and for the lab
sequence walkthrough.
Because Python module names can't start with a digit, the numbered stage files
are loaded dynamically with importlib wherever one stage needs another
(e.g. 03_chunking.py loads 02_preprocessing.py). streamlit_app.py loads
07_prompting.py as a module named rag, and stage 7 internally loads stage 6,
which loads stage 5, and so on down to stage 1. You never need to do this
manually — it's already wired up in every file.
Prerequisites: Python 3.10+
# 1. Clone your repository (or unzip the project)
git clone <your-repo-url>
cd <your-repo-folder>
# 2. Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Configure your API key locally
cp .env.example .env
# then open .env and paste your real OpenRouter key into OPENROUTER_API_KEYGet a free OpenRouter API key at https://openrouter.ai/keys.
python 01_documents.py
python 02_preprocessing.py
python 03_chunking.py
python 04_vector_representation.py
python 05_create_chroma_store.py
python 06_retrieve_context.py
python 07_prompting.pystreamlit run streamlit_app.pyThen open the local URL Streamlit prints (usually http://localhost:8501), click "Build / Rebuild Vector Store" in the sidebar, and start asking questions.
- Never write your real API key inside any
.pyfile. - Never commit or upload your real
.envfile —.gitignorealready excludes it. - Locally, keys are read from environment variables (via
.env+python-dotenv). - On Streamlit Cloud, keys are read from Streamlit secrets (TOML), not from files.
git init
git add .
git commit -m "Initial commit: complete RAG project"
git branch -M main
git remote add origin https://github.com/<your-username>/<your-repo-name>.git
git push -u origin mainBefore pushing, double-check:
-
.envis not staged (git statusshould not show it —.gitignoreblocks it) - No API key appears anywhere in any tracked file
-
chroma_store/is not committed (it's local-only, ignored by.gitignore)
-
Push your repository to GitHub (see above).
-
Go to https://share.streamlit.io and sign in.
-
Click "New app", select your repository, branch, and set the main file path to
streamlit_app.py. -
Before (or after) deploying, open your app, click "Manage app" → "Secrets", and add:
OPENROUTER_API_KEY = "your_openrouter_key_here" OPENROUTER_MODEL = "openai/gpt-4o-mini"
-
Click Deploy.
streamlit_app.pyautomatically reads these secrets and injects them into the RAG pipeline at runtime — no code changes needed. -
Once deployed, open the app, build the vector store from the sidebar, and test a question to confirm everything works end-to-end.
- All required Python files exist (
01_documents.py→07_prompting.py,streamlit_app.py). -
requirements.txtexists. - Real API key is not included in the ZIP file or GitHub repository.
- Streamlit secrets are configured in valid TOML format at deploy time.
- The Streamlit app runs successfully.
- The answer uses retrieved context (the LLM is only called when context is found).
- The answer cites sources (filenames shown alongside every generated answer).
- Embeddings run locally (
sentence-transformers, modelall-MiniLM-L6-v2) so the project only needs one paid API key (OpenRouter, for generation) — not two. - ChromaDB is used as the vector store, persisted to a local
chroma_store/folder. - OpenRouter is used for the generation step, defaulting to
openai/gpt-4o-mini, matching the API key rules in the instructions. - If retrieval returns no chunks, the app never calls the LLM and instead shows a clear "not enough information" message — this guarantees answers are always grounded in retrieved documents when they are given at all.