【C#】ChatGPT APIの使い方

ChatGPTは、OpenAIが開発した自然言語処理の大型言語モデルで、様々なタスクに利用されます。その中でも、APIを利用することで、誰でも簡単にChatGPTを利用することができます。この記事では、流行のChatGPTについて、APIをC#で使ってみたいと思います。

【検証環境】.NET6.0

利用準備

APIの利用にはOpenAIのアカウントを作成して、APIキーを発行する必要があります。

https://openai.com/blog/openai-api

APIキーを取得するために、OpenAIの管理画面からAPIキーを作成します。APIキーを作成すると、アクセストークンが発行されます。このアクセストークンを使って、APIにアクセスすることができます。

利用料についてはFree Trialで18ドル分まで利用できます。トライアルで使うには十分すぎますね。

APIの使い方

公式ドキュメント https://platform.openai.com/docs/api-reference/chat/create

もしかしたらサードパーティのライブラリがあるかもしれませんが、探すのが面倒なのでHttpClientで直接記述します。

リクエスト用のクラス

ドキュメントのリクエストパラメータは下記です。

modelgpt-3.5-turboを埋め込みで利用します。messagesを動的にするためにクラスを定義する必要があります。

{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "Hello!"}]
}

Messageクラスでリクエスト用のプロパティを定義します。


public class Message
{
    [JsonPropertyName("role")]
    public string Role { get; set; }
    [JsonPropertyName("content")]
    public string Content { get; set; }
}

MessagesクラスでMessageをListで持ちます。

これは会話の文脈を保持しておくために使います。質問を往復する場合などのためですね。

文脈を保持しすぎると、利用料に影響していくので注意が必要です(参考)

public class Messages
{
    private static List<Message> _messages;

    static Messages()
    {
        _messages = new List<Message>();
    }

    public static List<Message> GetMessages()
    {
        return  new List<Message>(_messages);
    }

    public static void AddMessage(Message message)
    {
        _messages.Add(message);
    }

    public static void ClearMessages()
    {
        _messages.Clear();
    }
}

レスポンス用のモデル

公式のレスポンス例がこちら。

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "nnHello there, how may I assist you today?",
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

レスポンス結果をデシリアライズするクラスです。

using System.Text.Json.Serialization;

public class ChatGptResponse
{
    // Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse);
    public class Choice
    {
        [JsonPropertyName("finish_reason")]
        public string FinishReason { get; set; }

        [JsonPropertyName("index")]
        public int Index { get; set; }

        [JsonPropertyName("message")]
        public Message Message { get; set; }
    }

    public class Message
    {
        [JsonPropertyName("content")]
        public string Content { get; set; }

        [JsonPropertyName("role")]
        public string Role { get; set; }
    }

    public class Root
    {
        [JsonPropertyName("choices")]
        public List<Choice> Choices { get; set; }

        [JsonPropertyName("created")]
        public int Created { get; set; }

        [JsonPropertyName("id")]
        public string Id { get; set; }

        [JsonPropertyName("model")]
        public string Model { get; set; }

        [JsonPropertyName("object")]
        public string Object { get; set; }

        [JsonPropertyName("usage")]
        public Usage Usage { get; set; }
    }

    public class Usage
    {
        [JsonPropertyName("completion_tokens")]
        public int CompletionTokens { get; set; }

        [JsonPropertyName("prompt_tokens")]
        public int PromptTokens { get; set; }

        [JsonPropertyName("total_tokens")]
        public int TotalTokens { get; set; }
    }
}

APIにリクエストするクラス

ポイントは文脈に追加して、それをリクエストの度に読み込む必要あるところだと思います。

using System.Text.Json.Serialization;
   
 public class ChatGPptAPI
{
    // エンドポイント
    const string _url = "https://api.openai.com/v1/chat/completions";
    // APIキー
    const string _token = "【YOUR API KEY】";
    // モデル
    const string _model = "gpt-3.5-turbo";

    public static async Task<string> RequestTChatGPptAsync(string text)
    {
        // 文脈に追加
        Messages.AddMessage(new Message() { Role = "user", Content = text });

        using var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
        var requestData = new
        {
            model = _model,
            messages = Messages.GetMessages(),
        };
        var content = new StringContent(
            JsonSerializer.Serialize(requestData),
            Encoding.UTF8,
            "application/json");
        try
        {
            var response = await httpClient.PostAsync(_url, content);
            if (response.IsSuccessStatusCode)
            {
                // レスポンスをJSONとしてパースし、必要な情報を取得
                var responseContent = await response.Content.ReadAsStringAsync();
                var chatGptResponse = JsonSerializer.Deserialize<ChatGptResponse.Root>(responseContent);
                // 文脈に追加
                Messages.AddMessage(new Message() { Role = "assistant", Content = chatGptResponse.Choices[0].Message.Content });
                return chatGptResponse.Choices[0].Message.Content;
            }
            else
            {
                return "";
            }
        }
        catch (Exception e)
        {
            return e.Message;
        }
    }
}

実行結果

// 入力を繰り返し受け取る
while (true)
{
    Console.Write("n User:");
    var input = Console.ReadLine();
    
    // 「exit」が入力されたらループを抜ける
    if (input.ToLower() == "exit")
    {
        break;
    }

    var res = await ChatGPptAPI.RequestTChatGPptAsync($"n{input}");
    Console.WriteLine($"n{res}");
}

とりあえず動作していることは確認できました。

Leave a Reply

Your email address will not be published. Required fields are marked *