NotebookLM — AI Research Assistant

A Google NotebookLM–style research assistant: multi-notebook knowledge bases, seven ingestible source types, hybrid retrieval with query transforms and reranking, and every answer traceable back to its source passage.

Grounded RAG chat with inline, click-through citations

// AI Systems / RAG / Monorepo · grounded Q&A over your own sources
NotebookLM: research assistant chat with cited answers and a source viewer panel
NotebookLM
PDF / web / YouTube / DOCX / VTT ingestion · hybrid retrieval + RRF + rerank · cited streaming answers · Source Viewer
  • A NotebookLM-style research assistant: users create isolated notebooks, ingest sources, and ask natural-language questions grounded in those sources — every answer is cited back to the exact chunk (page, timestamp, or passage).
  • Seven source types with per-type parsing:
    • PDF (pdf-parse, per-page text), plain text, Markdown, DOCX (mammoth)
    • Website URLs — Firecrawl scrape → markdown
    • YouTube — captions via youtube-caption-extractor
    • WebVTT transcripts — custom cue parser
  • Async ingestion pipeline (BullMQ worker, decoupled from the HTTP path):
    • parse → chunk → embed → index, with live status tracking (pending → parsing → chunking → embedding → indexing → ready/failed)
    • sliding-window chunking (1000 chars, 150 overlap) for documents; greedy transcript-merge chunking for YouTube/VTT that preserves start/end timestamps
    • idempotent re-index/delete — old Qdrant vectors and Postgres chunks are cleared before re-insert so no orphaned points accumulate
    • 3 retries with exponential backoff on failure
  • Advanced retrieval pipeline, not a single vector search:
    • query transform step (DeepSeek) produces a rewritten query, a HyDE passage, a step-back query, and sub-questions — and can skip retrieval entirely for chit-chat
    • parallel fan-out: each transformed query is embedded and searched in the notebook's Qdrant collection, plus a keyword full-text search on Postgres
    • Reciprocal Rank Fusion merges all ranked lists, then Voyage AI's rerank-2.5-lite cross-encoder reranks the top candidates down to a final context window (falls back to RRF order if reranking fails)
    • grounded prompt built with [[chunk-id]] citation markers, streamed via SSE, then parsed back into a citation list for the UI
  • One Qdrant collection per notebook (not a shared collection with filters) — retrieval is scoped by collection, and deleting a notebook drops both the Postgres cascade rows and the Qdrant collection.
  • Source Viewer: clicking a citation chip opens the original material at the right spot — PDF page via an authenticated blob iframe, text/markdown/DOCX with the passage highlighted, or a YouTube embed seeked to the cited timestamp.
  • Local embeddings — Supabase/bge-small-en (384-dim, mean-pooled, L2-normalized) running on-device via @huggingface/transformers/ONNX, so embedding cost doesn't scale with a hosted API.
  • pnpm monorepo: Next.js 16 frontend, Fastify 5 API + BullMQ worker as separate processes sharing the same codebase, and typed packages (db, queue, vector-store) so schema and client logic aren't duplicated.
  • Clerk auth with JIT organization/user provisioning on first authenticated request, and ownership checks on every notebook-scoped route.

// tech

Next.jsTypeScriptFastifyDrizzle ORMNeon PostgresQdrantBullMQUpstash RedisClerkDeepSeekVoyage AIFirecrawlHugging Face Transformers