Chat GPT　APIの料金を求める

近年OpenAIが開発したChatGPTは、驚くほど自然な文章生成能力を持つ言語モデルとして注目を集めています。

最近ではChatGPTをもとにしたアプリケーションも多数出てきています。

これらのアプリケーションはもちろんChatGPTのAPIを使っているのですが、そこで気になるのがAPI料金。

本記事ではこれからChatGPTを利用していきたい人向けにChatGPTのAPI料金を自動計算するプログラムを紹介します。

# APIの料金体系
まずは、ChatGPTのAPIの料金体系について説明します。（2024/2)

ChatGPTの料金体系は公式サイトのAPIタブ内にあるPricingに記載があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663858/21b5eca0-9a3f-a4f0-15c7-c301686fbabf.png)

基本的にChatGPTの料金体系は1000トークン（1K = 1000です）あたりの金額となっており、

例えばGPT-4の場合は以下のようにインプット1000トークンあたり0.03ドルとなっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663858/570d9d95-29ab-d1bc-7bf7-ec2c6b03ca47.png)

GPT-3.5の場合は以下の通り。

当たり前ですが、低機能なモデルになれば価格は下がっていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663858/27f336e2-6f12-833d-5507-91280b5057b0.png)

# APIの価格を求めるプログラムの全体像

前項目よりChatGPTのAPI料金を求めるには以下項目が必要ということが分かりました。

トークン数

モデルの1000トークンあたりの単価

今回はこれを自動で計算できるプログラムを作成してみました。

```python:token_calc_price.py
#ChatGPTのトークン数を計算するライブラリ
import tiktoken

#webサイトから情報を取得するライブラリ
import requests
from bs4 import BeautifulSoup

#文字列のパターンを検索できるライブラリ
import re

#時間を扱うライブラリ
import datetime

#スクレイピング用パラメータ
url_fx = "https://www.nikkei.com/markets/kawase/"
fx_selector = '#CONTENTS_MARROW > div.mk-top_exchange_rate.cmn-clearfix > div.cmn-clearfix > div.mkc-guidepost > div.mkc-prices > div.mkc-stock_prices'
gpt_selector_gpt35 = "#gpt-3-5-turbo > div > div > div.xs\:mt-40.md\:mt-48.lg\:mt-60 > div > div > div.overflow-hidden > table > tbody > tr:nth-of-type(2) > td:nth-of-type(2) > span:nth-of-type(1)"
encoding_model_gpt35 = "gpt-3.5-turbo-0301"
gpt_selector_gpt4 = "#gpt-4 > div > div > div.xs\:mt-40.md\:mt-48.lg\:mt-60 > div > div > div.overflow-hidden > table > tbody > tr:nth-of-type(2) > td:nth-of-type(2) > span:nth-of-type(1)"
encoding_model_gpt4 = "gpt-4"

#料金計算したい文を入力
chat="おはようございます。"

#トークン数を計算する関数
def calc_token(chat, encoding_name):
    encoding = tiktoken.get_encoding(encoding_name)
    num_tokens = len(encoding.encode(chat))
    return num_tokens

#スクレイピングにより取得した数値を処理する関数
def ex_num(ex_soup):
    regex = r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?'
    num = re.findall(rf'({regex})', str(ex_soup[0]))
    return num

#chatGPTのサイトから料金を抜き出す関数
def ex_gpt_pri(gpt_selector , encoding_model , chat):
    res_openai = requests.get("https://openai.com/pricing")
    soup_openai = BeautifulSoup(res_openai.text, "html.parser")
    soup_openai_gpt = soup_openai.select(gpt_selector)
    
    ex_num_gpt = ex_num(soup_openai_gpt)[1][0]
    
    uni_pri_gpt = float(ex_num_gpt)
    
    encoding_model = tiktoken.encoding_for_model(encoding_model)
    calc_token_num = float(calc_token(chat, encoding_model.name))
    
    pri_gpt = calc_token_num * uni_pri_gpt
    
    return pri_gpt

#ドル円レートを抜き出す関数
def fx_rate(url_fx , url_selector):
    url_fx = url_fx
    res_fx = requests.get(url_fx)
    soup_fx = BeautifulSoup(res_fx.text,'html.parser')

    now = datetime.datetime.now()
    now_time = "{0.year}年{0.month}月{0.day}日{0.hour}時{0.minute}分".format(now)

    ex_yen_price = soup_fx.select(url_selector)
    yen_price = float(ex_num(ex_yen_price)[1][0])
    return now_time , yen_price

#GPT-3.5とGPT-4について計算を行う。
ex_gpt_pri_35 = ex_gpt_pri(gpt_selector_gpt35 , encoding_model_gpt35 , chat)
ex_gpt_pri_4 = ex_gpt_pri(gpt_selector_gpt4 , encoding_model_gpt4 , chat)
fx_rate = fx_rate(url_fx , fx_selector)

gpt35_pri_yen = ex_gpt_pri_35 * fx_rate[1]
gpt4_pri_yen = ex_gpt_pri_4 * fx_rate[1]

#最終的な結果について表示する。
print("入力文："+ chat)
print("GPT3.5　{}円" .format(round(gpt35_pri_yen,2)))
print("GPT4　{}円" .format(round(gpt4_pri_yen,2)))
```
結果
入力文：おはようございます。 
GPT3.5　0.00052円 
GPT4　0.03147円

