A Retrieval-Augmented Generation (RAG) application that lets you ingest documents and ask natural language questions about their content. Built with durable workflow orchestration, local vector search, and LLM-powered answers.
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ Streamlit │──────▶│ Inngest │──────▶│ FastAPI │
│ Frontend │ event │ Dev Server │ invoke│ Workers │
└──────────────┘ └───────────────┘ └──────┬───────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ PDF Reader │ │ Embedding │ │ Groq │
│ (LlamaIdx) │ │ (MiniLM-L6) │ │ LLM (API) │
└─────────────┘ └──────┬──────┘ └─────────────┘
│
┌──────▼──────┐
│ Qdrant │
│ Vector DB │
└─────────────┘
- Ingest — Upload a document → text is extracted, chunked (800 chars, 200 overlap), embedded with
all-MiniLM-L6-v2, and stored in Qdrant. - Query — Ask a question → question is embedded, top-k similar chunks are retrieved from Qdrant, and a Groq-hosted Llama 3.1 model generates an answer grounded in those chunks.
- Orchestration — Inngest handles durable execution with automatic retries, throttling, and rate limiting.
RAG_PROJECT/
├── main.py # FastAPI app + Inngest function definitions (ingest & query)
├── data_loader.py # File reading, text chunking, and embedding logic
├── vector_db.py # Qdrant client wrapper (upsert & similarity search)
├── custom_types.py # Pydantic models for type-safe data passing between steps
├── streamlit_app.py # Streamlit UI for uploading PDFs and asking questions
├── pyproject.toml # Project metadata and dependencies
├── .env # Environment variables (API keys — not committed)
└── uploads/ # Uploaded Files stored here
- Python 3.14+
- uv (package manager)
- Qdrant running locally on port 6333
- Inngest Dev Server
- A Groq API key
git clone https://github.com/Alwazf99/RAG_PROJECT.git
cd RAG_PROJECT
uv syncCreate a .env file in the project root:
GROQ_API_KEY=<your-groq-api-key>docker run -p 6333:6333 qdrant/qdrantnpx inngest-cli@latest devuv run uvicorn main:app --reloaduv run streamlit run streamlit_app.py- Open the Streamlit app (default:
http://localhost:8501) - Upload a PDF file
- The ingestion pipeline runs automatically (chunking → embedding → storage)
- Type your question in the text input
- Choose how many chunks to retrieve (top-k)
- Click Ask — the answer appears with source references
| Decision | Rationale |
|---|---|
| Inngest for orchestration | Durable steps with automatic retries; throttle/rate-limit prevent overloading |
| Local embeddings (MiniLM) | Fast, free, no API calls needed for vectorization |
| Groq LLM | Extremely fast inference for Llama 3.1 via OpenAI-compatible API |
| Qdrant | Lightweight vector DB that runs locally with no setup overhead |
| Deterministic UUIDs | Re-ingesting the same PDF overwrites vectors instead of duplicating |
- Throttle: Max 2 ingestion runs per minute globally
- Rate Limit: Same PDF (
source_id) can only be re-ingested once every 4 hours
| Package | Purpose |
|---|---|
fastapi + uvicorn |
HTTP server exposing Inngest webhook |
inngest |
Durable workflow orchestration |
llama-index-core + llama-index-readers-file |
PDF parsing and text splitting |
sentence-transformers |
Local text embedding |
qdrant-client |
Vector database client |
openai |
OpenAI-compatible client (used for Groq) |
streamlit |
Web UI |
python-dotenv |
Environment variable loading |
MIT
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request