Skip to content

Commit 6312680

Browse files
committed
add support for new embeddings
1 parent 5f7c23a commit 6312680

File tree

6 files changed

+151
-83
lines changed

6 files changed

+151
-83
lines changed

OpenAI_API/Embedding/EmbeddingEndpoint.cs

+13-9
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ namespace OpenAI_API.Embedding
99
public class EmbeddingEndpoint : EndpointBase, IEmbeddingEndpoint
1010
{
1111
/// <summary>
12-
/// This allows you to send request to the recommended model without needing to specify. Every request uses the <see cref="Model.AdaTextEmbedding"/> model
12+
/// This allows you to send request to a default model without needing to specify for each request.
1313
/// </summary>
14-
public EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; } = new EmbeddingRequest() { Model = Model.AdaTextEmbedding };
14+
public EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; } = new EmbeddingRequest() { Model = Model.DefaultEmbeddingModel };
1515

1616
/// <summary>
1717
/// The name of the endpoint, which is the final path segment in the API URL. For example, "embeddings".
@@ -25,7 +25,7 @@ public class EmbeddingEndpoint : EndpointBase, IEmbeddingEndpoint
2525
internal EmbeddingEndpoint(OpenAIAPI api) : base(api) { }
2626

2727
/// <summary>
28-
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
28+
/// Ask the API to embed text using the default embedding model <see cref="Model.DefaultEmbeddingModel"/>
2929
/// </summary>
3030
/// <param name="input">Text to be embedded</param>
3131
/// <returns>Asynchronously returns the embedding result. Look in its <see cref="Data.Embedding"/> property of <see cref="EmbeddingResult.Data"/> to find the vector of floating point numbers</returns>
@@ -36,7 +36,7 @@ public async Task<EmbeddingResult> CreateEmbeddingAsync(string input)
3636
}
3737

3838
/// <summary>
39-
/// Ask the API to embedd text using a custom request
39+
/// Ask the API to embed text using a custom request
4040
/// </summary>
4141
/// <param name="request">Request to be send</param>
4242
/// <returns>Asynchronously returns the embedding result. Look in its <see cref="Data.Embedding"/> property of <see cref="EmbeddingResult.Data"/> to find the vector of floating point numbers</returns>
@@ -45,16 +45,20 @@ public async Task<EmbeddingResult> CreateEmbeddingAsync(EmbeddingRequest request
4545
return await HttpPost<EmbeddingResult>(postData: request);
4646
}
4747

48-
/// <summary>
49-
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
50-
/// </summary>
51-
/// <param name="input">Text to be embedded</param>
52-
/// <returns>Asynchronously returns the first embedding result as an array of floats.</returns>
48+
/// <inheritdoc/>
5349
public async Task<float[]> GetEmbeddingsAsync(string input)
5450
{
5551
EmbeddingRequest req = new EmbeddingRequest(DefaultEmbeddingRequestArgs.Model, input);
5652
var embeddingResult = await CreateEmbeddingAsync(req);
5753
return embeddingResult?.Data?[0]?.Embedding;
5854
}
55+
56+
/// <inheritdoc/>
57+
public async Task<float[]> GetEmbeddingsAsync(string input, Model model=null, int? dimensions = null)
58+
{
59+
EmbeddingRequest req = new EmbeddingRequest(model ?? Model.DefaultEmbeddingModel, input, dimensions);
60+
var embeddingResult = await CreateEmbeddingAsync(req);
61+
return embeddingResult?.Data?[0]?.Embedding;
62+
}
5963
}
6064
}

OpenAI_API/Embedding/EmbeddingRequest.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ public class EmbeddingRequest
2020
[JsonProperty("input")]
2121
public string Input { get; set; }
2222

23+
/// <summary>
24+
/// The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models.
25+
/// </summary>
26+
[JsonProperty("dimensions", NullValueHandling =NullValueHandling.Ignore)]
27+
public int? Dimensions { get; set; }
28+
2329
/// <summary>
2430
/// Cretes a new, empty <see cref="EmbeddingRequest"/>
2531
/// </summary>
@@ -33,19 +39,21 @@ public EmbeddingRequest()
3339
/// </summary>
3440
/// <param name="model">The model to use. You can use <see cref="ModelsEndpoint.GetModelsAsync()"/> to see all of your available models, or use a standard model like <see cref="Model.AdaTextEmbedding"/>.</param>
3541
/// <param name="input">The prompt to transform</param>
36-
public EmbeddingRequest(Model model, string input)
42+
/// <param name="dimensions">The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models.</param>
43+
public EmbeddingRequest(Model model, string input, int? dimensions = null)
3744
{
38-
Model = model;
45+
this.Model = model;
3946
this.Input = input;
47+
this.Dimensions = dimensions;
4048
}
4149

