Vercel Logo

First AI summary

You've built a great review site, but users have to read all reviews to understand a product. AI can summarize hundreds of reviews into a few sentences, saving users time and highlighting key themes.

Outcome

Create a summarizeReviews function that uses Claude via AI Gateway to generate review summaries, and display them on product pages.

Fast Track

  1. Create lib/ai-summary.ts with summarizeReviews(product) using generateText({ model: "anthropic/claude-sonnet-4.5", prompt })
  2. Create components/ai-review-summary.tsx as async Server Component that calls await summarizeReviews(product)
  3. Add <AIReviewSummary product={product} /> to app/[productId]/page.tsx, test at /mower

Hands-on Exercise 2.2

Implement AI-powered review summarization:

Requirements:

  1. Create lib/ai-summary.ts with a summarizeReviews function
  2. Use generateText from the AI SDK with model "anthropic/claude-sonnet-4.5"
  3. Write a basic prompt that includes all reviews
  4. Create an AIReviewSummary component to display the summary
  5. Add the component to product pages

Implementation hints:

  • generateText returns { text } with the generated content
  • Use template literals to build the prompt
  • The function should be async (AI calls take time)
  • Keep the prompt simple for now (we'll improve it in the next lesson)
  • The component should be a Server Component (it awaits the async function)

Understanding generateText

The AI SDK provides generateText for one-shot text generation:

import { generateText } from "ai";
 
const { text } = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "Your instructions here",
});

Key parameters:

  • model: AI Gateway model string
  • prompt: Your instructions and context

Response: Returns an object with text (the generated string) plus metadata like token usage.

Step 1: Create AI Summary Function

Create lib/ai-summary.ts:

lib/ai-summary.ts
import { generateText } from "ai";
import { Product } from "./types";
 
export async function summarizeReviews(product: Product): Promise<string> {
  const prompt = `Summarize the following customer reviews for the ${product.name} product:
 
${product.reviews.map((review) => review.review).join("\n\n")}
 
Provide a concise summary of the main themes and sentiments in 2-3 sentences.`;
 
  try {
    const { text } = await generateText({
      model: "anthropic/claude-sonnet-4.5",
      prompt,
    });
 
    return text;
  } catch (error) {
    console.error("Failed to generate summary:", error);
    throw new Error("Unable to generate review summary. Please try again.");
  }
}

What this does:

  1. Takes a Product object
  2. Builds a prompt with product name and all reviews
  3. Calls Claude via AI Gateway
  4. Returns the generated summary
  5. Handles errors gracefully

Step 2: Create AI Summary Component

Create components/ai-review-summary.tsx:

components/ai-review-summary.tsx
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Product } from "@/lib/types";
import { summarizeReviews } from "@/lib/ai-summary";
import { FiveStarRating } from "./five-star-rating";
 
export async function AIReviewSummary({ product }: { product: Product }) {
  const summary = await summarizeReviews(product);
 
  const averageRating =
    product.reviews.reduce((acc, review) => acc + review.stars, 0) /
    product.reviews.length;
 
  return (
    <Card className="w-full max-w-prose p-10 grid gap-10">
      <CardHeader className="items-center space-y-0 gap-4 p-0">
        <div className="grid gap-1 text-center">
          <CardTitle className="text-lg">AI Summary</CardTitle>
          <p className="text-xs text-muted-foreground">
            Based on {product.reviews.length} customer ratings
          </p>
        </div>
        <div className="bg-gray-100 px-3 rounded-full flex items-center py-2 dark:bg-gray-800">
          <FiveStarRating rating={Math.round(averageRating)} />
          <span className="text-sm ml-4 text-gray-500 dark:text-gray-400">
            {averageRating.toFixed(1)} out of 5
          </span>
        </div>
      </CardHeader>
      <CardContent className="p-0 grid gap-4">
        <p className="text-sm leading-loose text-gray-500 dark:text-gray-400">
          {summary}
        </p>
      </CardContent>
    </Card>
  );
}

Key features:

  • Server Component (no "use client")
  • Awaits summarizeReviews() before rendering
  • Displays average rating with stars
  • Shows review count
  • Clean card layout

