OpenAI-API-dotnet icon indicating copy to clipboard operation
OpenAI-API-dotnet copied to clipboard

InvalidOperationException, The given header was not found - on Azure

Open vermorel opened this issue 2 years ago • 0 comments

With the following config, I am able to do a request and get a proper response from the OpenAI served by Azure:

_api = new OpenAIAPI("..snipped" /*apiKey*/);
_api.ApiUrlFormat = "https://my-resource.openai.azure.com/openai/deployments/my-deployment/{1}?api-version={0}";
_api.ApiVersion = "2022-12-01";

However, processing the response fails with an InvalidOperationException thrown in EndpointBase.cs as the Openai-Organization header is not found.

I am getting the exact same problem with:

_api =  OpenAIAPI.ForAzure("my-resource", "my-deployment", ".. snipped..");
_api.ApiVersion = "2023-03-15-preview";

The faulty line seems to be https://github.com/OkGoDoIt/OpenAI-API-dotnet/blob/8bc534bc0163e4ca0ddad21a6d58a57910dc6189/OpenAI_API/EndpointBase.cs#L195

How can I get the package to work for the Azure endpoint?

Update:

I have been able to make package parse the Azure API response with the ugly hack below:

if (!response.Headers.Contains("Openai-Organization"))
{
    response.Headers.Add("Openai-Organization", "dummy");
    response.Headers.Add("Openai-Version", "dummy");

    var ms = float.Parse(response.Headers.GetValues("Openai-Processing-Ms").First());
    response.Headers.Remove("Openai-Processing-Ms");
    response.Headers.Add("Openai-Processing-Ms", ((int)ms).ToString());
}

Tweaking my existing IHttpClientFactory:

namespace Lokad.Prompting;

public class OpenAIClientFactory : IHttpClientFactory
{
    public HttpClient CreateClient(string name)
    {
        return new HttpClient(new RetryHandler(new HttpClientHandler()))
        {
            // The OpenAI API does usually answers albeit with considerable delay.
            Timeout = TimeSpan.FromMinutes(5)

        };
    }

    public class RetryHandler : DelegatingHandler
    {
        private const int maxRetries = 5;

        public RetryHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }

        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var delay = TimeSpan.FromSeconds(1); // Initial delay
            for (int i = 0; i < maxRetries; i++)
            {
                var response = await base.SendAsync(request, cancellationToken);

                if (response.StatusCode == (System.Net.HttpStatusCode)200 &&
                    !response.Headers.Contains("Openai-Organization"))
                {
                    response.Headers.Add("Openai-Organization", "dummy");
                    response.Headers.Add("Openai-Version", "dummy");

                    var ms = float.Parse(response.Headers.GetValues("Openai-Processing-Ms").First());
                    response.Headers.Remove("Openai-Processing-Ms");
                    response.Headers.Add("Openai-Processing-Ms", ((int)ms).ToString());
                }


                // 429 Too Many Requests
                if (response.StatusCode == (System.Net.HttpStatusCode)429 && i < maxRetries)
                {
                    await Task.Delay(delay, cancellationToken);
                    delay *= 2; // Exponential backoff
                    continue;
                }

                // 500 Internal Server Error
                if (response.StatusCode == (System.Net.HttpStatusCode)500 && i < maxRetries)
                {
                    await Task.Delay(delay, cancellationToken);
                    delay *= 2; // Exponential backoff
                    continue;
                }

                // 502 Bad Gateway
                if (response.StatusCode == (System.Net.HttpStatusCode)502 && i < maxRetries)
                {
                    await Task.Delay(delay, cancellationToken);
                    delay *= 2; // Exponential backoff
                    continue;
                }

                // 503 Service Unavailable
                if (response.StatusCode == (System.Net.HttpStatusCode)503 && i < maxRetries)
                {
                    await Task.Delay(delay, cancellationToken);
                    delay *= 2; // Exponential backoff
                    continue;
                }

                return response;
            }

            throw new HttpRequestException($"Retry attempts failed after {maxRetries} retries.");
        }
    }
}

This works although it would be nicer to update the response parsing accordingly.

vermorel avatar Jun 12 '23 15:06 vermorel