Skip to content

Commit 5d688c5

Browse files
authored
OpenAI client (Azure#20617)
Checking in @mikekistler's great work on the azopenai client. It covers completions, chat completions and embeddings, which places it at par with the features offered in our other beta Azure Open AI libraries. This client _also_ works against the public Open AI endpoint!
1 parent 32af329 commit 5d688c5

25 files changed

+2805
-0
lines changed

eng/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
"Name": "azfile",
3737
"CoverageGoal": 0.75
3838
},
39+
{
40+
"Name": "azopenai",
41+
"CoverageGoal": 0.45
42+
},
3943
{
4044
"Name": "aztemplate",
4145
"CoverageGoal": 0.50
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Release History
2+
3+
## 0.1.0 (unreleased)
4+
5+
* Initial release of the `azopenai` library
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation. All rights reserved.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Azure OpenAI client module for Go
2+
3+
Azure OpenAI is a managed service that allows developers to deploy, tune, and generate content from OpenAI models on Azure resources.
4+
5+
The Azure OpenAI client library for GO is an adaptation of OpenAI's REST APIs that provides an idiomatic interface and rich integration with the rest of the Azure SDK ecosystem.
6+
7+
[Source code][azopenai_repo] | [Package (pkg.go.dev)][azopenai_pkg_go] | [REST API documentation][openai_rest_docs] | [Product documentation][openai_docs]
8+
9+
## Getting started
10+
11+
### Prerequisites
12+
13+
* Go, version 1.18 or higher - [Install Go](https://go.dev/doc/install)
14+
* [Azure subscription][azure_sub]
15+
* [Azure OpenAI access][azure_openai_access]
16+
17+
### Install the packages
18+
19+
Install the `azopenai` and `azidentity` modules with `go get`:
20+
21+
```bash
22+
go get github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai
23+
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
24+
```
25+
26+
The [azidentity][azure_identity] module is used for authentication during client construction.
27+
28+
### Authentication
29+
30+
<!-- TODO: Add api-key authentication instructions -->
31+
32+
#### Create a client
33+
34+
Constructing the client requires your vault's URL, which you can get from the Azure CLI or the Azure Portal.
35+
36+
```go
37+
import (
38+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
39+
"github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai"
40+
)
41+
42+
func main() {
43+
endpoint := "https://<TODO: OpenAI endpoint>"
44+
apiKey := "<TODO: OpenAI API key>"
45+
46+
var err error
47+
cred := azopenai.KeyCredential{APIKey: apiKey}
48+
client, err := azopenai.NewClientWithKeyCredential(endpoint, cred, &options)
49+
if err != nil {
50+
// TODO: handle error
51+
}
52+
}
53+
```
54+
55+
## Key concepts
56+
57+
See [Key concepts][openai_key_concepts] in the product documentation for more details about general concepts.
58+
59+
## Troubleshooting
60+
61+
### Error Handling
62+
63+
All methods that send HTTP requests return `*azcore.ResponseError` when these requests fail. `ResponseError` has error details and the raw response from the service.
64+
65+
### Logging
66+
67+
This module uses the logging implementation in `azcore`. To turn on logging for all Azure SDK modules, set `AZURE_SDK_GO_LOGGING` to `all`. By default, the logger writes to stderr. Use the `azcore/log` package to control log output. For example, logging only HTTP request and response events, and printing them to stdout:
68+
69+
```go
70+
import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
71+
72+
// Print log events to stdout
73+
azlog.SetListener(func(cls azlog.Event, msg string) {
74+
fmt.Println(msg)
75+
})
76+
77+
// Includes only requests and responses in credential logs
78+
azlog.SetEvents(azlog.EventRequest, azlog.EventResponse)
79+
```
80+
81+
## Contributing
82+
83+
This project welcomes contributions and suggestions. Most contributions require you to agree to a [Contributor License Agreement (CLA)][cla] declaring that you have the right to, and actually do, grant us the rights to use your contribution.
84+
85+
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate
86+
the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to
87+
do this once across all repos using our CLA.
88+
89+
This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information, see
90+
the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or
91+
comments.
92+
93+
<!-- LINKS -->
94+
<!-- https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/cognitiveservices/azopenai ->
95+
<!-- https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai -->
96+
[azure_openai_access]: https://learn.microsoft.com/azure/cognitive-services/openai/overview#how-do-i-get-access-to-azure-openai
97+
[azopenai_repo]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk
98+
[azopenai_pkg_go]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk
99+
[azure_identity]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity
100+
[azure_sub]: https://azure.microsoft.com/free/
101+
[openai_docs]: https://learn.microsoft.com/azure/cognitive-services/openai
102+
[openai_key_concepts]: https://learn.microsoft.com/azure/cognitive-services/openai/overview#key-concepts
103+
[openai_rest_docs]: https://learn.microsoft.com/azure/cognitive-services/openai/reference
104+
[cla]: https://cla.microsoft.com
105+
[coc]: https://opensource.microsoft.com/codeofconduct/
106+
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
107+
[coc_contact]: mailto:opencode@microsoft.com
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"AssetsRepo": "Azure/azure-sdk-assets",
3+
"AssetsRepoPrefixPath": "go",
4+
"TagPrefix": "go/cognitiveservices/azopenai",
5+
"Tag": "go/cognitiveservices/azopenai_0bc6dc4171"
6+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Go
2+
3+
These settings apply only when `--go` is specified on the command line.
4+
5+
``` yaml
6+
input-file:
7+
- https://github.com/mikekistler/azure-rest-api-specs/blob/baed660fd853b4a387ca9f0b9491fd1414b66e9e/specification/cognitiveservices/data-plane/AzureOpenAI/inference/preview/2023-03-15-preview/inference.json
8+
output-folder: ../azopenai
9+
clear-output-folder: false
10+
module: github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai
11+
license-header: MICROSOFT_MIT_NO_VERSION
12+
openapi-type: data-plane
13+
go: true
14+
use: "@autorest/go@4.0.0-preview.50"
15+
```
16+
17+
## Transformations
18+
19+
``` yaml
20+
directive:
21+
# Add x-ms-parameter-location to parameters in x-ms-parameterized-host
22+
- from: openapi-document
23+
where: $.servers.0.variables.endpoint
24+
debug: true
25+
transform: $["x-ms-parameter-location"] = "client";
26+
27+
# Make deploymentId a client parameter
28+
# This must be done in each operation as the parameter is not defined in the components section
29+
- from: openapi-document
30+
where: $.paths..parameters..[?(@.name=='deploymentId')]
31+
transform: $["x-ms-parameter-location"] = "client";
32+
33+
# Update operationIds to combine all operations into a single client
34+
- rename-operation:
35+
from: getCompletions
36+
to: OpenAI_GetCompletions
37+
- rename-operation:
38+
from: getEmbeddings
39+
to: OpenAI_GetEmbeddings
40+
- rename-operation:
41+
from: getChatCompletions
42+
to: OpenAI_GetChatCompletions
43+
44+
# Mark request bodies as required (TypeSpec issue #1838)
45+
- from: openapi-document
46+
where: $.paths["/deployments/{deploymentId}/completions"].post.requestBody
47+
transform: $["required"] = true;
48+
- from: openapi-document
49+
where: $.paths["/deployments/{deploymentId}/embeddings"].post.requestBody
50+
transform: $["required"] = true;
51+
52+
# Remove stream property from CompletionsOptions and ChatCompletionsOptions
53+
- from: openapi-document
54+
where: $.components.schemas["CompletionsOptions"]
55+
transform: delete $.properties.stream;
56+
- from: openapi-document
57+
where: $.components.schemas["ChatCompletionsOptions"]
58+
transform: delete $.properties.stream;
59+
60+
# Replace anyOf schemas with an empty schema (no type) to get an "any" type generated
61+
- from: openapi-document
62+
where: '$.components.schemas["EmbeddingsOptions"].properties["input"]'
63+
transform: delete $.anyOf;
64+
65+
# Fix autorest bug
66+
- from: openapi-document
67+
where: $.components.schemas["ChatMessage"].properties.role
68+
transform: >
69+
delete $.allOf;
70+
$["$ref"] = "#/components/schemas/ChatRole";
71+
72+
# Fix another autorest bug
73+
- from: openapi-document
74+
where: $.components.schemas["Choice"].properties.finish_reason
75+
transform: >
76+
delete $.oneOf;
77+
$["$ref"] = "#/components/schemas/CompletionsFinishReason";
78+
- from: openapi-document
79+
where: $.components.schemas["ChatChoice"].properties.finish_reason
80+
transform: >
81+
delete $.oneOf;
82+
$["$ref"] = "#/components/schemas/CompletionsFinishReason";
83+
84+
# Fix "AutoGenerated" models
85+
- from: openapi-document
86+
where: $.components.schemas["ChatCompletions"].properties.usage
87+
transform: >
88+
delete $.allOf;
89+
$["$ref"] = "#/components/schemas/CompletionsUsage";
90+
- from: openapi-document
91+
where: $.components.schemas["Completions"].properties.usage
92+
transform: >
93+
delete $.allOf;
94+
$["$ref"] = "#/components/schemas/CompletionsUsage";
95+
96+
#
97+
# strip out the deploymentID validation code - we absorbed this into the endpoint.
98+
#
99+
# urlPath := "/deployments/{deploymentId}/embeddings"
100+
# if client.deploymentID == "" {
101+
# return nil, errors.New("parameter client.deploymentID cannot be empty")
102+
# }
103+
# urlPath = strings.ReplaceAll(urlPath, "{deploymentId}", url.PathEscape(client.deploymentID))
104+
- from: client.go
105+
where: $
106+
transform: >-
107+
return $.replace(
108+
/(\s+)urlPath\s*:=\s*"\/deployments\/\{deploymentId\}\/([^"]+)".+?url\.PathEscape.+?\n/gs,
109+
"$1urlPath := \"$2\"\n")
110+
111+
# splice out the auto-generated `deploymentID` field from the client
112+
- from: client.go
113+
where: $
114+
transform: >-
115+
return $.replace(
116+
/(type Client struct.+?)deploymentID string([^}]+})/s,
117+
"$1$2")
118+
119+
# delete unused error models
120+
- from: models.go
121+
where: $
122+
transform: >-
123+
return $.replace(
124+
/\/\/ AzureCoreFoundations.*?type AzureCoreFoundations(Error|ErrorResponse|ErrorResponseError|InnerError|InnerErrorInnererror|ErrorInnererror) struct \{[^}]+\}/gs,
125+
"")
126+
- from: models_serde.go
127+
where: $
128+
transform: >-
129+
return $.replace(
130+
/\/\/ (UnmarshalJSON|MarshalJSON) implements.*?AzureCoreFoundations.*?func.+?\n}/gs,
131+
"")
132+
- from: models_serde.go
133+
where: $
134+
transform: return $.replace(/(?:\/\/.*\s)?func \(\w \*?(?:ErrorResponse|ErrorResponseError|InnerError|InnerErrorInnererror)\).*\{\s(?:.+\s)+\}\s/g, "");
135+
136+
- from: constants.go
137+
where: $
138+
transform: >-
139+
return $.replace(
140+
/type ServiceAPIVersions string.+PossibleServiceAPIVersionsValues.+?\n}/gs,
141+
"")
142+
143+
# delete client name prefix from method options and response types
144+
- from:
145+
- client.go
146+
- models.go
147+
- response_types.go
148+
where: $
149+
transform: return $.replace(/Client(\w+)((?:Options|Response))/g, "$1$2");
150+
```
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
//go:generate autorest ./autorest.md
5+
//go:generate go mod tidy
6+
//go:generate goimports -w .
7+
8+
// Copyright (c) Microsoft Corporation. All rights reserved.
9+
// Licensed under the MIT License. See License.txt in the project root for license information.
10+
11+
package azopenai
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file.
2+
trigger:
3+
branches:
4+
include:
5+
- main
6+
- feature/*
7+
- hotfix/*
8+
- release/*
9+
paths:
10+
include:
11+
- sdk/cognitiveservices/azopenai
12+
- eng/
13+
14+
pr:
15+
branches:
16+
include:
17+
- main
18+
- feature/*
19+
- hotfix/*
20+
- release/*
21+
paths:
22+
include:
23+
- sdk/cognitiveservices/azopenai
24+
25+
stages:
26+
- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml
27+
parameters:
28+
ServiceDirectory: "cognitiveservices/azopenai"

0 commit comments

Comments
 (0)