0:00
/0:08

Video by Distill / Pexels

The Vercel AI SDK makes it incredibly easy to add AI capabilities to React applications. In this tutorial, we'll build several AI-powered components from scratch, including a streaming chatbot and intelligent content generator.

Getting Started

First, install the necessary packages:

npm install ai @ai-sdk/openai @ai-sdk/anthropic
npm install @types/react @types/node # if using TypeScript

Set up your environment variables:

# .env.local
OPENAI_API_KEY=your_openai_key
ANTHROPIC_API_KEY=your_anthropic_key

Basic Chat Component

Let's start with a simple chat interface that streams responses:

// components/ChatBot.jsx
import { useChat } from 'ai/react';
import { useState } from 'react';

export default function ChatBot() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: '/api/chat',
  });

  return (
    <div className="chat-container">
      <div className="messages">
        {messages.map((message) => (
          <div key={message.id} className={`message ${message.role}`}>
            <strong>{message.role === 'user' ? 'You' : 'AI'}:</strong>
            <p>{message.content}</p>
          </div>
        ))}
        {isLoading && <div className="loading">AI is thinking...</div>}
      </div>
      
      <form onSubmit={handleSubmit} className="input-form">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Ask me anything..."
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading}>
          Send
        </button>
      </form>
    </div>
  );
}

API Route Setup

// pages/api/chat.js (or app/api/chat/route.js for App Router)
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

export async function POST(req) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai('gpt-4-turbo'),
    messages,
    system: 'You are a helpful assistant that provides concise, accurate answers.',
  });

  return result.toAIStreamResponse();
}

useChat Hook Features:

Built-in State Management

  • Automatic message history
  • Loading states
  • Error handling
  • Input management

Streaming Support

  • Real-time response streaming
  • Partial message updates
  • Automatic UI updates

Customization Options

  • Custom API endpoints
  • Message preprocessing
  • Response formatting
  • Error callbacks

Advanced Content Generator

Let's build a more sophisticated component that generates blog content:

// components/ContentGenerator.jsx
import { useCompletion } from 'ai/react';
import { useState } from 'react';

export default function ContentGenerator() {
  const [topic, setTopic] = useState('');
  const [contentType, setContentType] = useState('blog-post');
  
  const {
    completion,
    input,
    handleInputChange,
    handleSubmit,
    isLoading,
    error,
  } = useCompletion({
    api: '/api/generate',
    body: {
      contentType,
      topic,
    },
  });

  const handleGenerate = (e) => {
    e.preventDefault();
    handleSubmit(e, {
      body: {
        prompt: input,
        contentType,
        topic,
      },
    });
  };

  return (
    <div className="content-generator">
      <div className="controls">
        <input
          type="text"
          placeholder="Enter topic..."
          value={topic}
          onChange={(e) => setTopic(e.target.value)}
        />
        
        <select
          value={contentType}
          onChange={(e) => setContentType(e.target.value)}
        >
          <option value="blog-post">Blog Post</option>
          <option value="social-media">Social Media</option>
          <option value="email">Email</option>
          <option value="product-description">Product Description</option>
        </select>
        
        <form onSubmit={handleGenerate}>
          <textarea
            value={input}
            onChange={handleInputChange}
            placeholder="Additional instructions..."
            rows={3}
          />
          <button type="submit" disabled={isLoading || !topic}>
            {isLoading ? 'Generating...' : 'Generate Content'}
          </button>
        </form>
      </div>

      {error && (
        <div className="error">
          Error: {error.message}
        </div>
      )}

      {completion && (
        <div className="generated-content">
          <h3>Generated Content:</h3>
          <div className="content-preview">
            {completion.split('\n').map((paragraph, index) => (
              <p key={index}>{paragraph}</p>
            ))}
          </div>
          <button onClick={() => navigator.clipboard.writeText(completion)}>
            Copy to Clipboard
          </button>
        </div>
      )}
    </div>
  );
}

API Route for Content Generation

// pages/api/generate.js
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

const contentPrompts = {
  'blog-post': 'Write a comprehensive blog post about',
  'social-media': 'Create engaging social media content about',
  'email': 'Write a professional email about',
  'product-description': 'Create a compelling product description for',
};

export async function POST(req) {
  const { prompt, contentType, topic } = await req.json();
  
  const systemPrompt = `${contentPrompts[contentType]} ${topic}. ${prompt || ''}
  
  Guidelines:
  - Keep the tone professional but engaging
  - Include relevant keywords naturally
  - Structure content with clear headings
  - Make it actionable and valuable`;

  const result = await streamText({
    model: openai('gpt-4-turbo'),
    prompt: systemPrompt,
    temperature: 0.7,
    maxTokens: 1000,
  });

  return result.toAIStreamResponse();
}