スポンサーリンク

C++でnlohmann::jsonでjson形式でOpenAIと通信する

準備

以下からダウンロードし、single_include/nlohmann を適切な場所に展開する。ヘッダオンリーなのでincludeパスを通すだけでよい。

https://github.com/nlohmann/json

使用例

使用例1 文字列を整形して標準出力

前回OpenAIから取得したjsonを整形して表示してみる。nlohmann:json::parseでパースし、dumpでstd::stringに変換できる。

#include <iostream>

#include <nlohmann/json.hpp>

int main()
{
    // json形式の文字列
    std::string res = R"({"id":"cmpl-7NcCYUs1IuINlSSc8Km6ulUTjrakG","object":"text_completion","created":1685862746,"model":"text-davinci-003","choices":[{"text":"\n\nKonnichiwa, sekai.","index":0,"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":11,"total_tokens":27}}
)";

    // パース
    nlohmann::json j = nlohmann::json::parse(res);

    // 4はインデント(スペース)の個数
    std::cout << j.dump(4);


}

出力

{
    "choices": [
        {
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null,
            "text": "\n\nKonnichiwa, sekai."
        }
    ],
    "created": 1685862746,
    "id": "cmpl-7NcCYUs1IuINlSSc8Km6ulUTjrakG",
    "model": "text-davinci-003",
    "object": "text_completion",
    "usage": {
        "completion_tokens": 11,
        "prompt_tokens": 16,
        "total_tokens": 27
    }
}

使用例2 データを一つだけ取り出す

#include <iostream>

#include <nlohmann/json.hpp>

int main()
{
    // json形式の文字列
    std::string res = R"({"id":"cmpl-7NcCYUs1IuINlSSc8Km6ulUTjrakG","object":"text_completion","created":1685862746,"model":"text-davinci-003","choices":[{"text":"\n\nKonnichiwa, sekai.","index":0,"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":11,"total_tokens":27}}
)";

    // パース
    nlohmann::json j = nlohmann::json::parse(res);


    // std::cout << j["choices"].type_name();  // 「array」なのでこれは配列
    // std::cout << j["choices"].size();       // 配列の要素数。この例では「1」となる。

    assert(j["choices"].type_name()=="array");

    // j["choices"]は要素数1の配列。"text"というキーのアイテムは0番に入っている
    std::string text = j["choices"][0]["text"];

    // 4はインデント(スペース)の個数
    std::cout << text << std::endl;


}

OpenAIとの通信例

#include <iostream>
#include <fstream>
#include <string>

// libcurlを使うために必要
#define CURL_STATICLIB 
#include <curl/curl.h>

// ssl対応したlibcurlに必要
#pragma comment(lib, "CRYPT32.LIB")
#pragma comment(lib, "wldap32.lib" )
#pragma comment(lib, "Ws2_32.lib")

// ssl対応したlibcurlに必要
#pragma comment(lib,"libcurl.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

////////////////////////////////
// jsonを扱うために必要
#include <nlohmann/json.hpp>

std::size_t WriteCallback(
    const char* in,
    std::size_t size,
    std::size_t num,
    std::string* out)
{
    const std::size_t totalBytes(size * num);
    out->append(in, totalBytes);
    return totalBytes;
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

int main() {

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    // まず、OpenAI APIへアクセスするURLと、送信するデータを定義する

    const std::string url = "https://api.openai.com/v1/completions";



    // 送信するデータをjsonで記述。
    nlohmann::json json_data;
    json_data["model"] = u8"text-davinci-003"; // モデル名
    json_data["prompt"] = u8"'Hello, world'を日本語に訳してください。";
    json_data["max_tokens"] = 60;

    const std::string data = json_data.dump();

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    // ここからlibcurlの処理開始

    CURL* curl = curl_easy_init();

    if (!curl) {
        std::cerr << "Error: Failed to initialize libcurl." << std::endl;
        return false;
    }
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    // httpsの場合は、以下の設定が必要
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1);
    curl_easy_setopt(curl, CURLOPT_CAINFO, R"(.\cacert.pem)");
    curl_easy_setopt(curl, CURLOPT_CAPATH, R"(.\cacert.pem)");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    // サーバー側からの返答を受け取る関数と受け取ったデータを保存する変数を渡す
    std::string response;
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

    // OpenAI APIへのアクセスをするURLを設定
    CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_setopt() failed: %s\n", curl_easy_strerror(res));
        return 1;
    }

    //sk-ABCDEFGHIJK1234567890 はAPIキー。これを自分のものに変える。
    curl_slist* hs = NULL;
    hs = curl_slist_append(hs, "Content-Type: application/json");
    hs = curl_slist_append(hs, "Authorization: Bearer sk-ABCDEFGHIJK1234567890");

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////

    // 通信の実行
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    }
    else {

        // エラーの場合は、response_codeが200以外になる
        long response_code;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
        if (response_code != 200) {
            std::wcout << "ERROR" << std::endl;
        }
        else
        {
	    std::wcout << "SUCCESS" << std::endl;
	}
        // 成功の場合、responseには結果が入る。
        // エラーの場合、responseにはエラーの原因などが入る。
        std::cout << "HTTP Response code: " << response_code << std::endl;
        std::cout << "Response: " << response << std::endl;

        // OpenAIの返答を取得して、答えの部分だけを抽出する
        nlohmann::json jout = nlohmann::json::parse(response);
        std::string out = jout["choices"][0]["text"];

        // utf8で受け取ったデータをファイルへ保存
        std::ofstream ofs("response.txt");
        ofs << out;
        ofs.close();

    }

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////

    curl_slist_free_all(hs);
    curl_easy_cleanup(curl);

    return 0;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: