Skip to content

Commit 13fe061

Browse files
committed
Updated embedding endpoint and result to match new composition style
1 parent 030891a commit 13fe061

File tree

5 files changed

+166
-189
lines changed

5 files changed

+166
-189
lines changed
Lines changed: 55 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,59 @@
1-
using Newtonsoft.Json;
2-
using System;
3-
using System.Collections.Generic;
4-
using System.Net.Http;
5-
using System.Security.Authentication;
6-
using System.Text;
7-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
82

93
namespace OpenAI_API.Embedding
104
{
11-
/// <summary>
12-
/// 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.
13-
/// </summary>
14-
public class EmbeddingEndpoint
15-
{
16-
OpenAIAPI Api;
17-
/// <summary>
18-
/// This allows you to send request to the recommended model without needing to specify. Every request uses the <see cref="Model.AdaTextEmbedding"/> model
19-
/// </summary>
20-
public EmbeddingRequest DefaultEmbeddingRequestArgs { get; set; } = new EmbeddingRequest() { Model = Model.AdaTextEmbedding };
21-
22-
/// <summary>
23-
/// Constructor of the api endpoint. Rather than instantiating this yourself, access it through an instance of <see cref="OpenAIAPI"/> as <see cref="OpenAIAPI.Embeddings"/>.
24-
/// </summary>
25-
/// <param name="api"></param>
26-
internal EmbeddingEndpoint(OpenAIAPI api)
27-
{
28-
this.Api = api;
29-
}
30-
31-
/// <summary>
32-
/// Ask the API to embedd text using the default embedding model <see cref="Model.AdaTextEmbedding"/>
33-
/// </summary>
34-
/// <param name="input">Text to be embedded</param>
35-
/// <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-
public async Task<EmbeddingResult> CreateEmbeddingAsync(string input)
37-
{
38-
DefaultEmbeddingRequestArgs.Input = input;
39-
return await CreateEmbeddingAsync(DefaultEmbeddingRequestArgs);
40-
}
41-
42-
/// <summary>
43-
/// Ask the API to embedd text using a custom request
44-
/// </summary>
45-
/// <param name="request">Request to be send</param>
46-
/// <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>
47-
public async Task<EmbeddingResult> CreateEmbeddingAsync(EmbeddingRequest request)
48-
{
49-
if (Api.Auth?.ApiKey is null)
50-
{
51-
throw new AuthenticationException("You must provide API authentication. Please refer to https://github.com/OkGoDoIt/OpenAI-API-dotnet#authentication for details.");
52-
}
53-
54-
HttpClient client = new HttpClient();
55-
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Api.Auth.ApiKey);
56-
client.DefaultRequestHeaders.Add("User-Agent", "okgodoit/dotnet_openai_api");
57-
58-
string jsonContent = JsonConvert.SerializeObject(request, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
59-
var stringContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
60-
61-
var response = await client.PostAsync($"https://api.openai.com/v1/embeddings", stringContent);
62-
if (response.IsSuccessStatusCode)
63-
{
64-
string resultAsString = await response.Content.ReadAsStringAsync();
65-
66-
var res = JsonConvert.DeserializeObject<EmbeddingResult>(resultAsString);
67-
68-
return res;
69-
}
70-
else
71-
{
72-
throw new HttpRequestException("Error calling OpenAi API to get completion. HTTP status code: " + response.StatusCode.ToString() + ". Request body: " + jsonContent);
73-
}
74-
}
75-
76-
}
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+
}
7759
}
Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,51 @@
11
using Newtonsoft.Json;
2-
using System;
3-
using System.Collections.Generic;
4-
using System.Text;
52

63
namespace OpenAI_API.Embedding
74
{
8-
/// <summary>
9-
/// 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>
10-
/// </summary>
11-
public class EmbeddingRequest
12-
{
13-
/// <summary>
14-
/// 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"/>.
15-
/// </summary>
16-
[JsonIgnore]
17-
public Model Model { get; set; }
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; }
1815

19-
/// <summary>
20-
/// The id/name of the model
21-
/// </summary>
22-
[JsonProperty("model")]
23-
public string ModelName => Model.ModelID;
16+
/// <summary>
17+
/// Main text to be embedded
18+
/// </summary>
19+
[JsonProperty("input")]
20+
public string Input { get; set; }
2421

25-
/// <summary>
26-
/// Main text to be embedded
27-
/// </summary>
28-
[JsonProperty("input")]
29-
public string Input { get; set; }
22+
/// <summary>
23+
/// Cretes a new, empty <see cref="EmbeddingRequest"/>
24+
/// </summary>
25+
public EmbeddingRequest()
26+
{
3027

31-
/// <summary>
32-
/// Cretes a new, empty <see cref="EmbeddingRequest"/>
33-
/// </summary>
34-
public EmbeddingRequest()
35-
{
28+
}
3629

37-
}
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+
}
3840

39-
/// <summary>
40-
/// Creates a new <see cref="EmbeddingRequest"/> with the specified parameters
41-
/// </summary>
42-
/// <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>
43-
/// <param name="input">The prompt to transform</param>
44-
public EmbeddingRequest(Model model, string input)
45-
{
46-
Model = model;
47-
this.Input = input;
48-
}
49-
}
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+
}
5051
}
Lines changed: 62 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,78 @@
11
using Newtonsoft.Json;
2-
using System;
3-
using System.Collections.Generic;
4-
using System.Text;
2+
using System.Linq;
53

