openai/openai-dotnet

Public

mirrored from https://github.com/openai/openai-dotnetAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.3.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/Custom/Embeddings/EmbeddingClient.cs

296lines · modecode

1using System;
2using System.ClientModel;
3using System.ClientModel.Primitives;
4using System.Collections.Generic;
5using System.Diagnostics.CodeAnalysis;
6using System.IO;
7using System.Linq;
8using System.Text.Json;
9using System.Threading;
10using System.Threading.Tasks;
11
12namespace OpenAI.Embeddings;
13
14// CUSTOM:
15// - Renamed.
16// - Suppressed constructor that takes endpoint parameter; endpoint is now a property in the options class.
17// - Suppressed methods that only take the options parameter.
18/// <summary> The service client for OpenAI embedding operations. </summary>
19[CodeGenType("Embeddings")]
20[CodeGenSuppress("EmbeddingClient", typeof(ClientPipeline), typeof(Uri))]
21[CodeGenSuppress("GenerateEmbeddingsAsync", typeof(EmbeddingGenerationOptions), typeof(CancellationToken))]
22[CodeGenSuppress("GenerateEmbeddings", typeof(EmbeddingGenerationOptions), typeof(CancellationToken))]
23public partial class EmbeddingClient
24{
25 private readonly string _model;
26
27 // CUSTOM: Added as a convenience.
28 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
29 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
30 /// <param name="apiKey"> The API key to authenticate with the service. </param>
31 /// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="apiKey"/> is null. </exception>
32 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
33 public EmbeddingClient(string model, string apiKey) : this(model, new ApiKeyCredential(apiKey), new OpenAIClientOptions())
34 {
35 }
36
37 // CUSTOM:
38 // - Added `model` parameter.
39 // - Used a custom pipeline.
40 // - Demoted the endpoint parameter to be a property in the options class.
41 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
42 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
43 /// <param name="credential"> The API key to authenticate with the service. </param>
44 /// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
45 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
46 public EmbeddingClient(string model, ApiKeyCredential credential) : this(model, credential, new OpenAIClientOptions())
47 {
48 }
49
50 // CUSTOM:
51 // - Added `model` parameter.
52 // - Used a custom pipeline.
53 // - Demoted the endpoint parameter to be a property in the options class.
54 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
55 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
56 /// <param name="credential"> The API key to authenticate with the service. </param>
57 /// <param name="options"> The options to configure the client. </param>
58 /// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
59 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
60 public EmbeddingClient(string model, ApiKeyCredential credential, OpenAIClientOptions options) : this(model, OpenAIClient.CreateApiKeyAuthenticationPolicy(credential), options)
61 {
62 }
63
64 // CUSTOM: Added as a convenience.
65 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
66 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
67 /// <param name="authenticationPolicy"> The authentication policy used to authenticate with the service. </param>
68 /// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="authenticationPolicy"/> is null. </exception>
69 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
70 [Experimental("OPENAI001")]
71 public EmbeddingClient(string model, AuthenticationPolicy authenticationPolicy) : this(model, authenticationPolicy, new OpenAIClientOptions())
72 {
73 }
74
75 // CUSTOM: Added as a convenience.
76 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
77 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
78 /// <param name="authenticationPolicy"> The authentication policy used to authenticate with the service. </param>
79 /// <param name="options"> The options to configure the client. </param>
80 /// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="authenticationPolicy"/> is null. </exception>
81 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
82 [Experimental("OPENAI001")]
83 public EmbeddingClient(string model, AuthenticationPolicy authenticationPolicy, OpenAIClientOptions options)
84 {
85 Argument.AssertNotNullOrEmpty(model, nameof(model));
86 Argument.AssertNotNull(authenticationPolicy, nameof(authenticationPolicy));
87 options ??= new OpenAIClientOptions();
88
89 _model = model;
90 Pipeline = OpenAIClient.CreatePipeline(authenticationPolicy, options);
91 _endpoint = OpenAIClient.GetEndpoint(options);
92 }
93
94 // CUSTOM:
95 // - Added `model` parameter.
96 // - Used a custom pipeline.
97 // - Demoted the endpoint parameter to be a property in the options class.
98 // - Made protected.
99 /// <summary> Initializes a new instance of <see cref="EmbeddingClient"/>. </summary>
100 /// <param name="pipeline"> The HTTP pipeline to send and receive REST requests and responses. </param>
101 /// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
102 /// <param name="options"> The options to configure the client. </param>
103 /// <exception cref="ArgumentNullException"> <paramref name="pipeline"/> or <paramref name="model"/> is null. </exception>
104 /// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
105 protected internal EmbeddingClient(ClientPipeline pipeline, string model, OpenAIClientOptions options)
106 {
107 Argument.AssertNotNull(pipeline, nameof(pipeline));
108 Argument.AssertNotNullOrEmpty(model, nameof(model));
109 options ??= new OpenAIClientOptions();
110
111 _model = model;
112 Pipeline = pipeline;
113 _endpoint = OpenAIClient.GetEndpoint(options);
114 }
115
116 /// <summary>
117 /// Gets the name of the model used in requests sent to the service.
118 /// </summary>
119 [Experimental("OPENAI001")]
120 public string Model => _model;
121
122 // CUSTOM: Added to simplify generating a single embedding from a string input.
123 /// <summary> Generates an embedding representing the text input. </summary>
124 /// <param name="input"> The text input to generate an embedding for. </param>
125 /// <param name="options"> The options to configure the embedding generation. </param>
126 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
127 /// <exception cref="ArgumentNullException"> <paramref name="input"/> is null. </exception>
128 /// <exception cref="ArgumentException"> <paramref name="input"/> is an empty string, and was expected to be non-empty. </exception>
129 public virtual async Task<ClientResult<OpenAIEmbedding>> GenerateEmbeddingAsync(string input, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
130 {
131 Argument.AssertNotNullOrEmpty(input, nameof(input));
132
133 options ??= new();
134 CreateEmbeddingGenerationOptions(input, ref options);
135
136 using BinaryContent content = options.ToBinaryContent();
137 ClientResult result = await GenerateEmbeddingsAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false);
138 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result).FirstOrDefault(), result.GetRawResponse());
139 }
140
141 // CUSTOM: Added to simplify generating a single embedding from a string input.
142 /// <summary> Generates an embedding representing the text input. </summary>
143 /// <param name="input"> The text input to generate an embedding for. </param>
144 /// <param name="options"> The options to configure the embedding generation. </param>
145 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
146 /// <exception cref="ArgumentNullException"> <paramref name="input"/> is null. </exception>
147 /// <exception cref="ArgumentException"> <paramref name="input"/> is an empty string, and was expected to be non-empty. </exception>
148 public virtual ClientResult<OpenAIEmbedding> GenerateEmbedding(string input, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
149 {
150 Argument.AssertNotNullOrEmpty(input, nameof(input));
151
152 options ??= new();
153 CreateEmbeddingGenerationOptions(input, ref options);
154
155 using BinaryContent content = options.ToBinaryContent();
156 ClientResult result = GenerateEmbeddings(content, cancellationToken.ToRequestOptions());
157 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result).FirstOrDefault(), result.GetRawResponse());
158 }
159
160 // CUSTOM: Added to simplify passing the input as a collection of strings instead of BinaryData.
161 /// <summary> Generates embeddings representing the text inputs. </summary>
162 /// <param name="inputs"> The text inputs to generate embeddings for. </param>
163 /// <param name="options"> The options to configure the embedding generation. </param>
164 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
165 /// <exception cref="ArgumentNullException"> <paramref name="inputs"/> is null. </exception>
166 /// <exception cref="ArgumentException"> <paramref name="inputs"/> is an empty collection, and was expected to be non-empty. </exception>
167 public virtual async Task<ClientResult<OpenAIEmbeddingCollection>> GenerateEmbeddingsAsync(IEnumerable<string> inputs, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
168 {
169 Argument.AssertNotNullOrEmpty(inputs, nameof(inputs));
170
171 options ??= new();
172 CreateEmbeddingGenerationOptions(inputs, ref options);
173
174 using BinaryContent content = options.ToBinaryContent();
175 ClientResult result = await GenerateEmbeddingsAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false);
176 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result), result.GetRawResponse());
177
178 }
179
180 // CUSTOM: Added to simplify passing the input as a collection of strings instead of BinaryData.
181 /// <summary> Generates embeddings representing the text inputs. </summary>
182 /// <param name="inputs"> The text inputs to generate embeddings for. </param>
183 /// <param name="options"> The options to configure the embedding generation. </param>
184 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
185 /// <exception cref="ArgumentNullException"> <paramref name="inputs"/> is null. </exception>
186 /// <exception cref="ArgumentException"> <paramref name="inputs"/> is an empty collection, and was expected to be non-empty. </exception>
187 public virtual ClientResult<OpenAIEmbeddingCollection> GenerateEmbeddings(IEnumerable<string> inputs, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
188 {
189 Argument.AssertNotNullOrEmpty(inputs, nameof(inputs));
190
191 options ??= new();
192 CreateEmbeddingGenerationOptions(inputs, ref options);
193
194 using BinaryContent content = options.ToBinaryContent();
195 ClientResult result = GenerateEmbeddings(content, cancellationToken.ToRequestOptions());
196 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result), result.GetRawResponse());
197 }
198
199 // CUSTOM: Added to simplify passing the input as a collection of ReadOnlyMemory tokens instead of BinaryData.
200 /// <summary> Generates embeddings representing the tokenized text inputs. </summary>
201 /// <param name="inputs"> The tokenized text inputs to generate embeddings for. </param>
202 /// <param name="options"> The options to configure the embedding generation. </param>
203 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
204 /// <exception cref="ArgumentNullException"> <paramref name="inputs"/> is null. </exception>
205 /// <exception cref="ArgumentException"> <paramref name="inputs"/> is an empty collection, and was expected to be non-empty. </exception>
206 public virtual async Task<ClientResult<OpenAIEmbeddingCollection>> GenerateEmbeddingsAsync(IEnumerable<ReadOnlyMemory<int>> inputs, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
207 {
208 Argument.AssertNotNullOrEmpty(inputs, nameof(inputs));
209
210 options ??= new();
211 CreateEmbeddingGenerationOptions(inputs, ref options);
212
213 using BinaryContent content = options.ToBinaryContent();
214 ClientResult result = await GenerateEmbeddingsAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false);
215 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result), result.GetRawResponse());
216 }
217
218 // CUSTOM: Added to simplify passing the input as a collection of ReadOnlyMemory of tokens instead of BinaryData.
219 /// <summary> Generates embeddings representing the tokenized text inputs. </summary>
220 /// <param name="inputs"> The tokenized text inputs to generate embeddings for. </param>
221 /// <param name="options"> The options to configure the embedding generation. </param>
222 /// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
223 /// <exception cref="ArgumentNullException"> <paramref name="inputs"/> is null. </exception>
224 /// <exception cref="ArgumentException"> <paramref name="inputs"/> is an empty collection, and was expected to be non-empty. </exception>
225 public virtual ClientResult<OpenAIEmbeddingCollection> GenerateEmbeddings(IEnumerable<ReadOnlyMemory<int>> inputs, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default)
226 {
227 Argument.AssertNotNullOrEmpty(inputs, nameof(inputs));
228
229 options ??= new();
230 CreateEmbeddingGenerationOptions(inputs, ref options);
231
232 using BinaryContent content = options.ToBinaryContent();
233 ClientResult result = GenerateEmbeddings(content, cancellationToken.ToRequestOptions());
234 return ClientResult.FromValue(OpenAIEmbeddingCollection.FromClientResult(result), result.GetRawResponse());
235 }
236
237 private void CreateEmbeddingGenerationOptions(string input, ref EmbeddingGenerationOptions options)
238 {
239 using MemoryStream stream = new();
240 using Utf8JsonWriter writer = new(stream);
241
242 writer.WriteStringValue(input);
243 writer.Flush();
244
245 options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
246 options.Model = _model;
247 options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
248 }
249
250 private void CreateEmbeddingGenerationOptions(IEnumerable<string> inputs, ref EmbeddingGenerationOptions options)
251 {
252 using MemoryStream stream = new();
253 using Utf8JsonWriter writer = new(stream);
254
255 writer.WriteStartArray();
256
257 foreach (string input in inputs)
258 {
259 writer.WriteStringValue(input);
260 }
261
262 writer.WriteEndArray();
263 writer.Flush();
264
265 options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
266 options.Model = _model;
267 options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
268 }
269
270 private void CreateEmbeddingGenerationOptions(IEnumerable<ReadOnlyMemory<int>> inputs, ref EmbeddingGenerationOptions options)
271 {
272 using MemoryStream stream = new();
273 using Utf8JsonWriter writer = new(stream);
274
275 writer.WriteStartArray();
276
277 foreach (ReadOnlyMemory<int> input in inputs)
278 {
279 writer.WriteStartArray();
280
281 foreach (int tokenId in input.ToArray())
282 {
283 writer.WriteNumberValue(tokenId);
284 }
285
286 writer.WriteEndArray();
287 }
288
289 writer.WriteEndArray();
290 writer.Flush();
291
292 options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
293 options.Model = _model;
294 options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
295 }
296}