The Problem
Users need a quick way to query the content of arbitrary PDFs without building a custom Retrieval‑Augmented Generation (RAG) pipeline. The pain point is wiring PDF storage, embedding, vector search, and LLM inference together in a production‑ready UI.
What This Does
pdftochat ships a full‑stack Next.js app that lets authenticated users upload PDFs, stores the files on Bytescale, creates embeddings in Chroma Cloud, and answers free‑form questions via a Mixtral model hosted on Together AI.
Key UI pieces live under app/dashboard/ (dashboard UI) and app/document/[id]/ (chat view). The API layer in app/api/ exposes three routes:
app/api/ingestPdf/route.ts– receives a multipart upload, saves the file, and triggersutils/ragChain.tsto create a Chroma collection.app/api/chat/route.ts– receives a user query, callsapp/api/utils/embeddings/index.tsto embed the prompt (via Chroma’s hybrid model) and then runs a LangChain RAG chain that fetches relevant chunks and forwards them to the LLM.app/api/document/[id]/route.ts– fetches document metadata from the Prisma‑backed Postgres table (utils/prisma.ts).
All styling is handled by Tailwind (tailwind.config.js, styles/*.css).
How It Is Wired
Entry point → request handling
- Client request – The chat UI (
app/document/[id]/page.tsx) issues aPOST /api/chatfetch. - Route handler –
app/api/chat/route.tsparses the JSON body and callsapp/api/utils/vector_store/index.ts→vectorStore.query(prompt)(implementation selected byNEXT_PUBLIC_VECTORSTORE). - Vector store – In
app/api/utils/vector_store/chroma.ts,querysends the prompt to Chroma Cloud, which returns the top‑k document chunks (dense + sparse via Qwen / SPLADE). - RAG chain –
utils/ragChain.tsbuilds a LangChainConversationalRetrievalQAChainusing the retrieved chunks and the LLM client (utils/config.tsholds the Together AI API key). - LLM call – The chain posts the assembled prompt to Together AI’s Mixtral endpoint and streams the answer back to the API route, which returns JSON to the frontend.
Upload flow
- UI (
app/dashboard/page.tsx) posts a file toPOST /api/ingestPdf. app/api/ingestPdf/route.tsuploads the binary to Bytescale via the helper inutils/config.ts, stores the resulting URL in theDocumenttable (utils/prisma.ts), and invokesutils/ragChain.tswithcreateCollection(documentId, fileUrl).utils/ragChain.tsdownloads the PDF, extracts text (viapdf-parseor similar), and callsvectorStore.upsert(docs)– the Chroma implementation creates a collection named after the document ID.
Persistence – Prisma schema (prisma/schema.prisma) defines a Document model; npx prisma db push creates the Postgres table used by both API routes.
Key ownership
app/api/utils/vector_store/*– all vector‑store communication; Chroma is the default hub.utils/ragChain.ts– the only place LangChain orchestration lives; any change to retrieval or prompt logic touches this file.utils/prisma.ts– Prisma client singleton; used by both upload and metadata routes.utils/config.ts– central place for environment‑driven secrets (Together AI key, Bytescale token, Chroma credentials).
No cyclic imports are present; the vector store module is a leaf, called only from API routes and the RAG chain.
How To Use It
# 1. Clone the repo
git clone https://github.com/moses-y/pdftochat.git
cd pdftochat
# 2. Install dependencies (pnpm is declared in package.json)
pnpm install
# 3. Copy and fill environment variables
cp .env.example .env
# Edit .env with:
# NEXT_PUBLIC_VECTORSTORE=chroma
# CHROMA_API_KEY=...
# CHROMA_TENANT=...
# CHROMA_DATABASE=...
# TOGETHER_API_KEY=...
# BYTESCALE_API_KEY=...
# DATABASE_URL=postgresql://<user>:<pw>@<host>/<db>
# 4. Push Prisma schema to the Postgres instance
npx prisma db push
# 5. Run locally
pnpm dev # starts Next.js on http://localhost:3000
The UI is reachable at /sign-up → create an account (Clerk handles auth). After signing in, the dashboard lets you upload PDFs and start chatting.
Real‑World Use
A SaaS product could embed this repo as a micro‑service: a front‑end sends a PDF URL to /api/ingestPdf, the service creates a Chroma collection, and downstream business logic queries /api/chat with domain‑specific prompts. The separation of vector store and LLM config makes swapping Chroma for Pinecone (see app/api/utils/vector_store/pinecone.ts) straightforward.
Code Health & Issues
- Medium – Untested code – No
*.test.*files detected; API routes and RAG logic lack unit or integration tests. - Medium – Missing CI/CD – Repository contains no
.github/workflowsor other pipeline definitions, so builds and linting are not automatically gated. - Low – License present –
LICENSEfile exists (MIT), satisfying open‑source distribution requirements. - Low – Secrets in repo – No API keys are committed; however,
.env.exampleexposes required variable names, which is appropriate.
No static analysis warnings were provided beyond the heuristic list above.
The Bottom Line
pdftochat delivers a ready‑to‑run RAG front‑end with clear separation of concerns (upload → vector store → LangChain → LLM). It is well‑structured for extension (alternative vector stores, custom prompts) but lacks automated testing and CI, so production teams should add those safeguards before scaling. Ideal for engineers who need a quick proof‑of‑concept or a baseline for a custom PDF‑chat product.