4250
/// <summary>
43-
/// Creates a new <see cref="EmbeddingRequest"/> with the specified input and the <see cref="Model.AdaTextEmbedding"/> model.
51+
/// Creates a new <see cref="EmbeddingRequest"/> with the specified input and the <see cref="Model.DefaultEmbeddingModel"/> model.
4452
/// </summary>
4553
/// <param name="input">The prompt to transform</param>
4654
public EmbeddingRequest(string input)
4755
{
48-
Model = OpenAI_API.Models.Model.AdaTextEmbedding;
56+
this.Model = OpenAI_API.Models.Model.DefaultEmbeddingModel;
4957
this.Input = input;
5058
}
5159
}

OpenAI_API/Embedding/IEmbeddingEndpoint.cs

+19-17
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,32 @@ namespace OpenAI_API.Embedding
88
/// </summary>
99
public interface IEmbeddingEndpoint
1010
{
11-
/// <summary>
12-
/// This allows you to send request to the recommended model without needing to specify. Every request uses the <see cref="Model.AdaTextEmbedding"/> model
13-
/// </summary>
14-
EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; }
11+
/// <summary>
12+
/// This allows you to send request to a default model without needing to specify for each request
13+
/// </summary>
14+
EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; }
1515

16-
/// <summary>
17-
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
18-
/// </summary>
19-
/// <param name="input">Text to be embedded</param>
20-
/// <returns>Asynchronously returns the embedding result. Look in its <see cref="Data.Embedding"/> property of <see cref="EmbeddingResult.Data"/> to find the vector of floating point numbers</returns>
21-
Task<EmbeddingResult> CreateEmbeddingAsync(string input);
16+
/// <summary>
17+
/// Ask the API to embed text using the default embedding model <see cref="Model.DefaultEmbeddingModel"/>
18+
/// </summary>
19+
/// <param name="input">Text to be embedded</param>
20+
/// <returns>Asynchronously returns the embedding result. Look in its <see cref="Data.Embedding"/> property of <see cref="EmbeddingResult.Data"/> to find the vector of floating point numbers</returns>
21+
Task<EmbeddingResult> CreateEmbeddingAsync(string input);
2222

2323
/// <summary>
24-
/// Ask the API to embedd text using a custom request
24+
/// Ask the API to embed text using a custom request
2525
/// </summary>
2626
/// <param name="request">Request to be send</param>
2727
/// <returns>Asynchronously returns the embedding result. Look in its <see cref="Data.Embedding"/> property of <see cref="EmbeddingResult.Data"/> to find the vector of floating point numbers</returns>
2828
Task<EmbeddingResult> CreateEmbeddingAsync(EmbeddingRequest request);
2929

30-
/// <summary>
31-
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
32-
/// </summary>
33-
/// <param name="input">Text to be embedded</param>
34-
/// <returns>Asynchronously returns the first embedding result as an array of floats.</returns>
35-
Task<float[]> GetEmbeddingsAsync(string input);
30+
/// <summary>
31+
/// Ask the API to embed text <see cref="Model.DefaultEmbeddingModel"/>
32+
/// </summary>
33+
/// <param name="input">Text to be embedded</param>
34+
/// <param name="model">The model to use. You can use <see cref="ModelsEndpoint.GetModelsAsync()"/> to see all of your available models, or use a standard model like <see cref="Model.AdaTextEmbedding"/>.</param>
35+
/// <param name="dimensions">The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models.</param>
36+
/// <returns>Asynchronously returns the first embedding result as an array of floats.</returns>
37+
Task<float[]> GetEmbeddingsAsync(string input, Model model = null, int? dimensions = null);
3638
}
3739
}

OpenAI_API/Model/Model.cs

+22-6
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public Model()
112112
/// </summary>
113113
public static Model DefaultTranscriptionModel { get; set; } = Whisper1;
114114

115+
/// <summary>
116+
/// The default model to use in embedding requests if no other model is specified.
117+
/// </summary>
118+
public static Model DefaultEmbeddingModel { get; set; } = AdaTextEmbedding;
119+
115120

