User: Давай писать функцию
func handleAiSearch(w http.ResponseWriter, r *http.Request) {
	log.Printf("Received request: %s %s\n", r.Method, r.URL.Path)
	deviceData := r.URL.Query().Get("deviceid")
	queryAI := r.URL.Query().Get("query")
	if deviceData == "" && queryAI == "" {
		http.Error(w, "Ошибка.", http.StatusInternalServerError)
		return
	}
	log.Printf("Requested deviceID: %s\n", deviceData)
	log.Printf("Requested queryAI: %s\n", queryAI)
	var exists bool
	err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM devices WHERE device_id = $1)", deviceData).Scan(&exists)
	if err != nil {
		fmt.Printf("Ошибка при проверке существования записей: %v\n", err)
		http.Error(w, "Ошибка при проверке существования записей", http.StatusInternalServerError)
		return
	}
	if exists {
		gptContent := fmt.Sprintf(
			"Порекомендуй список из 40 элементов по Теме из \"Запрос пользователя\" и обязательно разбей по категориям (10 штук на категорию!): фильмы, сериалы, мультфильмы и аниме\n"+
				"Твой ответ должен быть такой (в {} динамичные данные, без {} статичные) (названия должны быть реальными!!)(за другой буду ругать!) {number}; ru_name - {RU_NAME}; en_name - {EN_NAME}; orig_name - {ORIG_NAME}; date - {realise_date}; media_type - {movie,tv}; category - {category}\n"+
				"Запрос пользователя: %s", queryAI)
		gptUrl := os.Getenv("AI_QUERY")
	} else {
		fmt.Printf("Устройство не найдено, доступ запрещен\n")
		http.Error(w, "Устройство не найдено, доступ запрещен", http.StatusInternalServerError)
		return
	}
}
в if exists нужно отправить POST запрос на gptUrl с телом
{
  "messages": [
    {
      "role": "user",
      "content": gptContent
    }
  ],
  "model": "gpt-4o",
  "provider": "NexraChatGPT",
  "web_search": false
}
Content-Type будет либо application/json либо text/event-stream; charset=utf-8
нужно принтануть ответ в лог
Assistant: Для того чтобы отправить POST запрос к GPT API и обработать ответ, необходимо использовать стандартные пакеты, такие как `net/http` для отправки HTTP-запросов и `encoding/json` для работы с JSON. Ниже приведён пример того, как можно изменить вашу функцию `handleAiSearch`, чтобы это реализовать:

```go
package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "log"
        "net/http"
        "os"

        _ "github.com/lib/pq"
)

func handleAiSearch(w http.ResponseWriter, r *http.Request) {
        log.Printf("Received request: %s %s\n", r.Method, r.URL.Path)
        deviceData := r.URL.Query().Get("deviceid")
        queryAI := r.URL.Query().Get("query")
        if deviceData == "" && queryAI == "" {
                http.Error(w, "Ошибка.", http.StatusInternalServerError)
                return
        }
        log.Printf("Requested deviceID: %s\n", deviceData)
        log.Printf("Requested queryAI: %s\n", queryAI)

        var exists bool
        err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM devices WHERE device_id = $1)", deviceData).Scan(&exists)
        if err != nil {
                log.Printf("Ошибка при проверке существования записей: %v\n", err)
                http.Error(w, "Ошибка при проверке существования записей", http.StatusInternalServerError)
                return
        }

        if exists {
                gptContent := fmt.Sprintf(
                        "Порекомендуй список из 40 элементов по Теме из \"Запрос пользователя\" и обязательно разбей по категориям (10 штук на категорию!): фильмы, сериалы, мультфильмы и аниме\n"+
                                "Твой ответ должен быть такой (в {} динамичные данные, без {} статичные) (названия должны быть реальными!!)(за другой буду ругать!) {number}; ru_name - {RU_NAME}; en_name - {EN_NAME}; orig_name - {ORIG_NAME}; date - {realise_date}; media_type - {movie,tv}; category - {category}\n"+
                                "Запрос пользователя: %s", queryAI)

                gptUrl := os.Getenv("AI_QUERY")

                // Создание запроса
                payload := map[string]interface{}{
                        "messages": []map[string]string{
                                {
                                        "role":    "user",
                                        "content": gptContent,
                                },
                        },
                        "model":     "gpt-4o",
                        "provider":  "NexraChatGPT",
                        "web_search": false,
                }
                payloadBytes, err := json.Marshal(payload)
                if err != nil {
                        log.Printf("Ошибка при сериализации запроса: %v\n", err)
                        http.Error(w, "Ошибка при обработке запроса", http.StatusInternalServerError)
                        return
                }

                // Отправка POST запроса
                resp, err := http.Post(gptUrl, "application/json", bytes.NewBuffer(payloadBytes))
                if err != nil {
                        log.Printf("Ошибка при отправке запроса к API: %v\n", err)
                        http.Error(w, "Ошибка при отправке запроса", http.StatusInternalServerError)
                        return
                }
                defer resp.Body.Close()

                // Чтение ответа
                respBody, err := io.ReadAll(resp.Body)
                if err != nil {
                        log.Printf("Ошибка при чтении ответа: %v\n", err)
                        http.Error(w, "Ошибка при чтении ответа от API", http.StatusInternalServerError)
                        return
                }

                // Принт ответа в лог
                log.Printf("Ответ от GPT API: %s\n", respBody)

                // Отправка ответа пользователю
                w.Write(respBody)

        } else {
                log.Printf("Устройство не найдено, доступ запрещен\n")
                http.Error(w, "Устройство не найдено, доступ запрещен", http.StatusInternalServerError)
                return
        }
}
```

