Skip to content

Commit

Permalink
[azopenai] Readme and examples (#21192)
Browse files Browse the repository at this point in the history
Creating examples and a readme for azopenai.

Fixes #21038
  • Loading branch information
richardpark-msft authored Jul 19, 2023
1 parent ceca085 commit ba64496
Show file tree
Hide file tree
Showing 12 changed files with 634 additions and 219 deletions.
41 changes: 17 additions & 24 deletions sdk/cognitiveservices/azopenai/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Azure OpenAI client module for Go

Azure OpenAI is a managed service that allows developers to deploy, tune, and generate content from OpenAI models on Azure resources.
NOTE: this client can be used with Azure OpenAI and OpenAI.

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.
Azure OpenAI Service provides access to OpenAI's powerful language models including the GPT-4, GPT-35-Turbo, and Embeddings model series, as well as image generation using DALL-E.

[Source code][azopenai_repo] | [Package (pkg.go.dev)][azopenai_pkg_go] | [REST API documentation][openai_rest_docs] | [Product documentation][openai_docs]

Expand All @@ -20,42 +20,34 @@ Install the `azopenai` and `azidentity` modules with `go get`:

```bash
go get github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai

# optional
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
```

The [azidentity][azure_identity] module is used for authentication during client construction.
The [azidentity][azure_identity] module is used for Azure Active Directory authentication with Azure OpenAI.

### Authentication

<!-- TODO: Add api-key authentication instructions -->
#### Azure OpenAI

#### Create a client
Azure OpenAI clients can authenticate using Azure Active Directory or with an API key:

Constructing the client requires your vault's URL, which you can get from the Azure CLI or the Azure Portal.
* Using Azure Active Directory, with a TokenCredential: [example](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai#example-NewClient)
* Using an API key: [example](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai#example-NewClientWithKeyCredential)

```go
import (
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai"
)

func main() {
endpoint := "https://<TODO: OpenAI endpoint>"
apiKey := "<TODO: OpenAI API key>"

var err error
cred := azopenai.KeyCredential{APIKey: apiKey}
client, err := azopenai.NewClientWithKeyCredential(endpoint, cred, &options)
if err != nil {
// TODO: handle error
}
}
```
#### OpenAI

OpenAI supports connecting using an API key: [example](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai#example-NewClientForOpenAI)

## Key concepts

See [Key concepts][openai_key_concepts] in the product documentation for more details about general concepts.

# Examples

Examples for various scenarios can be found on [pkg.go.dev](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai#pkg-examples) or in the example*_test.go files in our GitHub repo for [azopenai](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/cognitiveservices/azopenai).

## Troubleshooting

### Error Handling
Expand Down Expand Up @@ -103,3 +95,4 @@ comments.
[coc]: https://opensource.microsoft.com/codeofconduct/
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
[coc_contact]: mailto:opencode@microsoft.com
[azure_openai_quickstart]: https://learn.microsoft.com/azure/cognitive-services/openai/quickstart
2 changes: 1 addition & 1 deletion sdk/cognitiveservices/azopenai/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "go",
"TagPrefix": "go/cognitiveservices/azopenai",
"Tag": "go/cognitiveservices/azopenai_63852f374c"
"Tag": "go/cognitiveservices/azopenai_e8362ae205"
}
37 changes: 14 additions & 23 deletions sdk/cognitiveservices/azopenai/client_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,23 @@ type ParamProperty struct {
Enum []string `json:"enum,omitempty"`
}

func getClientForFunctionsTest(t *testing.T, azure bool) *azopenai.Client {
if azure {
cred, err := azopenai.NewKeyCredential(apiKey)
require.NoError(t, err)

chatClient, err := azopenai.NewClientWithKeyCredential(endpoint, cred, chatCompletionsModelDeployment, newClientOptionsForTest(t))
require.NoError(t, err)

return chatClient
} else {
cred, err := azopenai.NewKeyCredential(openAIKey)
require.NoError(t, err)

chatClient, err := azopenai.NewClientForOpenAI(openAIEndpoint, cred, newClientOptionsForTest(t))
require.NoError(t, err)

return chatClient
}
func TestGetChatCompletions_usingFunctions(t *testing.T) {
// https://platform.openai.com/docs/guides/gpt/function-calling

t.Run("OpenAI", func(t *testing.T) {
chatClient := newOpenAIClientForTest(t)
testChatCompletionsFunctions(t, chatClient)
})

t.Run("AzureOpenAI", func(t *testing.T) {
chatClient := newAzureOpenAIClientForTest(t, chatCompletionsModelDeployment, false)
testChatCompletionsFunctions(t, chatClient)
})
}

func TestFunctions(t *testing.T) {
// https://platform.openai.com/docs/guides/gpt/function-calling#:~:text=For%20example%2C%20you%20can%3A%201%20Create%20chatbots%20that,...%203%20Extract%20structured%20data%20from%20text%20
chatClient := getClientForFunctionsTest(t, false)

func testChatCompletionsFunctions(t *testing.T, chatClient *azopenai.Client) {
resp, err := chatClient.GetChatCompletions(context.Background(), azopenai.ChatCompletionsOptions{
Model: to.Ptr("gpt-3.5-turbo-0613"),
Model: to.Ptr("gpt-4-0613"),
Messages: []azopenai.ChatMessage{
{
Role: to.Ptr(azopenai.ChatRoleUser),
Expand Down
8 changes: 5 additions & 3 deletions sdk/cognitiveservices/azopenai/client_shared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func getVars(suffix string) (endpoint, apiKey, completionsModelDeployment, chatC

apiKey = os.Getenv("AOAI_API_KEY" + suffix)
completionsModelDeployment = os.Getenv("AOAI_COMPLETIONS_MODEL_DEPLOYMENT" + suffix)

// ex: gpt-4-0613
chatCompletionsModelDeployment = os.Getenv("AOAI_CHAT_COMPLETIONS_MODEL_DEPLOYMENT" + suffix)

return
Expand All @@ -56,7 +58,7 @@ func getVars(suffix string) (endpoint, apiKey, completionsModelDeployment, chatC
const fakeEndpoint = "https://recordedhost/"
const fakeAPIKey = "redacted"

func init() {
func initEnvVars() {
if recording.GetRecordMode() == recording.PlaybackMode {
endpoint = fakeEndpoint
apiKey = fakeAPIKey
Expand All @@ -71,7 +73,7 @@ func init() {
completionsModelDeployment = "text-davinci-003"
openAICompletionsModel = "text-davinci-003"

chatCompletionsModelDeployment = "gpt-4"
chatCompletionsModelDeployment = "gpt-4-0613"
openAIChatCompletionsModel = "gpt-4"
} else {
if err := godotenv.Load(); err != nil {
Expand All @@ -85,7 +87,7 @@ func init() {
openAIKey = os.Getenv("OPENAI_API_KEY")
openAIEndpoint = os.Getenv("OPENAI_ENDPOINT")
openAICompletionsModel = os.Getenv("OPENAI_COMPLETIONS_MODEL")
openAIChatCompletionsModel = os.Getenv("OPENAI_CHAT_COMPLETIONS_MODEL")
openAIChatCompletionsModel = os.Getenv("OPENAI_CHAT_COMPLETIONS_MODEL") // ex: gpt-4-0613

if openAIEndpoint != "" && !strings.HasSuffix(openAIEndpoint, "/") {
// (this just makes recording replacement easier)
Expand Down
5 changes: 4 additions & 1 deletion sdk/cognitiveservices/azopenai/custom_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

// Package azopenai Azure OpenAI Service provides access to OpenAI's powerful language models including the GPT-4,
// GPT-35-Turbo, and Embeddings model series, as well as image generation using DALL-E.
//
// The [Client] in this package can be used with Azure OpenAI or OpenAI.
package azopenai

// this file contains handwritten additions to the generated code
Expand All @@ -21,7 +25,6 @@ import (

const (
clientName = "azopenai.Client"
apiVersion = "2023-03-15-preview"
tokenScope = "https://cognitiveservices.azure.com/.default"
)

Expand Down
66 changes: 66 additions & 0 deletions sdk/cognitiveservices/azopenai/example_client_createimage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package azopenai_test

import (
"context"
"fmt"
"net/http"
"os"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai"
)

func ExampleClient_CreateImage() {
azureOpenAIKey := os.Getenv("AOAI_API_KEY")

// Ex: "https://<your-azure-openai-host>.openai.azure.com"
azureOpenAIEndpoint := os.Getenv("AOAI_ENDPOINT")

if azureOpenAIKey == "" || azureOpenAIEndpoint == "" {
fmt.Fprintf(os.Stderr, "Skipping example, environment variables missing\n")
return
}

keyCredential, err := azopenai.NewKeyCredential(azureOpenAIKey)

if err != nil {
// TODO: handle error
}

client, err := azopenai.NewClientWithKeyCredential(azureOpenAIEndpoint, keyCredential, "", nil)

if err != nil {
// TODO: handle error
}

resp, err := client.CreateImage(context.TODO(), azopenai.ImageGenerationOptions{
Prompt: to.Ptr("a cat"),
ResponseFormat: to.Ptr(azopenai.ImageGenerationResponseFormatURL),
}, nil)

if err != nil {
// TODO: handle error
}

for _, generatedImage := range resp.Data {
// the underlying type for the generatedImage is dictated by the value of
// ImageGenerationOptions.ResponseFormat. In this example we used `azopenai.ImageGenerationResponseFormatURL`,
// so the underlying type will be ImageLocation.

resp, err := http.Head(*generatedImage.URL)

if err != nil {
// TODO: handle error
}

fmt.Fprintf(os.Stderr, "Image generated, HEAD request on URL returned %d\n", resp.StatusCode)
}

// Output:
}
55 changes: 55 additions & 0 deletions sdk/cognitiveservices/azopenai/example_client_embeddings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package azopenai_test

import (
"context"
"fmt"
"os"

"github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai"
)

func ExampleClient_GetEmbeddings() {
azureOpenAIKey := os.Getenv("AOAI_API_KEY")
modelDeploymentID := os.Getenv("AOAI_EMBEDDINGS_MODEL_DEPLOYMENT")

// Ex: "https://<your-azure-openai-host>.openai.azure.com"
azureOpenAIEndpoint := os.Getenv("AOAI_ENDPOINT")

if azureOpenAIKey == "" || modelDeploymentID == "" || azureOpenAIEndpoint == "" {
fmt.Fprintf(os.Stderr, "Skipping example, environment variables missing\n")
return
}

keyCredential, err := azopenai.NewKeyCredential(azureOpenAIKey)

if err != nil {
// TODO: handle error
}

// In Azure OpenAI you must deploy a model before you can use it in your client. For more information
// see here: https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource
client, err := azopenai.NewClientWithKeyCredential(azureOpenAIEndpoint, keyCredential, modelDeploymentID, nil)

if err != nil {
// TODO: handle error
}

resp, err := client.GetEmbeddings(context.TODO(), azopenai.EmbeddingsOptions{
Input: []string{"The food was delicious and the waiter..."},
Model: &modelDeploymentID,
}, nil)

if err != nil {
// TODO: handle error
}

for _, embed := range resp.Data {
// embed.Embedding contains the embeddings for this input index.
fmt.Fprintf(os.Stderr, "Got embeddings for input %d\n", *embed.Index)
}

// Output:
}
Loading

0 comments on commit ba64496

Please sign in to comment.