116121
/// <summary>
117122
/// Gets more details about this Model from the API, specifically properties such as <see cref="OwnedBy"/> and permissions.
@@ -143,7 +148,7 @@ public async Task<Model> RetrieveModelDetailsAsync(OpenAI_API.OpenAIAPI api)
143148
/// <summary>
144149
/// The latest GPT-4 model with improved instruction following, JSON mode, reproducible outputs, parallel function calling, and more. Returns a maximum of 4,096 output tokens. This preview model is not yet suited for production traffic.
145150
/// </summary>
146-
public static Model GPT4_Turbo => new Model("gpt-4-1106-preview") { OwnedBy = "openai" };
151+
public static Model GPT4_Turbo => new Model("gpt-4-turbo-preview") { OwnedBy = "openai" };
147152
#endregion
148153

149154
#region GPT-3.5
@@ -214,16 +219,27 @@ public async Task<Model> RetrieveModelDetailsAsync(OpenAI_API.OpenAIAPI api)
214219
/// </summary>
215220
[Obsolete("Will be deprecated by OpenAI on Jan 4th 2024.")]
216221
public static Model DavinciCode => new Model("code-davinci-002") { OwnedBy = "openai" };
217-
#endregion
222+
#endregion
218223

219-
#region Embeddings
224+
#region Embeddings
220225
/// <summary>
221-
/// OpenAI offers one second-generation embedding model for use with the embeddings API endpoint.
226+
/// 2nd generation embedding model.
222227
/// </summary>
223228
public static Model AdaTextEmbedding => new Model("text-embedding-ada-002") { OwnedBy = "openai" };
224-
#endregion
225229

226-
#region Moderation
230+
/// <summary>
231+
/// Most capable embedding model for both english and non-english tasks
232+
/// </summary>
233+
public static Model TextEmbedding3Large => new Model("text-embedding-3-large") { OwnedBy = "openai" };
234+
235+
/// <summary>
236+
/// Increased performance over 2nd generation ada embedding model
237+
/// </summary>
238+
public static Model TextEmbedding3Small => new Model("text-embedding-3-small") { OwnedBy = "openai" };
239+
240+
#endregion
241+
242+
#region Moderation
227243
/// <summary>
228244
/// Stable text moderation model that may provide lower accuracy compared to TextModerationLatest.
229245
/// OpenAI states they will provide advanced notice before updating this model.

OpenAI_Tests/ChatEndpointTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public void SimpleCompletion()
127127

