A Retrieval-Augmented Generation (RAG) pipeline that ingests PDF documents into Cloudflare Vectorize and answers questions using an LLM via OpenRouter. Built with Bun.
- Ingest - PDFs in the
data/folder are read, split into chunks, embedded, and stored in a Cloudflare Vectorize index. - Query - A user question is embedded, the most relevant chunks are retrieved from Vectorize, and an LLM generates an answer grounded in those chunks.
- Bun 1.0+
- An OpenRouter API key
- A Cloudflare account ID
- A Cloudflare API token with Vectorize permissions
-
Install dependencies
bun install
-
Configure environment variables
Copy the example file and fill in your credentials:
cp .env.example .env
-
Edit
.envOPENROUTER_API_BASE=https://openrouter.ai/api/v1 OPENROUTER_API_KEY=your_openrouter_api_key OPENROUTER_MODEL=deepseek/deepseek-v4-pro OPENROUTER_CONTEXT_MODEL=gpt-4o-mini OPENROUTER_MAX_TOKENS=512 OPENROUTER_EMBEDDING_MODEL=text-embedding-3-small CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id CLOUDFLARE_API_TOKEN=your_cloudflare_api_token CLOUDFLARE_VECTORIZE_INDEX=belajar-rag
-
Add PDF files
Place your PDF files in
data/.
bun ingest.jsTo completely reset the index before ingesting:
bun ingest.js --delete-oldThis will:
- Read all
.pdffiles fromdata/ - Split text into chunks with overlap
- (Optionally) Reset the Cloudflare Vectorize index if
--delete-oldis provided - Upload fresh embeddings with stable IDs (subsequent runs without
--delete-oldwill update existing documents rather than duplicating them)
bun query.js "What is the main topic of the document?"The output includes the answer and source chunks with relevance scores.
├── config.js
├── ingest.js
├── query.js
├── .env.example
├── package.json
└── data/