こんにちは、フロントエンドチームの亀ノ上です。
最近は画像生成AIやテキスト生成AIなど、AIによる自動生成に関する話題をよく目にします。特にここ最近は ChatGPT の勢いが凄まじく、毎日のようにニュースを見かけるような気もしています。
今回はそんな ChatGPT でも使用されている言語モデルである GPT-3 を用いて、Nuxt3 で簡単なテキスト生成アプリを作成します。
Nuxt3について
Nuxt3とは
Nuxt3 とは、Vue.js アプリケーションを構築するためのフレームワークです。特徴としては、高速な開発、シンプルな設計、高機能な機能などがあげられます。
Nuxt3の機能
今回 Nuxt3 を選択した理由として、Nuxt3 には、サーバーサイドレンダリングや API Routes などの機能が備わっています。API Routes は、アプリケーション内で API エンドポイントを定義し、簡単に呼び出すことができる機能です。この機能を使うことで、API 開発とフロントエンド開発を効率的に行うことができます。
Nuxt3インストール
それではまずは Nuxt3 をインストールしていきます。
npx nuxi init gpt3-app
🎉 Another prime Nuxt project just made! Next steps:
📁 `cd gpt3-app`
💿 Install dependencies with `npm install` or `yarn install`
🚀 Start development server with `npm run dev` or `yarn dev`
インストールが終わったら、ディレクトリを移動してパッケージをインストールします。
cd gpt3-app `npm install` or `yarn install`
今回はyarn installですすめます。
... success Saved lockfile. $ nuxt prepare Nuxi 3.1.2 ✔ Types generated in .nuxt ✨ Done in 113.76s.
パッケージのインストールが終わったら、Nuxt を起動してみます。
yarn dev
Nuxi 3.1.2 Nuxt 3.1.2 with Nitro 2.1.2 > Local: http://localhost:3000/ > Network: http://xxx.xx.xx.xxx:3000/ ℹ Vite client warmed up in 1388ms ✔ Nitro built in 421 ms
http://localhost:3000/にアクセスします。

Nuxt の画面が表示されていればOKです!
インデックスページの設定をする
次にコードの方を修正していきます。
現在表示されている画面はapp.vueの内容になります。
app.vue
<template> <div> <NuxtWelcome /> </div> </template>
まずは自身で作ったページを表示するためにpages/index.vueを作成します。pages/index.vueファイルは、アプリケーションの/ルートに自動的に設定されます。
pages/index.vue
<template> <h1>Hello Nuxt3!</h1> </template>
次にapp.vueを変更します
app.vue
<template> <div> <NuxtPage /> </div> </template>
<NuxtPage />はpages/index.vueが存在する場合は、pages/index.vue を自動的にレンダリングします。
それでは一度yarn devで画面を確認してみましょう。

