https://github.com/bluntbrain/rag-supabase-ts
A Retrieval-Augmented Generation (RAG) system built with TypeScript, Supabase vector storage, and OpenAI.
https://github.com/bluntbrain/rag-supabase-ts
embeddings rag
Last synced: about 1 month ago
JSON representation
A Retrieval-Augmented Generation (RAG) system built with TypeScript, Supabase vector storage, and OpenAI.
- Host: GitHub
- URL: https://github.com/bluntbrain/rag-supabase-ts
- Owner: bluntbrain
- Created: 2026-01-25T14:04:49.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-01-25T14:17:06.000Z (6 months ago)
- Last Synced: 2026-01-26T06:44:19.699Z (6 months ago)
- Topics: embeddings, rag
- Language: TypeScript
- Homepage:
- Size: 1.01 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# RAG System with Supabase and OpenAI


A Retrieval-Augmented Generation (RAG) system built with TypeScript, Supabase vector storage, and OpenAI.
## What is RAG?
RAG (Retrieval-Augmented Generation) is a technique that enhances LLM responses by providing relevant context from a knowledge base. Instead of relying solely on the model's training data, RAG retrieves relevant documents and includes them in the prompt.
```
User Query --> Vector Search --> Retrieve Relevant Docs --> Add to Prompt --> LLM Response
```
### Why RAG?
- **Reduces hallucinations** - Model answers based on provided context, not guesses
- **Up-to-date information** - Knowledge base can be updated without retraining
- **Domain-specific answers** - Use your own documents as the source of truth
- **Verifiable sources** - Responses can cite which documents were used
## Core Concepts
### 1. Embeddings
Embeddings convert text into numerical vectors (arrays of numbers) that capture semantic meaning. Similar texts have similar vectors.
```
"The cat sat on the mat" --> [0.12, -0.34, 0.56, ...] (1536 dimensions)
"A feline rested on the rug" --> [0.11, -0.33, 0.55, ...] (similar vector)
```
This project uses OpenAI's `text-embedding-3-small` model (1536 dimensions).
### 2. Vector Database
Supabase with pgvector extension stores embeddings and performs similarity search using cosine distance. When you query, it finds documents with vectors closest to your query's vector.
```sql
-- Cosine similarity: 1 - (distance between vectors)
1 - (documents.embedding <=> query_embedding) as similarity
```
### 3. Chunking
Large documents are split into smaller chunks before embedding. This improves:
- **Retrieval precision** - Find specific relevant sections
- **Context efficiency** - Don't waste tokens on irrelevant content
- **Embedding quality** - Models have token limits
```
Large Document --> [Chunk 1] [Chunk 2] [Chunk 3] ...
| | |
Embed Embed Embed
| | |
Store Store Store
```
This project uses overlapping chunks (default: 500 chars with 50 char overlap) to preserve context at boundaries.
### 4. Similarity Search
When a user asks a question:
1. Convert question to embedding
2. Find top N documents with closest embeddings (cosine similarity)
3. Return documents above similarity threshold
### 5. Prompt Construction
Retrieved documents are combined into a prompt that instructs the LLM to only answer based on the provided context:
```
System: Answer based ONLY on the provided context...
Context:
---
[Retrieved Document 1]
---
[Retrieved Document 2]
---
Question: User's question here
Answer:
```
## Tech Stack
| Component | Technology |
| ---------- | -------------------------------- |
| Language | TypeScript |
| Embeddings | OpenAI text-embedding-3-small |
| LLM | GPT-4o |
| Vector DB | Supabase (PostgreSQL + pgvector) |
| Runtime | Node.js |
## Project Structure
```
src/
config/
index.ts # OpenAI and Supabase client initialization
constants.ts # Configuration (chunk size, model names, etc.)
services/
ingestion.ts # Document chunking, embedding, and storage
retrieval.ts # Vector similarity search
types/
index.ts # TypeScript interfaces
utils/
prompt.ts # Prompt construction and text splitting
index.ts # Main entry point
docs/ # Knowledge base documents (add your .txt files here)
sql/
schema.sql # Supabase function for similarity search
```
## Setup
### 1. Prerequisites
- Node.js 18+
- Supabase project with pgvector enabled
- OpenAI API key
### 2. Supabase Setup
Create the documents table in Supabase SQL editor:
```sql
-- Enable pgvector extension
create extension if not exists vector;
-- Create documents table
create table documents (
id bigserial primary key,
content text,
embedding vector(1536),
metadata jsonb
);
-- Create index for faster similarity search
create index on documents using ivfflat (embedding vector_cosine_ops)
with (lists = 100);
```
Then run the function from `sql/schema.sql` to create `match_documents`.
### 3. Environment Variables
```bash
cp .env.example .env
```
Edit `.env`:
```
OPENAI_API_KEY=sk-...
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
```
### 4. Install and Build
```bash
npm install
npm run build
```
## Usage
### Ingest Documents
Add your text files to the `docs/` folder, then:
```bash
npm run ingest
```
Or uncomment line 38 in `src/index.ts` to ingest before querying.
### Query the Knowledge Base
```bash
npm start
```
Edit the query in `src/index.ts` or import and use `queryRag()`:
```typescript
import { queryRag } from "./index.js";
const result = await queryRag("What happened in 1843?");
console.log(result.answer);
console.log(result.sources);
```
## Configuration
Edit `src/config/constants.ts`:
| Constant | Default | Description |
| ------------------------ | ---------------------- | ------------------------------- |
| `CHUNK_SIZE` | 500 | Max characters per chunk |
| `CHUNK_OVERLAP` | 50 | Overlap between chunks |
| `SIMILARITY_MATCH_COUNT` | 5 | Number of documents to retrieve |
| `ANSWERING_MODEL` | gpt-4o | LLM for generating answers |
| `EMBEDDING_MODEL_NAME` | text-embedding-3-small | Model for embeddings |
## How It Works
```
┌─────────────────────────────────────────────────────────────┐
│ INGESTION PIPELINE │
├─────────────────────────────────────────────────────────────┤
│ docs/*.txt --> Chunk Text --> Create Embeddings --> Store │
│ | | | │
│ 500 chars OpenAI API Supabase │
│ 50 overlap 1536-dim vector pgvector │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ QUERY PIPELINE │
├─────────────────────────────────────────────────────────────┤
│ User Query --> Embed Query --> Vector Search --> Build │
│ | | Prompt │
│ OpenAI API Supabase RPC | │
│ match_documents | │
│ | v │
│ Top 5 docs -----> Send to GPT │
│ by similarity | │
│ v │
│ Answer with │
│ sources │
└─────────────────────────────────────────────────────────────┘
```
## Scripts
| Command | Description |
| ------------------- | --------------------------- |
| `npm run build` | Compile TypeScript |
| `npm start` | Run the compiled app |
| `npm run dev` | Build and run |
| `npm run ingest` | Ingest documents from docs/ |
| `npm run typecheck` | Type check without emitting |
## License
MIT