logo

AI SDKを利用して校正したテキストをdiffで表示する

2025-06-03
2 months ago

開発環境

  • @ai-sdk/openai 1.3.22
  • @ai-sdk/react 1.2.12
  • ai 4.3.16
  • diff 8.0.2
  • next 15.3.3

前提

本記事では、Vercel AI SDKを利用して、テキスト校正機能を実装する方法について解説します。

ユーザーが入力したテキストを自動的に校正し、誤字・脱字・誤変換を検出して修正する機能を簡単に実装できることを示します。

本題

システム構成

今回実装するシステムは、フロントエンドとバックエンドの2つの主要コンポーネントで構成されています。

  1. フロントエンド: ユーザーがテキストを入力し、校正結果を表示する部分
  2. バックエンド: OpenAI APIと連携して実際の校正処理を行う部分

バックエンドの実装

まずは、校正処理を行うAPIルートを見てみましょう。このファイルは src/app/api/completion/route.ts に配置されています。

import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

export async function POST(req: Request) {
  const { prompt }: { prompt: string } = await req.json();

  const result = streamText({
    model: openai('gpt-4o-mini'),
    system:
      'あなたは文章校正の専門アシスタントです。以下の文章について、誤字・脱字・誤変換を検出し、修正後の文章を出力してください。',
    prompt,
  });

  return result.toDataStreamResponse();
}

このコードでは

  1. OpenAI APIを使用するため、@ai-sdk/openaiからopenaiモデルをインポートしています
  2. ストリーミングレスポンスを扱うためにstreamText関数を使用しています
  3. POSTリクエストからプロンプト(校正対象のテキスト)を取得しています
  4. OpenAIモデルにシステムプロンプトとユーザープロンプトを送信しています
  5. 結果をストリーミングレスポンスとして返しています

フロントエンドの実装

次に、フロントエンドの実装を見てみましょう。このファイルは src/app/sample/page.tsx に配置されています。

'use client';

import { useState } from 'react';

import { useCompletion } from '@ai-sdk/react';
import { diffChars } from 'diff';

export default function Page() {
  const [input, setInput] = useState('');
  const [text, setText] = useState('');
  const { completion, complete, isLoading } = useCompletion({
    api: '/api/completion',
  });
  const diff = diffChars(text, completion);

  return (
    <div className="flex flex-col gap-4 p-10">
      <div className="flex gap-4">
        <textarea
          className="w-full min-w-1/2 rounded border"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          rows={20}
          placeholder="入力してください"
        />

        <div className="min-w-1/2 rounded border wrap-anywhere whitespace-pre-wrap">
          {completion && !isLoading ? (
            <>
              {diff.map((part, index) => (
                <span
                  key={index}
                  className={`${part.added && 'text-green-700'} ${part.removed && 'text-red-600 line-through'}`}
                >
                  {part.value}
                </span>
              ))}
            </>
          ) : (
            completion
          )}
        </div>
      </div>
      <button
        className="w-full rounded border bg-gray-50 p-2 hover:bg-gray-200"
        onClick={async () => {
          setText(input);
          await complete(input);
        }}
      >
        検証
      </button>
    </div>
  );
}

このコードでは

  1. useCompletion フックを使用してAPIとの通信を行っています
  2. ユーザー入力(input)と校正前のテキスト(text)を状態として管理しています
  3. diffChars 関数を使って、元のテキストと校正結果の差分を計算しています
  4. UIとして:
  5. 「検証」ボタンをクリックすると、現在の入力をtext状態にセットし、complete関数を呼び出してAPIリクエストを送信します
  6. 校正結果は差分として表示され、追加された部分は緑色、削除された部分は赤色で取り消し線付きで表示されます

動作の流れ

  1. ユーザーが左側のテキストエリアにテキストを入力します
  2. 「検証」ボタンをクリックすると、入力されたテキストがバックエンドAPIに送信されます
  3. バックエンドではOpenAI APIを使用して、テキストの校正処理を行います
  4. 校正結果がフロントエンドに返され、右側のエリアに表示されます
  5. 元のテキストと校正結果の差分が視覚的に強調表示されます

実装のポイント

  1. ストリーミングレスポンス: streamText関数を使用することで、OpenAI APIからの応答をリアルタイムでストリーミングできます。これにより、長いテキストでも徐々に結果が表示されるため、ユーザー体験が向上します。
  2. 差分表示: diffライブラリを使用して、元のテキストと校正結果の差分を計算し、変更点を視覚的に表示しています。これにより、ユーザーは何が変更されたかを簡単に確認できます。
  3. 状態管理の工夫: inputtextという2つの状態を管理しています。ユーザーが入力する値をinputで管理し、「検証」ボタンを押した時点での値をtextとして保存しています。これはストリーミングレスポンスの特性に対応するための重要な工夫です。もしinputをそのままdiffCharsに渡すと、ストリーミングの初期段階では校正結果が少しずつ生成されるため、画面に赤い取り消し線だらけの表示になってしまいます。「検証」ボタンを押した時点でのテキストをtextとして保存することで、完全な校正結果と比較することができ、より自然な差分表示を実現しています。

さいごに

Vercel AI SDKを使用することで、OpenAI APIを活用したテキスト校正機能を簡単に実装できることがわかりました。この実装方法は、他の自然言語処理タスクにも応用可能です。

例えば

  • テキスト要約
  • 翻訳
  • 文体変換
  • 文章のトーン調整

など、様々な用途に使用できます。

AI SDKは、AI機能の実装を大幅に簡略化し、開発者がAIの力を簡単にアプリケーションに統合できるようにしています。特にストリーミング応答の処理やUI連携が簡単に行えるのが大きな魅力です。

今回は基本的な実装にとどまりましたが、さらに機能を拡張することで、より高度なテキスト処理アプリケーションを構築することも可能です。

参照