Visakh.
All projects
PDF RAG preview
AI

PDF RAG

Chat with your PDFs — upload a document, ask questions in plain English, and get cited answers from a self-hosted RAG stack you can spin up with one Docker command.

Why

You download a dense PDF—a textbook, a report, a contract—and need answers fast. Skimming hundreds of pages or pasting chunks into a generic chatbot loses context and trust. PDF RAG is built for that moment: drag a file into the sidebar, ask for a bullet-point summary or a specific detail, and get a response grounded in your document with source citations so you can verify every claim. Under the hood it is a three-service stack meant to run anywhere, not just on a laptop in a Jupyter notebook. Qdrant holds embedded chunks in a pdf_chunks collection with persistent storage across restarts. A Node backend ingests uploads, chunks and embeds PDFs, and runs retrieval-augmented generation against that index. A React frontend is the chat surface you see in the demo—upload on the left, conversation on the right. Docker Compose ties it together with ordered health checks: Qdrant must be healthy before the API starts, and the API must pass /health before the UI comes up. Named volumes keep uploads and vector data between runs. Pre-built images on Docker Hub (vjnvisakh/rag-backend, vjnvisakh/rag-frontend) mean docker compose up is enough to go from zero to chatting with your own files.

Tech

Docker ComposeQdrantRAGNode.jsReactPDFVector search

How to run

  1. 1

    Prerequisites

    Install Docker and Docker Compose on your machine.

  2. 2

    Create the compose file

    Save the Docker Compose configuration below as docker-compose.yml in an empty project folder.

  3. 3

    Configure API keys

    Create a backend/.env file next to docker-compose.yml with the credentials your backend needs (for example, an OpenAI API key for embeddings and chat).

    # backend/.env — add the variables required by rag-backend
    OPENAI_API_KEY=your_key_here
  4. 4

    Start the stack

    From the folder containing docker-compose.yml, pull images and start all services. Compose waits for Qdrant and the backend health checks before starting the frontend.

    docker compose up -d
  5. 5

    Open the app

    When all containers are healthy, open the UI at http://localhost:5173. The API is available at http://localhost:3000 and Qdrant at http://localhost:6333.

  6. 6

    Upload and chat

    Upload one or more PDFs from the sidebar, then ask questions in the chat. Answers are grounded in your documents with source citations.

  7. 7

    Stop the stack

    Uploaded files and vector data persist in Docker volumes between runs.

    docker compose down

Docker Compose

services:
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant-storage:/qdrant/storage
    healthcheck:
      test: ["CMD", "bash", "-c", "echo > /dev/tcp/127.0.0.1/6333"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped

  backend:
    image: vjnvisakh/rag-backend:latest
    ports:
      - "3000:3000"
    environment:
      PORT: 3000
      QDRANT_URL: http://qdrant:6333
      QDRANT_COLLECTION: pdf_chunks
    env_file:
      - ./backend/.env
    volumes:
      - backend-uploads:/app/uploads
    depends_on:
      qdrant:
        condition: service_healthy
    healthcheck:
      test:
        [
          "CMD",
          "node",
          "-e",
          "fetch('http://localhost:3000/health').then((r) => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))",
        ]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped

  frontend:
    image: vjnvisakh/rag-frontend:latest
    ports:
      - "5173:80"
    depends_on:
      backend:
        condition: service_healthy
    restart: unless-stopped

volumes:
  backend-uploads:
  qdrant-storage:

What's next

  • Auth and multi-tenant collections
  • Streaming answers in the UI
  • Hybrid search (keyword + vector)
  • Single-VPS deploy with TLS

More projects