Интеграция с ChatGPT API на Go: от идеи до рабочего кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему Go и ChatGPT — это идеальный тандем?

Вы когда-нибудь задумывались, как быстро можно «научить» свою Go-программу общаться с пользователем как живой человек? Или, может быть, вы хотите автоматизировать генерацию контента, создать интеллектуального ассистента или просто добавить «изюминку» в свой сервис? Интеграция с ChatGPT API на Go — это не просто модный тренд, а мощный инструмент, который открывает двери в мир искусственного интеллекта. Go, с его скоростью и простотой, идеально подходит для создания быстрых и надежных запросов к нейросетям. В этой статье мы не просто разберем теорию, а напишем реальный код, который можно сразу использовать в своих проектах.

Готовим почву: что нужно для старта?

Прежде чем нырнуть в код, давайте убедимся, что у нас есть все необходимое. Вам понадобится:

  • Установленный Go (версия 1.21 или выше, чтобы использовать все современные возможности).
  • API-ключ OpenAI. Получить его можно на платформе OpenAI. Относитесь к нему как к паролю от банковской карты — храните в секрете!
  • Базовое понимание HTTP-запросов и структур данных в Go.

Весь код из статьи мы будем писать в одном файле main.go, чтобы не усложнять структуру. Поехали!

Шаг 1: Создаем HTTP-клиент и отправляем первый запрос

Сердцем нашей интеграции будет стандартный пакет net/http. Он легковесный, быстрый и не требует сторонних зависимостей. Наша задача — отправить POST-запрос к эндпоинту https://api.openai.com/v1/chat/completions с правильным телом и заголовками.

Структура запроса

ChatGPT API ожидает JSON определенного формата. Давайте создадим структуры Go, которые будут точно соответствовать этому формату:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type ChatMessage struct {
    Role    string `json:"role"`
    Content string `json:"content"`
}

type ChatRequest struct {
    Model    string        `json:"model"`
    Messages []ChatMessage `json:"messages"`
}

type ChatResponse struct {
    Choices []struct {
        Message ChatMessage `json:"message"`
    } `json:"choices"`
}

Обратите внимание на json:"..." тэги. Они гарантируют, что Go правильно «упакует» (сериализует) наши данные в JSON, который поймет OpenAI.

Функция-отправитель

Теперь напишем функцию, которая берет на себя всю «грязную» работу: формирует запрос, отправляет его и парсит ответ.

func askChatGPT(apiKey, prompt string) (string, error) {
    reqBody := ChatRequest{
        Model: "gpt-3.5-turbo",
        Messages: []ChatMessage{
            {Role: "user", Content: prompt},
        },
    }

    jsonData, err := json.Marshal(reqBody)
    if err != nil {
        return "", fmt.Errorf("ошибка маршалинга: %w", err)
    }

    request, err := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewBuffer(jsonData))
    if err != nil {
        return "", fmt.Errorf("ошибка создания запроса: %w", err)
    }

    request.Header.Set("Content-Type", "application/json")
    request.Header.Set("Authorization", "Bearer "+apiKey)

    client := &http.Client{}
    response, err := client.Do(request)
    if err != nil {
        return "", fmt.Errorf("ошибка выполнения запроса: %w", err)
    }
    defer response.Body.Close()

    body, err := io.ReadAll(response.Body)
    if err != nil {
        return "", fmt.Errorf("ошибка чтения ответа: %w", err)
    }

    // Проверяем статус-код
    if response.StatusCode != http.StatusOK {
        return "", fmt.Errorf("API вернул ошибку: %s, тело: %s", response.Status, string(body))
    }

    var chatResp ChatResponse
    err = json.Unmarshal(body, &chatResp)
    if err != nil {
        return "", fmt.Errorf("ошибка разбора JSON: %w", err)
    }

    if len(chatResp.Choices) == 0 {
        return "", fmt.Errorf("пустой ответ от API")
    }

    return chatResp.Choices[0].Message.Content, nil
}

Ключевые моменты:

  • Мы используем json.Marshal для превращения структуры в JSON.
  • Заголовок Authorization — это наш пропуск в мир ChatGPT.
  • Обязательно проверяем Status Code. Если он не 200, значит, что-то пошло не так (например, кончились деньги на счету).

Запускаем!

Добавим функцию main и проверим, как это работает:

func main() {
    apiKey := os.Getenv("OPENAI_API_KEY")
    if apiKey == "" {
        fmt.Println("Ошибка: не установлена переменная окружения OPENAI_API_KEY")
        return
    }

    answer, err := askChatGPT(apiKey, "Напиши короткое приветствие на русском языке от лица дружелюбного робота.")
    if err != nil {
        fmt.Printf("Ошибка: %v\n", err)
        return
    }

    fmt.Println("Ответ ChatGPT:")
    fmt.Println(answer)
}

Запустите код командой go run main.go, предварительно экспортировав ключ: export OPENAI_API_KEY="sk-...". Если вы увидели в консоли дружелюбное приветствие — поздравляю, первая интеграция удалась!

Шаг 2: Потоковая передача (Streaming) — говорим без пауз

Стандартный запрос заставляет нас ждать полный ответ. А что если ChatGPT думает 10 секунд? Пользователь будет смотреть на пустой экран и нервничать. Решение — потоковая передача данных (Server-Sent Events). Мы получаем ответ по кусочкам и выводим их сразу же. Это делает взаимодействие живым и быстрым.

Меняем структуру запроса

Добавим поле Stream в нашу структуру ChatRequest:

type ChatRequest struct {
    Model    string        `json:"model"`
    Messages []ChatMessage `json:"messages"`
    Stream   bool          `json:"stream"` // Новое поле!
}

Пишем потоковую функцию

func askChatGPTStream(apiKey, prompt string) error {
    reqBody := ChatRequest{
        Model: "gpt-3.5-turbo",
        Messages: []ChatMessage{
            {Role: "user", Content: prompt},
        },
        Stream: true, // Включаем стриминг
    }

    jsonData, _ := json.Marshal(reqBody)
    request, _ := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewBuffer(jsonData))
    request.Header.Set("Content-Type", "application/json")
    request.Header.Set("Authorization", "Bearer "+apiKey)
    request.Header.Set("Accept", "text/event-stream") // Важно!

    client := &http.Client{}
    response, err := client.Do(request)
    if err != nil {
        return err
    }
    defer response.Body.Close()

    // Создаем                

Блоги

Рекомендаций по книгам