AIチャットを作ろう~Webアプリケーション開発~

ブログ

Blog
  1. ホームページ制作・運営はアウラ:ホーム
  2. ブログ
  3. AIチャットを作ろう~Webアプリケーション開発~

AIチャットを作ろう~Webアプリケーション開発~

AIチャットを作ろう~Webアプリケーション開発~

こんにちは、エンジニアの仁木です。

最近開発をする上で、わからないことをAIに聞くのが当たり前になりました。
2~3ヶ月前くらいまでは、癖でまずはGoogleで調べていたものですが、今ではまずはAIに聞くということの方が増えてきました。

基本的に自分はコーディングしている時にAIに質問するので、エディターの拡張機能を利用します。
わからないことを聞く分にはエディターの拡張で十分で手軽なのですが、回答内容を後から読み直したりできるようにしたいと思い、簡単なAIチャットのWebアプリケーションを作り始めました。

色々作ってみたい機能はあるのですが、まずは基本となるチャットを作ってみたので、今回はチャットを実装した方法の紹介をしたいと思います。
細かく書くと主題がボヤケてしまうので、チャット機能の実装部分にフォーカスし、直接関係のない部分は省いて書いてみます。

開発環境

今回は以下の環境を用意しました。

  • Webサーバー … Node.js(v22)
  • バックエンド/フロントエンド … Next.js (v14)
  • データベース … SQLite

Next.jsはTypescriptで書いていきます。

ライブラリやAPI

CSSはCSS Module + SCSSを使います。
最初はTailwind CSSに挑戦しようとしたのですが、使い方を調べるのにあまり時間をかけたくなかったので、自分で書いていくSCSSスタイルに切り替えました。

データベースのやり取りはORMのprismaを使います。
余談ですが、prismaはマイグレーション、データベースのGUI、スキーマ定義したモデルの型生成など、ライブラリ1つでデータベースまわりの環境を整えられるのがお手軽で良いです。

型チェックやバリデーションにはzodを使います。

ChatGPTは、OpenAI APIを使うため、APIキーを発行しています。

チャットのUI

以下のようなチャット画面を作ります。

一般的なチャットのUIです。
LINEのようにユーザーとAIのメッセージを左右に分けて表示します。
メッセージ下部に入力フィールドを用意し、質問を入力/送信します。

AIの回答はマークダウンで返ってくるので、HTMLにパースして画面に表示させます。
また、AIの回答は全文を待ってから表示すると時間がかかるので、APIのレスポンスはストリーミングさせてリアルタイムで回答を反映します。

コードはシンタックスハイライトさせて可読性を良くします。

ファイル構成

Next.jsのファイル構成です。
今回はApp Routerを使います。

テーブル設計

AIの回答やユーザーの質問など、やり取りのメッセージはデータベースに保存するのでメッセージのテーブルを作成します。
本来はメッセージ毎にチャットグループやユーザーを紐づけますが、今回はメッセージの保存のみの設計で考えます。

必要な項目は、IDロールメッセージのテキストメッセージ送信日時です。
ロールはそのメッセージがAIのものなのかユーザーのものなのかを識別する項目です。

prisma/schema.prismaでスキーマ定義します

スキーマ定義後、npx prisma migrate dev --name message でテーブルを作成します。

メッセージの保存

テーブルを作成したので、メッセージを保存する処理を書いていきます。

メッセージの保存処理の作成

メッセージに関する機能はsrc/feature/messageに実装していきます。

DBの操作はprisma clientを使います。

src/feature/message/services/create/index.ts

登録パラメータのバリデーションルールを定義します。

src/feature/message/services/create/schema.ts

APIルーティングの作成

クライアントからのメッセージ保存のリクエストはAPIルーティング http://localhost/api/message/createを経由させます。
リクエストはPOSTで受け付けます。

src/app/api/message/create/route.ts

