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で直接記述します。
リクエスト用のクラス
ドキュメントのリクエストパラメータは下記です。
modelはgpt-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}");
}
とりあえず動作していることは確認できました。