64
namespace OpenAI_API.Embedding
75
{
8-
/// <summary>
9-
/// Represents an embedding result returned by the Embedding API.
10-
/// </summary>
11-
public class EmbeddingResult
12-
{
13-
/// <summary>
14-
/// Type of the response. In case of embeddings, this will be "list"
15-
/// </summary>
16-
[JsonProperty("object")]
6+
/// <summary>
7+
/// Represents an embedding result returned by the Embedding API.
8+
/// </summary>
9+
public class EmbeddingResult : ApiResultBase
10+
{
11+
/// <summary>
12+
/// List of results of the embedding
13+
/// </summary>
14+
[JsonProperty("data")]
15+
public Data[] Data { get; set; }
1716

18-
public string Object { get; set; }
17+
/// <summary>
18+
/// Usage statistics of how many tokens have been used for this request
19+
/// </summary>
20+
[JsonProperty("usage")]
21+
public Usage Usage { get; set; }
1922

20-
/// <summary>
21-
/// List of results of the embedding
22-
/// </summary>
23-
[JsonProperty("data")]
24-
public Data[] Data { get; set; }
23+
/// <summary>
24+
/// Allows an EmbeddingResult to be implicitly cast to the array of floats repsresenting the first ebmedding result
25+
/// </summary>
26+
/// <param name="embeddingResult">The <see cref="EmbeddingResult"/> to cast to an array of floats.</param>
27+
public static implicit operator float[](EmbeddingResult embeddingResult)
28+
{
29+
return embeddingResult.Data.FirstOrDefault()?.Embedding;
30+
}
31+
}
2532

26-
/// <summary>
27-
/// Name of the model used to generate this embedding
28-
/// </summary>
29-
[JsonProperty("model")]
30-
public string Model { get; set; }
33+
/// <summary>
34+
/// Data returned from the Embedding API.
35+
/// </summary>
36+
public class Data
37+
{
38+
/// <summary>
39+
/// Type of the response. In case of Data, this will be "embedding"
40+
/// </summary>
41+
[JsonProperty("object")]
3142

32-
/// <summary>
33-
/// Usage statistics of how many tokens have been used for this request
34-
/// </summary>
35-
[JsonProperty("usage")]
36-
public Usage Usage { get; set; }
37-
}
43+
public string Object { get; set; }
3844

39-
/// <summary>
40-
/// Data returned from the Embedding API.
41-
/// </summary>
42-
public class Data
43-
{
44-
/// <summary>
45-
/// Type of the response. In case of Data, this will be "embedding"
46-
/// </summary>
47-
[JsonProperty("object")]
45+
/// <summary>
46+
/// The input text represented as a vector (list) of floating point numbers
47+
/// </summary>
48+
[JsonProperty("embedding")]
49+
public float[] Embedding { get; set; }
4850

49-
public string Object { get; set; }
51+
/// <summary>
52+
/// Index
53+
/// </summary>
54+
[JsonProperty("index")]
55+
public int Index { get; set; }
5056

51-
/// <summary>
52-
/// The input text represented as a vector (list) of floating point numbers
53-
/// </summary>
54-
[JsonProperty("embedding")]
55-
public float[] Embedding { get; set; }
57+
}
5658

57-
/// <summary>
58-
/// Index
59-
/// </summary>
60-
[JsonProperty("index")]
61-
public int Index { get; set; }
59+
/// <summary>
60+
/// Usage statistics of how many tokens have been used for this request.
61+
/// </summary>
62+
public class Usage
63+
{
64+
/// <summary>
65+
/// How many tokens did the prompt consist of
66+
/// </summary>
67+
[JsonProperty("prompt_tokens")]
68+
public int PromptTokens { get; set; }
6269

63-
}
70+
/// <summary>
71+
/// How many tokens did the request consume total
72+
/// </summary>
73+
[JsonProperty("total_tokens")]
74+
public int TotalTokens { get; set; }
6475

65-
/// <summary>
66-
/// Usage statistics of how many tokens have been used for this request.
67-
/// </summary>
68-
public class Usage
69-
{
70-
/// <summary>
71-
/// How many tokens did the prompt consist of
72-
/// </summary>
73-
[JsonProperty("prompt_tokens")]
74-
public int PromptTokens { get; set; }
75-
76-
/// <summary>
77-
/// How many tokens did the request consume total
78-
/// </summary>
79-
[JsonProperty("total_tokens")]
80-
public int TotalTokens { get; set; }
81-
82-
}
76+
}
8377

8478
}

OpenAI_API/OpenAIAPI.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ namespace OpenAI_API
1010
/// </summary>
1111
public class OpenAIAPI
1212
{
13+
/// <summary>
14+
/// Base url for OpenAI
15+
/// </summary>
16+
public string ApiUrlBase = "https://api.openai.com/v1/";
17+
1318
/// <summary>
1419
/// The API authentication information to use for API calls
1520
/// </summary>
@@ -24,7 +29,7 @@ public OpenAIAPI(APIAuthentication apiKeys = null)
2429
this.Auth = apiKeys.ThisOrDefault();
2530
Completions = new CompletionEndpoint(this);
2631
Models = new ModelsEndpoint(this);
27-
Search = new SearchEndpoint(this);
32+
//Search = new SearchEndpoint(this);
2833
Embeddings = new EmbeddingEndpoint(this);
2934
}
3035

0 commit comments

Comments
 (0)