ちなみに、↑のルーティングのファイルに直接 src/features/message/services/create/index.ts の保存処理を書いても良いのですが、そうするとサーバーコンポーネント上の保存処理を別で書かないといけなくなるため、このように処理を分けています。

また、APIのルーティングは自身のアプリケーション内だけで利用するので本来はルーティング自体は不要です。
リクエストの処理はServer Actionsで実装するとより良いかもしれません。

OpenAI APIへのリクエスト

OpenAI APIは completion を使います。
completionはAIに質問を送り、回答を取得するAPIです。

リクエストは過去の履歴も含めて送ることが可能で、やり取りの文脈を踏まえた回答を得ることができます。

src/app/api/openai/completion/route.ts

APIへのリクエストは公式が用意しているライブラリを利用します。
APIキーの環境変数OPEN_AI_API_KEY.env.localで定義します。

APIのリクエスト部分

messages には履歴も含めたメッセージのオブジェクトを渡します。
使用するモデルはmodelで指定します。
また、AIの回答はストリーミングで取得したいので、stream: trueを指定します。

stream形式で取得したデータは、そのままクライアントのリクエストにもストリーミング形式で返す必要があります。
今回は Server-Send Event(SSE)という仕組みを使って実現します。

SSEについての詳細は以下の記事が参考になると思います。

MDN: サーバー送信イベントの使用
https://developer.mozilla.org/ja/docs/Web/API/Server-sent_events/Using_server-sent_events

ChatGPTをぬるぬるにする🐌Server-Sent Eventsの基礎知識
https://zenn.dev/sekapi/articles/a089c203adad74

注意しないといけないのが、SSEはGETのみ対応しており、POSTなどでリクエストボディを含めたリクエストはできません。
そのため、クライアント側の実装は少し工夫が必要になります。

クライアント側の実装は以下のコンポーネント作成のセクションに記載します。

チャットのコンポーネント作成

チャットのUIコンポーネントです。
まずはコンポーネントのコードの全文です。

src/features/message/components/Chat/index.tsx

状態管理

  • messages … AIとユーザーのメッセージ履歴
  • completion … APIで取得したAIの回答
  • question … ユーザーが入力した質問テキスト
  • isComposing … 日本語入力時、漢字変換などでEnterキーが押されてもSubmitされないようにするフラグ

質問を送信するイベント <onQuestionHandler>

ユーザーが質問を送信するイベントです。
OpenAI APIへのリクエスト処理がメインです。

fetch APIでhttp://localhost/api/openai/completionにリクエストします。
レスポンスはストリーミングで返ってくるので、レスポンスのBodygetReader()で戻り値を読み込むようにします。

データの読み込みはwhileのループ内で行い、完了フラグが渡されたタイミングでループから抜けるようにしています。
また、データは接頭辞にdata:が含まれるようになっているので、この文字列でデータを分割します。

分割したデータをsetCompletion(prevCompletion => prevCompletion + json) でAIの回答のステートcompletionにセットします。
completion のステートはuseEffectで変更があれば、回答内のコードのシンタックスハイライトを更新します。

ページの作成

最後にページを作成します。

src/spp/caht-room/page.tsx

メッセージの取得処理 getMessagesは今回省いておりますが、メッセージの保存処理同様にsrc/features/message内でprisma clientを使って取得処理を実装します。

まとめ

作ってみて思ったのが、シンプルな機能であれば思ったより簡潔に実装できることがわかりました。
Next.jsを始め、既存のフレームワークやライブラリを使うことで、肝心のアプリケーションのコアなロジック部分の実装に集中できるのは良いですね。

AIを組み込んだWebシステムの開発は今後需要があると思うので、今後もノウハウを培っていきたいと思います。

お電話でのお問い合わせはこちら:06-6292-8577。受付時間は平日9:30~18:30 インターネットからは24時間受付中!お問い合わせフォームはこちら
Webデザイナー、Webプログラマ募集中!