Skip to content

Commit 8f1bac8

Browse files
authored
Merge pull request #38 from OkGoDoIt/metjuperry/master
Merging of @metjuperry: Added embedding endpoint and tests
2 parents f3c2b75 + 0788505 commit 8f1bac8

File tree

5 files changed

+241
-2
lines changed

5 files changed

+241
-2
lines changed
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Threading.Tasks;
2+
3+
namespace OpenAI_API.Embedding
4+
{
5+
/// <summary>
6+
/// OpenAI’s text embeddings measure the relatedness of text strings by generating an embedding, which is a vector (list) of floating point numbers. The distance between two vectors measures their relatedness. Small distances suggest high relatedness and large distances suggest low relatedness.
7+
/// </summary>
8+
public class EmbeddingEndpoint : EndpointBase
9+
{
10+
/// <summary>
11+
/// This allows you to send request to the recommended model without needing to specify. Every request uses the <see cref="Model.AdaTextEmbedding"/> model
12+
/// </summary>
13+
public EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; } = new EmbeddingRequest() { Model = Model.AdaTextEmbedding };
14+
15+
/// <summary>
16+
/// The name of the endpoint, which is the final path segment in the API URL. For example, "embeddings".
17+
/// </summary>
18+
protected override string Endpoint { get { return "embeddings"; } }
19+
20+
/// <summary>
21+
/// Constructor of the api endpoint. Rather than instantiating this yourself, access it through an instance of <see cref="OpenAIAPI"/> as <see cref="OpenAIAPI.Embeddings"/>.
22+
/// </summary>
23+
/// <param name="api"></param>
24+
internal EmbeddingEndpoint(OpenAIAPI api) : base(api) { }
25+
26+
/// <summary>
27+
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
28+
/// </summary>
29+
/// <param name="input">Text to be embedded</param>
30+
/// <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>
31+
public async Task<EmbeddingResult> CreateEmbeddingAsync(string input)
32+
{
33+
EmbeddingRequest req = new EmbeddingRequest(DefaultEmbeddingRequestArgs.Model, input);
34+
return await CreateEmbeddingAsync(req);
35+
}
36+
37+
/// <summary>
38+
/// Ask the API to embedd text using a custom request
39+
/// </summary>
40+
/// <param name="request">Request to be send</param>
41+
/// <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>
42+
public async Task<EmbeddingResult> CreateEmbeddingAsync(EmbeddingRequest request)
43+
{
44+
return await HttpPost<EmbeddingResult>(postData: request);
45+
}
46+
47+
/// <summary>
48+
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
49+
/// </summary>
50+
/// <param name="input">Text to be embedded</param>
51+
/// <returns>Asynchronously returns the first embedding result as an array of floats.</returns>
52+
public async Task<float[]> GetEmbeddingsAsync(string input)
53+
{
54+
EmbeddingRequest req = new EmbeddingRequest(DefaultEmbeddingRequestArgs.Model, input);
55+
var embeddingResult = await CreateEmbeddingAsync(req);
56+
return embeddingResult?.Data?[0]?.Embedding;
57+
}
58+
}
59+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Newtonsoft.Json;
2+
3+
namespace OpenAI_API.Embedding
4+
{
5+
/// <summary>
6+
/// Represents a request to the Completions API. Matches with the docs at <see href="https://platform.openai.com/docs/api-reference/embeddings">the OpenAI docs</see>
7+
/// </summary>
8+
public class EmbeddingRequest
9+
{
10+
/// <summary>
11+
/// ID of 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"/>.
12+
/// </summary>
13+
[JsonProperty("model")]
14+
public string Model { get; set; }
15+
16+
/// <summary>
17+
/// Main text to be embedded
18+
/// </summary>
19+
[JsonProperty("input")]
20+
public string Input { get; set; }
21+
22+
/// <summary>
23+
/// Cretes a new, empty <see cref="EmbeddingRequest"/>
24+
/// </summary>
25+
public EmbeddingRequest()
26+
{
27+
28+
}
29+
30+
/// <summary>
31+
/// Creates a new <see cref="EmbeddingRequest"/> with the specified parameters
32+
/// </summary>
33+
/// <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>
34+
/// <param name="input">The prompt to transform</param>
35+
public EmbeddingRequest(Model model, string input)
36+
{
37+
Model = model;
38+
this.Input = input;
39+
}
40+
41+
/// <summary>
42+
/// Creates a new <see cref="EmbeddingRequest"/> with the specified input and the <see cref="Model.AdaTextEmbedding"/> model.
43+
/// </summary>
44+
/// <param name="input">The prompt to transform</param>
45+
public EmbeddingRequest(string input)
46+
{
47+
Model = OpenAI_API.Model.AdaTextEmbedding;
48+
this.Input = input;
49+
}
50+
}
51+
}
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using Newtonsoft.Json;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace OpenAI_API.Embedding
6+
{
7+
/// <summary>
8+
/// Represents an embedding result returned by the Embedding API.
9+
/// </summary>
10+
public class EmbeddingResult : ApiResultBase
11+
{
12+
/// <summary>
13+
/// List of results of the embedding
14+
/// </summary>
15+
[JsonProperty("data")]
16+
public List<Data> Data { get; set; }
17+
18+
/// <summary>
19+
/// Usage statistics of how many tokens have been used for this request
20+
/// </summary>
21+
[JsonProperty("usage")]
22+
public Usage Usage { get; set; }
23+
24+
/// <summary>
25+
/// Allows an EmbeddingResult to be implicitly cast to the array of floats repsresenting the first ebmedding result
26+
/// </summary>
27+
/// <param name="embeddingResult">The <see cref="EmbeddingResult"/> to cast to an array of floats.</param>
28+
public static implicit operator float[](EmbeddingResult embeddingResult)
29+
{
30+
return embeddingResult.Data.FirstOrDefault()?.Embedding;
31+
}
32+
}
33+
34+
/// <summary>
35+
/// Data returned from the Embedding API.
36+
/// </summary>
37+
public class Data
38+
{
39+
/// <summary>
40+
/// Type of the response. In case of Data, this will be "embedding"
41+
/// </summary>
42+
[JsonProperty("object")]
43+
44+
public string Object { get; set; }
45+
46+
/// <summary>
47+
/// The input text represented as a vector (list) of floating point numbers
48+
/// </summary>
49+
[JsonProperty("embedding")]
50+
public float[] Embedding { get; set; }
51+
52+
/// <summary>
53+
/// Index
54+
/// </summary>
55+
[JsonProperty("index")]
56+
public int Index { get; set; }
57+
58+
}
59+
60+
/// <summary>
61+
/// Usage statistics of how many tokens have been used for this request.
62+
/// </summary>
63+
public class Usage
64+
{
65+
/// <summary>
66+
/// How many tokens did the prompt consist of
67+
/// </summary>
68+
[JsonProperty("prompt_tokens")]
69+
public int PromptTokens { get; set; }
70+
71+
/// <summary>
72+
/// How many tokens did the request consume total
73+
/// </summary>
74+
[JsonProperty("total_tokens")]
75+
public int TotalTokens { get; set; }
76+
77+
}
78+
79+
}

