Почему 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()
// Создаем