How to Build an AI-Powered Document Summary Streamer with Next.js & Vercel AI SDK
AI engineering is no longer just for Python experts. Let's build a real-time, streaming document summarizer using Next.js and the Vercel AI SDK in pure JavaScript.
System Architecture
Our application will consist of two core halves:
A Serverless API Route (Backend): Built on Next.js Edge runtime to securely handle API authentication tokens and manage the connection stream with OpenAI/Gemini models.
A Client Component (Frontend): To handle user inputs, manage active loading streams, and render incoming tokens elegantly.
Installing Dependencies
Install the modular Vercel AI core package alongside your chosen AI provider wrapper:
Bash
npm install ai @ai-sdk/openai
Note: Remember to securely add your OPENAI_API_KEY="your_secret_key" into your project's .env.local environment file.
Creating the API Route
We will leverage Next.js App Router API directory. Create the following route. This endpoint reads incoming raw inputs and delegates the processing to the AI model.
// app/api/summarize/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
// Optional: Use Edge runtime for faster global execution speeds
export const runtime = 'edge';
export async function POST(req: Request) {
try {
const { text, detailLevel } = await req.json();
if (!text || text.length < 50) {
return new Response(JSON.stringify({ error: "Text is too short to summarize safely." }), { status: 400 });
}
// Call the structural LLM stream
const result = await streamText({
model: openai('gpt-4o-mini'),
system: `You are an elite corporate researcher. Summarize the provided text in exactly ${detailLevel} bullet points. Use crisp, clear professional language.`,
prompt: `Please process and summarize this transcript/text: \n\n${text}`,
});
// Converts the streaming response directly to an active stream readable by the frontend
return result.toDataStreamResponse();
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to communicate with AI gateway." }), { status: 500 });
}
}
Designing the Interface
On our client-side page, we will implement the specialized useCompletion hook. This hook automatically handles parsing chunked network tokens into a clean reactive state stream string.
// app/page.tsx
'use client';
import { useState } from 'react';
import { useCompletion } from 'ai/react';
export default function AIAppHome() {
const [detailLevel, setDetailLevel] = useState('3');
// Custom configurations passed directly to the AI hook
const { completion, input, handleInputChange, handleSubmit, isLoading, error } = useCompletion({
api: '/api/summarize',
body: { detailLevel } // Dynamic options injected inside the API payload
});
return (
<div className="min-h-screen bg-slate-50 dark:bg-zinc-950 py-12 px-4">
<div className="max-w-3xl mx-auto bg-white dark:bg-zinc-900 rounded-2xl shadow-xl p-8 border border-slate-100 dark:border-zinc-800">
<h1 className="text-3xl font-extrabold text-slate-900 dark:text-white tracking-tight">
🚀 Context-Aware AI Summarizer
</h1>
<p className="text-slate-500 mt-2 text-sm">
Paste dense operational logs, meeting transcripts, or blog drafts to compress them instantly.
</p>
<form onSubmit={handleSubmit} className="mt-8 space-y-6">
<div>
<label className="block text-sm font-medium mb-2 text-slate-700 dark:text-zinc-300">
Select Output Length:
</label>
<select
value={detailLevel}
onChange={(e) => setDetailLevel(e.target.value)}
className="w-full md:w-48 p-2 rounded-md border bg-transparent text-sm"
>
<option value="3">3 Quick Bullets</option>
<option value="5">5 Thorough Points</option>
<option value="7">7 Deep Executive Summary</option>
</select>
</div>
<div>
<textarea
value={input}
onChange={handleInputChange}
placeholder="Paste your extensive documentation text here (Minimum 50 characters)..."
className="w-full h-56 p-4 border rounded-xl font-mono text-sm dark:bg-zinc-950 focus:ring-2 focus:ring-indigo-500 outline-none transition"
required
/>
</div>
<button
type="submit"
disabled={isLoading || input.length < 50}
className="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 rounded-xl transition disabled:opacity-40 shadow-lg shadow-indigo-600/20"
>
{isLoading ? 'Processing Token Streams...' : 'Generate AI Summary'}
</button>
</form>
{error && (
<div className="mt-4 p-3 bg-red-50 text-red-600 text-sm rounded-lg">
⚠️ {error.message || "An issue occurred while fetching stream data."}
</div>
)}
{/* Streaming Text Output Area */}
{completion && (
<div className="mt-8 p-6 bg-slate-900 text-slate-100 rounded-xl border border-slate-800 shadow-inner">
<h3 className="text-xs uppercase tracking-widest text-indigo-400 font-bold mb-3 animate-pulse">
● Live Stream Response
</h3>
<p className="whitespace-pre-line leading-relaxed font-sans text-sm">
{completion}
</p>
</div>
)}
</div>
</div>
);
}
Conclusion
Building with AI no longer requires complex machine learning infrastructure. By leveraging Next.js Serverless functions and the Vercel AI SDK, front-end focused developers can build fast, streaming AI applications using pure TypeScript or JavaScript. The architecture we built today is highly scalable. You can easily extend this project by adding file uploads (PDF/Txt processing), integrating vector databases for custom knowledge (RAG), or swapping the OpenAI model for a free tier Google Gemini model with just one line of code change. What features are you planning to add to your next AI app? Let me know in the comments below, and don't forget to star the repository if you found this guide helpful!
