Clinical Document Intelligence Platform β Upload medical PDFs, ask natural language questions, and receive grounded, cited answers powered by an Agentic RAG pipeline.
- Overview
- Key Features
- Tech Stack
- AI Pipeline Architecture
- Project Structure
- Database Schema
- Getting Started
- Scripts Reference
- Deployment
- Contributing
- License
MediQuery is a full-stack clinical document intelligence platform built for healthcare professionals and researchers. It enables users to upload medical PDFs and interact with their content through a conversational interface backed by a sophisticated, multi-step Agentic RAG (Retrieval-Augmented Generation) pipeline.
Unlike naive RAG systems, MediQuery uses an AI agent that autonomously evaluates retrieval confidence and reformulates queries when needed β ensuring answers are always grounded in the source material, with explicit citations to prevent hallucinations.
- π PDF Ingestion β Upload clinical documents for automatic text extraction and intelligent chunking
- π€ Agentic RAG Pipeline β Multi-step AI agent with autonomous query reformulation on low-confidence retrievals
- π Semantic Vector Search β Cosine similarity search over 768-dimensional embeddings via pgvector
- π¬ Streamed Responses β Real-time answer streaming from Gemini 1.5 Pro with source citations
- π Google OAuth β Secure authentication via NextAuth.js
- β‘ Rate Limiting β Upstash Redis-backed API protection
- π RAG Evaluation β Built-in LLM-as-judge faithfulness and relevance scoring
- π§Ύ Cost & Token Tracking β Per-query token count, USD cost, and agent step logging
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript (Strict Mode) |
| Styling | Tailwind CSS v4, PostCSS, shadcn/ui |
| Database | PostgreSQL + pgvector (Supabase) |
| ORM | Prisma |
| AI Generation | Google Gemini API (gemini-1.5-pro) |
| Embeddings | Google text-embedding-004 (768 dims) |
| Authentication | NextAuth.js (Google OAuth 2.0) |
| Rate Limiting | Upstash Redis |
| Deployment | Vercel |
MediQuery's intelligence layer is a five-stage agentic pipeline designed for accuracy and grounded output.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MediQuery RAG Pipeline β
βββββββββββ¬βββββββββββββββ¬ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββ€
β Stage β Input β Operation β Output β Store β
βββββββββββΌβββββββββββββββΌββββββββββββββββΌβββββββββββββββΌβββββββββββββ€
β 1 β PDF Upload β Text Extract β Raw Text β β β
β 2 β Raw Text β Chunking β 512c/50ovlp β β β
β β β (512 chars, β β β
β β β 50 overlap) β β β
β 3 β Text Chunks β Embed via β 768-dim β pgvector β
β β β text-emb-004 β Vectors β β
β 4 β User Query β Embed β β Top-K β β β
β β β Cosine Sim β Chunks β β
β 5 β Top-K + β Agent Eval β Reformulate β β β
β β Similarity β (< 0.75?) β or Proceed β β
β 6 β Context β Gemini Gen β Streamed β Query DB β
β β β + Citations β Answer β β
βββββββββββ΄βββββββββββββββ΄ββββββββββββββββ΄βββββββββββββββ΄βββββββββββββ
- Stage 1 β Ingestion: Uploaded PDFs are parsed and raw text is extracted page-by-page.
- Stage 2 β Chunking: Text is split into 512-character chunks with a 50-character overlap to preserve context across boundaries.
- Stage 3 β Embedding & Storage: Each chunk is embedded using Google's
text-embedding-004model (768 dimensions) and stored in PostgreSQL via pgvector. - Stage 4 β Retrieval: The user's question is embedded and a cosine similarity search is performed against stored chunk vectors to surface the most relevant context.
- Stage 5 β Agent Evaluation: The AI agent inspects the top retrieval similarity score. If it falls below the 0.75 threshold, the agent autonomously reformulates the query and re-retrieves before proceeding.
- Stage 6 β Generation: Verified context is passed to
gemini-1.5-pro, which streams the final answer with strict source grounding and inline citations.
mediquery/
βββ prisma/
β βββ schema.prisma # Database schema and model definitions
βββ src/
β βββ app/ # Next.js App Router β pages and API routes
β β βββ api/ # Backend API route handlers
β β βββ (auth)/ # Authentication pages
β β βββ (dashboard)/ # Protected application pages
β βββ components/ # Reusable UI and feature layout components
β β βββ ui/ # shadcn/ui base primitives
β β βββ features/ # Domain-specific composite components
β βββ lib/
β β βββ ai/ # Core AI pipeline modules
β β β βββ gemini.ts # Gemini API client and generation logic
β β β βββ embeddings.ts # text-embedding-004 vector utilities
β β β βββ chunker.ts # Text chunking with overlap strategy
β β β βββ agent.ts # Agentic RAG orchestrator
β β βββ db/
β β βββ prisma.ts # Prisma client singleton
β βββ types/ # TypeScript interfaces and type definitions
βββ .env.example # Environment variable template
βββ next.config.ts # Next.js configuration
βββ tailwind.config.ts # Tailwind CSS configuration
βββ postcss.config.mjs # PostCSS configuration
βββ package.json
MediQuery uses five Prisma models to manage the full document-to-answer lifecycle.
// User β OAuth-backed account, owns documents and queries
model User {
id String @id @default(cuid())
email String @unique
name String?
image String?
documents Document[]
queries Query[]
}
// Document β Represents an uploaded PDF
model Document {
id String @id @default(cuid())
name String
storagePath String
fileSize Int
pageCount Int
status String @default("processing")
chunks Chunk[]
userId String
user User @relation(fields: [userId], references: [id])
}
// Chunk β Individual text node with vector embedding
model Chunk {
id String @id @default(cuid())
content String
chunkIndex Int
tokenCount Int
embedding Float[] // pgvector column (768 dims)
documentId String
document Document @relation(fields: [documentId], references: [id])
}
// Query β Full AI transaction log
model Query {
id String @id @default(cuid())
question String
answer String
confidence Float
tokenCount Int
costUsd Float
agentSteps Json // Array of agent reasoning steps
sources Json // Array of cited chunk references
userId String
user User @relation(fields: [userId], references: [id])
}
// EvalResult β RAG quality metrics per evaluation run
model EvalResult {
id String @id @default(cuid())
faithfulness Float // LLM-as-judge faithfulness score
relevance Float // Retrieval relevance score
precision Float // Context precision score
questionCount Int
createdAt DateTime @default(now())
}Ensure you have the following installed and configured before proceeding:
- Node.js
>= 18.x - npm
>= 9.x - A Supabase project with the
pgvectorextension enabled - A Google Cloud project with the Gemini API and OAuth 2.0 credentials configured
- An Upstash Redis database
# 1. Clone the repository
git clone https://github.com/your-username/mediquery.git
cd mediquery
# 2. Install dependencies
npm installCopy the example environment file and fill in your credentials:
cp .env.example .envOpen .env and configure the following variables:
# ββ Database (Supabase + Prisma) ββββββββββββββββββββββββββββββββββββββ
# Pooled connection URL for Prisma query engine (via PgBouncer)
DATABASE_URL="postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres?pgbouncer=true"
# Direct connection URL for Prisma Migrate (bypasses PgBouncer)
DIRECT_URL="postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres"
# ββ Google Gemini API βββββββββββββββββββββββββββββββββββββββββββββββββ
GEMINI_API_KEY="your-gemini-api-key"
# ββ NextAuth.js βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-nextauth-secret" # Generate: openssl rand -base64 32
# ββ Google OAuth 2.0 βββββββββββββββββββββββββββββββββββββββββββββββββ
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
# ββ Upstash Redis (Rate Limiting) βββββββββββββββββββββββββββββββββββββ
UPSTASH_REDIS_REST_URL="https://your-instance.upstash.io"
UPSTASH_REDIS_REST_TOKEN="your-upstash-token"Note:
DATABASE_URLuses the pooled connection for runtime queries.DIRECT_URLuses the direct connection and is required exclusively for Prisma migration commands (db:migrate,db:generate).
Run the following commands to initialize your database schema:
# Generate the Prisma client from your schema
npm run db:generate
# Apply migrations to your Supabase database
npm run db:migratepgvector: Ensure the
vectorextension is enabled in your Supabase project. RunCREATE EXTENSION IF NOT EXISTS vector;in the Supabase SQL editor if it is not already active.
npm run devThe application will be available at http://localhost:3000.
| Script | Command | Description |
|---|---|---|
| dev | npm run dev |
Starts the Next.js development server with hot reload |
| build | npm run build |
Compiles and bundles the application for production |
| lint | npm run lint |
Runs ESLint to validate code quality and style |
| db:migrate | npm run db:migrate |
Executes pending Prisma development migrations |
| db:generate | npm run db:generate |
Regenerates the Prisma client from schema.prisma |
| db:studio | npm run db:studio |
Opens Prisma Studio, a visual database explorer |
MediQuery is optimized for deployment on Vercel.
- Step 1 β Push to GitHub: Ensure your repository is connected to your Vercel project.
- Step 2 β Configure Environment Variables: Add all variables from your
.envfile to your Vercel project under Settings β Environment Variables. SetNEXTAUTH_URLto your production domain (e.g.,https://mediquery.vercel.app). - Step 3 β Deploy: Vercel will automatically build and deploy on every push to your main branch.
-
NEXTAUTH_URLis set to the correct production URL - Google OAuth 2.0 Authorized redirect URIs includes
https://your-domain.vercel.app/api/auth/callback/google - Supabase
DATABASE_URLandDIRECT_URLare configured in Vercel environment variables -
pgvectorextension is enabled on your Supabase instance - Upstash Redis credentials are set for production rate limiting
Contributions are welcome. To contribute:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Commit your changes:
git commit -m 'feat: add your feature' - Push to your branch:
git push origin feature/your-feature-name - Open a Pull Request against
master
Please ensure npm run lint and npm run build pass before submitting.
This project is licensed under the MIT License. See the LICENSE file for details.