|
| 1 | +# Guide for migrating to OpenAI 2.0.0-beta.1 or higher from OpenAI 1.11.0 |
| 2 | + |
| 3 | +This guide is intended to assist in the migration to the official OpenAI library (2.0.0-beta.1 or higher) from [OpenAI 1.11.0][openai_1110], focusing on side-by-side comparisons for similar operations between libraries. Version 2.0.0-beta.1 will be used for comparison with 1.11.0 but this guide can still be safely used when migrating to higher versions. |
| 4 | + |
| 5 | +Prior to 2.0.0-beta.1, the OpenAI package was a community library not officially supported by OpenAI. See the [CHANGELOG][changelog] for more details. |
| 6 | + |
| 7 | +Familiarity with the OpenAI 1.11.0 package is assumed. For those new to any OpenAI library for .NET, see the [README][readme] rather than this guide. |
| 8 | + |
| 9 | +## Table of contents |
| 10 | +- [Client usage](#client-usage) |
| 11 | +- [Authentication](#authentication) |
| 12 | +- [Highlighted scenarios](#highlighted-scenarios) |
| 13 | + - [Chat Completions: Text generation](#chat-completions-text-generation) |
| 14 | + - [Chat Completions: Streaming](#chat-completions-streaming) |
| 15 | + - [Chat Completions: JSON mode](#chat-completions-json-mode) |
| 16 | + - [Chat Completions: Vision](#chat-completions-vision) |
| 17 | + - [Audio: Speech-to-text](#audio-speech-to-text) |
| 18 | + - [Audio: Text-to-speech](#audio-text-to-speech) |
| 19 | + - [Image: Image generation](#image-image-generation) |
| 20 | +- [Additional examples](#additional-examples) |
| 21 | + |
| 22 | +## Client usage |
| 23 | + |
| 24 | +The client usage has considerably changed between libraries. While the OpenAI 1.11.0 had a single client, `OpenAIAPI`, from which multiple APIs could be accessed, OpenAI 2.0.0-beta.1 keeps a separate client per API. The following snippets illustrate this difference when invoking the image generation capability from the Image API: |
| 25 | + |
| 26 | +OpenAI 1.11.0: |
| 27 | +```cs |
| 28 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 29 | +ImageResult result = await api.ImageGenerations.CreateImageAsync("Draw a quick brown fox jumping over a lazy dog.", Model.DALLE3); |
| 30 | +``` |
| 31 | + |
| 32 | +OpenAI 2.0.0-beta.1: |
| 33 | +```cs |
| 34 | +ImageClient client = new ImageClient("dall-e-3", "<api-key>"); |
| 35 | +ClientResult<GeneratedImage> result = await client.GenerateImageAsync("Draw a quick brown fox jumping over a lazy dog."); |
| 36 | +``` |
| 37 | + |
| 38 | +Another major difference highlighted in the snippets above is that OpenAI 2.0.0-beta.1 requires the model to be explicitly set during client instantiation, while the `OpenAIAPI` client allows a model to be specified per call. |
| 39 | + |
| 40 | +The table below illustrates to which client each endpoint of `OpenAIAPI` was ported. Note that the deprecated Completions API is not supported in 2.0.0-beta.1: |
| 41 | + |
| 42 | +Old library's endpoint|New library's client |
| 43 | +|-|- |
| 44 | +|Chat | ChatClient |
| 45 | +|ImageGenerations | ImageClient |
| 46 | +|TextToSpeech | AudioClient |
| 47 | +|Transcriptions | AudioClient |
| 48 | +|Translations | AudioClient |
| 49 | +|Moderation | ModerationClient |
| 50 | +|Embeddings | EmbeddingClient |
| 51 | +|Files | FileClient |
| 52 | +|Models | ModelClient |
| 53 | +|Completions | Not supported |
| 54 | + |
| 55 | +## Authentication |
| 56 | + |
| 57 | +To authenticate to OpenAI, you must set an API key when creating a client. |
| 58 | + |
| 59 | +OpenAI 1.11.0 allowed setting the API key in 3 different ways: |
| 60 | +- Directly from a string |
| 61 | +- From an environment variable |
| 62 | +- From a configuration file |
| 63 | + |
| 64 | +```cs |
| 65 | +OpenAIAPI api; |
| 66 | + |
| 67 | +// Sets the API key directly from a string. |
| 68 | +api = new OpenAIAPI("<api-key>"); |
| 69 | + |
| 70 | +// Attempts to load the API key from environment variables OPENAI_KEY and OPENAI_API_KEY. |
| 71 | +api = new OpenAIAPI(APIAuthentication.LoadFromEnv()); |
| 72 | + |
| 73 | +// Attempts to load the API key from a configuration file. |
| 74 | +api = new OpenAIAPI(APIAuthentication.LoadFromPath("<directory>", "<filename>")); |
| 75 | +``` |
| 76 | + |
| 77 | +OpenAI 2.0.0-beta.1 only supports setting it from a string or from an environment variable. The following snippet illustrates the behavior with the `ChatClient`, but other clients behave the same: |
| 78 | + |
| 79 | +```cs |
| 80 | +ChatClient client; |
| 81 | + |
| 82 | +// Sets the API key directly from a string. |
| 83 | +client = new ChatClient("gpt-3.5-turbo", "<api-key>"); |
| 84 | + |
| 85 | +// When no API key string is specified, attempts to load the API key from the environment variable OPENAI_API_KEY. |
| 86 | +client = new ChatClient("gpt-3.5-turbo"); |
| 87 | +``` |
| 88 | + |
| 89 | +Note that, unlike the OpenAI 1.11.0, OpenAI 2.0.0-beta.1 will never attempt to load the API key from the `OPENAI_KEY` environment variable. Only `OPENAI_API_KEY` is supported. |
| 90 | + |
| 91 | +## Highlighted scenarios |
| 92 | + |
| 93 | +The following sections illustrate side-by-side comparisons for similar operations between the two libraries, highlighting common scenarios. |
| 94 | + |
| 95 | +### Chat Completions: Text generation |
| 96 | + |
| 97 | +OpenAI 1.11.0: |
| 98 | +```cs |
| 99 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 100 | +Conversation conversation = api.Chat.CreateConversation(); |
| 101 | + |
| 102 | +conversation.Model = Model.ChatGPTTurbo; |
| 103 | +conversation.AppendSystemMessage("You are a helpful assistant."); |
| 104 | +conversation.AppendUserInput("When was the Nobel Prize founded?"); |
| 105 | + |
| 106 | +await conversation.GetResponseFromChatbotAsync(); |
| 107 | + |
| 108 | +conversation.AppendUserInput("Who was the first person to be awarded one?"); |
| 109 | + |
| 110 | +await conversation.GetResponseFromChatbotAsync(); |
| 111 | + |
| 112 | +foreach (ChatMessage message in conversation.Messages) |
| 113 | +{ |
| 114 | + Console.WriteLine($"{message.Role}: {message.TextContent}"); |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | +OpenAI 2.0.0-beta.1: |
| 119 | +```cs |
| 120 | +ChatClient client = new ChatClient("gpt-3.5-turbo", "<api-key>"); |
| 121 | +List<ChatMessage> messages = new List<ChatMessage>() |
| 122 | +{ |
| 123 | + new SystemChatMessage("You are a helpful assistant."), |
| 124 | + new UserChatMessage("When was the Nobel Prize founded?") |
| 125 | +}; |
| 126 | + |
| 127 | +ClientResult<ChatCompletion> result = await client.CompleteChatAsync(messages); |
| 128 | + |
| 129 | +messages.Add(new AssistantChatMessage(result)); |
| 130 | +messages.Add(new UserChatMessage("Who was the first person to be awarded one?")); |
| 131 | + |
| 132 | +result = await client.CompleteChatAsync(messages); |
| 133 | + |
| 134 | +messages.Add(new AssistantChatMessage(result)); |
| 135 | + |
| 136 | +foreach (ChatMessage message in messages) |
| 137 | +{ |
| 138 | + string role = message.GetType().Name; |
| 139 | + string text = message.Content[0].Text; |
| 140 | + |
| 141 | + Console.WriteLine($"{role}: {text}"); |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +### Chat Completions: Streaming |
| 146 | + |
| 147 | +OpenAI 1.11.0: |
| 148 | +```cs |
| 149 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 150 | +Conversation conversation = api.Chat.CreateConversation(); |
| 151 | + |
| 152 | +conversation.Model = Model.ChatGPTTurbo; |
| 153 | +conversation.AppendUserInput("Give me a list of Nobel Prize winners of the last 5 years."); |
| 154 | + |
| 155 | +await foreach (string response in conversation.StreamResponseEnumerableFromChatbotAsync()) |
| 156 | +{ |
| 157 | + Console.Write(response); |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +OpenAI 2.0.0-beta.1: |
| 162 | +```cs |
| 163 | +ChatClient client = new ChatClient("gpt-3.5-turbo", "<api-key>"); |
| 164 | +List<ChatMessage> messages = new List<ChatMessage>() |
| 165 | +{ |
| 166 | + new UserChatMessage("Give me a list of Nobel Prize winners of the last 5 years.") |
| 167 | +}; |
| 168 | + |
| 169 | +await foreach (StreamingChatCompletionUpdate chatUpdate in client.CompleteChatStreamingAsync(messages)) |
| 170 | +{ |
| 171 | + if (chatUpdate.ContentUpdate.Count > 0) |
| 172 | + { |
| 173 | + Console.Write(chatUpdate.ContentUpdate[0].Text); |
| 174 | + } |
| 175 | +} |
| 176 | +``` |
| 177 | + |
| 178 | +### Chat Completions: JSON mode |
| 179 | + |
| 180 | +OpenAI 1.11.0: |
| 181 | +```cs |
| 182 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 183 | +ChatRequest request = new ChatRequest() |
| 184 | +{ |
| 185 | + Model = Model.ChatGPTTurbo, |
| 186 | + ResponseFormat = request.ResponseFormats.JsonObject, |
| 187 | + Messages = new List<ChatMessage>() |
| 188 | + { |
| 189 | + new ChatMessage(ChatMessageRole.System, "You are a helpful assistant designed to output JSON."), |
| 190 | + new ChatMessage(ChatMessageRole.User, "Give me a JSON object listing Nobel Prize winners of the last 5 years.") |
| 191 | + } |
| 192 | +}; |
| 193 | + |
| 194 | +ChatResult result = await api.Chat.CreateChatCompletionAsync(request); |
| 195 | + |
| 196 | +Console.WriteLine(result); |
| 197 | +``` |
| 198 | + |
| 199 | +OpenAI 2.0.0-beta.1: |
| 200 | +```cs |
| 201 | +ChatClient client = new ChatClient("gpt-3.5-turbo", "<api-key>"); |
| 202 | +List<ChatMessage> messages = new List<ChatMessage>() |
| 203 | +{ |
| 204 | + new SystemChatMessage("You are a helpful assistant designed to output JSON."), |
| 205 | + new UserChatMessage("Give me a JSON object listing Nobel Prize winners of the last 5 years.") |
| 206 | +}; |
| 207 | +ChatCompletionOptions options = new ChatCompletionOptions() |
| 208 | +{ |
| 209 | + ResponseFormat = ChatResponseFormat.JsonObject |
| 210 | +}; |
| 211 | + |
| 212 | +ClientResult<ChatCompletion> result = await client.CompleteChatAsync(messages, options); |
| 213 | +string text = result.Value.Content[0].Text; |
| 214 | + |
| 215 | +Console.WriteLine(text); |
| 216 | +``` |
| 217 | + |
| 218 | +### Chat Completions: Vision |
| 219 | + |
| 220 | +OpenAI 1.11.0: |
| 221 | +```cs |
| 222 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 223 | +Conversation conversation = api.Chat.CreateConversation(); |
| 224 | +byte[] imageData = await File.ReadAllBytesAsync("<file-path>"); |
| 225 | + |
| 226 | +conversation.Model = Model.GPT4_Vision; |
| 227 | +conversation.AppendUserInput("Describe this image.", ImageInput.FromImageBytes(imageData)); |
| 228 | + |
| 229 | +string response = await conversation.GetResponseFromChatbotAsync(); |
| 230 | + |
| 231 | +Console.WriteLine(response); |
| 232 | +``` |
| 233 | + |
| 234 | +OpenAI 2.0.0-beta.1: |
| 235 | +```cs |
| 236 | +ChatClient client = new ChatClient("gpt-4-vision-preview", "<api-key>"); |
| 237 | +using FileStream file = File.OpenRead("<file-path>"); |
| 238 | +BinaryData imageData = await BinaryData.FromStreamAsync(file); |
| 239 | +List<ChatMessage> messages = new List<ChatMessage>() |
| 240 | +{ |
| 241 | + new UserChatMessage( |
| 242 | + ChatMessageContentPart.CreateTextMessageContentPart("Describe this image."), |
| 243 | + ChatMessageContentPart.CreateImageMessageContentPart(imageData, "image/png")) |
| 244 | +}; |
| 245 | + |
| 246 | +ClientResult<ChatCompletion> result = await client.CompleteChatAsync(messages); |
| 247 | +string text = result.Value.Content[0].Text; |
| 248 | + |
| 249 | +Console.WriteLine(text); |
| 250 | +``` |
| 251 | + |
| 252 | +### Audio: Speech-to-text |
| 253 | + |
| 254 | +OpenAI 1.11.0: |
| 255 | +```cs |
| 256 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 257 | +string result = await api.Transcriptions.GetTextAsync("<file-path>", "fr"); |
| 258 | + |
| 259 | +Console.WriteLine(result); |
| 260 | +``` |
| 261 | + |
| 262 | +OpenAI 2.0.0-beta.1: |
| 263 | +```cs |
| 264 | +AudioClient client = new AudioClient("whisper-1", "<api-key>"); |
| 265 | +AudioTranscriptionOptions options = new AudioTranscriptionOptions() |
| 266 | +{ |
| 267 | + Language = "fr" |
| 268 | +}; |
| 269 | + |
| 270 | +ClientResult<AudioTranscription> result = await client.TranscribeAudioAsync("<file-path>", options); |
| 271 | +string text = result.Value.Text; |
| 272 | + |
| 273 | +Console.WriteLine(text); |
| 274 | +``` |
| 275 | + |
| 276 | +### Audio: Text-to-speech |
| 277 | + |
| 278 | +OpenAI 1.11.0: |
| 279 | +```cs |
| 280 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 281 | +TextToSpeechRequest request = new TextToSpeechRequest() |
| 282 | +{ |
| 283 | + Input = "Hasta la vista, baby.", |
| 284 | + Model = Model.TTS_Speed, |
| 285 | + Voice = "alloy" |
| 286 | +}; |
| 287 | + |
| 288 | +await api.TextToSpeech.SaveSpeechToFileAsync(request, "<file-path>"); |
| 289 | +``` |
| 290 | + |
| 291 | +OpenAI 2.0.0-beta.1: |
| 292 | +```cs |
| 293 | +AudioClient client = new AudioClient("tts-1", "<api-key>"); |
| 294 | + |
| 295 | +ClientResult<BinaryData> result = await client.GenerateSpeechFromTextAsync("Hasta la vista, baby.", GeneratedSpeechVoice.Alloy); |
| 296 | +BinaryData data = result.Value; |
| 297 | + |
| 298 | +await File.WriteAllBytesAsync("<file-path>", data.ToArray()); |
| 299 | +``` |
| 300 | + |
| 301 | +### Image: Image generation |
| 302 | + |
| 303 | +OpenAI 1.11.0: |
| 304 | +```cs |
| 305 | +OpenAIAPI api = new OpenAIAPI("<api-key>"); |
| 306 | +ImageGenerationRequest request = new ImageGenerationRequest() |
| 307 | +{ |
| 308 | + Prompt = "Draw a quick brown fox jumping over a lazy dog.", |
| 309 | + Model = Model.DALLE3, |
| 310 | + Quality = "standard", |
| 311 | + Size = ImageSize._1024 |
| 312 | +}; |
| 313 | + |
| 314 | +ImageResult result = await api.ImageGenerations.CreateImageAsync(request); |
| 315 | + |
| 316 | +Console.WriteLine(result.Data[0].Url); |
| 317 | +``` |
| 318 | + |
| 319 | +OpenAI 2.0.0-beta.1: |
| 320 | +```cs |
| 321 | +ImageClient client = new ImageClient("dall-e-3", "<api-key>"); |
| 322 | +ImageGenerationOptions options = new ImageGenerationOptions() |
| 323 | +{ |
| 324 | + Quality = GeneratedImageQuality.Standard, |
| 325 | + Size = GeneratedImageSize.W1024xH1024 |
| 326 | +}; |
| 327 | + |
| 328 | +ClientResult<GeneratedImage> result = await client.GenerateImageAsync("Draw a quick brown fox jumping over a lazy dog.", options); |
| 329 | +Uri imageUri = result.Value.ImageUri; |
| 330 | + |
| 331 | +Console.WriteLine(imageUri.AbsoluteUri); |
| 332 | +``` |
| 333 | + |
| 334 | +## Additional examples |
| 335 | + |
| 336 | +For additional examples, see [OpenAI Examples][examples]. |
| 337 | + |
| 338 | +[readme]: https://github.com/openai/openai-dotnet/blob/main/README.md |
| 339 | +[changelog]: https://github.com/openai/openai-dotnet/blob/main/CHANGELOG.md |
| 340 | +[examples]: https://github.com/openai/openai-dotnet/tree/main/examples |
| 341 | +[openai_1110]: https://aka.ms/openai1110 |
0 commit comments