Step 3: Add to Product Page

Update app/[productId]/page.tsx:

app/[productId]/page.tsx
import { Metadata } from "next";
import { notFound } from "next/navigation";
import { getProduct, getProducts } from "@/lib/sample-data";
import { Reviews } from "@/components/reviews";
import { AIReviewSummary } from "@/components/ai-review-summary";
 
export default async function ProductPage({
  params,
}: {
  params: Promise<{ productId: string }>;
}) {
  const { productId } = await params;
 
  let product;
  try {
    product = await getProduct(productId);
  } catch (error) {
    notFound();
  }
 
  return (
    <main className="min-h-screen p-8">
      <div className="max-w-4xl mx-auto space-y-8">
        <div>
          <h1 className="text-4xl font-bold">{product.name}</h1>
          <p className="text-lg text-muted-foreground mt-2">
            {product.description}
          </p>
        </div>
 
        <AIReviewSummary product={product} />
 
        <Reviews product={product} />
      </div>
    </main>
  );
}
 
// ... (generateStaticParams and generateMetadata remain the same)

Try It

  1. Run your dev server:

    pnpm dev
  2. Visit a product page:

    http://localhost:3000/mower
    
  3. Watch the terminal:

    GET /mower 200 in 2.3s
    

    That 2+ second delay is AI generation time.

  4. See the AI summary:

    • Summary card appears above reviews
    • Claude-generated text summarizes all reviews
    • Average rating and review count displayed
  5. Try different products:

    /ecoBright
    /aquaHeat
    

    Each gets its own unique AI-generated summary.

  6. Check AI Gateway dashboard:

    • Go to Vercel dashboard → AI Gateway
    • See API calls increasing
    • Check token usage
    • Monitor costs

What you'll notice:

The summaries work but vary in format and quality. Sometimes they include ratings, sometimes word counts, sometimes extra metadata. That's expected with a basic prompt. We'll fix this in the next lesson with prompt engineering.

How It Works

Request Flow:

  1. User visits /mower
  2. Next.js renders ProductPage (Server Component)
  3. <AIReviewSummary> component renders
  4. Calls await summarizeReviews(product)
  5. Function sends prompt to AI Gateway
  6. AI Gateway forwards to Claude API
  7. Claude generates summary (~2s)
  8. Returns text to your app
  9. Component renders with summary
  10. Full HTML sent to browser

Server-side rendering: Everything happens on the server. The user's browser never sees the AI Gateway API key or makes direct API calls.

Performance Note

Current behavior:

  • Every page load calls Claude
  • ~2 second delay per request
  • Costs tokens every time

Coming in Section 3:

  • Smart Caching (Lesson 3.1)
  • Cache summaries for 1 hour
  • First request: 2s (generates)
  • Subsequent requests: 50ms (cached)
  • 97% cost reduction

AI Gateway Dashboard

After visiting a few product pages, check your dashboard:

Metrics you'll see:

  • API Calls: 3+ (one per product visited)
  • Tokens Used: ~800-1000 per summary
  • Cost: ~$0.002 per summary
  • Model: anthropic/claude-sonnet-4.5
  • Success Rate: 100%

Example summary generation:

  • Input tokens: ~600 (your prompt + reviews)
  • Output tokens: ~100 (generated summary)
  • Total: ~700 tokens
  • Cost: ~$0.0021

Commit

git add lib/ai-summary.ts components/ai-review-summary.tsx app/\[productId\]/page.tsx
git commit -m "feat(ai): add basic AI review summarization"
git push

Done-When

  • lib/ai-summary.ts created with summarizeReviews function
  • generateText working with Claude via AI Gateway
  • AIReviewSummary component displays summaries
  • Summaries appear on all product pages
  • AI Gateway dashboard shows API calls and costs
  • No errors in terminal or browser console

What's Next

Your AI feature works, but the summaries are inconsistent. In the next lesson, you'll use prompt engineering techniques—few-shot examples, tone guidance, and output constraints—to make summaries production-ready with consistent format and quality.


Sources: