betalgo / openai

OpenAI .NET sdk - Azure OpenAI, ChatGPT, Whisper, and DALL-E
https://betalgo.github.io/openai/
MIT License
2.85k stars 513 forks source link

Return an error message when OpenAI returns an HTML error instead of JSON. #447

Closed kayhantolga closed 7 months ago

kayhantolga commented 7 months ago

OpenAI returns an HTML message whenever it encounters an internal error, which causes the SDK to throw an exception without any meaningful message. It is important to catch these cases and return meaningful error messages. here are sample issues: https://github.com/betalgo/openai/issues/408 https://github.com/betalgo/openai/issues/277

CongquanHu commented 7 months ago

I wonder if we can read the data type of the response first, if it is json format, then we can rest assured to deserialize to json object; If it is an html message, we first read it as a string, then build an object with code and Message, and finally deserialize the object to the generic TResponse. If this can avoid the bad exception crash problem.

      public static async Task<TResponse> PostAndReadAsAsync<TResponse>(this HttpClient client, string uri, object? requestModel, CancellationToken cancellationToken = default)
    {
        //var response = await client.PostAsJsonAsync(uri, requestModel, new JsonSerializerOptions
        //{
        //    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
        //}, cancellationToken);
        //return await response.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken) ?? throw new InvalidOperationException();

        var response = await client.PostAsJsonAsync(uri, requestModel, new JsonSerializerOptions
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
        }, cancellationToken);

        var contentType = response.Content.Headers.ContentType?.MediaType;
        // Check that the response is successful and of JSON type
        if (response.IsSuccessStatusCode && contentType != null && contentType.Contains("application/json"))
        {
            return await response.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken) ?? throw new InvalidOperationException();
        }
        else if (response.IsSuccessStatusCode && contentType != null && contentType.Contains("text/html"))
        {
            return JsonSerializer.Deserialize<TResponse>(JsonSerializer.Serialize(new
            {
                code = "500",
                message = await response.Content.ReadAsStringAsync(cancellationToken: cancellationToken)
            })) ?? throw new InvalidOperationException();
        }
        else
        {
            throw new InvalidOperationException("Unexpected  response from the server.");
        }
    }

Let me know if it helps. Thanks