Skip to content

Also consider cognitiveservices.azure.com an AzureEndpoint #470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

StefanLobbenmeierObjego

Fixes #469

@StefanLobbenmeierObjego StefanLobbenmeierObjego requested a review from a team as a code owner May 12, 2025 08:32
@@ -93,9 +93,11 @@ internal fun Any?.contentToString(): String {
internal fun isAzureEndpoint(baseUrl: String): Boolean {
// Azure Endpoint should be in the format of `https://<region>.openai.azure.com`.
// Or `https://<region>.azure-api.net` for Azure OpenAI Management URL.
// Or `<user>-random-<region>.cognitiveservices.azure.com`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Or `<user>-random-<region>.cognitiveservices.azure.com`.
// Or `<user>-random-<region>.cognitiveservices.azure.com` for deployments across regions.

this is my best guess regarding the reason that I got this URL for this deployment, but I cannot know for sure, if reason is optional I would prefer leaving it empty

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Or `<user>-random-<region>.cognitiveservices.azure.com`.
// Or `<user>-random-<region>.cognitiveservices.azure.com` for Azure AI services deployments.

It might also be that reason, my openai deployment has the openai.azure.com url, but my azure ai service deployment has cognitiveservices.azure.com

@TomerAberbach
Copy link
Collaborator

@jpalvarezl I'm not sure what's the right thing to do here

Can you weigh in on this PR and ticket? #469

@TomerAberbach
Copy link
Collaborator

Hmmm, wait, should the environment variable being set to that URL result in the same behavior as what this example is doing without an environment variable?

.credential(BearerTokenCredential.create(AuthenticationUtil.getBearerTokenSupplier(
new DefaultAzureCredentialBuilder().build(), "https://cognitiveservices.azure.com/.default")))

@TomerAberbach
Copy link
Collaborator

Although, maybe that's infeasible because we don't want to reference Azure dependencies from the openai-java-client-okhttp package, so it can't construct those objects

@StefanLobbenmeierObjego does doing it the way the example shows solve this for you?

@StefanLobbenmeierObjego
Copy link
Author

No this example does not help me:
Exception in thread "main" com.openai.errors.NotFoundException: 404: Resource not found

import com.azure.identity.AuthenticationUtil;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.openai.client.OpenAIClient;
import com.openai.credential.BearerTokenCredential;
import com.openai.models.ChatModel;
import com.openai.models.chat.completions.ChatCompletionCreateParams;

import static com.openai.client.okhttp.OpenAIOkHttpClient.*;

class Scratch {
    public static void main(String[] args) {
        assert System.getenv("AZURE_OPENAI_KEY") != null;
        assert System.getenv("OPENAI_BASE_URL") != null;
        assert System.getenv("OPENAI_BASE_URL").endsWith("cognitiveservices.azure.com");

        OpenAIClient client = builder()
                // Gets the API key from the `AZURE_OPENAI_KEY` environment variable
                .fromEnv()
                // Set the Azure Entra ID
                .credential(BearerTokenCredential.create(AuthenticationUtil.getBearerTokenSupplier(
                        new DefaultAzureCredentialBuilder().build(), "https://cognitiveservices.azure.com/.default")))
                .build();

        ChatCompletionCreateParams createParams = ChatCompletionCreateParams.builder()
                .model(ChatModel.GPT_3_5_TURBO)
                .maxCompletionTokens(2048)
                .addDeveloperMessage("Make sure you mention Stainless!")
                .addUserMessage("Tell me a story about building the best SDK!")
                .build();

        client.chat().completions().create(createParams).choices().stream()
                .flatMap(choice -> choice.message().content().stream())
                .forEach(System.out::println);
    }
}

@StefanLobbenmeierObjego
Copy link
Author

Hmmm, wait, should the environment variable being set to that URL result in the same behavior as what this example is doing without an environment variable?

.credential(BearerTokenCredential.create(AuthenticationUtil.getBearerTokenSupplier(
new DefaultAzureCredentialBuilder().build(), "https://cognitiveservices.azure.com/.default")))

Slightly confused by this comment, fromEnv() does not actually persist anything about if this is an azure endpoint or an openai endpoint:

fun fromEnv() = apply {
System.getenv("OPENAI_BASE_URL")?.let { baseUrl(it) }
val openAIKey = System.getenv("OPENAI_API_KEY")
val openAIOrgId = System.getenv("OPENAI_ORG_ID")
val openAIProjectId = System.getenv("OPENAI_PROJECT_ID")
val azureOpenAIKey = System.getenv("AZURE_OPENAI_KEY")
when {
!openAIKey.isNullOrEmpty() && !azureOpenAIKey.isNullOrEmpty() -> {
throw IllegalArgumentException(
"Both OpenAI and Azure OpenAI API keys, `OPENAI_API_KEY` and `AZURE_OPENAI_KEY`, are set. Please specify only one"
)
}
!openAIKey.isNullOrEmpty() -> {
credential(BearerTokenCredential.create(openAIKey))
organization(openAIOrgId)
project(openAIProjectId)
}
!azureOpenAIKey.isNullOrEmpty() -> {
credential(AzureApiKeyCredential.create(azureOpenAIKey))
}
}
}

The only way right now to get the "openai" and "deployment" into the path is by having isAzureEndpoint true here:

@JvmSynthetic
internal fun HttpRequest.Builder.addPathSegmentsForAzure(
clientOptions: ClientOptions,
deploymentModel: String?,
): HttpRequest.Builder = apply {
if (isAzureEndpoint(clientOptions.baseUrl)) {
addPathSegment("openai")
deploymentModel?.let { addPathSegments("deployments", it) }
}
}

And this is what I am trying to achieve with this PR.

A possible alternative could be to introduce "isAzureEndpoint" to the client options, which could be set to true when the URL matches or when "AZURE_OPENAI_KEY" env is set, but thats a bigger change so I would prefer to stick with the url matching kind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

URLs ending in cognitiveservices.azure.com are silently not considered Azure URLs
2 participants