Почему C++ и ChatGPT — это не странно, а мощно
Когда речь заходит об интеграции нейросетей, все почему-то сразу вспоминают Python. Да, у питонистов есть элегантные библиотеки вроде openai и requests. Но что делать, если ваш проект — высоконагруженный сервер на C++, десктопное приложение или игровой движок? Не переписывать же всё на Python?
Хорошая новость: интеграция с ChatGPT API на C++ — это не магия, а вполне решаемая инженерная задача. Вы получаете скорость нативного кода, контроль над памятью и возможность встраивать AI-функции прямо в ядро вашего приложения. Никаких прослоек на Python или Node.js — только чистый C++ и прямая работа с API.
В этой статье мы разберём, как написать клиент для OpenAI API на C++ с нуля. Вы узнаете, как отправлять HTTP-запросы, обрабатывать JSON и получать ответы от ChatGPT. Поехали!
Что нам понадобится: инструментарий
Для работы с ChatGPT API на C++ нам нужно решить две базовые задачи:
- Отправлять HTTP-запросы (желательно с поддержкой HTTPS)
- Парсить и формировать JSON
Мы будем использовать две проверенные библиотеки:
- libcurl — де-факто стандарт для HTTP в C/C++. Есть в любом пакетном менеджере.
- nlohmann/json — современная, удобная JSON-библиотека. Просто подключите заголовочный файл.
Также нам понадобится API-ключ от OpenAI. Если у вас его ещё нет — зайдите на platform.openai.com, зарегистрируйтесь и создайте ключ в разделе API keys. Храните его в безопасности, лучше всего — в переменной окружения.
Архитектура простого клиента
Наш клиент будет делать одну вещь: отправлять сообщение пользователя в ChatGPT и получать ответ. Всё общение с API происходит через эндпоинт https://api.openai.com/v1/chat/completions методом POST.
Структура будет такой:
- Формируем JSON с параметрами запроса (модель, сообщения, температура)
- Отправляем POST-запрос через libcurl
- Получаем JSON-ответ и парсим его
- Извлекаем текст ответа ассистента
Звучит просто? Давайте писать код.
Шаг 1: Подготовка JSON-запроса
Начнём с функции, которая формирует тело запроса. Мы будем использовать библиотеку nlohmann/json. Установить её проще простого: скачайте json.hpp с GitHub и положите в папку с проектом.
#include <string>
#include "json.hpp"
using json = nlohmann::json;
std::string build_chat_request(const std::string& user_message) {
json request;
request["model"] = "gpt-3.5-turbo";
json messages = json::array();
json user_msg;
user_msg["role"] = "user";
user_msg["content"] = user_message;
messages.push_back(user_msg);
request["messages"] = messages;
request["temperature"] = 0.7;
request["max_tokens"] = 1024;
return request.dump();
}
Обратите внимание: мы используем модель gpt-3.5-turbo — это оптимальный баланс между качеством и скоростью. Если вам нужно что-то помощнее, можно указать gpt-4, но это дороже.
Шаг 2: Отправка HTTP-запроса с libcurl
Теперь самое интересное — работа с C++ HTTP запросами. libcurl требует некоторой инициализации, но в целом всё прямолинейно.
Напишем функцию, которая принимает тело запроса и API-ключ, а возвращает сырой ответ от сервера.
#include <curl/curl.h>
#include <string>
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
size_t total_size = size * nmemb;
output->append((char*)contents, total_size);
return total_size;
}
std::string send_chat_request(const std::string& json_body, const std::string& api_key) {
CURL* curl = curl_easy_init();
std::string response;
if (curl) {
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
std::string auth_header = "Authorization: Bearer " + api_key;
headers = curl_slist_append(headers, auth_header.c_str());
curl_easy_setopt(curl, CURLOPT_URL, "https://api.openai.com/v1/chat/completions");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
// Важно для работы с HTTPS
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}
return response;
}
Разберём ключевые моменты:
WriteCallback— это функция обратного вызова, которая накапливает данные ответа в строку. libcurl вызывает её по мере получения данных.- Мы передаём API-ключ в заголовке
Authorization: Bearer. - Обязательно включаем проверку SSL-сертификатов, чтобы не попасть под MITM-атаку.
Шаг 3: Парсинг ответа и извлечение текста
Когда мы получили JSON-ответ от сервера, нужно извлечь из него текст сообщения ассистента. Ответ имеет такую структуру:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "Привет! Чем могу помочь?"
}
}
]
}
Функция для парсинга:
std::string extract_assistant_reply(const std::string& raw_response) {
try {
json response_json = json::parse(raw_response);
if (response_json.contains("choices") && !response_json["choices"].empty()) {
return response_json["choices"][0]["message"]["content"];
} else {
return "Ошибка: пустой ответ от API";
}
} catch (const std::exception& e) {
return "Ошибка парсинга JSON: " + std::string(e.what());
}
}
Обратите внимание на обработку ошибок. API может вернуть сообщение об ошибке, превышении лимита или некорректном запросе. В production-коде стоит добавить более детальную проверку.