AI Document Summarizer
Designing an AI feature from POC to production, with built-in quality measurement.
Stack: Next.js 14 · TypeScript · OpenAI GPT-4o-mini · shadcn/ui
Code: View on GitHub
The Problem
Users of learning management systems and document platforms upload dozens of files (lecture notes, worksheets, reports, scanned pages) and the only way to understand what each file contains is to open it one by one. In edtech, an educator might have 30 attachments in a single course module with no way to scan their content at a glance.
Alternatives like keyword extraction, tagging, or full-text search still require the user to interpret raw data. Summaries give an instant "should I care?" signal. They reduce cognitive load as well as improve findability.
The strategy: a narrow wedge. Summaries are generated automatically right after upload and shown inline wherever files appear. Immediate value with minimal user behavior change.
My Approach
How I think about building AI features:
- Start with the UX shape, not the model. The POC proves the interaction pattern (upload, summary, feedback) before adding infrastructure complexity. If the UX pattern doesn't work, the infrastructure doesn't matter.
- Evaluation is part of the product. The feedback widget in the POC is the foundation of the quality measurement framework. Without it, there's no way to know if summaries are actually helping users.
- Sequence around risk. Make the async pipeline reliable first, then add auth and cost controls, then expand to more file types. Don't introduce OCR failure modes before you can debug basic pipeline failures.
- Trust and control go hand-in-hand. Regenerate and manual override exist because users need control over AI output, especially in domains where accuracy matters for compliance or regulatory reasons. The number of manual overrides also becomes a proxy metric for quality.
- Single provider is an intentional bet. MVP uses one LLM provider (OpenAI). The interface supports future routing, but the complexity tax isn't paid until there's a reason: cost pressure, reliability issues, or a capability gap.
What I Built
The POC is intentionally minimal. It validates the core UX pattern and prompt quality before adding infrastructure complexity.
- Upload: drag-and-drop with client-side validation (PDF only, 50MB max). PDF-only because it's the most common attachment type; multi-format support is an MVP expansion.
- Text extraction: pdf-parse extracts text with error discrimination. Corrupt files, password-protected PDFs, and image-only PDFs each return a distinct error message with a clear next step for the user. No technical jargon is exposed.
- Summarization: two parallel OpenAI calls generate an 8-word headline and 3 bullet points simultaneously. I tested 5, 8, 12, and 15-word limits during development. Five words was too cryptic for users to judge relevance; twelve started feeling like a sentence you had to read carefully. Eight hit the sweet spot: meaningful enough to inform, short enough to scan instantly. The 3-bullet expansion gives enough detail without overwhelming.
- Centralized prompts: all AI behavior lives in a single file. Prompts are tunable without touching application code. Text is truncated at 15,000 characters as a pragmatic token budget control.
- Feedback collection: thumbs up/down inline with an optional comment field on negative feedback. Starting the feedback flywheel early is critical for AI features; it's how you build the data to improve prompt quality over time.
- Error handling: every error returns a human-readable message AND a suggested next step. Rate limits, timeouts, invalid API keys, and corrupt files each have tailored copy. Technical details are logged server-side, never shown to users.
- Cancellation: users can cancel in-flight summarization. Better UX when the wrong file is uploaded, and it avoids unnecessary token spend.
POC Data Flow
Upload (drag-and-drop)
→ /api/upload (pdf-parse extracts text)
→ /api/summarize (parallel OpenAI calls: headline + bullets)
→ Summary Card (display + feedback widget)
How I Would Measure Success
These are the success criteria and measurement framework I designed for this feature. The metrics are pre-launch targets; the framework is designed to validate or adjust them with real usage data.
Tiered metrics framework
Metrics are sequenced around what you can learn at each stage. Start with "does it work?", then "is it valuable?", then "how do we improve?"
Tier 1: MVP launch (weeks 1-4): reliability
- >95% summary generation rate: technical reliability baseline
- P95 latency <10s: user-perceived performance
- <1% error rate: system stability
- <$0.10 cost per summary: economic sustainability
Tier 2: Post-MVP (months 2-3): value
- >70% positive feedback (thumbs up): direct quality signal
- >10% feedback rate: if fewer than 5% of users give any feedback, the quality signal isn't meaningful yet. A/B test the feedback UX before trusting the number.
- <10% edit rate: the most important quality proxy. When users replace an AI summary with their own text, that's a direct signal the output isn't meeting expectations.
- Measurable reduction in files opened per search (A/B test): efficiency gain
Tier 3: Optimization (month 3+): continuous improvement
- Automated quality scores (LLM-as-judge): scalable measurement of faithfulness, relevance, and conciseness
- Edit pattern analysis: what users consistently change reveals actionable prompt improvements
- Time saved (user surveys): perceived value and ROI
Proxy metrics (no explicit feedback required)
- Manual summary replacement rate. When users replace an AI summary with their own text, that's a direct quality signal. Thresholds: under 5% is excellent, 5-10% is healthy, 10-15% warrants investigation by file type, and above 20% means users are doing manual work and the feature is failing. Tracking what users change (not just how often) reveals actionable prompt improvements. For example, if users consistently add pricing details the summary missed, the prompt should be updated to extract pricing explicitly.
- Session pattern analysis. If a user opens an attached file and returns to the app within 10 seconds, the file likely wasn't relevant, which may indicate a misleading summary. If they stay away for 2+ minutes, they're probably reading it, meaning the summary led them to the right content.
Metrics that don't work
Quick return rate (file opened then immediately closed) seems intuitive but is ambiguous. A user closing a file in under 10 seconds could mean three things: they were scanning multiple files (good behavior), the summary was misleading (bad quality), or the summary told them everything they needed (good summary). Without additional context, the metric is uninterpretable.
Similarly, "find files faster" only works if you first understand how users discover files (search, browse, or notification). The metric needs to be scoped to a specific discovery pattern before it means anything.
Quality management framework
- Regression set: 20 representative documents (short, long, technical, non-technical) evaluated after each prompt change
- Human rubric: scored 1-5 on four dimensions: correctness, coverage, specificity, tone
- Prompt versioning: changes can be A/B tested behind feature flags and rolled back if quality drops
Failure acceptance
Not all failures are equal. A failed summarization that surfaces a clear error message and retry option is acceptable because the user knows what happened and what to do. A silently wrong summary is not acceptable because it erodes trust without the user knowing.
Cost model
Rough estimates (prices subject to change with provider pricing updates):
- GPT-4o-mini input: ~$0.15 / 1M tokens
- Avg tokens per summary pair: ~2,000
- Cost per summary: ~$0.0003
- 10K summaries / month: ~$3 / month
OCR and multi-format parsing add cost. Cost-per-summary is tracked as a production metric alongside quality; the goal is to optimize without quality loss.
Production Roadmap
The roadmap is sequenced around risk, not features. Each phase builds on the reliability and observability of the previous one.
Phase 1: Make the pipeline reliable
The POC is synchronous: the user waits while the API processes. Production needs to handle timeouts, retries, and long documents gracefully.
- Async job queue: Supabase (chosen for built-in RLS, auth, and Postgres, giving one service for persistence and access control) creates a job row on upload. An AWS Lambda worker (serverless, scales to zero when idle, no infra to manage) processes jobs and writes results back.
- Summary persistence: summaries are stored in Supabase and served from the database on subsequent views, not regenerated. This eliminates redundant API calls, reduces cost, and makes summaries available instantly across sessions.
- Run telemetry from day 1: every summarization run logs the model, token count, latency, and errors to Supabase. This is non-negotiable. Without it, quality and cost issues are invisible.
- Feature flags: enable or disable summarization without breaking existing upload flows. This is both a launch mechanism and a rollback mechanism.
Phase 2: Add trust and access control
- Supabase Auth + RLS (row-level security): owner-only access by default. RLS is chosen over application-level permission checks because access control lives in the database layer, not scattered across API routes. A user cannot read another user's summaries, enforced at the query level.
- Status-driven UX: the summary card reflects real job states (queued, processing, succeeded, failed) pulled from the database, not local ephemeral state.
- Integration and E2E tests before expanding scope. The pipeline must be proven reliable before adding more complexity.
Phase 3: Expand capabilities
- Multi-format support: .txt, .md, .docx in addition to PDF.
- OCR for scanned PDFs: this comes after monitoring exists because OCR adds both cost and new failure modes that need the observability from Phase 1.
- Custom summary replacement + regenerate: users can write their own summary (replacing the AI version) or regenerate a new AI summary. Both are trust mechanisms that give users control. Replacement rate also feeds back into quality measurement.
- Manual and batch summarization: auto-summarization only covers new uploads. Manual triggers let users summarize existing files on demand, and batch triggers let admins backfill critical content sets. Without this, the feature only works going forward and ignores the existing library.
- Coverage metric: files with summaries divided by total files in the system. Tracks adoption over time. Target: above 80% within 6 months through a combination of auto-summarization, manual triggers, and batch backfill.
Phase 4: Production and observability
- Phased rollout via feature flags: start at 5% of users, expand to 25%, 50%, then 100% based on stability metrics. Rollback triggers: error rate exceeds 5%, P95 latency exceeds 10s, cost per summary exceeds $0.50, or user complaints exceed 10 tickets/day. Any trigger kills the feature instantly via feature flag, no code deploy required.
- Vercel for hosting: zero-config Next.js deployment with preview environments per PR.
- Dashboards: per-step latency, cost (tokens), success rate, breakdown by file type and provider.
- Automated alerts: spend spikes, error-rate thresholds, queue backlog, timeout surges, with runbooks for each scenario.
- Optimization based on production data: tune chunking, prompts, and retry strategies using real telemetry. Reduce cost without quality loss.
Phase 5: Future work
- Graph database for document relationships: once summaries are persisted, they become a foundation for understanding relationships between documents. A graph database (e.g., Neo4j) can store semantic similarity edges between documents based on their summary embeddings.
- Related document suggestions: when a user attaches a document to a project, the system suggests other documents with semantically similar content. This turns summaries from a passive feature (read and move on) into an active discovery tool.
- Embedding pipeline: summaries are embedded at generation time and stored as vectors. Similarity is computed against the existing corpus, and relationships above a confidence threshold are written as edges in the graph. This runs asynchronously alongside summarization, reusing the same job queue infrastructure from Phase 1.
Architecture
POC (what exists today)
File Browser UI
→ Next.js /api/upload (pdf-parse extracts text)
→ Next.js /api/summarize (OpenAI GPT-4o-mini)
→ Summary Card (display + feedback widget)
Synchronous. In-memory. No persistence.
Production (designed)
File Browser UI
→ Next.js on Vercel (zero-config deploys, preview environments)
→ Supabase (Postgres + RLS + Auth: persistence, access control, job queue)
→ AWS Lambda (serverless async worker: extraction + summarization + retry)
→ Supabase (results + run telemetry)
→ Next.js (polling for status updates)
→ Summary Card (display + feedback widget)
Feature flags. Run telemetry. Monitoring dashboards.
The POC proves the UX pattern works. The production architecture makes it reliable, secure, and observable at scale. A key shift: summaries move from ephemeral (generated on every request, lost on refresh) to persistent (stored in Supabase, served instantly on subsequent views).
Key Technical Decisions
Centralized prompts. All AI behavior lives in a single file (prompts/summarize.ts). Prompts are product decisions about tone, length, and specificity. Keeping them in one file makes them reviewable, versionable, and independently tunable without code changes.
Dual-call pattern. Short summary and expanded bullets are generated by parallel, independent OpenAI calls via Promise.all. This enables independent prompt tuning for each output format. A single structured-output call would couple them.
Error discrimination. The PDF parser inspects error messages to distinguish password-protected, corrupt, and image-only failures. Each returns a tailored user-facing message with a concrete next step. The user never sees a stack trace.
15,000 character truncation. A pragmatic token budget control for the POC. Production would use smarter chunking strategies informed by run telemetry data (document length distribution, truncation frequency).
What I Learned
The most consequential part of an AI feature is everything around the API call, including error handling, retry logic, quality measurement, and user trust. In this POC, the OpenAI integration was straightforward, so I focused on what actually creates the greatest impact: making the feature feel reliable.
Prompt engineering is a product concern. The prompts in this project are decisions about tone ("3rd person active voice"), length ("8 words or fewer"), and what to prioritize ("skip introductions, focus on substance"). These are product decisions, not engineering ones.
Defining success criteria before writing code changes what you build. The feedback widget exists because the measurement framework required it. The manual override feature exists because replacement rate is a proxy metric. Starting with "how will we know this works?" shapes the feature itself.