最近、ChatGPTを活用したアプリケーション開発が非常に注目されており、世間が騒ついています。
私も今までの努力が一瞬で否定されたような気がして少し落ち込んでいましたが、逆にこれはチャンスだと思い、大いに活用していこうと気持ちを切り替えています。(…..半分ホント)
そこで今回は、Node.js+TypeScriptとChatGPT APIを組み合わせて、ChatGPTのような簡単なチャットボットを作ってみたいと思います。すでに似たような記事や動画が色々と出回っていますが、備忘録としてまとめていきたいと思います。
少しでも誰かのお役に立てれば幸いですので、少しでも参考になれば幸いです。
実装の流れ
前回の記事を参考にNode.js + TypeScriptの実行環境を構築
openai
を中心として必要なライブラリをインストール
公式のチュートリアルを参考にTypeScriptで実装
APIを使って会話ができるのか検証
ChatGPTのようなチャットボットをTypeScriptで実装
開発環境
- Node.js:
v18.15.0
- npm:
v9.5.0
- TypeScript:
v4.9.5
構築手順
実行環境の構築
まずはNode.js + TypeScriptで実行できる環境を構築します。
構築方法は以下をベースに実施しましたので、まだ構築できていない方は参考にしてください。
この時点でのディレクトリ構成は以下
.
├── README.md
├── dist
│ └── index.js
├── src
│ └── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
ライブラリのインストール
下記ライブラリをインストールしていきます。
openai
:Node.jsからOpenAI APIへアクセスできる公式ライブラリreadline-sync
:対話型のインタフェースにするのに利用@types/readline-sync
:readline-syncの型定義が必要
ts-dotenv
:TypeScript用の.envファイルの簡単な読み込みをサポート
$ node install --save openai readline-sync
$ node install --save-dev ts-dotenv @types/readline-sync
API呼び出し処理の実装
まずは公式ドキュメントに記載されているコードをベースに実装してみる。
const { Configuration, OpenAIApi } = require("openai");
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const completion = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{role: "user", content: "Hello world"}],
});
console.log(completion.data.choices[0].message);
https://platform.openai.com/docs/api-reference/chat/create
上記コードをTypeScriptに置き換え、少し手を加えると以下のようになりました。
import {
ChatCompletionRequestMessageRoleEnum,
Configuration,
OpenAIApi,
} from 'openai';
import { load } from 'ts-dotenv';
const env = load({
OPENAI_API_KEY: String, //①
});
const configuration = new Configuration({
apiKey: env.OPENAI_API_KEY, //②
});
const openai = new OpenAIApi(configuration); //③
(async () => {
try {
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo', //④
messages: [
{
role: ChatCompletionRequestMessageRoleEnum.User, //⑤
content: 'ゴリラの生態について教えてください', //⑥
},
],
});
const answer = response.data.choices[0].message?.content; //⑦
console.log(answer);
} catch (error) {
console.log(error);
}
})();
コード解説
- 環境変数の読み込み:TypeScript用の
dotenv
を使って.env
ファイルに設定したOPENAI_API_KEY
を読み込む - 認証情報や設定情報:
Configuration
オブジェクトに認証情報や各種設定情報を渡す - OpenAI APIクライアントの作成:
Configuration
を渡すことでAPIに対してリクエストをする準備が完了 - OpenAIの言語モデルを指定:今回は「
gpt-3.5-turbo
」を指定 - ロールの指定:
system
,user
,assistant
の3つから選択。こちらから質問する場合は、user
を指定 - プロンプトの指定:ロールによって書く内容は変わるが、いわゆるプロンプトを設定
- レスポンスの取得:response内に含まれる返答内容を受け取る(ChatGPTからの返答結果)
ロールについて補足
System
: 「振る舞い」や「背景」など初期条件を設定する際に使用するロール- 例えば、語尾に「だぜ」をつけて会話してくださいなどキャラクター設定などに利用する
User
: ユーザーの質問や指示などを伝えるためのロールAssistant
: これまでの会話履歴を記録するためのロール- 例えば、チャットボットとして機能させる場合に利用
動作検証
では、実際にリクエストを投げてみます。
$ npm run build
$ node dist/index.js
すると以下のようになかなかの長文でレスポンスを受け取ることに成功しました
ChatGPTからの返答結果はコチラ
ゴリラは、アフリカ大陸の中央部に生息している哺乳動物であり、霊長類の中でも最大級の動物の一種です。以下は、ゴリラの生態についての詳細です。
【生息地】
ゴリラは、主にコンゴ盆地周辺の熱帯雨林や山岳地帯に生息しています。生息地はほかにも、カメルーンやウガンダ、ルワンダ、ブルンジ、タンザニアなどです。
【体格】
ゴリラは、体格が非常に大きく、オスの体重は300kgに達するほか、身長は1.5〜1.8mになることがあります。また、メスも雄に比べて大きく、体重は110kg以上、身長は1.2〜1.5mになることがあります。
【食性】
ゴリラは、主に植物を食べる草食動物です。主食は、木の葉や果実、茎、根、樹皮などで、特に葉や茎を好んで食べます。また、葉が不足した場合には、地面から草などを食べることもあります。
【生態】
ゴリラは、基本的には群れを作って生活しています。群れの中には、オスが1頭から10頭ほどのメスや子どもが含まれます。群れ内でのコミュニケーションは、様々な声で行われ、鳴き声やジェスチャーなどを用いて意志表示をします。また、オス同士は支配関係を競い合い、優位な位置に立つことがあります。
【繁殖】
ゴリラの繁殖期間は、基本的には一年中ですが、オス同士で闘争する場合に繁殖行動が見られることがあります。妊娠期間は、8ヶ月から9ヶ月ほどで、一度に1頭の子ゴリラが生まれます。生まれた子ゴリラは、メスの子どもが多数を占め、群れでの子育ては、メスだけが行います。子ゴリラの哺乳期間は、3年から4年ほどです。
【保護状況】
ゴリラは、熱帯雨林の破壊や密猟などにより、絶滅の危機に瀕しています。ゴリラは、現在、ワシントン条約によって国際取引の禁止がされているため、保護活動が進められています。その一環として、保護区や動物園での保護が行われています。
……想像の3倍ぐらいの情報を教えてくれました。内容に関してはほぼ知らなかったですが、無事にAPIとの疎通に成功しました。
ですが、これだと一方的な質問しかできず、さらにここから深ぼっての質問や会話のキャッチボールをすることができません。そこで、Assistant
ロールを活用してチャットボットのように会話をしてみたいと思います。
チャットボットの実装
先ほど言ったような課題を解決すべく、最後にチャットボットの実装をしていきます。
いきなりですが、完成形はコチラです。
import {
ChatCompletionRequestMessage,
ChatCompletionRequestMessageRoleEnum,
Configuration,
OpenAIApi,
} from 'openai';
import { load } from 'ts-dotenv';
import * as readlineSync from 'readline-sync';
type Message = {
inputText: string;
completionText: string;
};
const env = load({
OPENAI_API_KEY: String,
});
const configuration = new Configuration({
apiKey: env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const CHAT_GPT_SYSTEM_PROMPT = '孫悟空になりきって回答して下さい。'; //①
(async () => {
const history: Message[] = [];
while (true) {
const userInput = readlineSync.question('何か聞きたいことはありますか?: '); //②
const messages: Array<ChatCompletionRequestMessage> = [ //③
{
role: ChatCompletionRequestMessageRoleEnum.System,
content: CHAT_GPT_SYSTEM_PROMPT,
},
];
for (const message of history) { //④
messages.push({
role: ChatCompletionRequestMessageRoleEnum.User,
content: message.inputText,
});
messages.push({
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: message.completionText,
});
}
messages.push({ role: 'user', content: userInput }); //⑤
try {
const completion = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: messages,
max_tokens: 256,
});
const completionText = completion.data.choices[0].message;
console.log(completionText);
if (completionText) {
history.push({ //⑥
inputText: userInput,
completionText: completionText.toString(),
});
}
const userInputAgain = readlineSync.question( //⑦
'\nChatGPTとの会話を続けますか? (Y/N)'
);
if (userInputAgain.toUpperCase() === 'N') {
return;
} else if (userInputAgain.toUpperCase() !== 'Y') {
console.log("不正な値です。'Y' か 'N'を入力してください。");
return;
}
} catch (error) {
console.log(error);
}
}
})();
コード解説
- システムプロンプトの設定:Systemロールにて、ChatGPTに「孫悟空になりきる」よう指示
- ユーザー入力の取得:
readlineSync
を利用して、質問を表示し、ユーザーからの入力を受け取る - メッセージ配列の作成:
ChatCompletionRequestMessage
の形式に従って、メッセージ配列を作成。その際、システムプロンプトである指示を格納。 - 会話履歴の追加:
history
に格納されている会話履歴をメッセージ配列に追加 - ユーザー入力の追加:現在のユーザー入力をメッセージ配列に追加
- 会話履歴の更新:返答結果があれば、会話履歴(
history
)に追加。 - 続行の確認:ユーザーに会話を続けるかどうかを確認。続けない場合は、会話終了
動作検証
ChatGPTからの返答結果はコチラ
Q. 何か聞きたいことはありますか?: Node.jsについて200文字以内で説明してください。
おおっ!人間め、Node.jsについて教えてくれとはな。それは良い問いだ。聞こう。Node.jsとは、JavaScriptを使ってサーバーサイドのアプリケーションを開発するためのランタイム環境だ。これにより、JavaScriptを使ってWebアプリケーションを書くことができるだろう。また、非同期処理に優れ、高いパフォーマンスも期待できる。一言で言えば、Node.jsはJavaScriptでサーバーサイドを開発するための素晴らしいツールだと言えるだろう。気になることがあれば、なんでも質問してくれ。老孫が教えてやろう。
Q. ChatGPTとの会話を続けますか? (Y/N)Y
Q. 何か聞きたいことはありますか?: 考えられるユースケースを3つあげてください
A.
1. Webアプリケーションの構築: Node.jsは高速に動作することから、大量のリクエストを処理することに長けているため、Webアプリケーションの構築に利用されることが多くあります。
2. APIサーバーの構築: Node.jsはHTTPサーバーを内蔵しているため、APIサーバーの構築に利用されることが多くあります。また、非同期処理に強いことから、リアルタイム通信の構築にも利用されています。
3. ツールの開発: JavaScriptを用いた開発の場合、ブラウザ上でしか動作しないプログラムをNode.jsを使用することで、コマンドライン上でも動作するよう変換することができます。
1つ目の質問を知らないと2つ目の質問には回答できないような質問しましたが、回答結果よりちゃんと会話履歴を保持できていることがわかりました。
(2つ目の質問から普通の人間に戻ってしまったのは謎ですが。。。)
まとめ
本記事では、Node.jsとTypeScriptを用いて、ChatGPT APIを手軽に利用する方法を解説しました。この知識を活用して、さらなるアプリケーション開発やプロジェクトに役立てていただければ幸いです。
これらを応用してSlackやLineBotに連携することも可能ですので、別途まとめていきたいと思います。ご覧いただきありがとうございました。