OpenAI APIを利用して【感想文ジェネレーター】を作成しました

# はじめに

小学生の頃から嫌いなことがあります。
それは、プリントの「感想」の欄です.
自分の思いを文章にするのが苦手で、「箇条書きでよくないか、、、？」と常々思ってきました。

読書感想文なんて一番苦手でした。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/cf77c1c6-1a75-9568-c8e7-7a2637c6a98c.png" width="200px"/>

そんな私がOpenAI社のGPT-3を利用して
【感想文ジェネレーター】
を作成しました。

https://opinion-ai.vercel.app/

無料枠で作成したため、無料枠が尽きると動かなくなりますので、
突然サービス終了する可能性があります。ご容赦ください。

<font color="red">(特にCSSには)改善の余地があります。ちょっとずつ直します</font>

# 概要

(現在の画面と異なる可能性があります)

1. [感想文ジェネレーター](https://opinion-ai.vercel.app/)を開く

    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/21098711-fcb1-91a5-83dc-8465330e69a0.png" width="400px"/>

1. 必要な項目を入力

    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/0120d2f2-f99e-fc34-b159-42e259fac22f.png" width="400px"/>

    * 例) 
    * 何について
        * TypeScript初学者研修
    * 職業
        * 会社員3年目
    * 何文字程度で作成するか
        * 300

1. 生成

    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/6a112c3c-6022-350c-041d-ddf1acb53db5.png" width="400px"/>

    そこそこいい感じですね👍
    私が作る文章よりもしっかりしています

# ざっくり技術スタック

![opinion-ai.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/55c5a322-713e-6ef5-e43c-71faebd433ba.png)

# ざっくり構成

![構成.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/4f0359ae-530e-5e1b-e082-ee5bc1f2cec8.png)

ざっくり解説してみると、

## 利用者

1. ブラウザで必要な情報を入力し、回答生成のリクエストを送る。
1. `API Gateway`を通して`step functions`へ通じ処理が始まる。
1. `API Gateway`のtimeoutは29sのため、`step functions`を使い、タイムアウトの問題を解決している。
1. 非同期処理で、`OpenAI`からの回答が返ってきたら`Supabase`に回答を格納する。
1. ブラウザでは`Supabase`のリアルタイム機能を使い、特定のテーブルの`INSERT`イベントを検知し、回答を表示する。

## 開発

* フロントエンド側は`Vercel`でビルド・デプロイしているので、`github`の`main`ブランチの変更を検知してビルド・デプロイが走る
* バックエンド側のは`ServerlessFramework`でデプロイしている。

# `OpenAI`回答生成

## ソースコード

```typescript:handler.ts
import { Configuration, OpenAIApi } from 'openai'

const getAnswer = async (event) => {
  const config = new Configuration({ apiKey: ************** });
  const openai = new OpenAIApi(config);
  const prompt = `
  質問: あなたの職業は${event.occupation}です。${event.title}についての感想を以下を参考に${event.answer_length}文字程度で作成してください。
  ${event.feature}
  回答: 
  `
  const response = await openai.createCompletion(
    {
      model: "text-davinci-003",
      prompt: prompt,
      temperature: 1,
      max_tokens: 1000,
    }
  );
}
```

## 解説

nodejsでは、`openai`ライブラリをインストールして使います

```bash
# npm
npm i openai
# yarn
yarn add openai
# pnpm
pnpm i openai
```

1. config設定

    この時にapiKeyを使うのですが、この値は`GitHub`に上げたり、フロント側のソースコードに載せたりしないようにしましょう
    私は`process.env.*****`で環境変数にしました。
    
    ```typescript
    const config = new Configuration({ apiKey: ************** });
    ```

1. configを使って初期化をします。
    
    ```typescript
    const openai = new OpenAIApi(config);
    ```

1. createCompletion

    初期化をしたら`createCompletion`メソッドを使います。
    このメソッドはプロンプトに基づいてテキストを生成するメソッドです。
    
    主なプロパティは以下の通りです。
    
    * model: 使用するモデルの名前
    * prompt: テキスト生成のための入力となる文字列
    * max_tokens: 生成する最大トークン数
    * temperature: 生成されるテキストの多様性を制御するパラメータ。0から1までの値を設定し、1に近づくほど多様性が上がる。
    
    他にも色々なプロパティがあるので、もっとカスタマイズしたい場合は[公式ドキュメント](https://platform.openai.com/docs/introduction/overview)をご参照ください

    ```typescript
      const response = await openai.createCompletion(
        {
          model: "text-davinci-003",
          prompt: prompt,
          temperature: 1,
          max_tokens: 1000,
        }
      );
    ```

1. promptについて


    `createCompletion`メソッドは前の文から予測して次の文を考えるメソッドなので、例としては以下のように使います。
    
    ```
    Aさん: 昨日の星空は綺麗だったね。Bさんはどうだった？
    Bさん: 
    ```
    
    ここまでを`propmt`に入れることでBさんのセリフをBさんの立場で考えてくれるという仕組みです。
    
    私の場合は
    
    ```typescript
    const prompt = `
      質問: あなたの職業は${event.occupation}です。${event.title}についての感想を以下を参考に${event.answer_length}文字程度で作成してください。
      ${event.feature}
      回答: 
    `
    ```
    
    このようにすることで、感想文を書く立場・対象・特徴について設置を教え、回答を生成させています。

他の実装箇所については徐々に記事にして行こうと思います〜

# 最後に

AIを作るのは大変ですが、
AIを使うのは簡単でした。

楽しい世の中になってきましたね