ReactNativeでGPT-3を使う

# GPT-3がウェイトリストなしで利用可能になりました

OpenAIが開発した高精度な言語モデル**GPT-3**がウェイトリストなし、アカウント登録だけで誰でも利用可能になりました。

- [OpenAI’s API Now Available with No Waitlist](https://openai.com/blog/api-no-waitlist/)

Javascript用のライブラリもいくつか公開されています。そのうちの一つ、[openai-api](https://www.npmjs.com/package/openai-api)を使ってReactNativeアプリ内からGPT-3にリクエストを送信して文章を生成してみました。

# API keyの用意

[Open AI](https://openai.com/api/)でアカウントを登録してAPI keyを用意します。なお、アカウント登録ではSMS認証が必要です。

アカウント登録後、ダッシュボードでAPI keyを作成してコピーしておきます。

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681892/1935a59f-be35-11e5-992a-ef32e5a9b853.png)

# デモ用アプリを用意

APIにリクエストを送信してレスポンスを表示するだけなので、新規でアプリを作っても良いのですが、今回は自分用に作成したボイラープレートを使いました。

- [ReactNative-Expo-Firebase-Boilerplate-v2](https://github.com/kiyohken2000/ReactNative-Expo-Firebase-Boilerplate-v2)

# ライブラリのインストール

OpenAIのドキュメントページではJavascript用のライブラリがいくつか紹介されていますが、一番ダウンロード数の多い[openai-api](https://www.npmjs.com/package/openai-api)を使いました。

```shell
yarn add openai-api
```

# 完成画面

![img2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681892/d360beb0-41ed-05c6-eb9d-f327dc676a3c.jpeg)

上下にテキストボックスがあり、下のテキストボックスに文章を入力して**Generate**ボタンを押すと、上のテキストボックスにGPT-3により生成された文章が表示されます。

# コード

画面全体のコードです。

```javascript
import React, { useEffect, useState } from 'react'
import { Text, View, TextInput, Dimensions, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native'
import OpenAI from 'openai-api'

export default function Gpt() {
  const [comment, setComment] = useState('')
  const [message, setMessage] = useState('ここにGPT-3が生成した文章が入ります')
  const [isLoading, setIsLoading] = useState(false)
  const height = Dimensions.get('window').height
  const openai = new OpenAI('API keyは見せられないよ')

  useEffect(() => {
    console.log('Gpt screen')
  }, [])

  const generateMessage = async() => {
    setIsLoading(true)
    const prompt = comment
    const gptResponse = await openai.complete({
      engine: 'davinci',
      prompt: prompt,
      maxTokens: 300,
      temperature: 0.9,
      topP: 1,
      presencePenalty: 0,
      frequencyPenalty: 0,
      bestOf: 1,
      n: 1,
      stream: false,
      stop: ['\n', "testing"]
    });
    console.log(gptResponse.data)
    const responseMessage = gptResponse.data.choices[0].text
    setMessage(responseMessage)
    setIsLoading(false)
  }

  return (
    <View style={styles.container}>
      <View style={styles.content}>
        <TextInput
          multiline
          style={[styles.input, {height: height*0.3, backgroundColor: 'snow'}]}
          placeholder=''
          placeholderTextColor="#aaaaaa"
          value={message}
          underlineColorAndroid="transparent"
          autoCapitalize="none"
          editable={false}
        />
        <TextInput
          multiline
          style={[styles.input, {height: height*0.3, marginTop: 20}]}
          placeholder=''
          placeholderTextColor="#aaaaaa"
          onChangeText={(text) => setComment(text)}
          value={comment}
          underlineColorAndroid="transparent"
          autoCapitalize="none"
        />
        <TouchableOpacity
          style={styles.button}
          onPress={() => generateMessage()}
        >
          {!isLoading?
          <Text style={styles.buttonText}>Generate</Text>:
          <ActivityIndicator size="small" color="#0000ff" />
          }
        </TouchableOpacity>
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  content: {
    width: '100%',
    paddingHorizontal: 20,
  },
  input: {
    height: 48,
    borderRadius: 10,
    overflow: 'hidden',
    backgroundColor: 'white',
    paddingHorizontal: 10
  },
  button: {
    marginLeft: 30,
    marginRight: 30,
    marginTop: 20,
    height: 48,
    borderRadius: 5,
    alignItems: "center",
    justifyContent: 'center',
    backgroundColor: '#788eec'
  },
  buttonText: {
    color: 'white',
    fontSize: 16
  },
})
```

## GPT-3に関する部分

まずはライブラリをインポートします。

```javascript
import OpenAI from 'openai-api'
```

OpenAIのダッシュボードで確認したAPI keyを使って初期化します。

```javascript
const openai = new OpenAI('API keyは見せられないよ')
```

APIにリクエストを送信して、レスポンス表示用のテキストボックスにセットする関数です。

入力欄の値を`prompt`として格納してAPIにリクエストを送信しています。

```javascript
  const generateMessage = async() => {
    setIsLoading(true)
    const prompt = comment
    const gptResponse = await openai.complete({
      engine: 'davinci',
      prompt: prompt,
      maxTokens: 300,
      temperature: 0.9,
      topP: 1,
      presencePenalty: 0,
      frequencyPenalty: 0,
      bestOf: 1,
      n: 1,
      stream: false,
      stop: ['\n', "testing"]
    });
    console.log(gptResponse.data)
    const responseMessage = gptResponse.data.choices[0].text
    setMessage(responseMessage)
    setIsLoading(false)
  }
```

APIからのレスポンスは以下のようになっています。

```
Object {
  "choices": Array [
    Object {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "text": "2018年も、より良い1年になるよう、粘り強く頑張っていきましょう！",
    },
  ],
  "created": 1638347659,
  "id": "cmpl-4AFMBCd5PS3aMNFDL2q65G9NWBzS5",
  "model": "davinci:2020-05-03",
  "object": "text_completion",
}
```

# 注意

API keyはgitignoreしましょう。API keyをプッシュすると数秒で検知して使用が停止されます。

API keyが無効化されると以下のようなメールが届きます。

![img4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681892/b328bdca-1501-56f7-2acd-1280d7b1c575.png)