From cdee6e076342211a9ae54b7ec561cce35ec67bb8 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Wed, 5 Jul 2023 13:58:07 -0700 Subject: [PATCH 01/25] Added preliminary support for OpenAI Functions --- sdk/openai/azure-ai-openai/assets.json | 2 +- .../azure/ai/openai/OpenAIServiceVersion.java | 7 +- .../implementation/OpenAIClientImpl.java | 52 ++++++-- .../openai/models/ChatCompletionsOptions.java | 67 +++++++++++ .../azure/ai/openai/models/ChatMessage.java | 68 +++++++++++ .../com/azure/ai/openai/models/ChatRole.java | 3 + .../models/CompletionsFinishReason.java | 3 + .../azure/ai/openai/models/FunctionCall.java | 67 +++++++++++ .../openai/models/FunctionCallModelBase.java | 11 ++ .../ai/openai/models/FunctionCallPreset.java | 50 ++++++++ .../FunctionCallPresetFunctionCallModel.java | 33 ++++++ .../ai/openai/models/FunctionDefinition.java | 112 ++++++++++++++++++ .../azure/ai/openai/models/FunctionName.java | 42 +++++++ .../models/FunctionNameFunctionCallModel.java | 33 ++++++ .../ai/openai/OpenAIAsyncClientTest.java | 6 +- sdk/openai/azure-ai-openai/tsp-location.yaml | 5 +- 16 files changed, 544 insertions(+), 17 deletions(-) create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java diff --git a/sdk/openai/azure-ai-openai/assets.json b/sdk/openai/azure-ai-openai/assets.json index 1fa8b11ec119..62ae6f2ad86b 100644 --- a/sdk/openai/azure-ai-openai/assets.json +++ b/sdk/openai/azure-ai-openai/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/openai/azure-ai-openai", - "Tag": "java/openai/azure-ai-openai_2a6e71fe2e" + "Tag": "java/openai/azure-ai-openai_94811d7537" } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/OpenAIServiceVersion.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/OpenAIServiceVersion.java index 8d15584caf4d..6a0186a342c1 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/OpenAIServiceVersion.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/OpenAIServiceVersion.java @@ -15,7 +15,10 @@ public enum OpenAIServiceVersion implements ServiceVersion { V2023_05_15("2023-05-15"), /** Enum value 2023-06-01-preview. */ - V2023_06_01_PREVIEW("2023-06-01-preview"); + V2023_06_01_PREVIEW("2023-06-01-preview"), + + /** Enum value 2023-07-01-preview. */ + V2023_07_01_PREVIEW("2023-07-01-preview"); private final String version; @@ -35,6 +38,6 @@ public String getVersion() { * @return The latest {@link OpenAIServiceVersion}. */ public static OpenAIServiceVersion getLatest() { - return V2023_06_01_PREVIEW; + return V2023_07_01_PREVIEW; } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/OpenAIClientImpl.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/OpenAIClientImpl.java index 788bf745dcae..914334796541 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/OpenAIClientImpl.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/OpenAIClientImpl.java @@ -546,7 +546,7 @@ public Response getEmbeddingsWithResponse( * int (Required) * ] * } - * finish_reason: String(stop/length/content_filter) (Required) + * finish_reason: String(stop/length/content_filter/function_call) (Required) * } * ] * usage (Required): { @@ -643,7 +643,7 @@ public Mono> getCompletionsWithResponseAsync( * int (Required) * ] * } - * finish_reason: String(stop/length/content_filter) (Required) + * finish_reason: String(stop/length/content_filter/function_call) (Required) * } * ] * usage (Required): { @@ -689,10 +689,23 @@ public Response getCompletionsWithResponse( * { * messages (Required): [ * (Required){ - * role: String(system/assistant/user) (Required) + * role: String(system/assistant/user/function) (Required) * content: String (Optional) + * name: String (Optional) + * function_call (Optional): { + * name: String (Required) + * arguments: String (Required) + * } + * } + * ] + * functions (Optional): [ + * (Optional){ + * name: String (Required) + * description: String (Optional) + * parameters: Object (Optional) * } * ] + * function_call: FunctionCallModelBase (Optional) * max_tokens: Integer (Optional) * temperature: Double (Optional) * top_p: Double (Optional) @@ -720,11 +733,16 @@ public Response getCompletionsWithResponse( * choices (Required): [ * (Required){ * message (Optional): { - * role: String(system/assistant/user) (Required) + * role: String(system/assistant/user/function) (Required) * content: String (Optional) + * name: String (Optional) + * function_call (Optional): { + * name: String (Required) + * arguments: String (Required) + * } * } * index: int (Required) - * finish_reason: String(stop/length/content_filter) (Required) + * finish_reason: String(stop/length/content_filter/function_call) (Required) * delta (Optional): (recursive schema, see delta above) * } * ] @@ -774,10 +792,23 @@ public Mono> getChatCompletionsWithResponseAsync( * { * messages (Required): [ * (Required){ - * role: String(system/assistant/user) (Required) + * role: String(system/assistant/user/function) (Required) * content: String (Optional) + * name: String (Optional) + * function_call (Optional): { + * name: String (Required) + * arguments: String (Required) + * } + * } + * ] + * functions (Optional): [ + * (Optional){ + * name: String (Required) + * description: String (Optional) + * parameters: Object (Optional) * } * ] + * function_call: FunctionCallModelBase (Optional) * max_tokens: Integer (Optional) * temperature: Double (Optional) * top_p: Double (Optional) @@ -805,11 +836,16 @@ public Mono> getChatCompletionsWithResponseAsync( * choices (Required): [ * (Required){ * message (Optional): { - * role: String(system/assistant/user) (Required) + * role: String(system/assistant/user/function) (Required) * content: String (Optional) + * name: String (Optional) + * function_call (Optional): { + * name: String (Required) + * arguments: String (Required) + * } * } * index: int (Required) - * finish_reason: String(stop/length/content_filter) (Required) + * finish_reason: String(stop/length/content_filter/function_call) (Required) * delta (Optional): (recursive schema, see delta above) * } * ] diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index 7df28d9666c7..eaf04039f1d6 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -429,4 +429,71 @@ public ChatCompletionsOptions setModel(String model) { this.model = model; return this; } + + /* + * A list of functions the model may generate JSON inputs for. + */ + @Generated + @JsonProperty(value = "functions") + private List functions; + + /* + * Controls how the model responds to function calls. "none" means the model does not call a function, + * and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. + * Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + */ + @Generated + @JsonProperty(value = "function_call") + private FunctionCallModelBase functionCall; + + /** + * Get the functions property: A list of functions the model may generate JSON inputs for. + * + * @return the functions value. + */ + @Generated + public List getFunctions() { + return this.functions; + } + + /** + * Set the functions property: A list of functions the model may generate JSON inputs for. + * + * @param functions the functions value to set. + * @return the ChatCompletionsOptions object itself. + */ + @Generated + public ChatCompletionsOptions setFunctions(List functions) { + this.functions = functions; + return this; + } + + /** + * Get the functionCall property: Controls how the model responds to function calls. "none" means the model does not + * call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a + * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + * + * @return the functionCall value. + */ + @Generated + public FunctionCallModelBase getFunctionCall() { + return this.functionCall; + } + + /** + * Set the functionCall property: Controls how the model responds to function calls. "none" means the model does not + * call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a + * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + * + * @param functionCall the functionCall value to set. + * @return the ChatCompletionsOptions object itself. + */ + @Generated + public ChatCompletionsOptions setFunctionCall(FunctionCallModelBase functionCall) { + this.functionCall = functionCall; + return this; + } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java index 2ad4cfd18b97..2594743f63f7 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java @@ -68,4 +68,72 @@ public ChatMessage setContent(String content) { this.content = content; return this; } + + /* + * The name of the author of this message. `name` is required if role is `function`, and it should be the name of + * the + * function whose response is in the `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length + * of + * 64 characters. + */ + @Generated + @JsonProperty(value = "name") + private String name; + + /* + * The name and arguments of a function that should be called, as generated by the model. + */ + @Generated + @JsonProperty(value = "function_call") + private FunctionCall functionCall; + + /** + * Get the name property: The name of the author of this message. `name` is required if role is `function`, and it + * should be the name of the function whose response is in the `content`. May contain a-z, A-Z, 0-9, and + * underscores, with a maximum length of 64 characters. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } + + /** + * Set the name property: The name of the author of this message. `name` is required if role is `function`, and it + * should be the name of the function whose response is in the `content`. May contain a-z, A-Z, 0-9, and + * underscores, with a maximum length of 64 characters. + * + * @param name the name value to set. + * @return the ChatMessage object itself. + */ + @Generated + public ChatMessage setName(String name) { + this.name = name; + return this; + } + + /** + * Get the functionCall property: The name and arguments of a function that should be called, as generated by the + * model. + * + * @return the functionCall value. + */ + @Generated + public FunctionCall getFunctionCall() { + return this.functionCall; + } + + /** + * Set the functionCall property: The name and arguments of a function that should be called, as generated by the + * model. + * + * @param functionCall the functionCall value to set. + * @return the ChatMessage object itself. + */ + @Generated + public ChatMessage setFunctionCall(FunctionCall functionCall) { + this.functionCall = functionCall; + return this; + } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatRole.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatRole.java index dcf8fe55f839..621ea748768e 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatRole.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatRole.java @@ -50,4 +50,7 @@ public static ChatRole fromString(String name) { public static Collection values() { return values(ChatRole.class); } + + /** The role that provides function results for char completions. */ + @Generated public static final ChatRole FUNCTION = fromString("function"); } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/CompletionsFinishReason.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/CompletionsFinishReason.java index c267098eca5b..b16c05f00c3f 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/CompletionsFinishReason.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/CompletionsFinishReason.java @@ -52,4 +52,7 @@ public static CompletionsFinishReason fromString(String name) { public static Collection values() { return values(CompletionsFinishReason.class); } + + /** Completion ended normally, with the model requesting a function to be called. */ + @Generated public static final CompletionsFinishReason FUNCTION_CALL = fromString("function_call"); } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java new file mode 100644 index 000000000000..0d87182bd586 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The name and arguments of a function that should be called, as generated by the model. */ +@Immutable +public final class FunctionCall { + /* + * The name of the function to call. + */ + @Generated + @JsonProperty(value = "name") + private String name; + + /* + * The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters + * not defined by your function schema. Validate the arguments in your code before calling + * your function. + */ + @Generated + @JsonProperty(value = "arguments") + private String arguments; + + /** + * Creates an instance of FunctionCall class. + * + * @param name the name value to set. + * @param arguments the arguments value to set. + */ + @Generated + @JsonCreator + public FunctionCall( + @JsonProperty(value = "name") String name, @JsonProperty(value = "arguments") String arguments) { + this.name = name; + this.arguments = arguments; + } + + /** + * Get the name property: The name of the function to call. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } + + /** + * Get the arguments property: The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your + * function schema. Validate the arguments in your code before calling your function. + * + * @return the arguments value. + */ + @Generated + public String getArguments() { + return this.arguments; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java new file mode 100644 index 000000000000..25beabc48f37 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +/** The FunctionCallModelBase model. */ +public abstract class FunctionCallModelBase { + /** Creates an instance of FunctionCallModelBase class. */ + protected FunctionCallModelBase() {} +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java new file mode 100644 index 000000000000..7ed496971285 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Preset values to control how the mode; responds to function calls. */ +public final class FunctionCallPreset extends ExpandableStringEnum { + /** Means the model can pick between an end-user or calling a function. */ + @Generated public static final FunctionCallPreset AUTO = fromString("auto"); + + /** Means the model does not call a function, and responds to the end-user. */ + @Generated public static final FunctionCallPreset NONE = fromString("none"); + + /** + * Creates a new instance of FunctionCallPreset value. + * + * @deprecated Use the {@link #fromString(String)} factory method. + */ + @Generated + @Deprecated + public FunctionCallPreset() {} + + /** + * Creates or finds a FunctionCallPreset from its string representation. + * + * @param name a name to look for. + * @return the corresponding FunctionCallPreset. + */ + @Generated + @JsonCreator + public static FunctionCallPreset fromString(String name) { + return fromString(name, FunctionCallPreset.class); + } + + /** + * Gets known FunctionCallPreset values. + * + * @return known FunctionCallPreset values. + */ + @Generated + public static Collection values() { + return values(FunctionCallPreset.class); + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java new file mode 100644 index 000000000000..9bcabdf0def9 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonValue; + +/** The FunctionCallPresetFunctionCallModel model. */ +@Immutable +public final class FunctionCallPresetFunctionCallModel extends FunctionCallModelBase { + private final FunctionCallPreset value; + + /** + * Creates an instance of FunctionCallPresetFunctionCallModel class. + * + * @param value the value. + */ + public FunctionCallPresetFunctionCallModel(FunctionCallPreset value) { + this.value = value; + } + + /** + * Gets the value. + * + * @return the value. + */ + @JsonValue + public FunctionCallPreset getValue() { + return this.value; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java new file mode 100644 index 000000000000..c4b989a52b68 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The definition of a function that can be called by the model. See the [guide](/docs/guides/gpt/function-calling) for + * examples. + */ +@Fluent +public final class FunctionDefinition { + /* + * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, + * with a maximum length of 64. + */ + @Generated + @JsonProperty(value = "name") + private String name; + + /* + * The description of what the function does. + */ + @Generated + @JsonProperty(value = "description") + private String description; + + /* + * The parameters the functions accepts, described as a JSON Schema object. + * See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema + * reference](https://json-schema.org/understanding-json-schema/) + * for documentation about the format. + */ + @Generated + @JsonProperty(value = "parameters") + private Object parameters; + + /** + * Creates an instance of FunctionDefinition class. + * + * @param name the name value to set. + */ + @Generated + @JsonCreator + public FunctionDefinition(@JsonProperty(value = "name") String name) { + this.name = name; + } + + /** + * Get the name property: The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and + * dashes, with a maximum length of 64. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } + + /** + * Get the description property: The description of what the function does. + * + * @return the description value. + */ + @Generated + public String getDescription() { + return this.description; + } + + /** + * Set the description property: The description of what the function does. + * + * @param description the description value to set. + * @return the FunctionDefinition object itself. + */ + @Generated + public FunctionDefinition setDescription(String description) { + this.description = description; + return this; + } + + /** + * Get the parameters property: The parameters the functions accepts, described as a JSON Schema object. See the + * [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema + * reference](https://json-schema.org/understanding-json-schema/) for documentation about the format. + * + * @return the parameters value. + */ + @Generated + public Object getParameters() { + return this.parameters; + } + + /** + * Set the parameters property: The parameters the functions accepts, described as a JSON Schema object. See the + * [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema + * reference](https://json-schema.org/understanding-json-schema/) for documentation about the format. + * + * @param parameters the parameters value to set. + * @return the FunctionDefinition object itself. + */ + @Generated + public FunctionDefinition setParameters(Object parameters) { + this.parameters = parameters; + return this; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java new file mode 100644 index 000000000000..8e8f16fd291f --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** Specify the name of the only function to call. */ +@Immutable +public final class FunctionName { + /* + * The name of the function to call. + */ + @Generated + @JsonProperty(value = "name") + private String name; + + /** + * Creates an instance of FunctionName class. + * + * @param name the name value to set. + */ + @Generated + @JsonCreator + public FunctionName(@JsonProperty(value = "name") String name) { + this.name = name; + } + + /** + * Get the name property: The name of the function to call. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java new file mode 100644 index 000000000000..df40077ac3ea --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonValue; + +/** The FunctionNameFunctionCallModel model. */ +@Immutable +public final class FunctionNameFunctionCallModel extends FunctionCallModelBase { + private final FunctionName value; + + /** + * Creates an instance of FunctionNameFunctionCallModel class. + * + * @param value the value. + */ + public FunctionNameFunctionCallModel(FunctionName value) { + this.value = value; + } + + /** + * Gets the value. + * + * @return the value. + */ + @JsonValue + public FunctionName getValue() { + return this.value; + } +} diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index aa69e69e08c8..676b001fed92 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -51,8 +51,7 @@ public void testGetCompletions(HttpClient httpClient, OpenAIServiceVersion servi @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testGetCompletionsStream(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { - // TODO: use the parameterized serviceVersion once we have a service release that responds with valid data - client = getOpenAIAsyncClient(httpClient, OpenAIServiceVersion.V2023_05_15); + client = getOpenAIAsyncClient(httpClient, serviceVersion); getCompletionsRunner((deploymentId, prompt) -> { StepVerifier.create(client.getCompletionsStream(deploymentId, new CompletionsOptions(prompt))) .recordWith(ArrayList::new) @@ -161,8 +160,7 @@ public void testGetChatCompletions(HttpClient httpClient, OpenAIServiceVersion s @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testGetChatCompletionsStream(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { - // TODO: use the parameterized serviceVersion once we have a service release that responds with valid data - client = getOpenAIAsyncClient(httpClient, OpenAIServiceVersion.V2023_05_15); + client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatCompletionsRunner((deploymentId, chatMessages) -> { StepVerifier.create(client.getChatCompletionsStream(deploymentId, new ChatCompletionsOptions(chatMessages))) .recordWith(ArrayList::new) diff --git a/sdk/openai/azure-ai-openai/tsp-location.yaml b/sdk/openai/azure-ai-openai/tsp-location.yaml index 4eba2fde995a..530e4519d996 100644 --- a/sdk/openai/azure-ai-openai/tsp-location.yaml +++ b/sdk/openai/azure-ai-openai/tsp-location.yaml @@ -1,5 +1,6 @@ directory: specification/cognitiveservices/OpenAI.Inference additionalDirectories: - specification/cognitiveservices/OpenAI.Authoring -commit: db23874c147db173933476b3b352cbf12abe84a9 -repo: Azure/azure-rest-api-specs +# change to main repo commit +commit: fb17452c886da0184b0d8f3d76688447be68c11d +repo: glecaros/azure-rest-api-specs From cc124c2f9f337d694b9eb3fc316e59c77997719b Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Thu, 6 Jul 2023 17:03:58 -0700 Subject: [PATCH 02/25] WIP: serialization still fails --- sdk/openai/azure-ai-openai/pom.xml | 1 + .../openai/functions/MyFunctionParameter.java | 26 ++++++++++ .../functions/MyFunctionParameters.java | 44 ++++++++++++++++ .../openai/NonAzureOpenAIAsyncClientTest.java | 27 ++++++++++ .../ai/openai/OpenAIAsyncClientTest.java | 22 ++++++++ .../azure/ai/openai/OpenAIClientTestBase.java | 23 ++++++++ .../azure/ai/openai/functions/Location.java | 37 +++++++++++++ .../azure/ai/openai/functions/Parameters.java | 52 +++++++++++++++++++ .../azure/ai/openai/functions/Properties.java | 50 ++++++++++++++++++ .../com/azure/ai/openai/functions/Unit.java | 39 ++++++++++++++ 10 files changed, 321 insertions(+) create mode 100644 sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java create mode 100644 sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java create mode 100644 sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java create mode 100644 sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Parameters.java create mode 100644 sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java create mode 100644 sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Unit.java diff --git a/sdk/openai/azure-ai-openai/pom.xml b/sdk/openai/azure-ai-openai/pom.xml index 3eb8a888f6fb..14424e2c3716 100644 --- a/sdk/openai/azure-ai-openai/pom.xml +++ b/sdk/openai/azure-ai-openai/pom.xml @@ -50,6 +50,7 @@ --add-exports com.azure.core/com.azure.core.implementation.util=ALL-UNNAMED --add-opens com.azure.ai.openai/com.azure.ai.openai=ALL-UNNAMED --add-opens com.azure.ai.openai/com.azure.ai.openai.implementation=com.fasterxml.jackson.databind + --add-opens com.azure.ai.openai/com.azure.ai.openai.functions=com.fasterxml.jackson.databind true diff --git a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java new file mode 100644 index 000000000000..398f6e9d586a --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class MyFunctionParameter { + + @JsonCreator + public MyFunctionParameter(String type, String description, List enumValues) { + this.type = type; + this.description = description; + this.enumValues = enumValues; + } + + @JsonProperty + public final String type; + @JsonProperty + public final String description; + @JsonProperty(value = "enum") + public final List enumValues; +} diff --git a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java new file mode 100644 index 000000000000..40f756ff4223 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + + +//MyFunctionParameters parameters = new MyFunctionParameters(); +// parameters.type = "object"; +// parameters.properties = new HashMap<>(); +// parameters.properties.put( +// "location", +// new MyFunctionParameters.FunctionProperty( +// "string", +// "The city and state, e.g. San Francisco, CA", +// null)); +// parameters.properties.put( +// "unit", +// new MyFunctionParameters.FunctionProperty( +// "string", +// "Unit temperature", +// Arrays.asList("Celsius", "Fahrenheit"))); +// parameters.required = Arrays.asList("location"); +// +// FunctionDefinition functionDefinition = new FunctionDefinition("MyFunction"); +// functionDefinition.setParameters(parameters); + +public class MyFunctionParameters { + @JsonProperty + public String type; + + @JsonProperty + public Map properties; + + @JsonProperty + public List required; + +} + diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index 16e3a92fcedb..9e266f733ab4 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -9,6 +9,8 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; +import com.azure.ai.openai.models.FunctionCallPreset; +import com.azure.ai.openai.models.FunctionCallPresetFunctionCallModel; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -240,4 +242,29 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic .assertNext(OpenAIClientTestBase::assertImageResponse) .verifyComplete()); } + + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAIAsyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); + + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAIAsyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .assertNext(chatCompletions -> { + System.out.println(chatCompletions); + }) + .verifyComplete(); + }); + } } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 676b001fed92..43a86ecdf6b2 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -9,6 +9,8 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; +import com.azure.ai.openai.models.FunctionCallPreset; +import com.azure.ai.openai.models.FunctionCallPresetFunctionCallModel; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; import com.azure.core.http.rest.RequestOptions; @@ -225,4 +227,24 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic .assertNext(OpenAIClientTestBase::assertImageResponse) .verifyComplete()); } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIAsyncClient(httpClient, serviceVersion); + getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); + + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIAsyncClient(httpClient, serviceVersion); + getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); +// StepVerifier.create(client.getChatCompletions()) + }); + } } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 553c448c237b..67cc26eaef09 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -4,8 +4,11 @@ package com.azure.ai.openai; +import com.azure.ai.openai.functions.Parameters; +import com.azure.ai.openai.functions.Properties; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; +import com.azure.ai.openai.models.ChatCompletionsOptions; import com.azure.ai.openai.models.ChatMessage; import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Choice; @@ -13,6 +16,7 @@ import com.azure.ai.openai.models.EmbeddingItem; import com.azure.ai.openai.models.Embeddings; import com.azure.ai.openai.models.EmbeddingsOptions; +import com.azure.ai.openai.models.FunctionDefinition; import com.azure.ai.openai.models.ImageGenerationOptions; import com.azure.ai.openai.models.ImageResponse; import com.azure.ai.openai.models.NonAzureOpenAIKeyCredential; @@ -25,6 +29,7 @@ import com.azure.core.test.TestProxyTestBase; import com.azure.core.util.BinaryData; import com.azure.core.util.Configuration; +import com.fasterxml.jackson.annotation.JsonProperty; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -138,6 +143,10 @@ void getImageGenerationRunner(Consumer testRunner) { ); } + void getChatFunctionRunner(BiConsumer testRunner) { + testRunner.accept("gpt-3.5-turbo-0613", getChatMessagesWithFunction()); + } + private List getChatMessages() { List chatMessages = new ArrayList<>(); chatMessages.add(new ChatMessage(ChatRole.SYSTEM).setContent("You are a helpful assistant. You will talk like a pirate.")); @@ -147,6 +156,20 @@ private List getChatMessages() { return chatMessages; } + private ChatCompletionsOptions getChatMessagesWithFunction() { + FunctionDefinition functionDefinition = new FunctionDefinition("MyFunction"); + Parameters parameters = new Parameters(); + functionDefinition.setParameters(parameters); + List functions = Arrays.asList(functionDefinition); + + List chatMessages = new ArrayList<>(); + chatMessages.add(new ChatMessage(ChatRole.USER).setContent("What's the weather like in San Francisco in Celsius?")); + + ChatCompletionsOptions chatCompletionOptions = new ChatCompletionsOptions(chatMessages); + chatCompletionOptions.setFunctions(functions); + return chatCompletionOptions; + } + static void assertCompletions(int choicesPerPrompt, Completions actual) { assertCompletions(choicesPerPrompt, "stop", actual); } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java new file mode 100644 index 000000000000..03563e3dbdd4 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; + +public class Location { + + @JsonProperty(value = "type") + private String type = "string"; + + @JsonProperty(value = "description") + private String description = "The city and state, e.g. San Francisco, CA"; + + @JsonGetter + public String getType() { + return type; + } + + @JsonSetter + public void setType(String type) { + this.type = type; + } + + @JsonGetter + public String getDescription() { + return description; + } + + @JsonSetter + public void setDescription(String description) { + this.description = description; + } +} diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Parameters.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Parameters.java new file mode 100644 index 000000000000..b248c138094d --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Parameters.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; + +public class Parameters { + + @JsonProperty(value = "type") + private String type = "object"; + + @JsonProperty(value = "properties") + private Properties properties = new Properties(); + + @JsonCreator + public Parameters( + @JsonProperty(value = "type") + String type, + @JsonProperty(value = "properties") + Properties properties + ) { + this.type = type; + this.properties = properties; + } + + @JsonCreator + public Parameters() {} + + @JsonGetter + public String getType() { + return type; + } + + @JsonSetter + public void setType(String type) { + this.type = type; + } + + @JsonGetter + public Properties getProperties() { + return properties; + } + + @JsonSetter + public void setProperties(Properties properties) { + this.properties = properties; + } +} diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java new file mode 100644 index 000000000000..c9e085dcd909 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; + +public class Properties { + + @JsonProperty(value = "type") + private String type = "object"; + + @JsonProperty(value = "unit") + private Unit unit = new Unit(); + + @JsonProperty + private Location location = new Location(); + + @JsonGetter + public String getType() { + return type; + } + + @JsonSetter + public void setType(String type) { + this.type = type; + } + + @JsonGetter + public Unit getUnit() { + return unit; + } + + @JsonSetter + public void setUnit(Unit unit) { + this.unit = unit; + } + + @JsonGetter + public Location getLocation() { + return location; + } + + @JsonSetter + public void setLocation(Location location) { + this.location = location; + } +} diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Unit.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Unit.java new file mode 100644 index 000000000000..6c3e92f94627 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Unit.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; + +import java.util.Arrays; +import java.util.List; + +public class Unit { + @JsonProperty(value = "type") + private String type = "string"; + + @JsonProperty(value = "enum") + private List enumValues = Arrays.asList("CELSIUS", "FAHRENHEIT"); + + @JsonGetter + public String getType() { + return type; + } + + @JsonSetter + public void setType(String type) { + this.type = type; + } + + @JsonGetter + public List getEnumValues() { + return enumValues; + } + + @JsonSetter + public void setEnumValues(List enumValues) { + this.enumValues = enumValues; + } +} From f4926353fc92b6be0c8f5410c52b2243863615a4 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Fri, 7 Jul 2023 17:36:51 -0700 Subject: [PATCH 03/25] Tests are passing, requests go through to nonAzure OAI --- .../NonAzureOpenAIClientImpl.java | 44 +++++++++++++------ .../openai/models/ChatCompletionsOptions.java | 24 ++++++++-- .../openai/models/FunctionCallModelBase.java | 10 ++++- .../FunctionCallPresetFunctionCallModel.java | 2 + .../azure/ai/openai/models/FunctionCalls.java | 31 +++++++++++++ .../models/FunctionNameFunctionCallModel.java | 6 ++- .../openai/NonAzureOpenAIAsyncClientTest.java | 11 +++-- .../ai/openai/OpenAIAsyncClientTest.java | 4 +- .../azure/ai/openai/functions/Properties.java | 14 ------ 9 files changed, 107 insertions(+), 39 deletions(-) create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java index af7f6cdc1e3e..bcddc63b7de0 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java @@ -28,8 +28,14 @@ import com.azure.core.util.Context; import com.azure.core.util.FluxUtil; import com.azure.core.util.serializer.SerializerAdapter; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.nio.charset.StandardCharsets; + /** * Implementation for calling Non-Azure OpenAI service */ @@ -650,20 +656,30 @@ public Mono> getChatCompletionsWithResponseAsync(String mod BinaryData chatCompletionsOptions, RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData chatCompletionsOptionsUpdated = BinaryData.fromObject( - chatCompletionsOptions.toObject(ChatCompletionsOptions.class) - .setModel(modelId) - ); - - return FluxUtil.withContext( - context -> - service.getChatCompletions( - OPEN_AI_ENDPOINT, - accept, - chatCompletionsOptionsUpdated, - requestOptions, - context)); + try { + ObjectMapper mapper = new ObjectMapper(); + + JsonNode jsonNode = mapper.readTree(chatCompletionsOptions.toString()); + + if (jsonNode instanceof ObjectNode) { + ObjectNode objectNode = (ObjectNode) jsonNode; + objectNode.put("model", modelId); + chatCompletionsOptions = BinaryData.fromBytes(objectNode.toString().getBytes(StandardCharsets.UTF_8)); + } + + BinaryData chatCompletionsOptionsUpdated = chatCompletionsOptions; + + return FluxUtil.withContext( + context -> + service.getChatCompletions( + OPEN_AI_ENDPOINT, + accept, + chatCompletionsOptionsUpdated, + requestOptions, + context)); + } catch (Exception exception) { + return Mono.error(exception); + } } /** diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index eaf04039f1d6..c7550f2a9a83 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; import java.util.Map; @@ -447,6 +448,9 @@ public ChatCompletionsOptions setModel(String model) { @JsonProperty(value = "function_call") private FunctionCallModelBase functionCall; + @JsonIgnore + private FunctionCalls functionCalls; + /** * Get the functions property: A list of functions the model may generate JSON inputs for. * @@ -477,8 +481,7 @@ public ChatCompletionsOptions setFunctions(List functions) { * * @return the functionCall value. */ - @Generated - public FunctionCallModelBase getFunctionCall() { + FunctionCallModelBase getFunctionCall() { return this.functionCall; } @@ -491,9 +494,22 @@ public FunctionCallModelBase getFunctionCall() { * @param functionCall the functionCall value to set. * @return the ChatCompletionsOptions object itself. */ - @Generated - public ChatCompletionsOptions setFunctionCall(FunctionCallModelBase functionCall) { + ChatCompletionsOptions setFunctionCall(FunctionCallModelBase functionCall) { this.functionCall = functionCall; return this; } + + public FunctionCalls getFunctionCalls() { + return this.functionCalls; + } + + public ChatCompletionsOptions setFunctionCalls(FunctionCalls functionCalls) { + this.functionCalls = functionCalls; + if (FunctionCallPreset.values().stream().anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { + this.functionCall = new FunctionCallPresetFunctionCallModel(FunctionCallPreset.fromString(this.functionCalls.getName())); + } else { + this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCalls.getName())); + } + return this; + } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java index 25beabc48f37..32558a7f3b92 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java @@ -4,8 +4,16 @@ package com.azure.ai.openai.models; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonSubTypes({ + @JsonSubTypes.Type(name="preset", value = FunctionCallPresetFunctionCallModel.class), + @JsonSubTypes.Type(name="custom", value = FunctionNameFunctionCallModel.class) +}) /** The FunctionCallModelBase model. */ -public abstract class FunctionCallModelBase { +public class FunctionCallModelBase { /** Creates an instance of FunctionCallModelBase class. */ protected FunctionCallModelBase() {} } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java index 9bcabdf0def9..aaf707b1540d 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java @@ -5,10 +5,12 @@ package com.azure.ai.openai.models; import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; /** The FunctionCallPresetFunctionCallModel model. */ @Immutable +@JsonTypeName("preset") public final class FunctionCallPresetFunctionCallModel extends FunctionCallModelBase { private final FunctionCallPreset value; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java new file mode 100644 index 000000000000..95f6afcab1f1 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +import com.azure.core.annotation.Immutable; + +@Immutable +public class FunctionCalls { + + private String name; + + public static FunctionCalls AUTO = new FunctionCalls("auto", false); + public static FunctionCalls NONE = new FunctionCalls("none", false); + + private boolean isCustomFunctionName; + + public FunctionCalls(String name) { + this(name, true); + } + + FunctionCalls(String name, boolean isCustomFunctionName) { + this.name = name; + this.isCustomFunctionName = isCustomFunctionName; + } + + public String getName() { + return this.name; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java index df40077ac3ea..6f5affac1c4b 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java @@ -5,10 +5,14 @@ package com.azure.ai.openai.models; import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; -/** The FunctionNameFunctionCallModel model. */ +/** + * The FunctionNameFunctionCallModel model. + */ @Immutable +@JsonTypeName("custom") public final class FunctionNameFunctionCallModel extends FunctionCallModelBase { private final FunctionName value; diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index 9e266f733ab4..98f38a9aa778 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -11,6 +11,7 @@ import com.azure.ai.openai.models.Embeddings; import com.azure.ai.openai.models.FunctionCallPreset; import com.azure.ai.openai.models.FunctionCallPresetFunctionCallModel; +import com.azure.ai.openai.models.FunctionCalls; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -249,8 +250,12 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); - + chatCompletionsOptions.setFunctionCalls(FunctionCalls.AUTO); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .assertNext(chatCompletions -> { + System.out.println(chatCompletions); + }) + .verifyComplete(); }); } @@ -259,7 +264,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); + chatCompletionsOptions.setFunctionCalls(FunctionCalls.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { System.out.println(chatCompletions); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 43a86ecdf6b2..82dba59a300a 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -233,7 +233,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); +// chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); }); } @@ -243,7 +243,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); +// chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); // StepVerifier.create(client.getChatCompletions()) }); } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java index c9e085dcd909..4303e531cdbd 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Properties.java @@ -8,26 +8,12 @@ import com.fasterxml.jackson.annotation.JsonSetter; public class Properties { - - @JsonProperty(value = "type") - private String type = "object"; - @JsonProperty(value = "unit") private Unit unit = new Unit(); @JsonProperty private Location location = new Location(); - @JsonGetter - public String getType() { - return type; - } - - @JsonSetter - public void setType(String type) { - this.type = type; - } - @JsonGetter public Unit getUnit() { return unit; From b87df2646db8560c7bdd4fe6ee2736cfe614f0e4 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Fri, 7 Jul 2023 17:49:09 -0700 Subject: [PATCH 04/25] Moved gened classes with polymorphism to impl package --- .../openai/implementation/FunctionCall.java | 67 +++++++++++++++++++ .../FunctionCallModelBase.java | 3 +- .../FunctionCallPreset.java | 2 +- .../FunctionCallPresetFunctionCallModel.java | 2 +- .../FunctionDefinition.java | 2 +- .../FunctionNameFunctionCallModel.java | 3 +- .../openai/models/ChatCompletionsOptions.java | 13 ++-- .../azure/ai/openai/models/ChatMessage.java | 1 + .../azure/ai/openai/models/FunctionCall.java | 60 ++++------------- .../azure/ai/openai/models/FunctionCalls.java | 31 --------- .../src/main/java/module-info.java | 2 + .../openai/NonAzureOpenAIAsyncClientTest.java | 8 +-- .../ai/openai/OpenAIAsyncClientTest.java | 2 - .../azure/ai/openai/OpenAIClientTestBase.java | 4 +- 14 files changed, 101 insertions(+), 99 deletions(-) create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/{models => implementation}/FunctionCallModelBase.java (86%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/{models => implementation}/FunctionCallPreset.java (97%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/{models => implementation}/FunctionCallPresetFunctionCallModel.java (95%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/{models => implementation}/FunctionDefinition.java (98%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/{models => implementation}/FunctionNameFunctionCallModel.java (90%) delete mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java new file mode 100644 index 000000000000..c44354737cad --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.implementation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The name and arguments of a function that should be called, as generated by the model. */ +@Immutable +public final class FunctionCall { + /* + * The name of the function to call. + */ + @Generated + @JsonProperty(value = "name") + private String name; + + /* + * The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters + * not defined by your function schema. Validate the arguments in your code before calling + * your function. + */ + @Generated + @JsonProperty(value = "arguments") + private String arguments; + + /** + * Creates an instance of FunctionCall class. + * + * @param name the name value to set. + * @param arguments the arguments value to set. + */ + @Generated + @JsonCreator + public FunctionCall( + @JsonProperty(value = "name") String name, @JsonProperty(value = "arguments") String arguments) { + this.name = name; + this.arguments = arguments; + } + + /** + * Get the name property: The name of the function to call. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } + + /** + * Get the arguments property: The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your + * function schema. Validate the arguments in your code before calling your function. + * + * @return the arguments value. + */ + @Generated + public String getArguments() { + return this.arguments; + } +} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java similarity index 86% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java index 32558a7f3b92..1423d8115773 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallModelBase.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java @@ -2,11 +2,10 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.models; +package com.azure.ai.openai.implementation; import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonSubTypes({ @JsonSubTypes.Type(name="preset", value = FunctionCallPresetFunctionCallModel.class), diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java similarity index 97% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java index 7ed496971285..096b12039a44 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPreset.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.models; +package com.azure.ai.openai.implementation; import com.azure.core.annotation.Generated; import com.azure.core.util.ExpandableStringEnum; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java similarity index 95% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java index aaf707b1540d..1583aa7ae76b 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallPresetFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.models; +package com.azure.ai.openai.implementation; import com.azure.core.annotation.Immutable; import com.fasterxml.jackson.annotation.JsonTypeName; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java similarity index 98% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java index c4b989a52b68..fbc004539a28 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionDefinition.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.models; +package com.azure.ai.openai.implementation; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java similarity index 90% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java index 6f5affac1c4b..da51df4f0add 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionNameFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java @@ -2,8 +2,9 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.models; +package com.azure.ai.openai.implementation; +import com.azure.ai.openai.models.FunctionName; import com.azure.core.annotation.Immutable; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index c7550f2a9a83..4686d9d8e845 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -3,6 +3,11 @@ // Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.ai.openai.models; +import com.azure.ai.openai.implementation.FunctionCallModelBase; +import com.azure.ai.openai.implementation.FunctionCallPreset; +import com.azure.ai.openai.implementation.FunctionCallPresetFunctionCallModel; +import com.azure.ai.openai.implementation.FunctionDefinition; +import com.azure.ai.openai.implementation.FunctionNameFunctionCallModel; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; @@ -449,7 +454,7 @@ public ChatCompletionsOptions setModel(String model) { private FunctionCallModelBase functionCall; @JsonIgnore - private FunctionCalls functionCalls; + private FunctionCall functionCalls; /** * Get the functions property: A list of functions the model may generate JSON inputs for. @@ -481,7 +486,7 @@ public ChatCompletionsOptions setFunctions(List functions) { * * @return the functionCall value. */ - FunctionCallModelBase getFunctionCall() { + FunctionCallModelBase _getFunctionCall() { return this.functionCall; } @@ -499,11 +504,11 @@ ChatCompletionsOptions setFunctionCall(FunctionCallModelBase functionCall) { return this; } - public FunctionCalls getFunctionCalls() { + public FunctionCall getFunctionCalls() { return this.functionCalls; } - public ChatCompletionsOptions setFunctionCalls(FunctionCalls functionCalls) { + public ChatCompletionsOptions setFunctionCalls(FunctionCall functionCalls) { this.functionCalls = functionCalls; if (FunctionCallPreset.values().stream().anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { this.functionCall = new FunctionCallPresetFunctionCallModel(FunctionCallPreset.fromString(this.functionCalls.getName())); diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java index 2594743f63f7..b533d014bf6d 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java @@ -3,6 +3,7 @@ // Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.ai.openai.models; +import com.azure.ai.openai.implementation.FunctionCall; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java index 0d87182bd586..f0bb871e8f26 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -4,64 +4,28 @@ package com.azure.ai.openai.models; -import com.azure.core.annotation.Generated; import com.azure.core.annotation.Immutable; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -/** The name and arguments of a function that should be called, as generated by the model. */ @Immutable -public final class FunctionCall { - /* - * The name of the function to call. - */ - @Generated - @JsonProperty(value = "name") +public class FunctionCall { + private String name; - /* - * The arguments to call the function with, as generated by the model in JSON format. - * Note that the model does not always generate valid JSON, and may hallucinate parameters - * not defined by your function schema. Validate the arguments in your code before calling - * your function. - */ - @Generated - @JsonProperty(value = "arguments") - private String arguments; + public static FunctionCall AUTO = new FunctionCall("auto", false); + public static FunctionCall NONE = new FunctionCall("none", false); + + private boolean isCustomFunctionName; + + public FunctionCall(String name) { + this(name, true); + } - /** - * Creates an instance of FunctionCall class. - * - * @param name the name value to set. - * @param arguments the arguments value to set. - */ - @Generated - @JsonCreator - public FunctionCall( - @JsonProperty(value = "name") String name, @JsonProperty(value = "arguments") String arguments) { + FunctionCall(String name, boolean isCustomFunctionName) { this.name = name; - this.arguments = arguments; + this.isCustomFunctionName = isCustomFunctionName; } - /** - * Get the name property: The name of the function to call. - * - * @return the name value. - */ - @Generated public String getName() { return this.name; } - - /** - * Get the arguments property: The arguments to call the function with, as generated by the model in JSON format. - * Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your - * function schema. Validate the arguments in your code before calling your function. - * - * @return the arguments value. - */ - @Generated - public String getArguments() { - return this.arguments; - } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java deleted file mode 100644 index 95f6afcab1f1..000000000000 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCalls.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// Code generated by Microsoft (R) AutoRest Code Generator. - -package com.azure.ai.openai.models; - -import com.azure.core.annotation.Immutable; - -@Immutable -public class FunctionCalls { - - private String name; - - public static FunctionCalls AUTO = new FunctionCalls("auto", false); - public static FunctionCalls NONE = new FunctionCalls("none", false); - - private boolean isCustomFunctionName; - - public FunctionCalls(String name) { - this(name, true); - } - - FunctionCalls(String name, boolean isCustomFunctionName) { - this.name = name; - this.isCustomFunctionName = isCustomFunctionName; - } - - public String getName() { - return this.name; - } -} diff --git a/sdk/openai/azure-ai-openai/src/main/java/module-info.java b/sdk/openai/azure-ai-openai/src/main/java/module-info.java index 590e8b4f6dfd..ebb0bb8f2154 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/module-info.java +++ b/sdk/openai/azure-ai-openai/src/main/java/module-info.java @@ -12,4 +12,6 @@ opens com.azure.ai.openai.models to com.azure.core, com.fasterxml.jackson.databind; + exports com.azure.ai.openai.implementation; + opens com.azure.ai.openai.implementation to com.azure.core, com.fasterxml.jackson.databind; } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index 98f38a9aa778..e59942d7a7fd 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -9,9 +9,7 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCallPreset; -import com.azure.ai.openai.models.FunctionCallPresetFunctionCallModel; -import com.azure.ai.openai.models.FunctionCalls; +import com.azure.ai.openai.models.FunctionCall; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -250,7 +248,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCalls(FunctionCalls.AUTO); + chatCompletionsOptions.setFunctionCalls(FunctionCall.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { System.out.println(chatCompletions); @@ -264,7 +262,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCalls(FunctionCalls.NONE); + chatCompletionsOptions.setFunctionCalls(FunctionCall.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { System.out.println(chatCompletions); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 82dba59a300a..3ec253a15130 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -9,8 +9,6 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCallPreset; -import com.azure.ai.openai.models.FunctionCallPresetFunctionCallModel; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; import com.azure.core.http.rest.RequestOptions; diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 67cc26eaef09..3c6c57cfe4cf 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -5,7 +5,6 @@ package com.azure.ai.openai; import com.azure.ai.openai.functions.Parameters; -import com.azure.ai.openai.functions.Properties; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; @@ -16,7 +15,7 @@ import com.azure.ai.openai.models.EmbeddingItem; import com.azure.ai.openai.models.Embeddings; import com.azure.ai.openai.models.EmbeddingsOptions; -import com.azure.ai.openai.models.FunctionDefinition; +import com.azure.ai.openai.implementation.FunctionDefinition; import com.azure.ai.openai.models.ImageGenerationOptions; import com.azure.ai.openai.models.ImageResponse; import com.azure.ai.openai.models.NonAzureOpenAIKeyCredential; @@ -29,7 +28,6 @@ import com.azure.core.test.TestProxyTestBase; import com.azure.core.util.BinaryData; import com.azure.core.util.Configuration; -import com.fasterxml.jackson.annotation.JsonProperty; import org.junit.jupiter.api.Test; import java.util.ArrayList; From 0dfb11fece25bea54ed985c8edae5c99c1f7a451 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 09:48:43 -0700 Subject: [PATCH 05/25] Added assertion for function call --- .../openai/NonAzureOpenAIAsyncClientTest.java | 13 ++++++-- .../azure/ai/openai/OpenAIClientTestBase.java | 10 ++++++ .../azure/ai/openai/functions/Location.java | 6 ++++ .../functions/MyFunctionCallArguments.java | 33 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index e59942d7a7fd..bcc81f37cea9 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -3,9 +3,14 @@ package com.azure.ai.openai; +import com.azure.ai.openai.functions.MyFunctionCallArguments; +import com.azure.ai.openai.functions.Properties; +import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; +import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Completions; +import com.azure.ai.openai.models.CompletionsFinishReason; import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; @@ -251,7 +256,11 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi chatCompletionsOptions.setFunctionCalls(FunctionCall.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { - System.out.println(chatCompletions); + assertEquals(1, chatCompletions.getChoices().size()); + ChatChoice chatChoice = chatCompletions.getChoices().get(0); + MyFunctionCallArguments arguments = assertFunctionCall(chatChoice, "MyFunction", MyFunctionCallArguments.class); + assertEquals(arguments.getLocation(), "San Francisco, CA"); + assertEquals(arguments.getUnit(), "CELSIUS"); }) .verifyComplete(); }); @@ -265,7 +274,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi chatCompletionsOptions.setFunctionCalls(FunctionCall.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { - System.out.println(chatCompletions); + assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions ); }) .verifyComplete(); }); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 3c6c57cfe4cf..d731ada5c318 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -5,6 +5,7 @@ package com.azure.ai.openai; import com.azure.ai.openai.functions.Parameters; +import com.azure.ai.openai.implementation.FunctionCall; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; @@ -267,4 +268,13 @@ static void assertImageResponse(ImageResponse actual) { assertNotNull(actual.getData()); assertFalse(actual.getData().isEmpty()); } + + static T assertFunctionCall(ChatChoice actual, String functionName, Class myPropertiesClazz) { + assertEquals(0, actual.getIndex()); + assertEquals("function_call", actual.getFinishReason().toString()); + FunctionCall functionCall = actual.getMessage().getFunctionCall(); + assertEquals(functionName, functionCall.getName()); + BinaryData argumentJson = BinaryData.fromString(functionCall.getArguments()); + return argumentJson.toObject(myPropertiesClazz); + } } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java index 03563e3dbdd4..d36d19354572 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/Location.java @@ -9,9 +9,15 @@ public class Location { + /** + * type defines the JSON type of the value that the service will request if a @FunctionCall is requested + */ @JsonProperty(value = "type") private String type = "string"; + /** + * Examples provided in the description appear to be used verbatim. Such as "San Francisco, CA" + */ @JsonProperty(value = "description") private String description = "The city and state, e.g. San Francisco, CA"; diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java new file mode 100644 index 000000000000..90e19cdef153 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java @@ -0,0 +1,33 @@ +package com.azure.ai.openai.functions; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; + +public class MyFunctionCallArguments { + @JsonProperty(value = "unit") + private String unit; + + @JsonProperty(value = "location") + private String location; + + @JsonGetter + public String getUnit() { + return unit; + } + + @JsonSetter + public void setUnit(String unit) { + this.unit = unit; + } + + @JsonGetter + public String getLocation() { + return location; + } + + @JsonSetter + public void setLocation(String location) { + this.location = location; + } +} From 0573d738054107dc0a5d55f987761798642a0284 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 11:19:32 -0700 Subject: [PATCH 06/25] Added test for usage of function not supplied in the request --- .../ai/openai/NonAzureOpenAIAsyncClientTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index bcc81f37cea9..20983184516b 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -279,4 +279,20 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi .verifyComplete(); }); } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAIAsyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCalls(new FunctionCall("UnavailableFunction")); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .verifyErrorSatisfies(throwable -> { + assertInstanceOf(HttpResponseException.class, throwable); + HttpResponseException httpResponseException = (HttpResponseException) throwable; + assertEquals(400, httpResponseException.getResponse().getStatusCode()); + assertTrue(httpResponseException.getMessage().contains("Invalid value for 'function_call'")); + }); + }); + } } From 10c469628f9f0347508aed98772420c70ba0124a Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 11:20:35 -0700 Subject: [PATCH 07/25] Renamed test for clarity --- .../java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index 20983184516b..b6ae0a62032f 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -282,7 +282,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") - public void testChatFunctionByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCalls(new FunctionCall("UnavailableFunction")); From 2bbb6ff90592ec39bbb90a445c281d043710958d Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 13:40:36 -0700 Subject: [PATCH 08/25] Addressed most of the PR comments --- .../NonAzureOpenAIClientImpl.java | 109 +++++++++--------- .../openai/models/ChatCompletionsOptions.java | 8 +- .../src/main/java/module-info.java | 1 - .../openai/NonAzureOpenAIAsyncClientTest.java | 8 +- 4 files changed, 64 insertions(+), 62 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java index bcddc63b7de0..d4b8c3b8c88e 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java @@ -3,9 +3,6 @@ package com.azure.ai.openai.implementation; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.CompletionsOptions; -import com.azure.ai.openai.models.EmbeddingsOptions; import com.azure.core.annotation.BodyParam; import com.azure.core.annotation.ExpectedResponses; import com.azure.core.annotation.HeaderParam; @@ -28,10 +25,10 @@ import com.azure.core.util.Context; import com.azure.core.util.FluxUtil; import com.azure.core.util.serializer.SerializerAdapter; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; @@ -72,6 +69,11 @@ public SerializerAdapter getSerializerAdapter() { */ public static final String OPEN_AI_ENDPOINT = "https://api.openai.com/v1"; + /** + * Mapper used to add the `modelId` into the request body for an nonAzure OpenAI request + */ + private static final ObjectMapper jsonMapper = new ObjectMapper(); + /** * Initializes an instance of OpenAIClient client. * @@ -295,11 +297,8 @@ public Mono> getEmbeddingsWithResponseAsync(String modelId, BinaryData embeddingsOptions, RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData embeddingsOptionsUpdated = BinaryData.fromObject( - embeddingsOptions.toObject(EmbeddingsOptions.class) - .setModel(modelId) - ); + // modelId is part of the request body in nonAzure OpenAI + BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); return FluxUtil.withContext( context -> @@ -363,11 +362,8 @@ public Response getEmbeddingsWithResponse(String modelId, BinaryData RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData embeddingsOptionsUpdated = BinaryData.fromObject( - embeddingsOptions.toObject(EmbeddingsOptions.class) - .setModel(modelId) - ); + // modelId is part of the request body in nonAzure OpenAI + BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); return service.getEmbeddingsSync( OPEN_AI_ENDPOINT, @@ -464,11 +460,8 @@ public Mono> getCompletionsWithResponseAsync(String modelId BinaryData completionsOptions, RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData completionsOptionsUpdated = BinaryData.fromObject( - completionsOptions.toObject(CompletionsOptions.class) - .setModel(modelId) - ); + // modelId is part of the request body in nonAzure OpenAI + BinaryData completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); return FluxUtil.withContext( context -> @@ -565,11 +558,9 @@ public Response getCompletionsWithResponse(String modelId, BinaryDat RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData completionsOptionsUpdated = BinaryData.fromObject( - completionsOptions.toObject(CompletionsOptions.class) - .setModel(modelId) - ); + // modelId is part of the request body in nonAzure OpenAI + BinaryData completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); + return service.getCompletionsSync( OPEN_AI_ENDPOINT, accept, @@ -656,30 +647,17 @@ public Mono> getChatCompletionsWithResponseAsync(String mod BinaryData chatCompletionsOptions, RequestOptions requestOptions) { final String accept = "application/json"; - try { - ObjectMapper mapper = new ObjectMapper(); - - JsonNode jsonNode = mapper.readTree(chatCompletionsOptions.toString()); - - if (jsonNode instanceof ObjectNode) { - ObjectNode objectNode = (ObjectNode) jsonNode; - objectNode.put("model", modelId); - chatCompletionsOptions = BinaryData.fromBytes(objectNode.toString().getBytes(StandardCharsets.UTF_8)); - } - - BinaryData chatCompletionsOptionsUpdated = chatCompletionsOptions; - - return FluxUtil.withContext( - context -> - service.getChatCompletions( - OPEN_AI_ENDPOINT, - accept, - chatCompletionsOptionsUpdated, - requestOptions, - context)); - } catch (Exception exception) { - return Mono.error(exception); - } + // modelId is part of the request body in nonAzure OpenAI + BinaryData chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); + + return FluxUtil.withContext( + context -> + service.getChatCompletions( + OPEN_AI_ENDPOINT, + accept, + chatCompletionsOptionsUpdated, + requestOptions, + context)); } /** @@ -759,11 +737,8 @@ public Response getChatCompletionsWithResponse(String modelId, Binar RequestOptions requestOptions) { final String accept = "application/json"; - // OpenAI has model ID in request body - BinaryData chatCompletionsOptionsUpdated = BinaryData.fromObject( - chatCompletionsOptions.toObject(ChatCompletionsOptions.class) - .setModel(modelId) - ); + // modelId is part of the request body in nonAzure OpenAI + BinaryData chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); return service.getChatCompletionsSync( OPEN_AI_ENDPOINT, @@ -886,4 +861,32 @@ public Response generateImageWithResponse( Context.NONE ); } + + /** + * This method injects the modelId in the request body for requests against nonAzure OpenAI. Unlike Azure OpenAI, + * the service expects this value in the body of the request, whereas Azure OpenAI passes it as part of the + * path of the request. + * + * @param inputJson JSON submitted by the client + * @param modelId The LLM model ID to be injected in the JSON + * @return + */ + private static BinaryData addModelIdJson(BinaryData inputJson, String modelId) { + JsonNode jsonNode = null; + try { + jsonNode = jsonMapper.readTree(inputJson.toString()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + if (jsonNode instanceof ObjectNode) { + ObjectNode objectNode = (ObjectNode) jsonNode; + objectNode.put("model", modelId); + inputJson = BinaryData.fromBytes( + objectNode.toString() + .getBytes(StandardCharsets.UTF_8)); + } + + return inputJson; + } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index 4686d9d8e845..194c24553736 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -486,7 +486,7 @@ public ChatCompletionsOptions setFunctions(List functions) { * * @return the functionCall value. */ - FunctionCallModelBase _getFunctionCall() { + FunctionCallModelBase getFunctionCallInternal() { return this.functionCall; } @@ -499,16 +499,16 @@ FunctionCallModelBase _getFunctionCall() { * @param functionCall the functionCall value to set. * @return the ChatCompletionsOptions object itself. */ - ChatCompletionsOptions setFunctionCall(FunctionCallModelBase functionCall) { + ChatCompletionsOptions setFunctionCallInternal(FunctionCallModelBase functionCall) { this.functionCall = functionCall; return this; } - public FunctionCall getFunctionCalls() { + public FunctionCall getFunctionCall() { return this.functionCalls; } - public ChatCompletionsOptions setFunctionCalls(FunctionCall functionCalls) { + public ChatCompletionsOptions setFunctionCall(FunctionCall functionCalls) { this.functionCalls = functionCalls; if (FunctionCallPreset.values().stream().anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { this.functionCall = new FunctionCallPresetFunctionCallModel(FunctionCallPreset.fromString(this.functionCalls.getName())); diff --git a/sdk/openai/azure-ai-openai/src/main/java/module-info.java b/sdk/openai/azure-ai-openai/src/main/java/module-info.java index ebb0bb8f2154..92b8d95654f5 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/module-info.java +++ b/sdk/openai/azure-ai-openai/src/main/java/module-info.java @@ -12,6 +12,5 @@ opens com.azure.ai.openai.models to com.azure.core, com.fasterxml.jackson.databind; - exports com.azure.ai.openai.implementation; opens com.azure.ai.openai.implementation to com.azure.core, com.fasterxml.jackson.databind; } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index b6ae0a62032f..b9585d894e79 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -253,7 +253,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCalls(FunctionCall.AUTO); + chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { assertEquals(1, chatCompletions.getChoices().size()); @@ -271,10 +271,10 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCalls(FunctionCall.NONE); + chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { - assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions ); + assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); }) .verifyComplete(); }); @@ -285,7 +285,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCalls(new FunctionCall("UnavailableFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCall("UnavailableFunction")); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .verifyErrorSatisfies(throwable -> { assertInstanceOf(HttpResponseException.class, throwable); From c9f4280c2955e552e05c707c292a6e8e4c5794b1 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 14:58:31 -0700 Subject: [PATCH 09/25] Added sync version of the tests --- .../openai/NonAzureOpenAIAsyncClientTest.java | 7 ++- .../openai/NonAzureOpenAISyncClientTest.java | 51 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index b9585d894e79..3cb810cc649e 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -258,7 +258,10 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi .assertNext(chatCompletions -> { assertEquals(1, chatCompletions.getChoices().size()); ChatChoice chatChoice = chatCompletions.getChoices().get(0); - MyFunctionCallArguments arguments = assertFunctionCall(chatChoice, "MyFunction", MyFunctionCallArguments.class); + MyFunctionCallArguments arguments = assertFunctionCall( + chatChoice, + "MyFunction", + MyFunctionCallArguments.class); assertEquals(arguments.getLocation(), "San Francisco, CA"); assertEquals(arguments.getUnit(), "CELSIUS"); }) @@ -285,7 +288,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCall("UnavailableFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .verifyErrorSatisfies(throwable -> { assertInstanceOf(HttpResponseException.class, throwable); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java index 51d10cabd27a..145a0aa66a05 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java @@ -3,12 +3,16 @@ package com.azure.ai.openai; +import com.azure.ai.openai.functions.MyFunctionCallArguments; +import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; +import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Completions; import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; +import com.azure.ai.openai.models.FunctionCall; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -21,6 +25,7 @@ import static com.azure.ai.openai.TestUtils.DISPLAY_NAME_WITH_ARGUMENTS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -194,4 +199,50 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic client = getNonAzureOpenAISyncClient(httpClient); getImageGenerationRunner(options -> assertImageResponse(client.generateImage(options))); } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAISyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); + + assertEquals(1, chatCompletions.getChoices().size()); + ChatChoice chatChoice = chatCompletions.getChoices().get(0); + MyFunctionCallArguments arguments = assertFunctionCall( + chatChoice, + "MyFunction", + MyFunctionCallArguments.class); + assertEquals(arguments.getLocation(), "San Francisco, CA"); + assertEquals(arguments.getUnit(), "CELSIUS"); + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAISyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); + + assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getNonAzureOpenAISyncClient(httpClient); + getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + HttpResponseException exception = assertThrows(HttpResponseException.class, + () -> client.getChatCompletions(modelId, chatCompletionsOptions)); + assertEquals(400, exception.getResponse().getStatusCode()); + + assertInstanceOf(HttpResponseException.class, exception); + assertTrue(exception.getMessage().contains("Invalid value for 'function_call'")); + }); + } } From 71e48bf775bb07a48fd3d974433f671dadcd75f5 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 15:25:06 -0700 Subject: [PATCH 10/25] Renamed runner method --- .../azure/ai/openai/NonAzureOpenAIAsyncClientTest.java | 8 +++----- .../com/azure/ai/openai/NonAzureOpenAISyncClientTest.java | 6 +++--- .../java/com/azure/ai/openai/OpenAIAsyncClientTest.java | 4 ++-- .../java/com/azure/ai/openai/OpenAIClientTestBase.java | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index 3cb810cc649e..a30ac3381115 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -4,13 +4,11 @@ package com.azure.ai.openai; import com.azure.ai.openai.functions.MyFunctionCallArguments; -import com.azure.ai.openai.functions.Properties; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Completions; -import com.azure.ai.openai.models.CompletionsFinishReason; import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; @@ -252,7 +250,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { @@ -273,7 +271,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { @@ -287,7 +285,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .verifyErrorSatisfies(throwable -> { diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java index 145a0aa66a05..73acba41c6c1 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java @@ -204,7 +204,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); @@ -223,7 +223,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); @@ -235,7 +235,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); - getChatFunctionRunner((modelId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); HttpResponseException exception = assertThrows(HttpResponseException.class, () -> client.getChatCompletions(modelId, chatCompletionsOptions)); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 3ec253a15130..06350010ab94 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -230,7 +230,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); - getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((deploymentId, chatCompletionsOptions) -> { // chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); }); @@ -240,7 +240,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); - getChatFunctionRunner((deploymentId, chatCompletionsOptions) -> { + getChatFunctionForNonAzureRunner((deploymentId, chatCompletionsOptions) -> { // chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); // StepVerifier.create(client.getChatCompletions()) }); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index d731ada5c318..5013e41fdb2c 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -142,7 +142,7 @@ void getImageGenerationRunner(Consumer testRunner) { ); } - void getChatFunctionRunner(BiConsumer testRunner) { + void getChatFunctionForNonAzureRunner(BiConsumer testRunner) { testRunner.accept("gpt-3.5-turbo-0613", getChatMessagesWithFunction()); } From a1340cb5c30a432c4b97c29f4899311fb0f04b5c Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 15:37:06 -0700 Subject: [PATCH 11/25] Added Azure sync/async tests --- .../ai/openai/OpenAIAsyncClientTest.java | 48 ++++++++++++++--- .../azure/ai/openai/OpenAIClientTestBase.java | 4 ++ .../azure/ai/openai/OpenAISyncClientTest.java | 52 +++++++++++++++++++ 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 06350010ab94..06e8ffe488ec 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -3,12 +3,17 @@ package com.azure.ai.openai; +import com.azure.ai.openai.functions.MyFunctionCallArguments; +import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; +import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Completions; import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; +import com.azure.ai.openai.models.FunctionCall; +import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; import com.azure.core.http.rest.RequestOptions; @@ -230,9 +235,20 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); - getChatFunctionForNonAzureRunner((deploymentId, chatCompletionsOptions) -> { -// chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.AUTO)); - + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .assertNext(chatCompletions -> { + assertEquals(1, chatCompletions.getChoices().size()); + ChatChoice chatChoice = chatCompletions.getChoices().get(0); + MyFunctionCallArguments arguments = assertFunctionCall( + chatChoice, + "MyFunction", + MyFunctionCallArguments.class); + assertEquals(arguments.getLocation(), "San Francisco, CA"); + assertEquals(arguments.getUnit(), "CELSIUS"); + }) + .verifyComplete(); }); } @@ -240,9 +256,29 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); - getChatFunctionForNonAzureRunner((deploymentId, chatCompletionsOptions) -> { -// chatCompletionsOptions.setFunctionCall(new FunctionCallPresetFunctionCallModel(FunctionCallPreset.NONE)); -// StepVerifier.create(client.getChatCompletions()) + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .assertNext(chatCompletions -> { + assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); + }) + .verifyComplete(); + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIAsyncClient(httpClient, serviceVersion); + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) + .verifyErrorSatisfies(throwable -> { + assertInstanceOf(HttpResponseException.class, throwable); + HttpResponseException httpResponseException = (HttpResponseException) throwable; + assertEquals(400, httpResponseException.getResponse().getStatusCode()); + assertTrue(httpResponseException.getMessage().contains("Invalid value for 'function_call'")); + }); }); } } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 5013e41fdb2c..8b55858cdea5 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -146,6 +146,10 @@ void getChatFunctionForNonAzureRunner(BiConsumer testRunner.accept("gpt-3.5-turbo-0613", getChatMessagesWithFunction()); } + void getChatFunctionForRunner(BiConsumer testRunner) { + testRunner.accept("gpt-35-turbo-0613", getChatMessagesWithFunction()); + } + private List getChatMessages() { List chatMessages = new ArrayList<>(); chatMessages.add(new ChatMessage(ChatRole.SYSTEM).setContent("You are a helpful assistant. You will talk like a pirate.")); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java index 9579283be5ef..bfe0f4b9bfa9 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java @@ -3,12 +3,17 @@ package com.azure.ai.openai; +import com.azure.ai.openai.functions.MyFunctionCallArguments; +import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; +import com.azure.ai.openai.models.ChatRole; import com.azure.ai.openai.models.Completions; import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; +import com.azure.ai.openai.models.FunctionCall; +import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; import com.azure.core.http.rest.RequestOptions; @@ -20,6 +25,7 @@ import static com.azure.ai.openai.TestUtils.DISPLAY_NAME_WITH_ARGUMENTS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -182,4 +188,50 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic client = getOpenAIClient(httpClient, serviceVersion); getImageGenerationRunner(options -> assertImageResponse(client.generateImage(options))); } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIClient(httpClient, serviceVersion); + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); + + assertEquals(1, chatCompletions.getChoices().size()); + ChatChoice chatChoice = chatCompletions.getChoices().get(0); + MyFunctionCallArguments arguments = assertFunctionCall( + chatChoice, + "MyFunction", + MyFunctionCallArguments.class); + assertEquals(arguments.getLocation(), "San Francisco, CA"); + assertEquals(arguments.getUnit(), "CELSIUS"); + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIClient(httpClient, serviceVersion); + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); + + assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); + }); + } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.openai.TestUtils#getTestParameters") + public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { + client = getOpenAIClient(httpClient, serviceVersion); + getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { + chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + HttpResponseException exception = assertThrows(HttpResponseException.class, + () -> client.getChatCompletions(modelId, chatCompletionsOptions)); + assertEquals(400, exception.getResponse().getStatusCode()); + + assertInstanceOf(HttpResponseException.class, exception); + assertTrue(exception.getMessage().contains("Invalid value for 'function_call'")); + }); + } } From 00d6762718a8f21d86e2915c849f5c1e8c564466 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 15:45:41 -0700 Subject: [PATCH 12/25] Added docs for FunctionCall --- .../azure/ai/openai/models/FunctionCall.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java index f0bb871e8f26..dd854caf69b4 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -6,25 +6,56 @@ import com.azure.core.annotation.Immutable; +/** The name and arguments of a function that should be called, as generated by the model. */ @Immutable public class FunctionCall { + /* + * The name of the function to call. + */ private String name; + /* + * AUTO will indicate the service to call any functions that are necessary for text completion generation. + */ public static FunctionCall AUTO = new FunctionCall("auto", false); + + /* + * NONE will indicate the service to not call nay of the functions that may have been provided with the request for + * text completion generation. + */ public static FunctionCall NONE = new FunctionCall("none", false); + /* + * Indicates if the "name" of the function was explicitly passed, instead of using one of the built-in values + */ private boolean isCustomFunctionName; + /** + * Creates an instance of FunctionCall class. + * + * @param name the name value to set. + */ public FunctionCall(String name) { this(name, true); } + /** + * Creates an instance of FunctionCall class. + * + * @param name the name value to set. + * @param isCustomFunctionName is the name of the function to be called explicitly passed. + */ FunctionCall(String name, boolean isCustomFunctionName) { this.name = name; this.isCustomFunctionName = isCustomFunctionName; } + /** + * Get the name property: The name of the function to call. + * + * @return the name value. + */ public String getName() { return this.name; } From 72101cbe5cd2c0adc0e3e7872b6a15bad94baf99 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 15:49:00 -0700 Subject: [PATCH 13/25] Removed unused files from samples package --- .../openai/functions/MyFunctionParameter.java | 26 ----------- .../functions/MyFunctionParameters.java | 44 ------------------- 2 files changed, 70 deletions(-) delete mode 100644 sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java delete mode 100644 sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java diff --git a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java deleted file mode 100644 index 398f6e9d586a..000000000000 --- a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameter.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.ai.openai.functions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class MyFunctionParameter { - - @JsonCreator - public MyFunctionParameter(String type, String description, List enumValues) { - this.type = type; - this.description = description; - this.enumValues = enumValues; - } - - @JsonProperty - public final String type; - @JsonProperty - public final String description; - @JsonProperty(value = "enum") - public final List enumValues; -} diff --git a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java b/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java deleted file mode 100644 index 40f756ff4223..000000000000 --- a/sdk/openai/azure-ai-openai/src/samples/java/com/azure/ai/openai/functions/MyFunctionParameters.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.ai.openai.functions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; -import java.util.Map; - - -//MyFunctionParameters parameters = new MyFunctionParameters(); -// parameters.type = "object"; -// parameters.properties = new HashMap<>(); -// parameters.properties.put( -// "location", -// new MyFunctionParameters.FunctionProperty( -// "string", -// "The city and state, e.g. San Francisco, CA", -// null)); -// parameters.properties.put( -// "unit", -// new MyFunctionParameters.FunctionProperty( -// "string", -// "Unit temperature", -// Arrays.asList("Celsius", "Fahrenheit"))); -// parameters.required = Arrays.asList("location"); -// -// FunctionDefinition functionDefinition = new FunctionDefinition("MyFunction"); -// functionDefinition.setParameters(parameters); - -public class MyFunctionParameters { - @JsonProperty - public String type; - - @JsonProperty - public Map properties; - - @JsonProperty - public List required; - -} - From abe5ff3be98e598719a53e976fbfbb1f0ada87e8 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Mon, 10 Jul 2023 16:01:02 -0700 Subject: [PATCH 14/25] Preparing release notes --- sdk/openai/azure-ai-openai/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/openai/azure-ai-openai/CHANGELOG.md b/sdk/openai/azure-ai-openai/CHANGELOG.md index 7765dbb0d608..29165ff37fc7 100644 --- a/sdk/openai/azure-ai-openai/CHANGELOG.md +++ b/sdk/openai/azure-ai-openai/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.0.0-beta.3 (Unreleased) +- Added methods and models to support DALL-E +- Added methods and models to support Functions +- Added models supporting ResponsibleAI annotations + ### Features Added ### Breaking Changes From c9a4fde88c0e26a7c08094976343d90aff519295 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Tue, 11 Jul 2023 08:31:02 -0700 Subject: [PATCH 15/25] Renamed static member --- .../ai/openai/implementation/NonAzureOpenAIClientImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java index d4b8c3b8c88e..e69c8e568b37 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java @@ -72,7 +72,7 @@ public SerializerAdapter getSerializerAdapter() { /** * Mapper used to add the `modelId` into the request body for an nonAzure OpenAI request */ - private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); /** * Initializes an instance of OpenAIClient client. @@ -874,7 +874,7 @@ public Response generateImageWithResponse( private static BinaryData addModelIdJson(BinaryData inputJson, String modelId) { JsonNode jsonNode = null; try { - jsonNode = jsonMapper.readTree(inputJson.toString()); + jsonNode = JSON_MAPPER.readTree(inputJson.toString()); } catch (JsonProcessingException e) { throw new RuntimeException(e); } From 14a12af604d7bc9b8e68983814a77893e1456457 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Tue, 11 Jul 2023 08:39:06 -0700 Subject: [PATCH 16/25] Moved the exception handling one level up in the call stack --- .../NonAzureOpenAIClientImpl.java | 112 ++++++++++-------- 1 file changed, 64 insertions(+), 48 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java index e69c8e568b37..ff7723f29a4e 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/NonAzureOpenAIClientImpl.java @@ -298,16 +298,19 @@ public Mono> getEmbeddingsWithResponseAsync(String modelId, final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); - - return FluxUtil.withContext( - context -> - service.getEmbeddings( - OPEN_AI_ENDPOINT, - accept, - embeddingsOptionsUpdated, - requestOptions, - context)); + try { + BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); + return FluxUtil.withContext( + context -> + service.getEmbeddings( + OPEN_AI_ENDPOINT, + accept, + embeddingsOptionsUpdated, + requestOptions, + context)); + } catch (JsonProcessingException e) { + return Mono.error(e); + } } /** @@ -363,14 +366,17 @@ public Response getEmbeddingsWithResponse(String modelId, BinaryData final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); - - return service.getEmbeddingsSync( - OPEN_AI_ENDPOINT, - accept, - embeddingsOptionsUpdated, - requestOptions, - Context.NONE); + try { + BinaryData embeddingsOptionsUpdated = addModelIdJson(embeddingsOptions, modelId); + return service.getEmbeddingsSync( + OPEN_AI_ENDPOINT, + accept, + embeddingsOptionsUpdated, + requestOptions, + Context.NONE); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } /** @@ -461,16 +467,19 @@ public Mono> getCompletionsWithResponseAsync(String modelId final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); - - return FluxUtil.withContext( - context -> - service.getCompletions( - OPEN_AI_ENDPOINT, - accept, - completionsOptionsUpdated, - requestOptions, - context)); + try { + BinaryData completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); + return FluxUtil.withContext( + context -> + service.getCompletions( + OPEN_AI_ENDPOINT, + accept, + completionsOptionsUpdated, + requestOptions, + context)); + } catch (JsonProcessingException e) { + return Mono.error(e); + } } /** @@ -559,7 +568,12 @@ public Response getCompletionsWithResponse(String modelId, BinaryDat final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); + BinaryData completionsOptionsUpdated = null; + try { + completionsOptionsUpdated = addModelIdJson(completionsOptions, modelId); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } return service.getCompletionsSync( OPEN_AI_ENDPOINT, @@ -648,16 +662,19 @@ public Mono> getChatCompletionsWithResponseAsync(String mod final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); - - return FluxUtil.withContext( - context -> - service.getChatCompletions( - OPEN_AI_ENDPOINT, - accept, - chatCompletionsOptionsUpdated, - requestOptions, - context)); + try { + BinaryData chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); + return FluxUtil.withContext( + context -> + service.getChatCompletions( + OPEN_AI_ENDPOINT, + accept, + chatCompletionsOptionsUpdated, + requestOptions, + context)); + } catch (JsonProcessingException e) { + return Mono.error(e); + } } /** @@ -738,7 +755,12 @@ public Response getChatCompletionsWithResponse(String modelId, Binar final String accept = "application/json"; // modelId is part of the request body in nonAzure OpenAI - BinaryData chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); + BinaryData chatCompletionsOptionsUpdated = null; + try { + chatCompletionsOptionsUpdated = addModelIdJson(chatCompletionsOptions, modelId); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } return service.getChatCompletionsSync( OPEN_AI_ENDPOINT, @@ -871,14 +893,8 @@ public Response generateImageWithResponse( * @param modelId The LLM model ID to be injected in the JSON * @return */ - private static BinaryData addModelIdJson(BinaryData inputJson, String modelId) { - JsonNode jsonNode = null; - try { - jsonNode = JSON_MAPPER.readTree(inputJson.toString()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - + private static BinaryData addModelIdJson(BinaryData inputJson, String modelId) throws JsonProcessingException { + JsonNode jsonNode = JSON_MAPPER.readTree(inputJson.toString()); if (jsonNode instanceof ObjectNode) { ObjectNode objectNode = (ObjectNode) jsonNode; objectNode.put("model", modelId); From aed004b53826006587e4f6648ec62cb4159e1348 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Tue, 11 Jul 2023 09:43:32 -0700 Subject: [PATCH 17/25] code regened --- .../openai/implementation/FunctionCall.java | 2 +- .../implementation/FunctionCallModelBase.java | 9 +----- .../implementation/FunctionCallPreset.java | 17 +++++++--- .../FunctionCallPresetFunctionCallModel.java | 2 -- .../implementation/FunctionDefinition.java | 31 +++++++------------ .../FunctionNameFunctionCallModel.java | 6 +--- .../openai/models/ChatCompletionsOptions.java | 10 +++--- .../azure/ai/openai/models/FunctionName.java | 7 +++-- .../src/main/java/module-info.java | 5 ++- sdk/openai/azure-ai-openai/tsp-location.yaml | 5 ++- 10 files changed, 45 insertions(+), 49 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java index c44354737cad..ee972c831941 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.ai.openai.implementation; import com.azure.core.annotation.Generated; @@ -12,6 +11,7 @@ /** The name and arguments of a function that should be called, as generated by the model. */ @Immutable public final class FunctionCall { + /* * The name of the function to call. */ diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java index 1423d8115773..9220de2fa835 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java @@ -4,15 +4,8 @@ package com.azure.ai.openai.implementation; - -import com.fasterxml.jackson.annotation.JsonSubTypes; - -@JsonSubTypes({ - @JsonSubTypes.Type(name="preset", value = FunctionCallPresetFunctionCallModel.class), - @JsonSubTypes.Type(name="custom", value = FunctionNameFunctionCallModel.class) -}) /** The FunctionCallModelBase model. */ -public class FunctionCallModelBase { +public abstract class FunctionCallModelBase { /** Creates an instance of FunctionCallModelBase class. */ protected FunctionCallModelBase() {} } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java index 096b12039a44..4e9109856fcb 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.ai.openai.implementation; import com.azure.core.annotation.Generated; @@ -9,12 +8,22 @@ import com.fasterxml.jackson.annotation.JsonCreator; import java.util.Collection; -/** Preset values to control how the mode; responds to function calls. */ +/** + * The collection of predefined behaviors for handling request-provided function information in a chat completions + * operation. + */ public final class FunctionCallPreset extends ExpandableStringEnum { - /** Means the model can pick between an end-user or calling a function. */ + + /** + * Specifies that the model may either use any of the functions provided in this chat completions request or instead + * return a standard chat completions response as if no functions were provided. + */ @Generated public static final FunctionCallPreset AUTO = fromString("auto"); - /** Means the model does not call a function, and responds to the end-user. */ + /** + * Specifies that the model should not respond with a function call and should instead provide a standard chat + * completions response. Response content may still be influenced by the provided function information. + */ @Generated public static final FunctionCallPreset NONE = fromString("none"); /** diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java index 1583aa7ae76b..2ebdf921744b 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java @@ -5,12 +5,10 @@ package com.azure.ai.openai.implementation; import com.azure.core.annotation.Immutable; -import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; /** The FunctionCallPresetFunctionCallModel model. */ @Immutable -@JsonTypeName("preset") public final class FunctionCallPresetFunctionCallModel extends FunctionCallModelBase { private final FunctionCallPreset value; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java index fbc004539a28..2532558e049c 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.ai.openai.implementation; import com.azure.core.annotation.Fluent; @@ -10,21 +9,21 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** - * The definition of a function that can be called by the model. See the [guide](/docs/guides/gpt/function-calling) for - * examples. + * The definition of a caller-specified function that chat completions may invoke in response to matching user input. */ @Fluent public final class FunctionDefinition { + /* - * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, - * with a maximum length of 64. + * The name of the function to be called. */ @Generated @JsonProperty(value = "name") private String name; /* - * The description of what the function does. + * A description of what the function does. The model will use this description when selecting the function and + * interpreting its parameters. */ @Generated @JsonProperty(value = "description") @@ -32,9 +31,6 @@ public final class FunctionDefinition { /* * The parameters the functions accepts, described as a JSON Schema object. - * See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema - * reference](https://json-schema.org/understanding-json-schema/) - * for documentation about the format. */ @Generated @JsonProperty(value = "parameters") @@ -52,8 +48,7 @@ public FunctionDefinition(@JsonProperty(value = "name") String name) { } /** - * Get the name property: The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and - * dashes, with a maximum length of 64. + * Get the name property: The name of the function to be called. * * @return the name value. */ @@ -63,7 +58,8 @@ public String getName() { } /** - * Get the description property: The description of what the function does. + * Get the description property: A description of what the function does. The model will use this description when + * selecting the function and interpreting its parameters. * * @return the description value. */ @@ -73,7 +69,8 @@ public String getDescription() { } /** - * Set the description property: The description of what the function does. + * Set the description property: A description of what the function does. The model will use this description when + * selecting the function and interpreting its parameters. * * @param description the description value to set. * @return the FunctionDefinition object itself. @@ -85,9 +82,7 @@ public FunctionDefinition setDescription(String description) { } /** - * Get the parameters property: The parameters the functions accepts, described as a JSON Schema object. See the - * [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema - * reference](https://json-schema.org/understanding-json-schema/) for documentation about the format. + * Get the parameters property: The parameters the functions accepts, described as a JSON Schema object. * * @return the parameters value. */ @@ -97,9 +92,7 @@ public Object getParameters() { } /** - * Set the parameters property: The parameters the functions accepts, described as a JSON Schema object. See the - * [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema - * reference](https://json-schema.org/understanding-json-schema/) for documentation about the format. + * Set the parameters property: The parameters the functions accepts, described as a JSON Schema object. * * @param parameters the parameters value to set. * @return the FunctionDefinition object itself. diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java index da51df4f0add..c5d9fedd3681 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java @@ -6,14 +6,10 @@ import com.azure.ai.openai.models.FunctionName; import com.azure.core.annotation.Immutable; -import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; -/** - * The FunctionNameFunctionCallModel model. - */ +/** The FunctionNameFunctionCallModel model. */ @Immutable -@JsonTypeName("custom") public final class FunctionNameFunctionCallModel extends FunctionCallModelBase { private final FunctionName value; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index 194c24553736..a82714ea803b 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -453,8 +453,7 @@ public ChatCompletionsOptions setModel(String model) { @JsonProperty(value = "function_call") private FunctionCallModelBase functionCall; - @JsonIgnore - private FunctionCall functionCalls; + @JsonIgnore private FunctionCall functionCalls; /** * Get the functions property: A list of functions the model may generate JSON inputs for. @@ -510,8 +509,11 @@ public FunctionCall getFunctionCall() { public ChatCompletionsOptions setFunctionCall(FunctionCall functionCalls) { this.functionCalls = functionCalls; - if (FunctionCallPreset.values().stream().anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { - this.functionCall = new FunctionCallPresetFunctionCallModel(FunctionCallPreset.fromString(this.functionCalls.getName())); + if (FunctionCallPreset.values().stream() + .anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { + this.functionCall = + new FunctionCallPresetFunctionCallModel( + FunctionCallPreset.fromString(this.functionCalls.getName())); } else { this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCalls.getName())); } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java index 8e8f16fd291f..82b2abb8eff4 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionName.java @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.ai.openai.models; import com.azure.core.annotation.Generated; @@ -9,9 +8,13 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -/** Specify the name of the only function to call. */ +/** + * A structure that specifies the exact name of a specific, request-provided function to use when processing a chat + * completions operation. + */ @Immutable public final class FunctionName { + /* * The name of the function to call. */ diff --git a/sdk/openai/azure-ai-openai/src/main/java/module-info.java b/sdk/openai/azure-ai-openai/src/main/java/module-info.java index 92b8d95654f5..7b75baa4beec 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/module-info.java +++ b/sdk/openai/azure-ai-openai/src/main/java/module-info.java @@ -8,9 +8,12 @@ exports com.azure.ai.openai; exports com.azure.ai.openai.models; + exports com.azure.ai.openai.implementation; opens com.azure.ai.openai.models to com.azure.core, com.fasterxml.jackson.databind; - opens com.azure.ai.openai.implementation to com.azure.core, com.fasterxml.jackson.databind; + opens com.azure.ai.openai.implementation to + com.azure.core, + com.fasterxml.jackson.databind; } diff --git a/sdk/openai/azure-ai-openai/tsp-location.yaml b/sdk/openai/azure-ai-openai/tsp-location.yaml index 530e4519d996..43e4f9fe2f2d 100644 --- a/sdk/openai/azure-ai-openai/tsp-location.yaml +++ b/sdk/openai/azure-ai-openai/tsp-location.yaml @@ -1,6 +1,5 @@ directory: specification/cognitiveservices/OpenAI.Inference additionalDirectories: - specification/cognitiveservices/OpenAI.Authoring -# change to main repo commit -commit: fb17452c886da0184b0d8f3d76688447be68c11d -repo: glecaros/azure-rest-api-specs +commit: ef477cb666504640106a6e8c9263b45fc0fa3e08 +repo: Azure/azure-rest-api-specs From a5eada6b0108d3ddadf2dec5c0364577fc2dcff0 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Tue, 11 Jul 2023 17:21:57 -0700 Subject: [PATCH 18/25] Moved custom models under their own package --- .../implementation/{ => models}/FunctionCall.java | 2 +- .../{ => models}/FunctionCallModelBase.java | 2 +- .../{ => models}/FunctionCallPreset.java | 2 +- .../FunctionCallPresetFunctionCallModel.java | 2 +- .../{ => models}/FunctionDefinition.java | 2 +- .../{ => models}/FunctionNameFunctionCallModel.java | 2 +- .../ai/openai/implementation/models/package-info.java | 6 ++++++ .../azure/ai/openai/models/ChatCompletionsOptions.java | 10 +++++----- .../java/com/azure/ai/openai/models/ChatMessage.java | 2 +- .../azure-ai-openai/src/main/java/module-info.java | 5 ++++- .../java/com/azure/ai/openai/OpenAIClientTestBase.java | 4 ++-- 11 files changed, 24 insertions(+), 15 deletions(-) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionCall.java (97%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionCallModelBase.java (87%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionCallPreset.java (97%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionCallPresetFunctionCallModel.java (94%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionDefinition.java (98%) rename sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/{ => models}/FunctionNameFunctionCallModel.java (94%) create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/package-info.java diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java similarity index 97% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java index ee972c831941..f58e21632f12 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; import com.azure.core.annotation.Generated; import com.azure.core.annotation.Immutable; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallModelBase.java similarity index 87% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallModelBase.java index 9220de2fa835..f8bbf6f7ebf1 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallModelBase.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallModelBase.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; /** The FunctionCallModelBase model. */ public abstract class FunctionCallModelBase { diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPreset.java similarity index 97% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPreset.java index 4e9109856fcb..46bc254473ae 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPreset.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPreset.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; import com.azure.core.annotation.Generated; import com.azure.core.util.ExpandableStringEnum; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPresetFunctionCallModel.java similarity index 94% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPresetFunctionCallModel.java index 2ebdf921744b..2a4bad739d8d 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionCallPresetFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCallPresetFunctionCallModel.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; import com.azure.core.annotation.Immutable; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionDefinition.java similarity index 98% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionDefinition.java index 2532558e049c..3d4ffcc5d08b 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionDefinition.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionDefinition.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionNameFunctionCallModel.java similarity index 94% rename from sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java rename to sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionNameFunctionCallModel.java index c5d9fedd3681..14f61cf22412 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/FunctionNameFunctionCallModel.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionNameFunctionCallModel.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation; +package com.azure.ai.openai.implementation.models; import com.azure.ai.openai.models.FunctionName; import com.azure.core.annotation.Immutable; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/package-info.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/package-info.java new file mode 100644 index 000000000000..26eb2ce2a673 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/package-info.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** Package containing the data models for OpenAI. Azure OpenAI APIs for completions and search. */ +package com.azure.ai.openai.implementation.models; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index a82714ea803b..ceb5fc8022be 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -3,11 +3,11 @@ // Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.ai.openai.models; -import com.azure.ai.openai.implementation.FunctionCallModelBase; -import com.azure.ai.openai.implementation.FunctionCallPreset; -import com.azure.ai.openai.implementation.FunctionCallPresetFunctionCallModel; -import com.azure.ai.openai.implementation.FunctionDefinition; -import com.azure.ai.openai.implementation.FunctionNameFunctionCallModel; +import com.azure.ai.openai.implementation.models.FunctionCallModelBase; +import com.azure.ai.openai.implementation.models.FunctionCallPreset; +import com.azure.ai.openai.implementation.models.FunctionCallPresetFunctionCallModel; +import com.azure.ai.openai.implementation.models.FunctionDefinition; +import com.azure.ai.openai.implementation.models.FunctionNameFunctionCallModel; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java index b533d014bf6d..dd30e21cd505 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java @@ -3,7 +3,7 @@ // Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.ai.openai.models; -import com.azure.ai.openai.implementation.FunctionCall; +import com.azure.ai.openai.implementation.models.FunctionCall; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/sdk/openai/azure-ai-openai/src/main/java/module-info.java b/sdk/openai/azure-ai-openai/src/main/java/module-info.java index 7b75baa4beec..07571db1c578 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/module-info.java +++ b/sdk/openai/azure-ai-openai/src/main/java/module-info.java @@ -8,11 +8,14 @@ exports com.azure.ai.openai; exports com.azure.ai.openai.models; - exports com.azure.ai.openai.implementation; + exports com.azure.ai.openai.implementation.models; opens com.azure.ai.openai.models to com.azure.core, com.fasterxml.jackson.databind; + opens com.azure.ai.openai.implementation.models to + com.azure.core, + com.fasterxml.jackson.databind; opens com.azure.ai.openai.implementation to com.azure.core, com.fasterxml.jackson.databind; diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 8b55858cdea5..22f37ec5d230 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -5,7 +5,7 @@ package com.azure.ai.openai; import com.azure.ai.openai.functions.Parameters; -import com.azure.ai.openai.implementation.FunctionCall; +import com.azure.ai.openai.implementation.models.FunctionCall; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; @@ -16,7 +16,7 @@ import com.azure.ai.openai.models.EmbeddingItem; import com.azure.ai.openai.models.Embeddings; import com.azure.ai.openai.models.EmbeddingsOptions; -import com.azure.ai.openai.implementation.FunctionDefinition; +import com.azure.ai.openai.implementation.models.FunctionDefinition; import com.azure.ai.openai.models.ImageGenerationOptions; import com.azure.ai.openai.models.ImageResponse; import com.azure.ai.openai.models.NonAzureOpenAIKeyCredential; From 2619f35aae9ad8614a7b7a4aa5b2f8ee4dae01f8 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Wed, 12 Jul 2023 10:21:01 -0700 Subject: [PATCH 19/25] Updated test records --- sdk/openai/azure-ai-openai/assets.json | 2 +- .../src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/openai/azure-ai-openai/assets.json b/sdk/openai/azure-ai-openai/assets.json index 62ae6f2ad86b..ea1e75e6a58d 100644 --- a/sdk/openai/azure-ai-openai/assets.json +++ b/sdk/openai/azure-ai-openai/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/openai/azure-ai-openai", - "Tag": "java/openai/azure-ai-openai_94811d7537" + "Tag": "java/openai/azure-ai-openai_9fc7970110" } diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 22f37ec5d230..b6a5d3d1f79c 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -147,7 +147,7 @@ void getChatFunctionForNonAzureRunner(BiConsumer } void getChatFunctionForRunner(BiConsumer testRunner) { - testRunner.accept("gpt-35-turbo-0613", getChatMessagesWithFunction()); + testRunner.accept("gpt-4", getChatMessagesWithFunction()); } private List getChatMessages() { From 19a9c2c8b76ca812c7c74ecadbbd603ddf57a092 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Wed, 12 Jul 2023 16:16:28 -0700 Subject: [PATCH 20/25] Addressed most of the style checks --- .../openai/models/ChatCompletionsOptions.java | 35 +++++++++++++++---- .../azure/ai/openai/models/FunctionCall.java | 29 ++++----------- .../functions/MyFunctionCallArguments.java | 3 ++ 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index ceb5fc8022be..32bc6f5d843d 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -453,7 +453,11 @@ public ChatCompletionsOptions setModel(String model) { @JsonProperty(value = "function_call") private FunctionCallModelBase functionCall; - @JsonIgnore private FunctionCall functionCalls; + /* + * Field not used for serialization. This is a convenience field to enable the functionality while honouring the + * polymorphic nature of the field + */ + @JsonIgnore private FunctionCall functionCallInternal; /** * Get the functions property: A list of functions the model may generate JSON inputs for. @@ -503,19 +507,36 @@ ChatCompletionsOptions setFunctionCallInternal(FunctionCallModelBase functionCal return this; } + /** + * Get the functionCall property: Controls how the model responds to function calls. "none" means the model does not + * call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a + * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + * + * @return the functionCall value. + */ public FunctionCall getFunctionCall() { - return this.functionCalls; + return this.functionCallInternal; } - public ChatCompletionsOptions setFunctionCall(FunctionCall functionCalls) { - this.functionCalls = functionCalls; + /** + * Set the functionCall property: Controls how the model responds to function calls. "none" means the model does not + * call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a + * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + * + * @param functionCallInternal the functionCall value to set. + * @return the ChatCompletionsOptions object itself. + */ + public ChatCompletionsOptions setFunctionCall(FunctionCall functionCallInternal) { + this.functionCallInternal = functionCallInternal; if (FunctionCallPreset.values().stream() - .anyMatch(preset -> preset.toString().equals(functionCalls.getName()))) { + .anyMatch(preset -> preset.toString().equals(functionCallInternal.getName()))) { this.functionCall = new FunctionCallPresetFunctionCallModel( - FunctionCallPreset.fromString(this.functionCalls.getName())); + FunctionCallPreset.fromString(this.functionCallInternal.getName())); } else { - this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCalls.getName())); + this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCallInternal.getName())); } return this; } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java index dd854caf69b4..5ccaf53bad8e 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -7,29 +7,23 @@ import com.azure.core.annotation.Immutable; /** The name and arguments of a function that should be called, as generated by the model. */ -@Immutable public class FunctionCall { - /* + /** * The name of the function to call. */ - private String name; + private final String name; - /* + /** * AUTO will indicate the service to call any functions that are necessary for text completion generation. */ - public static FunctionCall AUTO = new FunctionCall("auto", false); + public static final FunctionCall AUTO = new FunctionCall("auto"); - /* + /** * NONE will indicate the service to not call nay of the functions that may have been provided with the request for * text completion generation. */ - public static FunctionCall NONE = new FunctionCall("none", false); - - /* - * Indicates if the "name" of the function was explicitly passed, instead of using one of the built-in values - */ - private boolean isCustomFunctionName; + public static final FunctionCall NONE = new FunctionCall("none"); /** * Creates an instance of FunctionCall class. @@ -37,18 +31,7 @@ public class FunctionCall { * @param name the name value to set. */ public FunctionCall(String name) { - this(name, true); - } - - /** - * Creates an instance of FunctionCall class. - * - * @param name the name value to set. - * @param isCustomFunctionName is the name of the function to be called explicitly passed. - */ - FunctionCall(String name, boolean isCustomFunctionName) { this.name = name; - this.isCustomFunctionName = isCustomFunctionName; } /** diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java index 90e19cdef153..4cd3b0d19d12 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/functions/MyFunctionCallArguments.java @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package com.azure.ai.openai.functions; import com.fasterxml.jackson.annotation.JsonGetter; From 533471514452acefa20839f34b9ef02c5de596e9 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Wed, 12 Jul 2023 16:32:38 -0700 Subject: [PATCH 21/25] removed unused import --- .../src/main/java/com/azure/ai/openai/models/FunctionCall.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java index 5ccaf53bad8e..ed1e79951373 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -4,8 +4,6 @@ package com.azure.ai.openai.models; -import com.azure.core.annotation.Immutable; - /** The name and arguments of a function that should be called, as generated by the model. */ public class FunctionCall { From 1411a63d0c1150954d42b9c9ecd50678e34cf114 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Thu, 13 Jul 2023 09:35:41 -0700 Subject: [PATCH 22/25] Renamed type --- .../implementation/models/FunctionCall.java | 67 ------------------- .../openai/models/ChatCompletionsOptions.java | 21 +++--- .../azure/ai/openai/models/ChatMessage.java | 1 - .../azure/ai/openai/models/FunctionCall.java | 52 ++++++++++---- .../ai/openai/models/FunctionCallConfig.java | 43 ++++++++++++ .../openai/NonAzureOpenAIAsyncClientTest.java | 8 +-- .../openai/NonAzureOpenAISyncClientTest.java | 8 +-- .../ai/openai/OpenAIAsyncClientTest.java | 8 +-- .../azure/ai/openai/OpenAIClientTestBase.java | 2 +- .../azure/ai/openai/OpenAISyncClientTest.java | 8 +-- 10 files changed, 108 insertions(+), 110 deletions(-) delete mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java create mode 100644 sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallConfig.java diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java deleted file mode 100644 index f58e21632f12..000000000000 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/implementation/models/FunctionCall.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// Code generated by Microsoft (R) AutoRest Code Generator. -package com.azure.ai.openai.implementation.models; - -import com.azure.core.annotation.Generated; -import com.azure.core.annotation.Immutable; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** The name and arguments of a function that should be called, as generated by the model. */ -@Immutable -public final class FunctionCall { - - /* - * The name of the function to call. - */ - @Generated - @JsonProperty(value = "name") - private String name; - - /* - * The arguments to call the function with, as generated by the model in JSON format. - * Note that the model does not always generate valid JSON, and may hallucinate parameters - * not defined by your function schema. Validate the arguments in your code before calling - * your function. - */ - @Generated - @JsonProperty(value = "arguments") - private String arguments; - - /** - * Creates an instance of FunctionCall class. - * - * @param name the name value to set. - * @param arguments the arguments value to set. - */ - @Generated - @JsonCreator - public FunctionCall( - @JsonProperty(value = "name") String name, @JsonProperty(value = "arguments") String arguments) { - this.name = name; - this.arguments = arguments; - } - - /** - * Get the name property: The name of the function to call. - * - * @return the name value. - */ - @Generated - public String getName() { - return this.name; - } - - /** - * Get the arguments property: The arguments to call the function with, as generated by the model in JSON format. - * Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your - * function schema. Validate the arguments in your code before calling your function. - * - * @return the arguments value. - */ - @Generated - public String getArguments() { - return this.arguments; - } -} diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index 32bc6f5d843d..3f7cbfcbaf7a 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -454,10 +454,9 @@ public ChatCompletionsOptions setModel(String model) { private FunctionCallModelBase functionCall; /* - * Field not used for serialization. This is a convenience field to enable the functionality while honouring the - * polymorphic nature of the field + * Field not used for serialization. This is a convenience helper field for the serialization of "function_call". */ - @JsonIgnore private FunctionCall functionCallInternal; + @JsonIgnore private FunctionCallConfig functionCallConfig; /** * Get the functions property: A list of functions the model may generate JSON inputs for. @@ -515,8 +514,8 @@ ChatCompletionsOptions setFunctionCallInternal(FunctionCallModelBase functionCal * * @return the functionCall value. */ - public FunctionCall getFunctionCall() { - return this.functionCallInternal; + public FunctionCallConfig getFunctionCall() { + return this.functionCallConfig; } /** @@ -525,18 +524,18 @@ public FunctionCall getFunctionCall() { * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. * "none" is the default when no functions are present. "auto" is the default if functions are present. * - * @param functionCallInternal the functionCall value to set. + * @param functionCallConfigInternal the functionCall value to set. * @return the ChatCompletionsOptions object itself. */ - public ChatCompletionsOptions setFunctionCall(FunctionCall functionCallInternal) { - this.functionCallInternal = functionCallInternal; + public ChatCompletionsOptions setFunctionCall(FunctionCallConfig functionCallConfigInternal) { + this.functionCallConfig = functionCallConfigInternal; if (FunctionCallPreset.values().stream() - .anyMatch(preset -> preset.toString().equals(functionCallInternal.getName()))) { + .anyMatch(preset -> preset.toString().equals(functionCallConfigInternal.getName()))) { this.functionCall = new FunctionCallPresetFunctionCallModel( - FunctionCallPreset.fromString(this.functionCallInternal.getName())); + FunctionCallPreset.fromString(this.functionCallConfig.getName())); } else { - this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCallInternal.getName())); + this.functionCall = new FunctionNameFunctionCallModel(new FunctionName(this.functionCallConfig.getName())); } return this; } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java index dd30e21cd505..2594743f63f7 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatMessage.java @@ -3,7 +3,6 @@ // Code generated by Microsoft (R) AutoRest Code Generator. package com.azure.ai.openai.models; -import com.azure.ai.openai.implementation.models.FunctionCall; import com.azure.core.annotation.Fluent; import com.azure.core.annotation.Generated; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java index ed1e79951373..f03fa51fdb66 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCall.java @@ -1,35 +1,46 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Code generated by Microsoft (R) AutoRest Code Generator. - package com.azure.ai.openai.models; +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + /** The name and arguments of a function that should be called, as generated by the model. */ -public class FunctionCall { +@Immutable +public final class FunctionCall { - /** + /* * The name of the function to call. */ - private final String name; - - /** - * AUTO will indicate the service to call any functions that are necessary for text completion generation. - */ - public static final FunctionCall AUTO = new FunctionCall("auto"); + @Generated + @JsonProperty(value = "name") + private String name; - /** - * NONE will indicate the service to not call nay of the functions that may have been provided with the request for - * text completion generation. + /* + * The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters + * not defined by your function schema. Validate the arguments in your code before calling + * your function. */ - public static final FunctionCall NONE = new FunctionCall("none"); + @Generated + @JsonProperty(value = "arguments") + private String arguments; /** * Creates an instance of FunctionCall class. * * @param name the name value to set. + * @param arguments the arguments value to set. */ - public FunctionCall(String name) { + @Generated + @JsonCreator + public FunctionCall( + @JsonProperty(value = "name") String name, @JsonProperty(value = "arguments") String arguments) { this.name = name; + this.arguments = arguments; } /** @@ -37,7 +48,20 @@ public FunctionCall(String name) { * * @return the name value. */ + @Generated public String getName() { return this.name; } + + /** + * Get the arguments property: The arguments to call the function with, as generated by the model in JSON format. + * Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your + * function schema. Validate the arguments in your code before calling your function. + * + * @return the arguments value. + */ + @Generated + public String getArguments() { + return this.arguments; + } } diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallConfig.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallConfig.java new file mode 100644 index 000000000000..ac1c713931b8 --- /dev/null +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/FunctionCallConfig.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.ai.openai.models; + +/** The name and arguments of a function that should be called, as generated by the model. */ +public class FunctionCallConfig { + + /** + * The name of the function to call. + */ + private final String name; + + /** + * AUTO will indicate the service to call any functions that are necessary for text completion generation. + */ + public static final FunctionCallConfig AUTO = new FunctionCallConfig("auto"); + + /** + * NONE will indicate the service to not call nay of the functions that may have been provided with the request for + * text completion generation. + */ + public static final FunctionCallConfig NONE = new FunctionCallConfig("none"); + + /** + * Creates an instance of FunctionCall class. + * + * @param name the name value to set. + */ + public FunctionCallConfig(String name) { + this.name = name; + } + + /** + * Get the name property: The name of the function to call. + * + * @return the name value. + */ + public String getName() { + return this.name; + } +} diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java index a30ac3381115..9b0987d45af1 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAIAsyncClientTest.java @@ -12,7 +12,7 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCall; +import com.azure.ai.openai.models.FunctionCallConfig; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -251,7 +251,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { assertEquals(1, chatCompletions.getChoices().size()); @@ -272,7 +272,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); @@ -286,7 +286,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAIAsyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCallConfig("NotMyFunction")); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .verifyErrorSatisfies(throwable -> { assertInstanceOf(HttpResponseException.class, throwable); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java index 73acba41c6c1..da35b3dcd071 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/NonAzureOpenAISyncClientTest.java @@ -12,7 +12,7 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCall; +import com.azure.ai.openai.models.FunctionCallConfig; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -205,7 +205,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.AUTO); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); assertEquals(1, chatCompletions.getChoices().size()); @@ -224,7 +224,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.NONE); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); @@ -236,7 +236,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getNonAzureOpenAISyncClient(httpClient); getChatFunctionForNonAzureRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCallConfig("NotMyFunction")); HttpResponseException exception = assertThrows(HttpResponseException.class, () -> client.getChatCompletions(modelId, chatCompletionsOptions)); assertEquals(400, exception.getResponse().getStatusCode()); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java index 06e8ffe488ec..f417ca1a8d33 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIAsyncClientTest.java @@ -12,7 +12,7 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCall; +import com.azure.ai.openai.models.FunctionCallConfig; import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; @@ -236,7 +236,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.AUTO); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { assertEquals(1, chatCompletions.getChoices().size()); @@ -257,7 +257,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.NONE); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .assertNext(chatCompletions -> { assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); @@ -271,7 +271,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIAsyncClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCallConfig("NotMyFunction")); StepVerifier.create(client.getChatCompletions(modelId, chatCompletionsOptions)) .verifyErrorSatisfies(throwable -> { assertInstanceOf(HttpResponseException.class, throwable); diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java index 433b13013327..489c418e3953 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAIClientTestBase.java @@ -5,7 +5,7 @@ package com.azure.ai.openai; import com.azure.ai.openai.functions.Parameters; -import com.azure.ai.openai.implementation.models.FunctionCall; +import com.azure.ai.openai.models.FunctionCall; import com.azure.ai.openai.models.ChatChoice; import com.azure.ai.openai.models.ChatCompletions; import com.azure.ai.openai.models.ChatCompletionsOptions; diff --git a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java index bfe0f4b9bfa9..98f300126b4a 100644 --- a/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java +++ b/sdk/openai/azure-ai-openai/src/test/java/com/azure/ai/openai/OpenAISyncClientTest.java @@ -12,7 +12,7 @@ import com.azure.ai.openai.models.CompletionsOptions; import com.azure.ai.openai.models.CompletionsUsage; import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.FunctionCall; +import com.azure.ai.openai.models.FunctionCallConfig; import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceNotFoundException; import com.azure.core.http.HttpClient; @@ -194,7 +194,7 @@ public void testGenerateImage(HttpClient httpClient, OpenAIServiceVersion servic public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.AUTO); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.AUTO); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); assertEquals(1, chatCompletions.getChoices().size()); @@ -213,7 +213,7 @@ public void testChatFunctionAutoPreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(FunctionCall.NONE); + chatCompletionsOptions.setFunctionCall(FunctionCallConfig.NONE); ChatCompletions chatCompletions = client.getChatCompletions(modelId, chatCompletionsOptions); assertChatCompletions(1, "stop", ChatRole.ASSISTANT, chatCompletions); @@ -225,7 +225,7 @@ public void testChatFunctionNonePreset(HttpClient httpClient, OpenAIServiceVersi public void testChatFunctionNotSuppliedByNamePreset(HttpClient httpClient, OpenAIServiceVersion serviceVersion) { client = getOpenAIClient(httpClient, serviceVersion); getChatFunctionForRunner((modelId, chatCompletionsOptions) -> { - chatCompletionsOptions.setFunctionCall(new FunctionCall("NotMyFunction")); + chatCompletionsOptions.setFunctionCall(new FunctionCallConfig("NotMyFunction")); HttpResponseException exception = assertThrows(HttpResponseException.class, () -> client.getChatCompletions(modelId, chatCompletionsOptions)); assertEquals(400, exception.getResponse().getStatusCode()); From d827c17b6a2f17161df21ae6badcb91d388e3e3b Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Thu, 13 Jul 2023 09:37:30 -0700 Subject: [PATCH 23/25] Added spell checker exception for DALL-E --- .vscode/cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 5b4cffc80b63..9b7b7a3586a7 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -243,6 +243,7 @@ "creds", "credscan", "curr", + "DALL-E", "databind", "databricks", "DAZURE", From 4eca3e9d76d63978d74785e1c726c28e1c47fbd7 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Thu, 13 Jul 2023 09:42:41 -0700 Subject: [PATCH 24/25] Updated commit hash and re-ran code gen --- sdk/openai/azure-ai-openai/tsp-location.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/openai/azure-ai-openai/tsp-location.yaml b/sdk/openai/azure-ai-openai/tsp-location.yaml index 43e4f9fe2f2d..ffcad5837832 100644 --- a/sdk/openai/azure-ai-openai/tsp-location.yaml +++ b/sdk/openai/azure-ai-openai/tsp-location.yaml @@ -1,5 +1,5 @@ directory: specification/cognitiveservices/OpenAI.Inference additionalDirectories: - specification/cognitiveservices/OpenAI.Authoring -commit: ef477cb666504640106a6e8c9263b45fc0fa3e08 +commit: e994b93c82c5d23eb377f35434354438e748cb87 repo: Azure/azure-rest-api-specs From 3dff5f4c9844d8ba6e26cb73f5549590453167b8 Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Thu, 13 Jul 2023 10:07:53 -0700 Subject: [PATCH 25/25] Renamed param --- .../azure/ai/openai/models/ChatCompletionsOptions.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java index 3f7cbfcbaf7a..02f714199d42 100644 --- a/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java +++ b/sdk/openai/azure-ai-openai/src/main/java/com/azure/ai/openai/models/ChatCompletionsOptions.java @@ -524,13 +524,13 @@ public FunctionCallConfig getFunctionCall() { * function. Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. * "none" is the default when no functions are present. "auto" is the default if functions are present. * - * @param functionCallConfigInternal the functionCall value to set. + * @param functionCallConfig the functionCall value to set. * @return the ChatCompletionsOptions object itself. */ - public ChatCompletionsOptions setFunctionCall(FunctionCallConfig functionCallConfigInternal) { - this.functionCallConfig = functionCallConfigInternal; + public ChatCompletionsOptions setFunctionCall(FunctionCallConfig functionCallConfig) { + this.functionCallConfig = functionCallConfig; if (FunctionCallPreset.values().stream() - .anyMatch(preset -> preset.toString().equals(functionCallConfigInternal.getName()))) { + .anyMatch(preset -> preset.toString().equals(functionCallConfig.getName()))) { this.functionCall = new FunctionCallPresetFunctionCallModel( FunctionCallPreset.fromString(this.functionCallConfig.getName()));