OpenAIのAPIで遊ぶ(1):Pythonで言葉を投げかける篇

ChatGPTが面白すぎる。リリース初日からかなり色々試して、得意不得意がだいぶわかってきた。特に彼(彼女?)は平然と嘘をつくevilさがある一方で、間違ったことを教えても素直に受け止める不思議な子である。とはいえ、「間違っているかもしれないと思ったら言わずにわかりませんと言ってください」など、こちらが伝えた指示には実直に従うし、頼んだ情報収集でも人間がよくやるミスに易々と引っかかるし、とまあ”凡庸な優等生を自由にこき使える感じ”というのが正しい気がする。個人的には与えられた文章の要約やちょっとしたブレスト/ディスカッション、あとは暇つぶし相手としては十分遊べるなあという印象。

実に優等生的である。

ということでOpenAIのAPIを取得して遊ぶ。将来的に必要になったタイミングですぐ使えるように今は遊んでおく。色々やりたいことはあるけど、公言しても大丈夫なネタでいうと将来的にChatGPTのAPIが公開されたタイミングでゼミのSlackにbotとして組み込むつもりでいる(現状で公開されているGPT3.5は厳密にはChatGPTのそれではないと思う)。

以下のいずれの方法でやるにせよ、あらかじめOpenAIのサイト上でOrganization IDとAPI KEYを取得しておく(僕は今回研究室の名義で契約したのでOrganization IDが必要だったけど、登録時にIndividualにしたら不要だったかもしれない)。英語が読めれば大して難しくないので割愛。

1. とりあえずPython + 公式ライブラリでやってみる

もちろん普通にHTTP Requestで叩けるんだけど、まずは公式に提供されているライブラリopenai/openai-pythonで触ってみる。実行はColabで。ただしデフォルトでは入っていないのでpipで入れておく。

!pip install openai

入れたら早速作業に入る。ちなみに今回はAPI_KEYとか諸々平文でやるけどそういうのはちゃんと考えることが必要。たとえばGCPのSecret Managerを使うとか、もう少しどうでもいい方法であればGoogle Drive上のパスワード付きのzipに入れておいて使うたびにそこのパスワードだけ入力を求めるとかね。

とりあえずライブラリを読み込んで、事前に取得しておいたOrganization IDとAPI KEYを入れる。この辺はフリープランで無料枠が残ってないとか関係なく、KEYなどがまともなら特に問題なく進むはず。

import openai
openai.organization = '<YOUR_ORGANIZATION_ID>'
openai.api_key = '<YOUR_API_KEY>'

試しにいま利用可能なモデルの一覧を取得してみる。openai.Model.list()でモデル一覧が返ってくる。

for m in openai.Model.list()['data']:
    print(m['id'])

ちなみに今回はGPT3.5で構築されたtext-davinci-003を使う。そして今回のようにテキストを投げて返してもらうタスクはCompletionにあたる。よって、

model = 'text-davinci-003'
prompt = 'Hi, this is a test.'
completion = openai.Completion.create(engine=model, prompt=prompt)
print(completion.choices[0].text)

無事に通ればこんな感じで返ってくる。なぜか頭に’\n\n’がついてるのが鬱陶しい。

もしここでFree planがどうこうなどのエラーが返ってきたらあなたの無償枠はもう空です。大人しくクレジットカードを登録して遊びましょう。

ちなみに生のcompletionはこんな感じのJSONで返ってくる。

print(completion)
正直別に隠す意味もないけど

usageを見ると今回のタスクにtokenがいくつ使われたかわかる。プロンプトに7、タスクに16で計23トークン消費されている。ちなみに、Tokenと価格の関係についてはPricingに示されていて、

今回はDavinciを用いていて、$0.0200 per 1K token、下には約750wordsとの表記がある。まあちょっと遊ぶぐらいなら良いおもちゃになりますね。

当然日本語でも叩ける。面倒なので関数化して、

def ask(prompt):
    completion = openai.Completion.create(engine='text-davinci-003', prompt=prompt)
    text = completion.choices[0].text
    print(text)
    return completion
c = ask('こんにちは!これはテストです。')

「は?なんか途切れてるんだけど?」みたいな気持ちを抑えてAPIのdocを読み返すと、Completion.createは引数にmax_tokensを取っており、それ以上のtokenを消費しないようになっている模様。現にcompletionの中身でも”finish_reason”: “length”とのことで、トークンベースで生成する長さの上限を区切りそれ以上は吐かないようになっているっぽい。デフォルトは16になっているようなのでとりあえず50にしてみる。

基本的にはgenerativeなので全く同じ回答が返ってくることはほぼないと思っていい。テストありがとうございます!からなんとなく意識高い系みたいな嫌な空気を感じることは置いておいて、長さは調整できることがわかった。公式のPlaygroundみたいにstop_sequenceで”。”とか”!”とか取ったら止まるようにできると良いんだけどね。

っていうか冒頭の\n\nが鬱陶しい。どうすればいいのかWeb上のChatGPTに訊く(Colab側ではコードを表示する機能を実装していないので面倒)。

なるほどね。そこをいじるついでに翻訳タスクをやらせてみる。

def ask(prompt):
    completion = openai.Completion.create(
        engine='text-davinci-003', 
        prompt=prompt, 
        max_tokens=60
        )
    text = completion.choices[0].text.strip()
    print(text)
    return completion
c = ask('次の文章を翻訳してください:\n"This is the pen you gave to me."')

うん、いい感じですね。

2. 同じことをPythonのHTTP Requestで実装

これはひたすらにぼくの練習なので、わざわざ同じことをまたやります。まあ、といってもこの辺はいまさらなんだけど。

url = "https://api.openai.com/v1/completions"
headers = {
    "Content-Type": "application/json",
    "Authorization": 'Bearer '+API_KEY,
    "OpenAI-Organization": ORGANIZATION_ID
}
data = {
    "model": "text-davinci-003",
    "prompt": "Hi, this is a test."
}
res = requests.post(url, headers=headers, json=data)
print(res.status_code)
res.json()

まあこんな感じで返ってくる。つまりこんな感じで取り出せる。

res.json()['choices'][0]['text'].strip()

とりあえずPython上でHTTPリクエストでAPI叩いて必要な情報を取り出すことはできるようになったので、続きはまた次回やることにする。

次回OpenAIのAPIで遊ぶ(2):Pythonで会話を実装する篇に続く。