https://cortex-rag-ui.onrender.com
A source-grounded research workspace for turning a selected document set into cited answers, briefs, memos, and claims ledgers.
Built with FastAPI, ChromaDB, Anthropic Claude, OpenAI embeddings, SQLite, and React.
┌─────────────┐ ┌──────────────────────────────────────────────┐
│ React SPA │────▶│ FastAPI Backend │
│ (Cortex) │◀────│ │
│ │ │ POST /documents → ingest pipeline │
│ Upload │ │ GET /documents → list documents │
│ Ask │ │ POST /query → retrieve + generate │
│ Chat │ │ DEL /documents/:id → remove doc + vectors │
│ │ │ │
│ │ │ ┌────────────┐ ┌────────────┐ │
│ │ │ │ ChromaDB │ │ SQLite │ │
│ │ │ │ (vectors) │ │ (metadata) │ │
│ │ │ └────────────┘ └────────────┘ │
└─────────────┘ └──────────────────────────────────────────────┘
- Upload: Drop a PDF, TXT, or MD file. The backend extracts text, splits it into ~500-token chunks with overlap, and embeds each chunk into ChromaDB.
- Ask: Type a question. The backend embeds your query with OpenAI, retrieves the most relevant chunks via vector similarity search, and sends them as context to Claude.
- Answer: Claude responds using only the retrieved context, citing which sources it drew from. The UI displays the answer beside a ledger of retrieved source passages.
| Layer | Technology |
|---|---|
| LLM | Anthropic Claude (via SDK) |
| Embeddings | OpenAI text-embedding-3-small |
| Vector store | ChromaDB |
| Metadata DB | SQLite (via SQLAlchemy) |
| Backend | FastAPI, Uvicorn |
| Text extraction | PyPDF2, raw read for TXT/MD |
| Chunking | Recursive character splitter |
| Frontend | React, Vite |
- Python 3.11+
- Node.js 18+
- An Anthropic API key
- An OpenAI API key
# Clone the repo
git clone https://github.com/YOUR_USERNAME/cortex-rag.git
cd cortex-rag
# Create environment file
cp .env.example .env
# Add your ANTHROPIC_API_KEY and OPENAI_API_KEY to .env
# Set up Python environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies
pip install -e .
# Run the server
uvicorn backend.main:app --reload --port 8000cd frontend
npm install
npm run devOpen http://localhost:5173. The frontend proxies API requests to localhost:8000.
If you are switching from an older local-embedding setup, clear data/chromadb/ and re-upload documents so ChromaDB does not mix vectors from incompatible embedding models.
pip install -e ".[dev]"
python -m pytest tests/ -v| Method | Endpoint | Description |
|---|---|---|
POST |
/documents |
Upload a document (multipart) |
GET |
/documents |
List all documents |
DELETE |
/documents/{id} |
Remove document and its vectors |
POST |
/query |
Ask a question against the corpus |
POST /query
{
"question": "What is the system's caching strategy?",
"document_ids": ["abc-123"],
"top_k": 5
}Response includes the answer, source chunks with similarity scores, model name, and latency.
cortex-rag/
├── backend/
│ ├── main.py # FastAPI app, CORS, lifespan
│ ├── config.py # Settings (pydantic-settings)
│ ├── database.py # SQLAlchemy engine + session
│ ├── models.py # ORM models (Document, Chunk, Query)
│ ├── schemas.py # Pydantic request/response schemas
│ ├── vector_store.py # ChromaDB wrapper
│ ├── routers/
│ │ ├── documents.py # /documents endpoints
│ │ └── query.py # /query endpoint
│ └── services/
│ ├── ingestion.py # Extract → chunk → embed → store
│ ├── retrieval.py # Vector search + context building
│ └── generation.py # Claude API call + prompt construction
├── frontend/
│ └── src/
│ ├── App.jsx
│ ├── api.js
│ └── components/ # Sidebar, ChatArea, AnswerCard, SourceCard, etc.
├── tests/
├── .env.example
├── pyproject.toml
└── README.md
The frontend uses an institutional evidence-desk aesthetic: warm mineral grounds, ink rules, a single spectral retrieval plate, Geist for the operating interface, and upright Newsreader for display statements. Citations, coverage, and retrieval details carry the visual hierarchy.
- No LangChain: direct Anthropic SDK usage for full control over prompt construction and retrieval logic.
- Dual storage: SQLite for relational metadata (document status, chunk ordering, query logs) alongside ChromaDB for vector search. IDs are shared across both stores.
- Async ingestion: document processing runs in the background after the upload response, with status tracking (
processing→ready→error). - Source attribution: every answer includes the specific chunks used, with retrieval scores and text previews.
MIT