OpenAI_API/OpenAIAPI.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using OpenAI_API.Files;
2+
using Newtonsoft.Json;
3+
using OpenAI_API.Embedding;
24
using System;
35

46
namespace OpenAI_API
@@ -12,7 +14,7 @@ public class OpenAIAPI
1214
/// Base url for OpenAI
1315
/// </summary>
1416
public string ApiUrlBase = "https://api.openai.com/v1/";
15-
17+
1618
/// <summary>
1719
/// The API authentication information to use for API calls
1820
/// </summary>
@@ -28,14 +30,19 @@ public OpenAIAPI(APIAuthentication apiKeys = null)
2830
Completions = new CompletionEndpoint(this);
2931
Models = new ModelsEndpoint(this);
3032
//Search = new SearchEndpoint(this);
31-
Files = new FilesEndpoint(this);
33+
Embeddings = new EmbeddingEndpoint(this);
3234
}
3335

3436
/// <summary>
3537
/// Text generation is the core function of the API. You give the API a prompt, and it generates a completion. The way you “program” the API to do a task is by simply describing the task in plain english or providing a few written examples. This simple approach works for a wide range of use cases, including summarization, translation, grammar correction, question answering, chatbots, composing emails, and much more (see the prompt library for inspiration).
3638
/// </summary>
3739
public CompletionEndpoint Completions { get; }
3840

41+
/// <summary>
42+
/// The API lets you transform text into a vector (list) of floating point numbers. The distance between two vectors measures their relatedness. Small distances suggest high relatedness and large distances suggest low relatedness.
43+
/// </summary>
44+
public EmbeddingEndpoint Embeddings { get; }
45+
3946
/// <summary>
4047
/// The API endpoint for querying available Engines/models
4148
/// </summary>
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using NUnit.Framework;
2+
using OpenAI_API;
3+
using OpenAI_API.Embedding;
4+
using System;
5+
using System.Linq;
6+
7+
namespace OpenAI_Tests
8+
{
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+
Assert.NotNull(results.Object);
27+
Assert.NotZero(results.Data.Count);
28+
Assert.That(results.Data.First().Embedding.Length == 1536);
29+
}
30+
31+
[Test]
32+
public void GetSimpleEmbedding()
33+
{
34+
var api = new OpenAI_API.OpenAIAPI();
35+
36+
Assert.IsNotNull(api.Embeddings);
37+
38+
var results = api.Embeddings.GetEmbeddingsAsync("A test text for embedding").Result;
39+
Assert.IsNotNull(results);
40+
Assert.That(results.Length == 1536);
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)