Unity using API openai Error en la solicitud: HTTP/1.1 400 Bad Request
题意:使用 Unity 与 OpenAI API 进行交互时遇到 HTTP/1.1 400 Bad Request
错误
问题背景:
I am trying to use the openai API in a new unity project. However try whatever I try I always get the same 400 bad request error
我正在尝试在一个新的 Unity 项目中使用 OpenAI API。但无论我尝试什么,我总是收到相同的 400 错误请求错误。
I have tried both options interleaving between simple JSON and using wwwform but always the same error. The reason why I use classes is to be able to use the utility to transform to JSON because otherwise it can't be done.
我已经尝试了在简单的 JSON和使用 wwwform之间交替使用的两种选项,但总是遇到相同的错误。我使用类的原因是为了能够利用它们提供的工具将数据转换为 JSON,因为如果不这样做就无法实现。
I have a two versions of my code: 我的代码有2个版本
Version1
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
public class OpenAICommunication : MonoBehaviour
{
private string apiKey = "sk-....."; // hide apikey
private string apiUrl = "https://api.openai.com/v1/completions";
private void Update()
{
if(Input.GetButtonDown("Jump"))
AskQuestion("Hola! Este es un juego de unity!");
}
IEnumerator SendQuestion(string question)
{
MessagesList messages = new MessagesList();
messages.list = new Message[] { new Message() };
messages.list[0].role = "user";
messages.list[0].content = question;
ApiCall apiCall = new ApiCall();
apiCall.model = "text-davinci-003";
apiCall.prompt = question;
string json = JsonUtility.ToJson(apiCall);
Debug.Log("JSON: " + json);
// Configurar el encabezado de autorizaci�n
Dictionary<string, string> headers = new Dictionary<string, string>
{
{ "Content-Type", "application/json" },
{ "Authorization", "Bearer " + apiKey }
};
// headers.Add("Authorization", "Bearer " + apiKey);
// Enviar la solicitud POST a la API de OpenAI
using (UnityWebRequest www = UnityWebRequest.PostWwwForm(apiUrl, json))
{
foreach (var header in headers)
{
Debug.Log("HEADER: " + header.Key + header.Value);
www.SetRequestHeader(header.Key, header.Value);
}
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError("Error en la solicitud: " + www.error);
}
else
{
string responseJson = www.downloadHandler.text;
// Procesar la respuesta JSON aqu� (extraer y mostrar la respuesta del asistente)
Debug.Log("Response: " + responseJson);
}
}
}
public void AskQuestion(string question)
{
StartCoroutine(SendQuestion(question));
}
}
[System.Serializable]
public class Message
{
public string role;
public string content;
}
public class MessagesList
{
public Message[] list;
}
public class ApiCall
{
public string model;
public string prompt;
}
Version2
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
public class OpenAICommunication : MonoBehaviour
{
private string apiKey = "sk-...."; // hide apikey
private string apiUrl = "https://api.openai.com/v1/chat/completions";
private void Update()
{
if (Input.GetButtonDown("Jump"))
AskQuestion("Hola! Este es un juego de unity!");
}
IEnumerator SendQuestion(string question)
{
// Configurar el encabezado de autorizaci�n
Dictionary<string, string> headers = new Dictionary<string, string>
{
{ "Content-Type", "application/json" },
{ "Authorization", "Bearer " + apiKey }
};
// headers.Add("Authorization", "Bearer " + apiKey);
MessagesList messages = new MessagesList();
messages.list = new Message[] { new Message() };
messages.list[0].role = "user";
messages.list[0].content = question;
string json = JsonUtility.ToJson(messages);
// elimino la parte del string que no corresponde para formatear bien el json.
// lo eliminado es: { list: .... y el final }
json = json.Substring(8, json.Length - 8 - 1);
// verifico y es correcto.
Debug.Log("JSON: " + json);
// Preparar los datos para la solicitud POST utilizo la de chat también para probar pero no cambia nada...
WWWForm form = new WWWForm();
form.AddField("model", "gpt-3.5-turbo");
form.AddField("messages", json);
// Enviar la solicitud POST a la API de OpenAI
using (UnityWebRequest www = UnityWebRequest.Post(apiUrl, form))
{
foreach (var header in headers)
{
Debug.Log("HEADER: " + header.Key + header.Value);
www.SetRequestHeader(header.Key, header.Value);
}
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError("Error en la solicitud: " + www.error);
}
else
{
string responseJson = www.downloadHandler.text;
// Procesar la respuesta JSON aqu� (extraer y mostrar la respuesta del asistente)
Debug.Log("Response: " + responseJson);
}
}
}
public void AskQuestion(string question)
{
StartCoroutine(SendQuestion(question));
}
}
[System.Serializable]
public class Message
{
public string role;
public string content;
}
public class MessagesList
{
public Message[] list;
}
I use both variations of the code with two of the openai urls but always get the same error.
“我使用了代码的两个不同版本,并尝试了两个 OpenAI 的 URL,但总是遇到相同的错误。”
ERROR:
Error en la solicitud: HTTP/1.1 400 Bad Request
0x00007ff62ae8229d (Unity) StackWalker::GetCurrentCallstack
0x00007ff62ae87249 (Unity) StackWalker::ShowCallstack
0x00007ff62be533a1 (Unity) GetStacktrace
0x00007ff62c514c02 (Unity) DebugStringToFile
0x00007ff629d98736 (Unity) DebugLogHandler_CUSTOM_Internal_Log
0x0000025ca0dfc363 (Mono JIT Code) (wrapper managed-to-native) UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object)
0x0000025ca0dfc27b (Mono JIT Code) UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
0x0000025ca0dfbfc0 (Mono JIT Code) UnityEngine.Logger:Log (UnityEngine.LogType,object)
0x0000025c7c685ab5 (Mono JIT Code) UnityEngine.Debug:LogError (object)
0x0000025c7c67b363 (Mono JIT Code) OpenAICommunication/<SendQuestion>d__3:MoveNext () (at D:/Projects/Unity/AI_Project/Assets/Scripts/OpenAICommunication.cs:57)
0x0000025c7c67ab00 (Mono JIT Code) UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)
0x0000025c7c67ac2f (Mono JIT Code) (wrapper runtime-invoke) <Module>:runtime_invoke_void_object_intptr (object,intptr,intptr,intptr)
0x00007ffcf45ee0d4 (mono-2.0-bdwgc) mono_jit_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/mini/mini-runtime.c:3445)
0x00007ffcf452eb74 (mono-2.0-bdwgc) do_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3066)
0x00007ffcf452ed0c (mono-2.0-bdwgc) mono_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3113)
0x00007ff62ad99724 (Unity) scripting_method_invoke
0x00007ff62ad77944 (Unity) ScriptingInvocation::Invoke
0x00007ff62ad4041a (Unity) Coroutine::Run
0x00007ff62ad3de0f (Unity) Coroutine::ContinueCoroutine
0x00007ff62a9fb653 (Unity) AsyncOperation::InvokeCoroutine
0x00007ff62b33d7bc (Unity) UnityWebRequestAsyncOperation::InvokeCoroutine
0x00007ff62b33d9a1 (Unity) UnityWebRequestProto<UnityWebRequestTransport,AtomicRefCounter,RedirectHelper,ResponseHelper,DownloadHandler,UploadHandler,CertificateHandler,HeaderHelper,AsyncOperation>::Job_InvokeCoroutine
0x00007ff62a9aed9a (Unity) BackgroundJobQueue::ExecuteMainThreadJobs
0x00007ff62aa3127c (Unity) `InitPlayerLoopCallbacks'::`2'::EarlyUpdateExecuteMainThreadJobsRegistrator::Forward
0x00007ff62aa1133a (Unity) ExecutePlayerLoop
0x00007ff62aa114c6 (Unity) ExecutePlayerLoop
0x00007ff62aa17d85 (Unity) PlayerLoop
0x00007ff62b9dac6f (Unity) PlayerLoopController::InternalUpdateScene
0x00007ff62b9e784d (Unity) PlayerLoopController::UpdateSceneIfNeededFromMainLoop
0x00007ff62b9e5b51 (Unity) Application::TickTimer
0x00007ff62be59cda (Unity) MainMessageLoop
0x00007ff62be5f540 (Unity) WinMain
0x00007ff62d248bae (Unity) __scrt_common_main_seh
0x00007ffd46ea7614 (KERNEL32) BaseThreadInitThunk
0x00007ffd47c026b1 (ntdll) RtlUserThreadStart
I tried the API in my terminal and it worked fine with the -k
prefix.
我在终端中尝试了 API,并使用了 -k
前缀,它工作正常。
I don't know why I have the 400 error in unity.
“我不知道为什么在 Unity 中会出现 400 错误。”
问题解决:
I ended up generating a server with NodeJS to see what I got from unity. Then I discovered that the POST was sending this information in data:
“我最终使用 Node.js 创建了一个服务器来查看从 Unity 发送的数据。然后我发现 POST 请求在数据部分发送了这条信息:”
Received data: %7b%22model%22%3a%22gpt-3.5-turbo%22%2c%22messages%22%3a%5b%7b%22role%22%3a%22s ystem%22%2c%22content%22%3a%22Tu%20heres%20el%20master%20en%20un%20juego%20de%20roles%22%7d%2c %7b%22role%22%3a%22user%22%2c%22content%22%3a%22Hola%21%20Este%20es%20un%20juego%20de%20unity% 21%22%7d%5d%7d Erorr al formatear el json
Then I found a comment on the web that someone said that sometimes it was better to generate the byte string personally and not automatically, the answer was the following:
“然后我在网上找到了一个评论,有人说有时候最好手动生成字节字符串而不是自动生成。答案如下:”
Received data: {"model":"gpt-3.5-turbo","messages":[{"role":"system","content":"Tu heres el ma ster en un juego de roles"},{"role":"user","content":"Hola! Este es un juego de unity!"}]}
This is the code that finally worked for any of the options in the original post.
“这是最终适用于原始帖子中任一选项的代码。”
using (UnityWebRequest www = UnityWebRequest.PostWwwForm(apiUrl, json))
{
www.method = "POST"; //alternative
//funtional code
byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);
www.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
//end funtional code
foreach (var header in headers)
{
www.SetRequestHeader(header.Key, header.Value);
}
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError("Error en la solicitud: " + www.error);
}
else
{
string responseJson = www.downloadHandler.text;
// Procesar la respuesta JSON aqu� (extraer y mostrar la respuesta del asistente)
Debug.Log("Response: " + responseJson);
}
}