A comprehensive web app that finds relevant documents and produces query-focused summaries (not QA) using Gemini. Features PDF upload with one-time multimodal preprocessing into per-page Markdown + metadata, document management, and citation-rich search results.
- Document Management: Upload PDFs → Gemini extracts per-page Markdown + doc summary/sections
- Hybrid Search: Semantic embeddings (Google) + Full-Text Search + MMR ranking
- Query-Focused Summaries: Returns relevant documents with per-document summaries and clean paragraph-level citations
- Document Viewer: Browse uploaded documents, view/edit extracted content, stream original PDFs
- Rich Evidence: Search results include meaningful snippets with direct PDF page links
- PostgreSQL + pgvector: Production-ready vector storage with full-text search
- FastAPI backend, Next.js frontend: Docker + Cloud Run deploy-ready
cp .env.example .envand fill:GOOGLE_API_KEY=...(required - get from Google AI Studio)GCP_PROJECT=...(required)- Database and other settings are pre-configured for Docker
-
Create a Service Account and Key in Google Cloud:
- Go to the Service Accounts page in the Google Cloud Console.
- Select your project.
- Click + CREATE SERVICE ACCOUNT.
- Give it a name (e.g., pdf-app-runner) and click CREATE AND CONTINUE.
- Grant it the Vertex AI User role to allow it to access the Gemini API, then click CONTINUE.
- Click DONE.
- Find your new service account, click the three-dot menu under Actions, and select Manage keys.
- Click ADD KEY > Create new key.
- Select JSON as the key type and click CREATE. A JSON key file will be downloaded.
-
Place the Key in Your Project:
- Rename the downloaded file to gcp-credentials.json.
- Move it to the root of your project directory (your-pdfs-with-gemini/).
mkdir -p data(create data directory for persistence)docker-compose up --build- Open
http://localhost:3000
- Backend (API):
http://localhost:8000- FastAPI with automatic docs at/docs - Frontend (Web):
http://localhost:3000- Next.js application - Database: PostgreSQL with pgvector extension for vector storage
- Data persistence:
./data/directory contains PostgreSQL data and PDF uploads
# Start services
docker-compose up --build
# Start in background
docker-compose up -d --build
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Rebuild specific service
docker-compose build api
docker-compose build web
# Shell into containers
docker-compose exec api bash
docker-compose exec web sh- Go to /upload, drag & drop PDF(s)
- Backend preprocessing with Gemini:
- Document-level:
title,summary,keywords,year - Per-page:
markdowncontent, table/figure detection, sections - Stores in PostgreSQL with pgvector embeddings
- Document-level:
- View uploaded documents with View Details and Open PDF buttons
- Document Detail Page:
- Side-by-side PDF viewer and extracted content
- Edit page markdown with automatic re-embedding
- Navigate between PDF pages and extracted content
- Home page: Enter natural-language questions
- Hybrid retrieval: Semantic + keyword search with MMR fusion
- Rich results: Document summaries with clean paragraph-level citations
- Evidence panel: Expandable source pages with:
- Document title and page numbers
- Relevant content snippets
- Direct links to PDF pages
POST /upload- Upload PDF file →{doc_id, message}GET /documents- List all documents →DocMeta[]GET /documents/{doc_id}- Get document details with pages →DocDetailGET /documents/{doc_id}/pdf- Stream original PDF fileGET /documents/{doc_id}/pages- Get paginated document pages →PaginatedPagesPATCH /pages/{page_id}- Update page content and re-embed →{page_id, updated_at}
POST /api/search- Search documents →SearchResponsewith query-focused summariesGET /api/healthz- Health check →{status: "ok"}GET /api/status- System status →{status, database}
- PDF Processing (
app/infra/pdf/): Gemini-powered content extraction to per-page Markdown - Storage (
app/infra/storage/): PostgreSQL with pgvector extension for embeddings - Retrieval Pipeline:
SemanticRetriever: Google embedding-based similarity searchLexicalRetriever: PostgreSQL full-text search with pg_bigmHybridRetriever: MMR fusion with configurable weighting
- Search Orchestrator (
app/services/orchestrator.py):- Document routing via embeddings and keyword matching
- Per-document page collection and snippet generation
- Query-focused summarization with citation extraction
- Summarization (
app/services/summarizer.py):- Gemini-powered QFS with paragraph-level citations
- Automatic citation extraction and inline token removal
- API Routes (
app/api/routes.py): RESTful endpoints with dependency injection - Configuration (
app/core/config.py): Environment-based settings management
- Next.js 15 with App Router and TypeScript
- API Client (
lib/api.ts): Centralized HTTP client with error handling - Components:
DocumentCard: Search results with summaries and expandable evidenceEvidenceList: Source pages with snippets and PDF linksSearchBox: Query input with loading states
- Pages:
/- Search interface with results display/upload- Document management with upload and action buttons/documents/[id]- Document detail with PDF viewer and content editor
- Proxy Routes (
app/api/): Next.js API routes forwarding to FastAPI backend
documents- Document metadata with title, keywords, embeddingspages- Per-page content with markdown, embeddings, and metadata- Uses pgvector for semantic search and pg_bigm for full-text search
- Configure GitHub repo variables/secrets (see CI/CD workflow).
- Push to
main→ Actions builds, pushes images, and deploys to Cloud Run. - Store PDFs in GCS if desired; set
GCS_BUCKETand persist file URIs inuploads.
- Preprocessing cost amortized: One-time Gemini processing per document; fast query-time retrieval
- PostgreSQL + pgvector: Production-ready vector storage with ACID compliance
- Hybrid search: Balances semantic understanding with exact keyword matching
- Snippet generation: Server-side content extraction for relevant search result previews
- Document-centric workflow: Upload → Browse → Search → Discover
- Citation transparency: Clean summaries with separate, clickable citation lists
- Direct PDF access: Navigate from search results to original source pages
- Content editing: In-place markdown editing with automatic re-embedding
- Clean architecture: Dependency injection, typed APIs, separation of concerns
- Docker-based: Consistent development and deployment environments
- Next.js + FastAPI: Modern stack with excellent TypeScript and Python ecosystems
Internal assignment deliverable.