В этом коде кроме изменений в логике обработки `exists`, мы также добавили:

1. **Сериализацию** вашего запроса в JSON с помощью `json.Marshal`.
2. **Отправку POST запроса** к `gptUrl`.
3. **Чтение и логирование** ответа от API.
4. **Отправка ответа** от GPT обратно в `http.ResponseWriter`.

Не забудьте импортировать дополнительные пакеты `io` для чтения ответа от API и убедитесь, что у вас правильно настроены зависимости для работы с HTTP и JSON в вашем проекте на Go.
User: а у нас не будет проблем с ответом text/event-stream; charset=utf-8?
Assistant: , ответ с типом `text/event-stream` может вызвать некоторые проблемы при обработке, поскольку это формат, предназначенный для потоковой передачи данных (например, SSE - Server-Sent Events) и отличается от стандартного JSON-ответа. 

Если ваш API может вернуть данные в формате `text/event-stream`, вам следует учесть это и обрабатывать данные соответствующим образом. В этом случае, вместо того чтобы пытаться прочитать тело ответа как обычный JSON, вам нужно будет обрабатывать его как поток.

Вот как вы можете модифицировать вашу функцию, чтобы удерживать эту логику в производительности:

1. Определите, какой тип контента возвращается, и обработайте его соответственно.
2. Если это `text/event-stream`, читайте данные из `resp.Body` напрямую и логируйте их по мере поступления.
3. Если это стандартный JSON (например, `application/json`), обрабатывайте его как обычно.

Вот обновлённый фрагмент кода:

```go
package main

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

func handleAiSearch(w http.ResponseWriter, r *http.Request) {
        // Остальная часть функции остается без изменений...

        if exists {
                // Код для построения командного запроса остается без изменений...

                // Отправка POST запроса
                resp, err := http.Post(gptUrl, "application/json", bytes.NewBuffer(payloadBytes))
                if err != nil {
                        log.Printf("Ошибка при отправке запроса к API: %v\n", err)
                        http.Error(w, "Ошибка при отправке запроса", http.StatusInternalServerError)
                        return
                }
                defer resp.Body.Close()

                // Обработка ответа
                contentType := resp.Header.Get("Content-Type")
                if contentType == "application/json" {
                        // Чтение ответа JSON
                        respBody, err := io.ReadAll(resp.Body)
                        if err != nil {
                                log.Printf("Ошибка при чтении ответа: %v\n", err)
                                http.Error(w, "Ошибка при чтении ответа от API", http.StatusInternalServerError)
                                return
                        }
                        log.Printf("Ответ от GPT API: %s\n", respBody)
                        w.Header().Set("Content-Type", "application/json")
                        w.Write(respBody)

                } else if contentType == "text/event-stream" {
                        // Чтение и запись в ответ в режиме потока
                        log.Println("Получен поток ответов от GPT API:")
                        _, err := io.Copy(w, resp.Body)
                        if err != nil {
                                log.Printf("Ошибка при обработке потока ответа: %v\n", err)
                        }
                } else {
                        log.Printf("Неизвестный тип контента: %s\n", contentType)
                        http.Error(w, "Неизвестный тип ответа от API", http.StatusInternalServerError)
                }

        } else {
                // Код для обработки случая, когда устройство не найдено, остается без изменений...
        }
}
```

Таким образом, если API вернёт `text/event-stream`, ваш сервер будет считывать поток данных и отправлять их клиенту.

Учтите, что обработка потокового ответа может потребовать дополнительных мер предосторожности, так как такие ответы могут содержать уведомления, события или другие данные в реальном времени. Если вы планируете использовать этот функционал часто, убедитесь, что запросы и сигналы от вашего API хорошо структурированы и легко обрабатываются клиентом.
User: нам собрать ответ с text/event-stream тоже нужно
он будет примерно таким
{"type": "provider", "provider": {"name": "NexraChatGPT", "url": "https://nexra.aryahcr.cc/documentation/chatgpt/en", "model": "gpt-4o", "label": "Nexra ChatGPT"}}
{"type": "content", "content": "\u0412\u043e\u0442"}
{"type": "content", "content": " \u0441\u043f\u0438\u0441\u043e\u043a"}
{"type": "content", "content": " \u0438\u0437"}
{"type": "content", "content": " "}
{"type": "content", "content": "40"}
{"type": "content", "content": " \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434"}
{"type": "content", "content": "\u0435\u043d\u0438\u0439"}
{"type": "content", "content": ","}
{"type": "content", "content": " \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445"}
{"type": "content", "content": " \u0441"}
{"type": "content", "content": " \u0442\u0435\u043c"}
{"type": "content", "content": "\u043e\u0439"}
{"type": "content", "content": " \u043c\u0435\u0447"}
{"type": "content", "content": "\u0435\u0439"}
{"type": "content", "content": " \u0438"}
{"type": "content", "content": " \u0444"}
{"type": "content", "content": "\u0435\u0445"}
{"type": "content", "content": "\u0442"}
{"type": "content", "content": "\u043e\u0432\u0430\u043d\u0438\u044f"}
{"type": "content", "content": ","}
{"type": "content", "content": " \u0432\u043a\u043b\u044e\u0447\u0430\u044f"}
{"type": "content", "content": " \u0430"}
{"type": "content", "content": "\u043d\u0438\u043c"}
{"type": "content", "content": "\u0435"}
{"type": "content", "content": ","}
{"type": "content", "content": " \u0444\u0438\u043b\u044c\u043c\u044b"}
{"type": "content", "content": " \u0438"}
{"type": "content", "content": " \u0441\u0435\u0440\u0438"}
{"type": "content", "content": "\u0430\u043b\u044b"}
{"type": "content", "content": ":"}
Assistant: