diff --git a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj
index 57d627f8..3fda3adf 100644
--- a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj
+++ b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj
@@ -10,7 +10,7 @@
Betalgo-Ranul-OpenAI-icon.png
true
OpenAI SDK by Betalgo
- 8.9.0
+ 8.10.0
Tolga Kayhan, Betalgo
Betalgo Up Ltd.
OpenAI .NET library by Betalgo Ranul
@@ -74,4 +74,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/OpenAI.SDK/Managers/OpenAIChatClient.cs b/OpenAI.SDK/Managers/OpenAIChatClient.cs
new file mode 100644
index 00000000..57ba3117
--- /dev/null
+++ b/OpenAI.SDK/Managers/OpenAIChatClient.cs
@@ -0,0 +1,390 @@
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using Betalgo.Ranul.OpenAI.ObjectModels;
+using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
+using Betalgo.Ranul.OpenAI.ObjectModels.ResponseModels;
+using Betalgo.Ranul.OpenAI.ObjectModels.SharedModels;
+using Microsoft.Extensions.AI;
+using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
+
+namespace Betalgo.Ranul.OpenAI.Managers;
+
+public partial class OpenAIService : IChatClient
+{
+ private ChatClientMetadata? _chatMetadata;
+
+ ///
+ ChatClientMetadata IChatClient.Metadata => _chatMetadata ??= new(nameof(OpenAIService), _httpClient.BaseAddress, _defaultModelId);
+
+ ///
+ TService? IChatClient.GetService(object? key) where TService : class
+ {
+ return this as TService;
+ }
+
+ ///
+ void IDisposable.Dispose()
+ {
+ }
+
+ ///
+ async Task IChatClient.CompleteAsync(IList chatMessages, ChatOptions? options, CancellationToken cancellationToken)
+ {
+ var request = CreateRequest(chatMessages, options);
+
+ var response = await ChatCompletion.CreateCompletion(request, options?.ModelId, cancellationToken);
+ ThrowIfNotSuccessful(response);
+
+ string? finishReason = null;
+ List responseMessages = [];
+ foreach (var choice in response.Choices)
+ {
+ finishReason ??= choice.FinishReason;
+
+ ChatMessage m = new()
+ {
+ Role = new(choice.Message.Role),
+ AuthorName = choice.Message.Name,
+ RawRepresentation = choice
+ };
+
+ PopulateContents(choice.Message, m.Contents);
+
+ if (response.ServiceTier is string serviceTier)
+ {
+ (m.AdditionalProperties ??= [])[nameof(response.ServiceTier)] = serviceTier;
+ }
+
+ if (response.SystemFingerPrint is string fingerprint)
+ {
+ (m.AdditionalProperties ??= [])[nameof(response.SystemFingerPrint)] = fingerprint;
+ }
+
+ responseMessages.Add(m);
+ }
+
+ return new(responseMessages)
+ {
+ CreatedAt = response.CreatedAt,
+ CompletionId = response.Id,
+ FinishReason = finishReason is not null ? new(finishReason) : null,
+ ModelId = response.Model,
+ RawRepresentation = response,
+ Usage = response.Usage is { } usage ? GetUsageDetails(usage) : null
+ };
+ }
+
+ ///
+ async IAsyncEnumerable IChatClient.CompleteStreamingAsync(IList chatMessages, ChatOptions? options, [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ var request = CreateRequest(chatMessages, options);
+
+ await foreach (var response in ChatCompletion.CreateCompletionAsStream(request, options?.ModelId, cancellationToken: cancellationToken))
+ {
+ ThrowIfNotSuccessful(response);
+
+ foreach (var choice in response.Choices)
+ {
+ StreamingChatCompletionUpdate update = new()
+ {
+ AuthorName = choice.Delta.Name,
+ CompletionId = response.Id,
+ CreatedAt = response.CreatedAt,
+ FinishReason = choice.FinishReason is not null ? new(choice.FinishReason) : null,
+ ModelId = response.Model,
+ RawRepresentation = response,
+ Role = choice.Delta.Role is not null ? new(choice.Delta.Role) : null
+ };
+
+ if (choice.Index is not null)
+ {
+ update.ChoiceIndex = choice.Index.Value;
+ }
+
+ if (response.ServiceTier is string serviceTier)
+ {
+ (update.AdditionalProperties ??= [])[nameof(response.ServiceTier)] = serviceTier;
+ }
+
+ if (response.SystemFingerPrint is string fingerprint)
+ {
+ (update.AdditionalProperties ??= [])[nameof(response.SystemFingerPrint)] = fingerprint;
+ }
+
+ PopulateContents(choice.Delta, update.Contents);
+
+ yield return update;
+
+ if (response.Usage is { } usage)
+ {
+ yield return new()
+ {
+ AuthorName = choice.Delta.Name,
+ CompletionId = response.Id,
+ Contents = [new UsageContent(GetUsageDetails(usage))],
+ CreatedAt = response.CreatedAt,
+ FinishReason = choice.FinishReason is not null ? new(choice.FinishReason) : null,
+ ModelId = response.Model,
+ Role = choice.Delta.Role is not null ? new(choice.Delta.Role) : null
+ };
+ }
+ }
+ }
+ }
+
+ private static void ThrowIfNotSuccessful(ChatCompletionCreateResponse response)
+ {
+ if (!response.Successful)
+ {
+ throw new InvalidOperationException(response.Error is { } error ? $"{response.Error.Code}: {response.Error.Message}" : "Betalgo.Ranul Unknown error");
+ }
+ }
+
+ private ChatCompletionCreateRequest CreateRequest(IList chatMessages, ChatOptions? options)
+ {
+ ChatCompletionCreateRequest request = new()
+ {
+ Model = options?.ModelId ?? _defaultModelId
+ };
+
+ if (options is not null)
+ {
+ // Strongly-typed properties from options
+ request.MaxCompletionTokens = options.MaxOutputTokens;
+ request.Temperature = options.Temperature;
+ request.TopP = options.TopP;
+ request.FrequencyPenalty = options.FrequencyPenalty;
+ request.PresencePenalty = options.PresencePenalty;
+ request.StopAsList = options.StopSequences;
+
+ // Non-strongly-typed properties from additional properties
+ request.LogitBias = options.AdditionalProperties?.TryGetValue(nameof(request.LogitBias), out var logitBias) is true ? logitBias : null;
+ request.LogProbs = options.AdditionalProperties?.TryGetValue(nameof(request.LogProbs), out bool logProbs) is true ? logProbs : null;
+ request.N = options.AdditionalProperties?.TryGetValue(nameof(request.N), out int n) is true ? n : null;
+ request.ParallelToolCalls = options.AdditionalProperties?.TryGetValue(nameof(request.ParallelToolCalls), out bool parallelToolCalls) is true ? parallelToolCalls : null;
+ request.Seed = options.AdditionalProperties?.TryGetValue(nameof(request.Seed), out int seed) is true ? seed : null;
+ request.ServiceTier = options.AdditionalProperties?.TryGetValue(nameof(request.ServiceTier), out string? serviceTier) is true ? serviceTier : null!;
+ request.User = options.AdditionalProperties?.TryGetValue(nameof(request.User), out string? user) is true ? user : null!;
+ request.TopLogprobs = options.AdditionalProperties?.TryGetValue(nameof(request.TopLogprobs), out int topLogprobs) is true ? topLogprobs : null;
+
+ // Response format
+ switch (options.ResponseFormat)
+ {
+ case ChatResponseFormatText:
+ request.ResponseFormat = new() { Type = StaticValues.CompletionStatics.ResponseFormat.Text };
+ break;
+
+ case ChatResponseFormatJson { Schema: not null } json:
+ request.ResponseFormat = new()
+ {
+ Type = StaticValues.CompletionStatics.ResponseFormat.JsonSchema,
+ JsonSchema = new()
+ {
+ Name = json.SchemaName ?? "JsonSchema",
+ Schema = JsonSerializer.Deserialize(json.Schema),
+ Description = json.SchemaDescription
+ }
+ };
+ break;
+
+ case ChatResponseFormatJson:
+ request.ResponseFormat = new() { Type = StaticValues.CompletionStatics.ResponseFormat.Json };
+ break;
+ }
+
+ // Tools
+ request.Tools = options.Tools
+ ?.OfType()
+ .Select(f =>
+ {
+ return ToolDefinition.DefineFunction(new()
+ {
+ Name = f.Metadata.Name,
+ Description = f.Metadata.Description,
+ Parameters = CreateParameters(f)
+ });
+ })
+ .ToList() is { Count: > 0 } tools
+ ? tools
+ : null;
+ if (request.Tools is not null)
+ {
+ request.ToolChoice = options.ToolMode is RequiredChatToolMode r ? new()
+ {
+ Type = StaticValues.CompletionStatics.ToolChoiceType.Required,
+ Function = r.RequiredFunctionName is null ? null : new ToolChoice.FunctionTool() { Name = r.RequiredFunctionName }
+ } :
+ options.ToolMode is AutoChatToolMode ? new() { Type = StaticValues.CompletionStatics.ToolChoiceType.Auto } : new ToolChoice() { Type = StaticValues.CompletionStatics.ToolChoiceType.None };
+ }
+ }
+
+ // Messages
+ request.Messages = [];
+ foreach (var message in chatMessages)
+ {
+ foreach (var content in message.Contents)
+ {
+ switch (content)
+ {
+ case TextContent tc:
+ request.Messages.Add(new()
+ {
+ Content = tc.Text,
+ Name = message.AuthorName,
+ Role = message.Role.ToString()
+ });
+ break;
+
+ case ImageContent ic:
+ request.Messages.Add(new()
+ {
+ Contents =
+ [
+ new()
+ {
+ Type = "image_url",
+ ImageUrl = new()
+ {
+ Url = ic.Uri,
+ Detail = ic.AdditionalProperties?.TryGetValue(nameof(MessageImageUrl.Detail), out string? detail) is true ? detail : null
+ }
+ }
+ ],
+ Name = message.AuthorName,
+ Role = message.Role.ToString()
+ });
+ break;
+
+ case FunctionResultContent frc:
+ request.Messages.Add(new()
+ {
+ ToolCallId = frc.CallId,
+ Content = frc.Result?.ToString(),
+ Name = message.AuthorName,
+ Role = message.Role.ToString()
+ });
+ break;
+ }
+ }
+
+ var functionCallContents = message.Contents.OfType().ToArray();
+ if (functionCallContents.Length > 0)
+ {
+ request.Messages.Add(new()
+ {
+ Name = message.AuthorName,
+ Role = message.Role.ToString(),
+ ToolCalls = functionCallContents.Select(fcc => new ToolCall()
+ {
+ Type = "function",
+ Id = fcc.CallId,
+ FunctionCall = new()
+ {
+ Name = fcc.Name,
+ Arguments = JsonSerializer.Serialize(fcc.Arguments)
+ }
+ })
+ .ToList()
+ });
+ }
+ }
+
+ return request;
+ }
+
+ private static PropertyDefinition CreateParameters(AIFunction f)
+ {
+ List required = [];
+ Dictionary properties = [];
+
+ var parameters = f.Metadata.Parameters;
+
+ foreach (var parameter in parameters)
+ {
+ properties.Add(parameter.Name, parameter.Schema is JsonElement e ? e.Deserialize()! : PropertyDefinition.DefineObject(null, null, null, null, null));
+
+ if (parameter.IsRequired)
+ {
+ required.Add(parameter.Name);
+ }
+ }
+
+ return PropertyDefinition.DefineObject(properties, required, null, null, null);
+ }
+
+ private static void PopulateContents(ObjectModels.RequestModels.ChatMessage source, IList destination)
+ {
+ if (source.Content is not null)
+ {
+ destination.Add(new TextContent(source.Content));
+ }
+
+ if (source.Contents is { } contents)
+ {
+ foreach (var content in contents)
+ {
+ if (content.Text is string text)
+ {
+ destination.Add(new TextContent(text));
+ }
+
+ if (content.ImageUrl is { } url)
+ {
+ destination.Add(new ImageContent(url.Url));
+ }
+ }
+ }
+
+ if (source.ToolCalls is { } toolCalls)
+ {
+ foreach (var tc in toolCalls)
+ {
+ destination.Add(new FunctionCallContent(tc.Id ?? string.Empty, tc.FunctionCall?.Name ?? string.Empty, tc.FunctionCall?.Arguments is string a ? JsonSerializer.Deserialize>(a) : null));
+ }
+ }
+ }
+
+ private static UsageDetails GetUsageDetails(UsageResponse usage)
+ {
+ var details = new UsageDetails()
+ {
+ InputTokenCount = usage.PromptTokens,
+ OutputTokenCount = usage.CompletionTokens,
+ TotalTokenCount = usage.TotalTokens
+ };
+
+ if (usage.PromptTokensDetails is { } promptDetails)
+ {
+ Dictionary d = new(StringComparer.OrdinalIgnoreCase);
+ (details.AdditionalProperties ??= [])[nameof(usage.PromptTokensDetails)] = d;
+
+ if (promptDetails.CachedTokens is int cachedTokens)
+ {
+ d[nameof(promptDetails.CachedTokens)] = cachedTokens;
+ }
+
+ if (promptDetails.AudioTokens is int audioTokens)
+ {
+ d[nameof(promptDetails.AudioTokens)] = audioTokens;
+ }
+ }
+
+ if (usage.CompletionTokensDetails is { } completionDetails)
+ {
+ Dictionary d = new(StringComparer.OrdinalIgnoreCase);
+ (details.AdditionalProperties ??= [])[nameof(usage.CompletionTokensDetails)] = d;
+
+ if (completionDetails.ReasoningTokens is int reasoningTokens)
+ {
+ d[nameof(completionDetails.ReasoningTokens)] = reasoningTokens;
+ }
+
+ if (completionDetails.AudioTokens is int audioTokens)
+ {
+ d[nameof(promptDetails.AudioTokens)] = audioTokens;
+ }
+ }
+
+ return details;
+ }
+}
\ No newline at end of file
diff --git a/OpenAI.SDK/Managers/OpenAIEmbeddingGenerator.cs b/OpenAI.SDK/Managers/OpenAIEmbeddingGenerator.cs
new file mode 100644
index 00000000..4b7e5717
--- /dev/null
+++ b/OpenAI.SDK/Managers/OpenAIEmbeddingGenerator.cs
@@ -0,0 +1,41 @@
+using Microsoft.Extensions.AI;
+
+namespace Betalgo.Ranul.OpenAI.Managers;
+
+public partial class OpenAIService : IEmbeddingGenerator>
+{
+ private EmbeddingGeneratorMetadata? _embeddingMetadata;
+
+ EmbeddingGeneratorMetadata IEmbeddingGenerator>.Metadata =>
+ _embeddingMetadata ??= new(nameof(OpenAIService), _httpClient.BaseAddress, _defaultModelId);
+
+ TService? IEmbeddingGenerator>.GetService(object? key) where TService : class =>
+ this as TService;
+
+ async Task>> IEmbeddingGenerator>.GenerateAsync(IEnumerable values, EmbeddingGenerationOptions? options, CancellationToken cancellationToken)
+ {
+ var response = await this.Embeddings.CreateEmbedding(new()
+ {
+ Model = options?.ModelId ?? _defaultModelId,
+ Dimensions = options?.Dimensions,
+ InputAsList = values.ToList(),
+ }, cancellationToken);
+
+ if (!response.Successful)
+ {
+ throw new InvalidOperationException(response.Error is { } error ?
+ $"{response.Error.Code}: {response.Error.Message}" :
+ "Betalgo.Ranul Unknown error");
+ }
+
+ return new(response.Data.Select(e => new Embedding(e.Embedding.Select(d => (float)d).ToArray()) { ModelId = response.Model }))
+ {
+ Usage = response.Usage is { } usage ? new()
+ {
+ InputTokenCount = usage.PromptTokens,
+ OutputTokenCount = usage.CompletionTokens,
+ TotalTokenCount = usage.TotalTokens,
+ } : null,
+ };
+ }
+}
\ No newline at end of file
diff --git a/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs
index 4763a194..af60d842 100644
--- a/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs
+++ b/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs
@@ -308,4 +308,17 @@ public IEnumerable Validate()
///
[JsonPropertyName("service_tier")]
public string? ServiceTier { get; set; }
-}
\ No newline at end of file
+
+
+ ///
+ /// Whether or not to store the output of this chat completion request for use in our model distillation or evals products.
+ /// https://platform.openai.com/docs/api-reference/chat/create?lang=python#chat-create-store
+ ///
+ ///
+ /// more about distillation: https://platform.openai.com/docs/guides/distillation
+ ///
+ /// more about evals: https://platform.openai.com/docs/guides/evals
+ ///
+ [JsonPropertyName("store")]
+ public bool? Store { get; set; } = false;
+}
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/BatchResponseModel/BatchResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/BatchResponseModel/BatchResponse.cs
index 8d2512e3..714fb9ff 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/BatchResponseModel/BatchResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/BatchResponseModel/BatchResponse.cs
@@ -53,7 +53,12 @@ public record BatchResponse : BaseResponse, IOpenAIModels.IMetaData
/// The Unix timestamp (in seconds) for when the batch was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// DateTimeOffset for when the batch was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The Unix timestamp (in seconds) for when the batch started processing.
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/ChatCompletionCreateResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/ChatCompletionCreateResponse.cs
index c4207770..8bd01d3a 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/ChatCompletionCreateResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/ChatCompletionCreateResponse.cs
@@ -38,11 +38,10 @@ public record ChatCompletionCreateResponse : BaseResponse, IOpenAIModels.IId, IO
[JsonPropertyName("service_tier")]
public string? ServiceTier { get; set; }
- ///
- /// The Unix timestamp (in seconds) of when the chat completion was created.
- ///
[JsonPropertyName("created")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// A unique identifier for the chat completion.
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/CompletionCreateResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/CompletionCreateResponse.cs
index c4165a1a..05a94c83 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/CompletionCreateResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/CompletionCreateResponse.cs
@@ -15,7 +15,9 @@ public record CompletionCreateResponse : BaseResponse, IOpenAIModels.IId, IOpenA
public UsageResponse Usage { get; set; }
[JsonPropertyName("created")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
[JsonPropertyName("id")]
public string Id { get; set; }
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/EditCreateResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/EditCreateResponse.cs
index 8e933fca..2064d42a 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/EditCreateResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/EditCreateResponse.cs
@@ -15,5 +15,7 @@ public record EditCreateResponse : BaseResponse, IOpenAIModels.ICreatedAt
public UsageResponse Usage { get; set; }
[JsonPropertyName("created")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
}
\ No newline at end of file
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FileResponseModels/FileUploadResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FileResponseModels/FileUploadResponse.cs
index 652c0615..585be3f3 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/FileResponseModels/FileUploadResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/FileResponseModels/FileUploadResponse.cs
@@ -18,5 +18,7 @@ public record FileUploadResponse : BaseResponse, IOpenAIModels.ICreatedAt
public string Purpose { get; set; }
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
}
\ No newline at end of file
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuneResponseModels/FineTuneResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuneResponseModels/FineTuneResponse.cs
index f75e5305..8f3eca59 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuneResponseModels/FineTuneResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuneResponseModels/FineTuneResponse.cs
@@ -33,7 +33,9 @@ public record FineTuneResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels.
public int? UpdatedAt { get; set; }
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
[JsonPropertyName("id")]
public string Id { get; set; }
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs
index c7aa4c78..b3f940a8 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs
@@ -67,7 +67,12 @@ public record FineTuningJobResponse : BaseResponse, IOpenAIModels.IId, IOpenAIMo
/// The Unix timestamp (in seconds) for when the fine-tuning job was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// for when the fine-tuning job was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The object identifier, which can be referenced in the API endpoints.
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/ImageResponseModel/ImageCreateResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/ImageResponseModel/ImageCreateResponse.cs
index db02d838..4542c5b3 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/ImageResponseModel/ImageCreateResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/ImageResponseModel/ImageCreateResponse.cs
@@ -9,7 +9,8 @@ public record ImageCreateResponse : BaseResponse, IOpenAIModels.ICreatedAt
public List Results { get; set; }
[JsonPropertyName("created")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
public record ImageDataResult
{
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/RunStepListResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/RunStepListResponse.cs
index 41be6e64..5b9946a4 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/RunStepListResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/RunStepListResponse.cs
@@ -93,7 +93,9 @@ public record RunStepResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels.I
/// The Unix timestamp (in seconds) for when the run step was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The identifier of the run step, which can be referenced in API endpoints.
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileBatchObject.cs b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileBatchObject.cs
index 60229ad4..e3643682 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileBatchObject.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileBatchObject.cs
@@ -15,7 +15,11 @@ public record VectorStoreFileBatchObject : BaseResponse
/// The Unix timestamp (in seconds) for when the vector store files batch was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+ ///
+ /// for when the vector store files batch was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The ID of the [vector store](/docs/api-reference/vector-stores/object) that the [File](/docs/api-reference/files)
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileObject.cs b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileObject.cs
index d26dcb60..e0d77be1 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileObject.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreFileObject.cs
@@ -26,7 +26,12 @@ public record VectorStoreFileObject : BaseResponse
/// The Unix timestamp (in seconds) for when the vector store file was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// for when the vector store file was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The ID of the [vector store](/docs/api-reference/vector-stores/object) that the [File](/docs/api-reference/files)
diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreObjectResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreObjectResponse.cs
index b56b9ed6..46e79bc3 100644
--- a/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreObjectResponse.cs
+++ b/OpenAI.SDK/ObjectModels/ResponseModels/VectorStoreResponseModels/VectorStoreObjectResponse.cs
@@ -15,7 +15,12 @@ public record VectorStoreObjectResponse : BaseResponse
/// The Unix timestamp (in seconds) for when the vector store was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// for when the vector store was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The name of the vector store.
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/AssistantFileResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/AssistantFileResponse.cs
index 98ad7930..9fe7166c 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/AssistantFileResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/AssistantFileResponse.cs
@@ -15,7 +15,9 @@ public record AssistantFileResponse : BaseResponse, IOpenAIModels.IId, IOpenAIMo
/// The Unix timestamp (in seconds) for when the assistant file was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The identifier, which can be referenced in API endpoints.
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/AssistantResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/AssistantResponse.cs
index 82d2f3eb..268e4947 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/AssistantResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/AssistantResponse.cs
@@ -58,11 +58,29 @@ public record AssistantResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels
[JsonPropertyName("response_format")]
public ResponseFormatOneOfType ResponseFormatOneOfType { get; set; }
+ ///
+ /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while
+ /// lower values like 0.2 will make it more focused and deterministic.
+ ///
+ [JsonPropertyName("temperature")]
+ public float? Temperature { get; set; }
+
+ ///
+ /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the
+ /// tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are
+ /// considered.
+ /// We generally recommend altering this or temperature but not both.
+ ///
+ [JsonPropertyName("top_p")]
+ public double? TopP { get; set; }
+
///
/// The Unix timestamp (in seconds) for when the assistant was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The identifier, which can be referenced in API endpoints.
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs
index ae0d6766..35b6f06f 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs
@@ -2,7 +2,7 @@
namespace Betalgo.Ranul.OpenAI.ObjectModels.SharedModels;
-public record EventResponse
+public record EventResponse:IOpenAIModels.ICreatedAt
{
[JsonPropertyName("object")]
public string? ObjectTypeName { get; set; }
@@ -11,7 +11,9 @@ public record EventResponse
public string? Id { get; set; }
[JsonPropertyName("created_at")]
- public int? CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
+
[JsonPropertyName("level")]
public string Level { get; set; }
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FileResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/FileResponse.cs
index 3c8f9ccb..97f90049 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/FileResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/FileResponse.cs
@@ -20,7 +20,9 @@ public record FileResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels.ICre
public string Status { get; set; }
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
[JsonPropertyName("id")]
public string Id { get; set; }
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/IOpenAiModels.cs b/OpenAI.SDK/ObjectModels/SharedModels/IOpenAiModels.cs
index ad402598..10aaba7c 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/IOpenAiModels.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/IOpenAiModels.cs
@@ -36,7 +36,8 @@ public interface IAssistantId
public interface ICreatedAt
{
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+ public DateTimeOffset CreatedAt { get; }
}
public interface ICompletedAt
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/MessageResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/MessageResponse.cs
index 1a6ac767..1d2c5cc5 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/MessageResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/MessageResponse.cs
@@ -14,6 +14,7 @@ public MessageResponse Delta
{
set => Content = value.Content;
}
+
///
/// The thread ID that this message belongs to.
///
@@ -82,7 +83,11 @@ public MessageResponse Delta
/// The Unix timestamp (in seconds) for when the message was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+ ///
+ /// for when the message was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The identifier, which can be referenced in API endpoints.
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/RunResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/RunResponse.cs
index 93205b0f..19568ed5 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/RunResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/RunResponse.cs
@@ -143,7 +143,12 @@ public record RunResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels.IMode
/// The Unix timestamp (in seconds) for when the run was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// for when the run was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The list of File IDs the assistant used for this run.
diff --git a/OpenAI.SDK/ObjectModels/SharedModels/ThreadResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/ThreadResponse.cs
index cb97217d..c8c7e209 100644
--- a/OpenAI.SDK/ObjectModels/SharedModels/ThreadResponse.cs
+++ b/OpenAI.SDK/ObjectModels/SharedModels/ThreadResponse.cs
@@ -18,7 +18,12 @@ public record ThreadResponse : BaseResponse, IOpenAIModels.IId, IOpenAIModels.IC
/// The Unix timestamp (in seconds) for when the assistant was created.
///
[JsonPropertyName("created_at")]
- public int CreatedAt { get; set; }
+ public long CreatedAtUnix { get; set; }
+
+ ///
+ /// for when the assistant was created.
+ ///
+ public DateTimeOffset CreatedAt => DateTimeOffset.FromUnixTimeSeconds(CreatedAtUnix);
///
/// The identifier, which can be referenced in API endpoints.
diff --git a/OpenAI.UtilitiesPlayground/OpenAI.UtilitiesPlayground.csproj b/OpenAI.UtilitiesPlayground/OpenAI.UtilitiesPlayground.csproj
index 9d21e5ac..488bebec 100644
--- a/OpenAI.UtilitiesPlayground/OpenAI.UtilitiesPlayground.csproj
+++ b/OpenAI.UtilitiesPlayground/OpenAI.UtilitiesPlayground.csproj
@@ -18,6 +18,7 @@
+
diff --git a/Readme.md b/Readme.md
index 7767efa6..1d9e8102 100644
--- a/Readme.md
+++ b/Readme.md
@@ -117,6 +117,14 @@ Due to time constraints, not all methods have been thoroughly tested or fully do
Needless to say, I cannot accept responsibility for any damage caused by using the library.
## Changelog
+### 8.10.0
+- Added support for `Microsoft.Extensions.AI` `IChatClient` and `IEmbeddingGenerator` (more information will be coming soon to the Wiki).
+- Added missing `Temperature` and `TopP` parameters to `AssistantResponse`.
+- Added missing `Store` parameter to `ChatCompletionCreateRequest`.
+
+- Breaking Changes:
+ - ⚠️ `CreatedAt` parameter renamed to `CreatedAtUnix` and converted to `long` instead of `int`. Added `CreatedAt` parameter as `DateTimeOffset` type, which will automatically convert Unix time to `DateTime`.
+
### 8.9.0
- Realtime API implementation is completed. As usual this is the first version and it may contain bugs. Please report any issues you encounter.
- [Realtime Sample](https://github.com/betalgo/openai/wiki/realtime)