問題なく表示されていますね。
フロントエンド開発
今回の GPT-3 アプリは、キーワードを入力して、テキストを生成するといったアプリにしたいと思いますので。キーワードの入力エリアと、ボタンを作成します。
pages/index.vue
<script setup> const keyword = ref(''); const handleClick = () => { // ここに生成する処理をかく } </script> <template> <h1>GPT-3 APP</h1> <div> <input type="text" v-model="keyword"> </div> <div> <button type="button" @click="handleClick">テキスト生成</button> </div> </template>

Nuxt3はもちろんVue.jsベースのフレームワークなのでVue3の機能をフル活用できます。v-bindやv-modelといったディレクティブからref()などの API も使用できます。ただ、<script setup>でimport { ref } from 'vue'しなくて良いのか気になった方がいるかもしれません。
Nuxt3では自動 importの機能が搭載されています。この機能により、APIの import 文を記述することが不要になります。また、APIだけでなく、作成したコンポーネントなども自動で import してくれるので、これにより少ないコード量で Webアプリケーションを開発することができます。
バックエンド開発
次に、server/api/generate.post.jsを作成しますが、少しだけ API Routesについて説明します。
冒頭でも少しお話しましたが、Nuxt3はAPI Routesをサポートしています。API Routesは、サーバーサイドで動作する API エンドポイントを指し、外部のデータソースからデータを取得したり、データを更新することができます。
そのAPI Routesを実装するためのディレクトリが server/api であり、このディレクトリ内で API を簡単に実装することができます。
それではコードを書いていきます。
server/api/generate.post.js
export default defineEventHandler(async (event) => { const { prompt } = await readBody(event); const payload = { model: "text-davinci-003", prompt, temperature: 0.7, top_p: 1, frequency_penalty: 0, presence_penalty: 0, max_tokens: 300, n: 1, }; const response = await fetch("https://api.openai.com/v1/completions", { headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.OPENAI_API_KEY ?? ""}`, }, method: "POST", body: JSON.stringify(payload), }); const json = await response.json(); return json; })
処理は以下のような流れとなっています。
- フロント側から渡されたリクエストデータを取得
OpenAIのAPIに渡すpayloadを作成fetchメソッドでOpenAIからレスポンスオブジェクトを取得- レスポンスオブジェクトから
jsonデータを取得しフロントに返す
まず GPT-3 にテキスト生成してもらうキーワードをフロント側から受け取るのですが、リクエストデータの body をreadBody(event) で取得することができます。
その後フロント側から渡されたキーワードと定義した payload を fetch メソッドへ定義して応答を待ちます。
OpenAIのAPI Keysを作成
バックエンドの処理で、fetch メソッドのヘッダーに API Key を設定していました。OpenAI の API を使用するには API Key が必要なので作成していきます。
まずは公式サイトへ行き右上の SIGN UP をクリックしてください。

ログインができたら右上のアイコンから View API Keys をクリックします

画面中央付近にある Create new secret key をクリックします

表示された API Key をコピーして下さい。右の緑のアイコンからもコピーできます。

コピーしたら .env を作成しコピーした API Key をはりつけます
OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
フロントエンドとバックエンドを連携
それでは最後にフロントエンドとバックエンドを連携して確認してみましょう。app.vue から作成した API を実行します。
app.vue
const generateText = ref('') const handleClick = async () => { const { data } = await useFetch('/api/generate', { method: 'POST', }) generateText.value = data.value.choices[0].text }
<template> <h1>GPT-3 APP</h1> <div> <input type="text" v-model="keyword"> </div> <div> <button type="button" @click="handleClick">テキスト生成</button> </div> <div> <h2>生成テキスト</h2> <div> {{ generateText }}</div> </div> </template>
大まかな流れとしては以下の通りです。
templateで表示するために、リアクティブな変数generateTextを宣言。useFetchでAPIから生成テキストを取得。generateTextにセットし、画面に表示する。
useFetch は Nuxt3 が提供しているデータを取得するための関数です。もちろん自動 importなため、import 文は不要です。今回は POST リクエストのため method:'POST' を指定しています。GET リクエストの場合は第2引数を省略できます。useFetchで返ってくるデータですが、data の他には error, pending, execute, refresh が含まれます。今回は data のみを使用するので、分割代入で取得しています。また、data は、リアクティブデータである Ref で返ってくるので、data.value で取り出すことができます。data.value には GPT-3 で生成されたデータが含まれており、data.value.choices[0].text で取り出します。取り出したデータは generateText にセットします
ただ、現在は入力したキーワードを渡せていません。GPT-3 から期待したテキストが生成されるように、キーワードから文章を加工して、渡すようにします。
<script setup> const keyword = ref(''); const generateText = ref('') const prompt = computed(() => ` 日本語で回答して下さい。${keyword.value}について最大150文字で説明してください。 `) const handleClick = async () => { const { data } = await useFetch('/api/generate', { method: 'POST', body: { prompt } }) generateText.value = data.value.choices[0].text } </script> <template> <h1>GPT-3 APP</h1> <div> <input type="text" v-model="keyword"> </div> <div> <button type="button" @click="handleClick">テキスト生成</button> </div> <div> <h2>生成テキスト</h2> <div> {{ generateText }}</div> </div> </template>
それでは実行してみましょう(最大1分ほどかかる場合があります)

キーワードを元にテキストの生成ができました!
おわりに
今回触ってみて感じましたが、GPT-3 アプリ作成は Nuxt3 の機能を理解するのにちょうどよい題材だと思いました。自動Import についてや、特にAPI Routesについて知識を深めることができていい経験になりました。
デザインを整えたり、生成履歴を残して ChatGPT 風にしたり、テキスト生成の待機中の状態を表示したり…など、まだまだできることが多いと思います。よかったら参考にいろいろ試してみて下さい。
参考
エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。

https://career-recruit.rakus.co.jp/career_engineer/
カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.com
ラクスDevelopers登録フォーム

https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/
イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!
◆TECH PLAY
techplay.jp
◆connpass
rakus.connpass.com