128128
[TestCase("gpt-3.5-turbo")]
129129
[TestCase("gpt-4")]
130-
[TestCase("gpt-4-1106-preview")]
130+
[TestCase("gpt-4-turbo-preview")]
131131
public void ChatBackAndForth(string model)
132132
{
133133
var api = new OpenAI_API.OpenAIAPI();

OpenAI_Tests/EmbeddingEndpointTests.cs

+84-46
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,101 @@
66

77
namespace OpenAI_Tests
88
{
9-
public class EmbeddingEndpointTests
10-
{
11-
[SetUp]
12-
public void Setup()
13-
{
14-
OpenAI_API.APIAuthentication.Default = new OpenAI_API.APIAuthentication(Environment.GetEnvironmentVariable("TEST_OPENAI_SECRET_KEY"));
15-
}
16-
17-
[Test]
18-
public void GetBasicEmbedding()
19-
{
20-
var api = new OpenAI_API.OpenAIAPI();
21-
22-
Assert.IsNotNull(api.Embeddings);
23-
24-
var results = api.Embeddings.CreateEmbeddingAsync(new EmbeddingRequest(Model.AdaTextEmbedding, "A test text for embedding")).Result;
25-
Assert.IsNotNull(results);
26-
if (results.CreatedUnixTime.HasValue)
27-
{
28-
Assert.NotZero(results.CreatedUnixTime.Value);
29-
Assert.NotNull(results.Created);
30-
Assert.Greater(results.Created.Value, new DateTime(2018, 1, 1));
9+
public class EmbeddingEndpointTests
10+
{
11+
[SetUp]
12+
public void Setup()
13+
{
14+
OpenAI_API.APIAuthentication.Default = new OpenAI_API.APIAuthentication(Environment.GetEnvironmentVariable("TEST_OPENAI_SECRET_KEY"));
15+
}
16+
17+
[Test]
18+
public void GetBasicEmbedding()
19+
{
20+
var api = new OpenAI_API.OpenAIAPI();
21+
22+
Assert.IsNotNull(api.Embeddings);
23+
24+
var results = api.Embeddings.CreateEmbeddingAsync(new EmbeddingRequest(Model.AdaTextEmbedding, "A test text for embedding")).Result;
25+
Assert.IsNotNull(results);
26+
if (results.CreatedUnixTime.HasValue)
27+
{
28+
Assert.NotZero(results.CreatedUnixTime.Value);
29+
Assert.NotNull(results.Created);
30+
Assert.Greater(results.Created.Value, new DateTime(2018, 1, 1));
3131
Assert.Less(results.Created.Value, DateTime.Now.AddDays(1));
32-
} else
33-
{
34-
Assert.Null(results.Created);
3532
}
36-
Assert.NotNull(results.Object);
37-
Assert.NotZero(results.Data.Count);
38-
Assert.That(results.Data.First().Embedding.Length == 1536);
39-
}
33+
else
34+
{
35+
Assert.Null(results.Created);
36+
}
37+
Assert.NotNull(results.Object);
38+
Assert.NotZero(results.Data.Count);
39+
Assert.That(results.Data.First().Embedding.Length == 1536);
40+
}
4041

41-
[Test]
42-
public void ReturnedUsage()
43-
{
44-
var api = new OpenAI_API.OpenAIAPI();
42+
[Test]
43+
public void ReturnedUsage()
44+
{
45+
var api = new OpenAI_API.OpenAIAPI();
4546

46-
Assert.IsNotNull(api.Embeddings);
47+
Assert.IsNotNull(api.Embeddings);
4748

48-
var results = api.Embeddings.CreateEmbeddingAsync(new EmbeddingRequest(Model.AdaTextEmbedding, "A test text for embedding")).Result;
49-
Assert.IsNotNull(results);
49+
var results = api.Embeddings.CreateEmbeddingAsync(new EmbeddingRequest(Model.AdaTextEmbedding, "A test text for embedding")).Result;
50+
Assert.IsNotNull(results);
5051

5152
Assert.IsNotNull(results.Usage);
5253
Assert.GreaterOrEqual(results.Usage.PromptTokens, 5);
5354
Assert.GreaterOrEqual(results.Usage.TotalTokens, results.Usage.PromptTokens);
5455
}
5556

56-
[Test]
57-
public void GetSimpleEmbedding()
58-
{
59-
var api = new OpenAI_API.OpenAIAPI();
57+
[Test]
58+
public void GetSimpleEmbedding()
59+
{
60+
var api = new OpenAI_API.OpenAIAPI();
61+
62+
Assert.IsNotNull(api.Embeddings);
63+
64+
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding").Result;
65+
Assert.IsNotNull(results);
66+
Assert.That(results.Length == 1536);
67+
}
68+
69+
[Test]
70+
public void GetEmbeddingWithLargeModel()
71+
{
72+
var api = new OpenAI_API.OpenAIAPI();
6073

61-
Assert.IsNotNull(api.Embeddings);
74+
Assert.IsNotNull(api.Embeddings);
6275

63-
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding").Result;
64-
Assert.IsNotNull(results);
65-
Assert.That(results.Length == 1536);
66-
}
67-
}
76+
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding", Model.TextEmbedding3Large).Result;
77+
Assert.IsNotNull(results);
78+
Assert.That(results.Length == 3072);
79+
}
80+
81+
[Test]
82+
public void GetEmbeddingWithSmallModel()
83+
{
84+
var api = new OpenAI_API.OpenAIAPI();
85+
86+
Assert.IsNotNull(api.Embeddings);
87+
88+
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding", Model.TextEmbedding3Small).Result;
89+
Assert.IsNotNull(results);
90+
Assert.That(results.Length == 1536);
91+
}
92+
93+
94+
[Test]
95+
public void GetEmbeddingWithDimensions()
96+
{
97+
var api = new OpenAI_API.OpenAIAPI();
98+
99+
Assert.IsNotNull(api.Embeddings);
100+
101+
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding", Model.TextEmbedding3Small, 350).Result;
102+
Assert.IsNotNull(results);
103+
Assert.That(results.Length == 350);
104+
}
105+
}
68106
}

0 commit comments

Comments
 (0)