このプログラムを使うことで、入力した文章のGPT-3.5とGPT-4でのAPI料金が日本円で算出できます。

# 関数の解説
以下各関数でどのような処理をしているかをざっくり書いていきます。

## トークン数を計算する関数
ここではtiktokenを使い、入力した文章のトークン数を計算しています。

トークン数の計算についてはこちらに詳しく記載しています。

入力は文章、計算したいモデルの名前とし、出力はトークン数としています。

```python:token_calc_price.py
def calc_token(chat, encoding_name):
    encoding = tiktoken.get_encoding(encoding_name)
    num_tokens = len(encoding.encode(chat))
    return num_tokens
```

## スクレイピングにより取得した数値を処理する関数
ここではChatGPTのサイトから抜き出したモデルごとの料金部分から計算に使えるよう数値を抜き出す処理をしています。

入力はChatGPTサイトからのスクレイピング結果、出力はAPIの料金単価としています。

```python:token_calc_price.py
def ex_num(ex_soup):
    regex = r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?'
    num = re.findall(rf'({regex})', str(ex_soup[0]))
    return num
```

## chatGPTのサイトから料金を抜き出す関数
ここではChatGPTのホームページから指定したモデルの1000K当たりの金額（＄）を抜き出し、計算したトークン数と掛け合わせることで入力した文の料金をドル建てで算出しています。

入力はchatGPTの料金サイト内にある料金部分のCSSセレクタ、モデルの名称、入力文とし、出力はドル建てのAPI料金となっています。

```python:token_calc_price.py
def ex_gpt_pri(gpt_selector , encoding_model , chat):
    res_openai = requests.get("https://openai.com/pricing")
    soup_openai = BeautifulSoup(res_openai.text, "html.parser")
    soup_openai_gpt = soup_openai.select(gpt_selector)
    
    ex_num_gpt = ex_num(soup_openai_gpt)[1][0]
    
    uni_pri_gpt = float(ex_num_gpt)
    
    encoding_model = tiktoken.encoding_for_model(encoding_model)
    
    calc_token_num = float(calc_token(chat, encoding_model.name))
    
    pri_gpt = (calc_token_num * uni_pri_gpt)/1000
    
    return pri_gpt
```

## 為替レートを抽出する関数

ここでは為替を掲載しているサイトからドル円のレートを抜き出す処理をしています。

ドル円のレートは都度変わるため、プログラムを回したときに都度計算するようにしています。

実際はおそらくどこかの時期のドル円レートで計算をしているはずですが、、、

入力はFXサイトのURL、URLのドル円レートが記載されているCSSセレクタとし、出力は時間とドル円レートとしています。

```python:token_calc_price.py
def fx_rate(url_fx , url_selector):
    url_fx = url_fx

    res_fx = requests.get(url_fx)

    soup_fx = BeautifulSoup(res_fx.text,'html.parser')

    now = datetime.datetime.now()
    now_time = "{0.year}年{0.month}月{0.day}日{0.hour}時{0.minute}分".format(now)

    ex_yen_price = soup_fx.select(url_selector)
    yen_price = float(ex_num(ex_yen_price)[1][0])
    return now_time , yen_price
```

## 関数を使った計算
上記で作成した関数を使い計算をしていきます。

関数で処理をまとめているので、実際の計算部分はとてもシンプルです。

これで料金をスクレイピングし、トークン数と掛け合わせ、API費用を求めるプログラムが完成しました。

```python:token_calc_price.py
ex_gpt_pri_35 = ex_gpt_pri(gpt_selector_gpt35 , encoding_model_gpt35 , chat)
ex_gpt_pri_4 = ex_gpt_pri(gpt_selector_gpt4 , encoding_model_gpt4 , chat)
fx_rate = fx_rate(url_fx , fx_selector)

gpt35_pri_yen = ex_gpt_pri_35 * fx_rate[1]
gpt4_pri_yen = ex_gpt_pri_4 * fx_rate[1]

print("入力文："+ chat)
print("GPT3.5　{}円" .format(round(gpt35_pri_yen,5)))
print("GPT4　{}円" .format(round(gpt4_pri_yen,5)))
```

# まとめ
今回はスクレイピング、トークン数の計算を使い、APIの料金を求めました。

処理を関数に分割して処理することで、わかりやすいプログラムになった気がしますが、実際はもう少し処理を分割できるなとは思っています。改善あるのみですね。

また、実際に計算してみると意外と安く使えるんだなということが分かったので、どんどん使っていこうと思っています。