LLM APIの料金算出方法
現場にてLLMを利用した際、
どのように料金を算出するかの簡単なコードを備忘のため作成することにしました
他にもtiktokenというライブラリを使うこともできるようです
ソースコード
レスポンスのusageにそれぞれのトークンが入っています
import os
import sys
import base64
from dotenv import load_dotenv
from azure.ai.openai import OpenAIClient
from azure.core.credentials import AzureKeyCredential
def load_env():
load_dotenv()
cfg = {
"azure_openai_endpoint": os.getenv("AZURE_OPENAI_ENDPOINT"),
"azure_openai_key": os.getenv("AZURE_OPENAI_KEY"),
# Azureで作成したデプロイ名(マルチモーダル/画像対応のデプロイである必要があります)
"deployment": os.getenv("AZURE_OPENAI_DEPLOYMENT"),
# 任意: tiktoken でのトークンエンコーディングに使うモデル名(例: "gpt-4o-mini-vision")
"model_name": os.getenv("AZURE_OPENAI_MODEL", "gpt-4o-mini-vision")
}
return cfg
def image_to_data_uri(path: str) -> str:
"""画像を読み込み、チャットメッセージに埋め込むのに適した data URI(base64)文字列を返します。
注意: この方法はメッセージ内に data URI として埋め込まれた画像を受け取れるマルチモーダルモデルを前提としています
(markdown の <img> タグや HTML)。Azure OpenAI のデプロイが Vision をサポートしていることを確認してください。
"""
with open(path, "rb") as f:
b = f.read()
b64 = base64.b64encode(b).decode("utf-8")
# 拡張子から MIME タイプを推測する
ext = os.path.splitext(path)[1].lower()
if ext in [".jpg", ".jpeg"]:
mime = "image/jpeg"
elif ext == ".png":
mime = "image/png"
elif ext == ".gif":
mime = "image/gif"
else:
mime = "application/octet-stream"
return f"data:{mime};base64,{b64}"
def pretty_token_list(encoding, token_ids):
"""各トークンIDを個別にデコードして (id, text) の一覧を返します。
1トークンずつデコードすると、マルチバイトのトークンでは完全な文字列にならないことがありますが、
トークン境界の断片を確認するのに便利です。
"""
out = []
for tid in token_ids:
try:
txt = encoding.decode([tid])
except Exception:
# フォールバック: 空文字にする
txt = ""
out.append((int(tid), txt))
return out
def main(image_path: str):
if OpenAIClient is None:
print("azure.ai.openai がインポートできません。\nインストール: python -m pip install azure-ai-openai python-dotenv tiktoken")
sys.exit(1)
cfg = load_env()
endpoint = cfg["azure_openai_endpoint"]
key = cfg["azure_openai_key"]
deployment = cfg["deployment"]
model_name = cfg["model_name"]
if not endpoint or not key or not deployment:
print("環境変数 AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, AZURE_OPENAI_DEPLOYMENT を設定してください。")
sys.exit(1)
# 画像から data URI を作成し、markdown の <img> タグに埋め込む
data_uri = image_to_data_uri(image_path)
# メッセージを用意。画像は埋め込まれており、マルチモーダル対応モデルなら読み取るはずです。
user_msg = {
"role": "user",
"content": f"以下の画像からテキストを抽出してください。抽出したテキストをそのまま出力してください。\n\n<img src=\"{data_uri}\" />"
}
client = OpenAIClient(endpoint=endpoint, credential=AzureKeyCredential(key))
# 指定デプロイに対して chat completions を呼び出す
try:
resp = client.get_chat_completions(deployment_name=deployment, messages=[system_msg, user_msg])
except Exception as e:
print("Azure OpenAI へのリクエスト中にエラーが発生しました:", e)
print("注意: デプロイがマルチモーダル(画像入力対応)である必要があります。例: gpt-4o-mini-vision など")
sys.exit(1)
# アシスタントの応答を取得(最初の choice を使用)
choice = resp.choices[0]
assistant_text = choice.message.content
print("\n=== 抽出テキスト(モデル出力)===\n")
print(assistant_text)
# usage 情報があれば表示
usage = getattr(resp, "usage", None)
if usage:
print("\n=== Usage (count) ===")
try:
print(f"prompt_tokens: {usage.get('prompt_tokens')}")
print(f"completion_tokens: {usage.get('completion_tokens')}")
print(f"total_tokens: {usage.get('total_tokens')}")
except Exception:
# 属性としてのフォールバック
print(usage)
print("\n=== Assistant tokens (model output) ===")
print(f"count: {len(assistant_token_ids)}")
for tid, txt in pretty_token_list(enc, assistant_token_ids):
print(f"{tid}: {repr(txt)}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("使い方: python gpt.py <画像ファイルパス>\n例: python gpt.py D:\\images\\sample.jpg")
sys.exit(1)
image_path = sys.argv[1]
main(image_path)