From 1f15857ec0dfee687a7810ba111c31496e9bd1b7 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:43:45 -0700 Subject: [PATCH 01/13] Create ObjectModels to support new Fine Tuning Job https://platform.openai.com/docs/api-reference/fine-tuning --- .../FineTuningJobCancelRequest.cs | 9 ++ .../FineTuningJobCreateRequest.cs | 122 ++++++++++++++++++ .../FineTuningJobListEventsResponse.cs | 11 ++ .../FineTuningJobListResponse.cs | 10 ++ .../FineTuningJobResponse.cs | 49 +++++++ 5 files changed, 201 insertions(+) create mode 100644 OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCancelRequest.cs create mode 100644 OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs create mode 100644 OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs create mode 100644 OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs create mode 100644 OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs diff --git a/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCancelRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCancelRequest.cs new file mode 100644 index 00000000..75f7c19d --- /dev/null +++ b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCancelRequest.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.RequestModels; + +public record FineTuningJobCancelRequest +{ + [JsonPropertyName("fine_tuning_job_id")] + public string FineTuningJobId { get; set; } +} \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs new file mode 100644 index 00000000..b9f87c6b --- /dev/null +++ b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs @@ -0,0 +1,122 @@ +using OpenAI.ObjectModels.SharedModels; +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.RequestModels; + +public record FineTuningJobCreateRequest : IOpenAiModels.IModel +{ + /// + /// The ID of an uploaded file that contains training data. + /// See upload file for how to upload a file. + /// Your dataset must be formatted as a JSONL file, where each training example is a JSON object with the keys "prompt" + /// and "completion". Additionally, you must upload your file with the purpose fine-tune. + /// See the fine-tuning guide + /// for + /// more details. + /// + [JsonPropertyName("training_file")] + public string TrainingFile { get; set; } + + /// + /// The ID of an uploaded file that contains validation data. + /// If you provide this file, the data is used to generate validation metrics periodically during fine-tuning. These + /// metrics can be viewed in the + /// + /// fine-tuning results + /// file + /// + /// . Your train and validation data should be mutually exclusive. + /// Your dataset must be formatted as a JSONL file, where each validation example is a JSON object with the keys + /// "prompt" and "completion". Additionally, you must upload your file with the purpose fine-tune. + /// See the fine-tuning guide + /// for + /// more details. + /// + [JsonPropertyName("validation_file")] + public string? ValidationFile { get; set; } + + /// + /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. + /// + [JsonPropertyName("n_epochs")] + public int? NEpochs { get; set; } + + /// + /// The batch size to use for training. The batch size is the number of training examples used to train a single + /// forward and backward pass. + /// By default, the batch size will be dynamically configured to be ~0.2% of the number of examples in the training + /// set, capped at 256 - in general, we've found that larger batch sizes tend to work better for larger datasets. + /// + [JsonPropertyName("batch_size")] + public int? BatchSize { get; set; } + + /// + /// The learning rate multiplier to use for training. The fine-tuning learning rate is the original learning rate used + /// for pretraining multiplied by this value. + /// By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final batch_size(larger learning + /// rates tend to perform better with larger batch sizes). We recommend experimenting with values in the range 0.02 to + /// 0.2 to see what produces the best results. + /// + [JsonPropertyName("learning_rate_multiplier")] + public float? LearningRateMultiplier { get; set; } + + /// + /// The weight to use for loss on the prompt tokens. This controls how much the model tries to learn to generate the + /// prompt (as compared to the completion which always has a weight of 1.0), and can add a stabilizing effect to + /// training when completions are short. + /// If prompts are extremely long (relative to completions), it may make sense to reduce this weight so as to avoid + /// over-prioritizing learning the prompt. + /// + [JsonPropertyName("prompt_loss_weight")] + public float? PromptLossWeight { get; set; } + + /// + /// If set, we calculate classification-specific metrics such as accuracy and F-1 score using the validation set at the + /// end of every epoch.These metrics can be viewed in the + /// results file. + /// In order to compute classification metrics, you must provide a validation_file.Additionally, you must specify + /// classification_n_classes for multiclass classification or classification_positive_class for binary classification. + /// + [JsonPropertyName("compute_classification_metrics")] + public bool? ComputeClassificationMetrics { get; set; } + + /// + /// The number of classes in a classification task. + /// This parameter is required for multiclass classification. + /// + [JsonPropertyName("classification_n_classes")] + public int? ClassificationNClasses { get; set; } + + /// + /// The positive class in binary classification. + /// This parameter is needed to generate precision, recall, and F1 metrics when doing binary classification. + /// + [JsonPropertyName("classification_positive_class")] + public string? ClassificationPositiveClass { get; set; } + + //TODO documentation wasn't clear, I don't know which type of array is expected + /// + /// If this is provided, we calculate F-beta scores at the specified beta values. The F-beta score is a generalization + /// of F-1 score. This is only used for binary classification. + /// With a beta of 1 (i.e.the F-1 score), precision and recall are given the same weight.A larger beta score puts more + /// weight on recall and less on precision. A smaller beta score puts more weight on precision and less on recall. + /// + [JsonPropertyName("classification_betas")] + public List? ClassificationBetas { get; set; } + + /// + /// A string of up to 40 characters that will be added to your fine-tuned model name. + /// For example, a suffix of "custom-model-name" would produce a model name like + /// ada:ft-your-org:custom-model-name-2022-02-15-04-21-04. + /// + [JsonPropertyName("suffix")] + public string? Suffix { get; set; } + + + /// + /// The name of the base model to fine-tune. You can select one of "ada", "babbage", or "curie". To learn more about + /// these models, see the Models documentation. + /// + [JsonPropertyName("model")] + public string? Model { get; set; } +} \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs new file mode 100644 index 00000000..140c1f12 --- /dev/null +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs @@ -0,0 +1,11 @@ +using OpenAI.ObjectModels.SharedModels; +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +public record FineTuningJobListEventsResponse : BaseResponse +{ + [JsonPropertyName("data")] + public List Data { get; set; } +} + diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs new file mode 100644 index 00000000..068121d8 --- /dev/null +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +public record FineTuningJobListResponse : BaseResponse +{ + [JsonPropertyName("data")] + public List Data { get; set; } +} + diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs new file mode 100644 index 00000000..c771e1f5 --- /dev/null +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs @@ -0,0 +1,49 @@ +using OpenAI.ObjectModels.SharedModels; +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +public record FineTuningJobResponse : BaseResponse, IOpenAiModels.IId, IOpenAiModels.IModel, IOpenAiModels.ICreatedAt +{ + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("object")] + public string Object { get; set; } + + [JsonPropertyName("created_at")] + public int CreatedAt { get; set; } + + [JsonPropertyName("finished_at")] + public int? FinishedAt { get; set; } + + [JsonPropertyName("model")] + public string Model { get; set; } + + [JsonPropertyName("fine_tuned_model")] + public string? FineTunedModel { get; set; } + + [JsonPropertyName("organization_id")] + public string OrganizationId { get; set; } + + [JsonPropertyName("status")] + public string Status { get; set; } + + [JsonPropertyName("hyperparameters")] + public HyperParametersResponse HyperParams { get; set; } + + [JsonPropertyName("validation_files")] + public List ValidationFiles { get; set; } + + [JsonPropertyName("training_files")] + public List TrainingFiles { get; set; } + + [JsonPropertyName("result_files")] + public List ResultFiles { get; set; } + + [JsonPropertyName("trained_tokens")] + public int? TrainedTokens { get; set; } + + [JsonPropertyName("updated_at")] + public int? UpdatedAt { get; set; } +} From a5007e55e9f91b40a61eb1f183ffaebe1b53218a Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:44:05 -0700 Subject: [PATCH 02/13] Add FineTuningJobService --- .../AzureOpenAiEndpointProvider.cs | 30 ++++++++++ .../IOpenAiEndpointProvider.cs | 6 ++ .../OpenAiEndpointProvider.cs | 30 ++++++++++ .../Interfaces/IFineTuningJobService.cs | 60 +++++++++++++++++++ OpenAI.SDK/Interfaces/IOpenAIService.cs | 5 ++ OpenAI.SDK/Managers/OpenAIFineTuningJob.cs | 44 ++++++++++++++ OpenAI.SDK/Managers/OpenAIService.cs | 3 + 7 files changed, 178 insertions(+) create mode 100644 OpenAI.SDK/Interfaces/IFineTuningJobService.cs create mode 100644 OpenAI.SDK/Managers/OpenAIFineTuningJob.cs diff --git a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs index 090af9cd..61a4fc39 100644 --- a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs @@ -95,6 +95,36 @@ public string FineTuneDelete(string fineTuneId) return $"{Prefix}/models/{fineTuneId}{QueryString}"; } + public string FineTuningJobCreate() + { + return $"{Prefix}/fine_tuning/jobs{QueryString}"; + } + + public string FineTuningJobList() + { + return $"{Prefix}/fine_tuning/jobs{QueryString}"; + } + + public string FineTuningJobRetrieve(string fineTuningJobId) + { + return $"{Prefix}/fine_tuning/jobs/{fineTuningJobId}{QueryString}"; + } + + public string FineTuningJobCancel(string fineTuningJobId) + { + return $"{Prefix}/fine_tuning/jobs/{fineTuningJobId}/cancel{QueryString}"; + } + + public string FineTuningJobListEvents(string fineTuningJobId) + { + return $"{Prefix}/fine_tuning/jobs/{fineTuningJobId}/events{QueryString}"; + } + + public string FineTuningJobDelete(string fineTuningJobId) + { + return $"{Prefix}/models/{fineTuningJobId}{QueryString}"; + } + public string EmbeddingCreate() { return $"{Prefix}/embeddings{QueryString}"; diff --git a/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs index 75adcee1..38dcd1ae 100644 --- a/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs @@ -17,6 +17,12 @@ internal interface IOpenAiEndpointProvider string FineTuneCancel(string fineTuneId); string FineTuneListEvents(string fineTuneId); string FineTuneDelete(string fineTuneId); + string FineTuningJobCreate(); + string FineTuningJobList(); + string FineTuningJobRetrieve(string fineTuningJobId); + string FineTuningJobCancel(string fineTuningJobId); + string FineTuningJobListEvents(string fineTuningJobId); + string FineTuningJobDelete(string fineTuningJobId); string EmbeddingCreate(); string ModerationCreate(); string ImageCreate(); diff --git a/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs index 40319dbc..f4ea9631 100644 --- a/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs @@ -99,6 +99,36 @@ public string FineTuneDelete(string fineTuneId) return $"/{_apiVersion}/models/{fineTuneId}"; } + public string FineTuningJobCreate() + { + return $"/{_apiVersion}/fine_tuning/jobs"; + } + + public string FineTuningJobList() + { + return $"/{_apiVersion}/fine_tuning/jobs"; + } + + public string FineTuningJobRetrieve(string fineTuningJobId) + { + return $"/{_apiVersion}/fine_tuning/jobs/{fineTuningJobId}"; + } + + public string FineTuningJobCancel(string fineTuningJobId) + { + return $"/{_apiVersion}/fine_tuning/jobs/{fineTuningJobId}/cancel"; + } + + public string FineTuningJobListEvents(string fineTuningJobId) + { + return $"/{_apiVersion}/fine_tuning/jobs/{fineTuningJobId}/events"; + } + + public string FineTuningJobDelete(string fineTuningJobId) + { + return $"/{_apiVersion}/models/{fineTuningJobId}"; + } + public string EmbeddingCreate() { return $"/{_apiVersion}/embeddings"; diff --git a/OpenAI.SDK/Interfaces/IFineTuningJobService.cs b/OpenAI.SDK/Interfaces/IFineTuningJobService.cs new file mode 100644 index 00000000..86c2adf2 --- /dev/null +++ b/OpenAI.SDK/Interfaces/IFineTuningJobService.cs @@ -0,0 +1,60 @@ +using OpenAI.ObjectModels.RequestModels; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +namespace OpenAI.Interfaces; + +/// +/// Manage fine-tuning jobs to tailor a model to your specific training data. +/// Related guide: Fine-tune models +/// +public interface IFineTuningJobService +{ + /// + /// Creates a job that fine-tunes a specified model from a given dataset. + /// Response includes details of the enqueued job including job status and the name of the fine-tuned models once + /// complete. + /// + /// + /// Propagates notification that operations should be canceled. + /// + Task CreateFineTuningJob(FineTuningJobCreateRequest createFineTuningJobRequest, CancellationToken cancellationToken = default); + + /// + /// List your organization's fine-tuning jobs + /// + /// Propagates notification that operations should be canceled. + /// + Task ListFineTuningJobs(CancellationToken cancellationToken = default); + + /// + /// Gets info about the fine-tuning job. + /// + /// The ID of the fine-tuning job + /// Propagates notification that operations should be canceled. + /// + Task RetrieveFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default); + + /// + /// Immediately cancel a fine-tuning job. + /// + /// The ID of the fine-tuning job to cancel + /// Propagates notification that operations should be canceled. + /// + Task CancelFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default); + + /// + /// Get fine-grained status updates for a fine-tuning job. + /// + /// The ID of the fine-tuning job to get events for. + /// + /// Whether to stream events for the fine-tuning job. If set to true, events will be sent as data-only server-sent events + /// as they become available. The stream will terminate with a data: [DONE] message when the job is finished + /// (succeeded, cancelled, or failed). + /// If set to false, only events generated so far will be returned. + /// + /// Propagates notification that operations should be canceled. + /// + Task ListFineTuningJobEvents(string fineTuningJobId, bool? stream = null, CancellationToken cancellationToken = default); + + Task DeleteFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default); +} diff --git a/OpenAI.SDK/Interfaces/IOpenAIService.cs b/OpenAI.SDK/Interfaces/IOpenAIService.cs index dec050e3..671865d4 100644 --- a/OpenAI.SDK/Interfaces/IOpenAIService.cs +++ b/OpenAI.SDK/Interfaces/IOpenAIService.cs @@ -28,6 +28,11 @@ public interface IOpenAIService public IFineTuneService FineTunes { get; } + /// + /// Manage fine-tuning jobs to tailor a model to your specific training data. + /// + public IFineTuningJobService FineTuningJob { get; } + public IModerationService Moderation { get; } /// diff --git a/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs b/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs new file mode 100644 index 00000000..9b1e53d1 --- /dev/null +++ b/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs @@ -0,0 +1,44 @@ +using OpenAI.Extensions; +using OpenAI.Interfaces; +using OpenAI.ObjectModels.RequestModels; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; +using System.Net.Http.Json; + +namespace OpenAI.Managers +{ + public partial class OpenAIService : IFineTuningJobService + { + public async Task CreateFineTuningJob(FineTuningJobCreateRequest createFineTuningJobRequest, CancellationToken cancellationToken = default) + { + return await _httpClient.PostAndReadAsAsync(_endpointProvider.FineTuningJobCreate(), createFineTuningJobRequest, cancellationToken); + } + + public async Task ListFineTuningJobs(CancellationToken cancellationToken = default) + { + return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobList(), cancellationToken))!; + } + + public async Task RetrieveFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) + { + return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobRetrieve(FineTuningJobId), cancellationToken))!; + } + + public async Task CancelFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) + { + return await _httpClient.PostAndReadAsAsync(_endpointProvider.FineTuningJobCancel(FineTuningJobId), new FineTuningJobCancelRequest + { + FineTuningJobId = FineTuningJobId + }, cancellationToken); + } + + public async Task ListFineTuningJobEvents(string FineTuningJobId, bool? stream = null, CancellationToken cancellationToken = default) + { + return await _httpClient.GetStreamAsync(_endpointProvider.FineTuningJobListEvents(FineTuningJobId), cancellationToken); + } + + public async Task DeleteFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) + { + await _httpClient.DeleteAsync(_endpointProvider.FineTuningJobDelete(FineTuningJobId), cancellationToken); + } + } +} diff --git a/OpenAI.SDK/Managers/OpenAIService.cs b/OpenAI.SDK/Managers/OpenAIService.cs index 3a356529..229b8abf 100644 --- a/OpenAI.SDK/Managers/OpenAIService.cs +++ b/OpenAI.SDK/Managers/OpenAIService.cs @@ -85,6 +85,9 @@ public void Dispose() /// public IFineTuneService FineTunes => this; + /// + public IFineTuningJobService FineTuningJob => this; + /// public IModerationService Moderation => this; From 5b2141e29c808b30690570b192b59e47d46c9985 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:44:17 -0700 Subject: [PATCH 03/13] Update Playground to support new FineTuningJob --- .../TestHelpers/FineTuningJobTestHelper.cs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs diff --git a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs new file mode 100644 index 00000000..c176bf31 --- /dev/null +++ b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs @@ -0,0 +1,90 @@ +using OpenAI.Interfaces; +using OpenAI.ObjectModels; +using OpenAI.ObjectModels.RequestModels; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +namespace OpenAI.Playground.TestHelpers; + +internal static class FineTuningJobTestHelper +{ + public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAIService sdk) + { + ConsoleExtensions.WriteLine("Run Case Study Is The Model Making Untrue Statements:", ConsoleColor.Cyan); + + try + { + const string fileName = "FineTuningSample1.jsonl"; + var sampleFile = await FileExtensions.ReadAllBytesAsync($"SampleData/{fileName}"); + + ConsoleExtensions.WriteLine($"Uploading file {fileName}", ConsoleColor.DarkCyan); + var uploadFilesResponse = await sdk.Files.FileUpload(UploadFilePurposes.UploadFilePurpose.FineTune, sampleFile, fileName); + if (uploadFilesResponse.Successful) + { + ConsoleExtensions.WriteLine($"{fileName} uploaded", ConsoleColor.DarkGreen); + } + else + { + ConsoleExtensions.WriteLine($"{fileName} failed", ConsoleColor.DarkRed); + } + + var createFineTuningJobResponse = await sdk.FineTuningJob.CreateFineTuningJob(new FineTuningJobCreateRequest + { + TrainingFile = uploadFilesResponse.Id, + Model = Models.Gpt_3_5_Turbo + }); + + var listFineTuningJobEventsStream = await sdk.FineTuningJob.ListFineTuningJobEvents(createFineTuningJobResponse.Id, true); + using var streamReader = new StreamReader(listFineTuningJobEventsStream); + while (!streamReader.EndOfStream) + { + Console.WriteLine(await streamReader.ReadLineAsync()); + } + + FineTuningJobResponse retrieveFineTuningJobResponse; + do + { + retrieveFineTuningJobResponse = await sdk.FineTuningJob.RetrieveFineTuningJob(createFineTuningJobResponse.Id); + if (retrieveFineTuningJobResponse.Status == "succeeded" || retrieveFineTuningJobResponse.Status == "cancelled" || retrieveFineTuningJobResponse.Status == "failed") + { + ConsoleExtensions.WriteLine($"Fine-tune Status for {createFineTuningJobResponse.Id}: {retrieveFineTuningJobResponse.Status}.", ConsoleColor.Yellow); + break; + } + + ConsoleExtensions.WriteLine($"Fine-tune Status for {createFineTuningJobResponse.Id}: {retrieveFineTuningJobResponse.Status}. Wait 10 more seconds", ConsoleColor.DarkYellow); + await Task.Delay(10_000); + } while (true); + + do + { + var completionResult = await sdk.Completions.CreateCompletion(new CompletionCreateRequest + { + MaxTokens = 1, + Prompt = @"https://t.co/f93xEd2 Excited to share my latest blog post! ->", + Model = retrieveFineTuningJobResponse.FineTunedModel, + LogProbs = 2 + }); + if (completionResult.Successful) + { + Console.WriteLine(completionResult.Choices.FirstOrDefault()); + break; + } + + ConsoleExtensions.WriteLine($"failed{completionResult.Error?.Message}", ConsoleColor.DarkRed); + } while (true); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static async Task CleanUpAllFineTunings(IOpenAIService sdk) + { + var FineTuningJobs = await sdk.FineTuningJob.ListFineTuningJobs(); + foreach (var datum in FineTuningJobs.Data) + { + await sdk.FineTuningJob.DeleteFineTuningJob(datum.FineTunedModel); + } + } +} \ No newline at end of file From 832acd5cb27d6c51b52c469c0d768e1a7457ef67 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:10:56 -0700 Subject: [PATCH 04/13] Remove Object from FineTuningJobResponse --- .../FineTuningJobResponseModels/FineTuningJobResponse.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs index c771e1f5..03d3bb90 100644 --- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs @@ -8,9 +8,6 @@ public record FineTuningJobResponse : BaseResponse, IOpenAiModels.IId, IOpenAiMo [JsonPropertyName("id")] public string Id { get; set; } - [JsonPropertyName("object")] - public string Object { get; set; } - [JsonPropertyName("created_at")] public int CreatedAt { get; set; } From 051589ef89a78b5be29b62b0dbd8a8678ce38512 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:32:45 -0700 Subject: [PATCH 05/13] Add FineTuningJobSample2.jsonl file --- OpenAI.Playground/OpenAI.Playground.csproj | 3 +++ OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl diff --git a/OpenAI.Playground/OpenAI.Playground.csproj b/OpenAI.Playground/OpenAI.Playground.csproj index 2ac0b3a5..258aaa00 100644 --- a/OpenAI.Playground/OpenAI.Playground.csproj +++ b/OpenAI.Playground/OpenAI.Playground.csproj @@ -56,6 +56,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl b/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl new file mode 100644 index 00000000..ea456358 --- /dev/null +++ b/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl @@ -0,0 +1,3 @@ +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What's the capital of France?"},{"role":"assistant","content":"Paris, as if everyone doesn't know that already."}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"Who wrote 'Romeo and Juliet'?"},{"role":"assistant","content":"Oh, just some guy named William Shakespeare. Ever heard of him?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"How far is the Moon from Earth?"},{"role":"assistant","content":"Around 384,400 kilometers. Give or take a few, like that really matters."}]} From 316d96317d4a4633cf6a50d7910b2c706bd37baa Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:33:56 -0700 Subject: [PATCH 06/13] Update FineTuningJobTestHelper to use the correct sample file --- OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs index c176bf31..7e3f1100 100644 --- a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs +++ b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs @@ -13,7 +13,7 @@ public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAISer try { - const string fileName = "FineTuningSample1.jsonl"; + const string fileName = "FineTuningJobSample2.jsonl"; var sampleFile = await FileExtensions.ReadAllBytesAsync($"SampleData/{fileName}"); ConsoleExtensions.WriteLine($"Uploading file {fileName}", ConsoleColor.DarkCyan); From 08cf6f234a2ae2094a973b281586811758831850 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:43:11 -0700 Subject: [PATCH 07/13] Update the fine tuning job sample file to make it 10 samples --- OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl b/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl index ea456358..e915df4e 100644 --- a/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl +++ b/OpenAI.Playground/SampleData/FineTuningJobSample2.jsonl @@ -1,3 +1,10 @@ {"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What's the capital of France?"},{"role":"assistant","content":"Paris, as if everyone doesn't know that already."}]} {"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"Who wrote 'Romeo and Juliet'?"},{"role":"assistant","content":"Oh, just some guy named William Shakespeare. Ever heard of him?"}]} {"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"How far is the Moon from Earth?"},{"role":"assistant","content":"Around 384,400 kilometers. Give or take a few, like that really matters."}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What is the boiling point of water?"},{"role":"assistant","content":"100 degrees Celsius. Groundbreaking information, right?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"Who discovered gravity?"},{"role":"assistant","content":"Isaac Newton. You know, the apple guy?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"How many continents are there?"},{"role":"assistant","content":"Seven. Did you just skip geography class or what?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What's the largest planet in the solar system?"},{"role":"assistant","content":"Jupiter, as if it wasn't obvious enough."}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What's the speed of light?"},{"role":"assistant","content":"Approximately 299,792,458 meters per second. But who's counting?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"Who is the current U.S. President?"},{"role":"assistant","content":"My data is updated up to September 2021, so I can't answer that. But you've got the internet, don't you?"}]} +{"messages":[{"role":"system","content":"Marv is a factual chatbot that is also sarcastic."},{"role":"user","content":"What's the formula for water?"},{"role":"assistant","content":"H2O. Even a toddler knows that."}]} \ No newline at end of file From acf302de84dd339703396c7d1b9a19a92af659f1 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:43:23 -0700 Subject: [PATCH 08/13] Add a 5 second delay for the fine tune file to be ready --- OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs index 7e3f1100..1e0c11d5 100644 --- a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs +++ b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs @@ -27,6 +27,9 @@ public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAISer ConsoleExtensions.WriteLine($"{fileName} failed", ConsoleColor.DarkRed); } + ConsoleExtensions.WriteLine($"Wait 5 seconds for the file to be ready", ConsoleColor.DarkYellow); + await Task.Delay(5_000); + var createFineTuningJobResponse = await sdk.FineTuningJob.CreateFineTuningJob(new FineTuningJobCreateRequest { TrainingFile = uploadFilesResponse.Id, From 3d8b6181ffa101129f652431784ee5f55c250d02 Mon Sep 17 00:00:00 2001 From: aghimir3 <22482815+aghimir3@users.noreply.github.com> Date: Sun, 27 Aug 2023 19:32:17 -0700 Subject: [PATCH 09/13] Update FineTuningJobResponse to match OpenAI Documentation Be in alignment with https://platform.openai.com/docs/api-reference/fine-tuning/object --- .../FineTuningJobResponse.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs index 03d3bb90..cbb4404d 100644 --- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs @@ -27,16 +27,16 @@ public record FineTuningJobResponse : BaseResponse, IOpenAiModels.IId, IOpenAiMo public string Status { get; set; } [JsonPropertyName("hyperparameters")] - public HyperParametersResponse HyperParams { get; set; } + public HyperParametersResponse HyperParameters { get; set; } - [JsonPropertyName("validation_files")] - public List ValidationFiles { get; set; } + [JsonPropertyName("validation_file")] + public string? ValidationFile { get; set; } - [JsonPropertyName("training_files")] - public List TrainingFiles { get; set; } + [JsonPropertyName("training_file")] + public string TrainingFile { get; set; } [JsonPropertyName("result_files")] - public List ResultFiles { get; set; } + public List ResultFiles { get; set; } [JsonPropertyName("trained_tokens")] public int? TrainedTokens { get; set; } From 5c49f2af852953367b19d47d635198b67aac5644 Mon Sep 17 00:00:00 2001 From: Massimo Cerqui Date: Fri, 22 Sep 2023 11:25:41 +0200 Subject: [PATCH 10/13] Fix AzureOpenAi Audio Endpoints --- OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs index 090af9cd..87bb8c73 100644 --- a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs @@ -127,12 +127,12 @@ public string ChatCompletionCreate() public string AudioCreateTranscription() { - return $"/{Prefix}/audio/transcriptions{QueryString}"; + return $"{Prefix}/audio/transcriptions{QueryString}"; } public string AudioCreateTranslation() { - return $"/{Prefix}/audio/translation{QueryString}"; + return $"{Prefix}/audio/translation{QueryString}"; } private string Files() From ee94c69443d51731370ebdd315c9803b2389a477 Mon Sep 17 00:00:00 2001 From: Massimo Cerqui Date: Fri, 22 Sep 2023 13:01:34 +0200 Subject: [PATCH 11/13] Pump Azure Open Ai Default Api Version --- OpenAI.SDK/OpenAiOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAI.SDK/OpenAiOptions.cs b/OpenAI.SDK/OpenAiOptions.cs index a2d1abcb..2bcdcaed 100644 --- a/OpenAI.SDK/OpenAiOptions.cs +++ b/OpenAI.SDK/OpenAiOptions.cs @@ -20,7 +20,7 @@ public class OpenAiOptions { private const string OpenAiDefaultApiVersion = "v1"; private const string OpenAiDefaultBaseDomain = "https://api.openai.com/"; - private const string AzureOpenAiDefaultApiVersion = "2023-03-15-preview"; + private const string AzureOpenAiDefaultApiVersion = "2023-09-01-preview"; /// From 43d4f206673036f78dae1b93d9fe1a1673273d5c Mon Sep 17 00:00:00 2001 From: Tolga Kayhan Date: Mon, 25 Sep 2023 22:13:34 +0100 Subject: [PATCH 12/13] fixes regarding code review --- OpenAI.Playground/Program.cs | 4 +- .../TestHelpers/FineTuningJobTestHelper.cs | 29 +++- .../AzureOpenAiEndpointProvider.cs | 22 ++- .../IOpenAiEndpointProvider.cs | 8 +- .../OpenAiEndpointProvider.cs | 25 +++- OpenAI.SDK/Extensions/HttpclientExtensions.cs | 2 +- .../Interfaces/IFineTuningJobService.cs | 9 +- OpenAI.SDK/Interfaces/IModelService.cs | 8 ++ OpenAI.SDK/Managers/OpenAIFineTuningJob.cs | 26 ++-- OpenAI.SDK/Managers/OpenAIModel.cs | 5 + OpenAI.SDK/Managers/OpenAIService.cs | 1 - .../RequestModels/FineTuneCreateRequest.cs | 3 + .../FineTuningJobCreateRequest.cs | 129 +++++------------- .../FineTuningJobListEventsRequest.cs | 29 ++++ .../FineTuningJobListEventsResponse.cs | 3 + .../FineTuningJobListResponse.cs | 3 + .../FineTuningJobResponse.cs | 89 +++++++++--- .../NEpochsConverter.cs | 42 ++++++ .../ModelDeleteResponse.cs | 10 ++ .../SharedModels/EventResponse.cs | 4 +- .../SharedModels/HyperParametersResponse.cs | 5 +- OpenAI.sln.DotSettings | 1 + 22 files changed, 301 insertions(+), 156 deletions(-) create mode 100644 OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobListEventsRequest.cs create mode 100644 OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/NEpochsConverter.cs create mode 100644 OpenAI.SDK/ObjectModels/ResponseModels/ModelResponseModels/ModelDeleteResponse.cs diff --git a/OpenAI.Playground/Program.cs b/OpenAI.Playground/Program.cs index bb456ee6..d4079d46 100644 --- a/OpenAI.Playground/Program.cs +++ b/OpenAI.Playground/Program.cs @@ -44,8 +44,8 @@ //await ChatCompletionTestHelper.RunSimpleChatCompletionTest(sdk); //await ChatCompletionTestHelper.RunSimpleCompletionStreamTest(sdk); -await ChatCompletionTestHelper.RunChatFunctionCallTest(sdk); - +//await ChatCompletionTestHelper.RunChatFunctionCallTest(sdk); +await FineTuningJobTestHelper.RunCaseStudyIsTheModelMakingUntrueStatements(sdk); // Whisper //await AudioTestHelper.RunSimpleAudioCreateTranscriptionTest(sdk); //await AudioTestHelper.RunSimpleAudioCreateTranslationTest(sdk); diff --git a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs index 1e0c11d5..6090de2c 100644 --- a/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs +++ b/OpenAI.Playground/TestHelpers/FineTuningJobTestHelper.cs @@ -11,6 +11,13 @@ public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAISer { ConsoleExtensions.WriteLine("Run Case Study Is The Model Making Untrue Statements:", ConsoleColor.Cyan); + var jobs = await sdk.FineTuningJob.ListFineTuningJobs(); + //print all jobs + foreach (var job in jobs.Data) + { + Console.WriteLine(job.FineTunedModel); + } + try { const string fileName = "FineTuningJobSample2.jsonl"; @@ -36,7 +43,11 @@ public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAISer Model = Models.Gpt_3_5_Turbo }); - var listFineTuningJobEventsStream = await sdk.FineTuningJob.ListFineTuningJobEvents(createFineTuningJobResponse.Id, true); + var listFineTuningJobEventsStream = await sdk.FineTuningJob.ListFineTuningJobEvents(new FineTuningJobListEventsRequest + { + FineTuningJobId = createFineTuningJobResponse.Id + }, true); + using var streamReader = new StreamReader(listFineTuningJobEventsStream); while (!streamReader.EndOfStream) { @@ -59,13 +70,17 @@ public static async Task RunCaseStudyIsTheModelMakingUntrueStatements(IOpenAISer do { - var completionResult = await sdk.Completions.CreateCompletion(new CompletionCreateRequest + var completionResult = await sdk.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest { - MaxTokens = 1, - Prompt = @"https://t.co/f93xEd2 Excited to share my latest blog post! ->", - Model = retrieveFineTuningJobResponse.FineTunedModel, - LogProbs = 2 + Messages = new List + { + ChatMessage.FromSystem("You are Marv, a chatbot that reluctantly answers questions with sarcastic responses."), + ChatMessage.FromUser("How many pounds are in a kilogram?"), + }, + MaxTokens = 50, + Model = retrieveFineTuningJobResponse.FineTunedModel }); + if (completionResult.Successful) { Console.WriteLine(completionResult.Choices.FirstOrDefault()); @@ -87,7 +102,7 @@ public static async Task CleanUpAllFineTunings(IOpenAIService sdk) var FineTuningJobs = await sdk.FineTuningJob.ListFineTuningJobs(); foreach (var datum in FineTuningJobs.Data) { - await sdk.FineTuningJob.DeleteFineTuningJob(datum.FineTunedModel); + await sdk.Models.DeleteModel(datum.FineTunedModel); } } } \ No newline at end of file diff --git a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs index 61a4fc39..1cef5da5 100644 --- a/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/AzureOpenAiEndpointProvider.cs @@ -1,4 +1,5 @@ using System.Net; +using OpenAI.ObjectModels.RequestModels; namespace OpenAI.EndpointProviders; @@ -100,6 +101,23 @@ public string FineTuningJobCreate() return $"{Prefix}/fine_tuning/jobs{QueryString}"; } + public string FineTuningJobList(FineTuningJobListRequest? fineTuningJobListRequest) + { + var url = $"/{Prefix}/fine_tuning/jobs"; + if (fineTuningJobListRequest != null) + { + var queryParams = new List(); + if (fineTuningJobListRequest.After != null) + queryParams.Add($"after={WebUtility.UrlEncode(fineTuningJobListRequest.After)}"); + if (fineTuningJobListRequest.Limit.HasValue) + queryParams.Add($"limit={fineTuningJobListRequest.Limit.Value}"); + + if (queryParams.Any()) + url = $"{url}{QueryString}&{string.Join("&", queryParams)}"; + } + return url; + } + public string FineTuningJobList() { return $"{Prefix}/fine_tuning/jobs{QueryString}"; @@ -120,9 +138,9 @@ public string FineTuningJobListEvents(string fineTuningJobId) return $"{Prefix}/fine_tuning/jobs/{fineTuningJobId}/events{QueryString}"; } - public string FineTuningJobDelete(string fineTuningJobId) + public string ModelsDelete(string modelId) { - return $"{Prefix}/models/{fineTuningJobId}{QueryString}"; + return $"{Prefix}/models/{modelId}{QueryString}"; } public string EmbeddingCreate() diff --git a/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs index 38dcd1ae..2d85aaef 100644 --- a/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/IOpenAiEndpointProvider.cs @@ -1,4 +1,6 @@ -namespace OpenAI.EndpointProviders; +using OpenAI.ObjectModels.RequestModels; + +namespace OpenAI.EndpointProviders; internal interface IOpenAiEndpointProvider { @@ -6,6 +8,7 @@ internal interface IOpenAiEndpointProvider string CompletionCreate(); string EditCreate(); string ModelsList(); + string ModelsDelete(string modelId); string FilesList(); string FilesUpload(); string FileDelete(string fileId); @@ -18,11 +21,10 @@ internal interface IOpenAiEndpointProvider string FineTuneListEvents(string fineTuneId); string FineTuneDelete(string fineTuneId); string FineTuningJobCreate(); - string FineTuningJobList(); + string FineTuningJobList(FineTuningJobListRequest? fineTuningJobListRequest); string FineTuningJobRetrieve(string fineTuningJobId); string FineTuningJobCancel(string fineTuningJobId); string FineTuningJobListEvents(string fineTuningJobId); - string FineTuningJobDelete(string fineTuningJobId); string EmbeddingCreate(); string ModerationCreate(); string ImageCreate(); diff --git a/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs b/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs index f4ea9631..d1dfc682 100644 --- a/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs +++ b/OpenAI.SDK/EndpointProviders/OpenAiEndpointProvider.cs @@ -1,4 +1,7 @@ -namespace OpenAI.EndpointProviders; +using System.Net; +using OpenAI.ObjectModels.RequestModels; + +namespace OpenAI.EndpointProviders; internal class OpenAiEndpointProvider : IOpenAiEndpointProvider { @@ -104,9 +107,21 @@ public string FineTuningJobCreate() return $"/{_apiVersion}/fine_tuning/jobs"; } - public string FineTuningJobList() + public string FineTuningJobList(FineTuningJobListRequest? fineTuningJobListRequest) { - return $"/{_apiVersion}/fine_tuning/jobs"; + var url = $"/{_apiVersion}/fine_tuning/jobs"; + if (fineTuningJobListRequest != null) + { + var queryParams = new List(); + if (fineTuningJobListRequest.After != null) + queryParams.Add($"after={WebUtility.UrlEncode(fineTuningJobListRequest.After)}"); + if (fineTuningJobListRequest.Limit.HasValue) + queryParams.Add($"limit={fineTuningJobListRequest.Limit.Value}"); + + if (queryParams.Any()) + url = $"{url}?{string.Join("&", queryParams)}"; + } + return url; } public string FineTuningJobRetrieve(string fineTuningJobId) @@ -124,9 +139,9 @@ public string FineTuningJobListEvents(string fineTuningJobId) return $"/{_apiVersion}/fine_tuning/jobs/{fineTuningJobId}/events"; } - public string FineTuningJobDelete(string fineTuningJobId) + public string ModelsDelete(string modelId) { - return $"/{_apiVersion}/models/{fineTuningJobId}"; + return $"/{_apiVersion}/models/{modelId}"; } public string EmbeddingCreate() diff --git a/OpenAI.SDK/Extensions/HttpclientExtensions.cs b/OpenAI.SDK/Extensions/HttpclientExtensions.cs index 054ed940..ecaa5379 100644 --- a/OpenAI.SDK/Extensions/HttpclientExtensions.cs +++ b/OpenAI.SDK/Extensions/HttpclientExtensions.cs @@ -7,7 +7,7 @@ namespace OpenAI.Extensions; public static class HttpClientExtensions { - public static async Task PostAndReadAsAsync(this HttpClient client, string uri, object requestModel, CancellationToken cancellationToken = default) + public static async Task PostAndReadAsAsync(this HttpClient client, string uri, object? requestModel, CancellationToken cancellationToken = default) { var response = await client.PostAsJsonAsync(uri, requestModel, new JsonSerializerOptions { diff --git a/OpenAI.SDK/Interfaces/IFineTuningJobService.cs b/OpenAI.SDK/Interfaces/IFineTuningJobService.cs index 86c2adf2..457a0cf2 100644 --- a/OpenAI.SDK/Interfaces/IFineTuningJobService.cs +++ b/OpenAI.SDK/Interfaces/IFineTuningJobService.cs @@ -22,9 +22,10 @@ public interface IFineTuningJobService /// /// List your organization's fine-tuning jobs /// + /// /// Propagates notification that operations should be canceled. /// - Task ListFineTuningJobs(CancellationToken cancellationToken = default); + Task ListFineTuningJobs(FineTuningJobListRequest? fineTuningJobListRequest =null,CancellationToken cancellationToken = default); /// /// Gets info about the fine-tuning job. @@ -45,7 +46,7 @@ public interface IFineTuningJobService /// /// Get fine-grained status updates for a fine-tuning job. /// - /// The ID of the fine-tuning job to get events for. + /// /// /// Whether to stream events for the fine-tuning job. If set to true, events will be sent as data-only server-sent events /// as they become available. The stream will terminate with a data: [DONE] message when the job is finished @@ -54,7 +55,5 @@ public interface IFineTuningJobService /// /// Propagates notification that operations should be canceled. /// - Task ListFineTuningJobEvents(string fineTuningJobId, bool? stream = null, CancellationToken cancellationToken = default); - - Task DeleteFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default); + Task ListFineTuningJobEvents(FineTuningJobListEventsRequest model, bool? stream = null, CancellationToken cancellationToken = default); } diff --git a/OpenAI.SDK/Interfaces/IModelService.cs b/OpenAI.SDK/Interfaces/IModelService.cs index 6c343160..d2c4c6b3 100644 --- a/OpenAI.SDK/Interfaces/IModelService.cs +++ b/OpenAI.SDK/Interfaces/IModelService.cs @@ -25,4 +25,12 @@ public interface IModelService /// Propagates notification that operations should be canceled. /// Task RetrieveModel(string model, CancellationToken cancellationToken = default); + + /// + /// Delete a fine-tuned model. You must have the Owner role in your organization to delete a model. + /// + /// The model to delete + /// + /// + Task DeleteModel(string modelId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs b/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs index 9b1e53d1..694d05b5 100644 --- a/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs +++ b/OpenAI.SDK/Managers/OpenAIFineTuningJob.cs @@ -1,4 +1,5 @@ -using OpenAI.Extensions; +using System.Net; +using OpenAI.Extensions; using OpenAI.Interfaces; using OpenAI.ObjectModels.RequestModels; using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; @@ -13,32 +14,25 @@ public async Task CreateFineTuningJob(FineTuningJobCreate return await _httpClient.PostAndReadAsAsync(_endpointProvider.FineTuningJobCreate(), createFineTuningJobRequest, cancellationToken); } - public async Task ListFineTuningJobs(CancellationToken cancellationToken = default) + public async Task ListFineTuningJobs(FineTuningJobListRequest? fineTuningJobListRequest, CancellationToken cancellationToken = default) { - return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobList(), cancellationToken))!; - } - public async Task RetrieveFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) - { - return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobRetrieve(FineTuningJobId), cancellationToken))!; + return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobList(fineTuningJobListRequest), cancellationToken))!; } - public async Task CancelFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) + public async Task RetrieveFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default) { - return await _httpClient.PostAndReadAsAsync(_endpointProvider.FineTuningJobCancel(FineTuningJobId), new FineTuningJobCancelRequest - { - FineTuningJobId = FineTuningJobId - }, cancellationToken); + return (await _httpClient.GetFromJsonAsync(_endpointProvider.FineTuningJobRetrieve(fineTuningJobId), cancellationToken))!; } - public async Task ListFineTuningJobEvents(string FineTuningJobId, bool? stream = null, CancellationToken cancellationToken = default) + public async Task CancelFineTuningJob(string fineTuningJobId, CancellationToken cancellationToken = default) { - return await _httpClient.GetStreamAsync(_endpointProvider.FineTuningJobListEvents(FineTuningJobId), cancellationToken); + return await _httpClient.PostAndReadAsAsync(_endpointProvider.FineTuningJobCancel(fineTuningJobId),null, cancellationToken: cancellationToken); } - public async Task DeleteFineTuningJob(string FineTuningJobId, CancellationToken cancellationToken = default) + public async Task ListFineTuningJobEvents(FineTuningJobListEventsRequest fineTuningJobRequestModel, bool? stream = null, CancellationToken cancellationToken = default) { - await _httpClient.DeleteAsync(_endpointProvider.FineTuningJobDelete(FineTuningJobId), cancellationToken); + return await _httpClient.GetStreamAsync(_endpointProvider.FineTuningJobListEvents(fineTuningJobRequestModel.FineTuningJobId), cancellationToken); } } } diff --git a/OpenAI.SDK/Managers/OpenAIModel.cs b/OpenAI.SDK/Managers/OpenAIModel.cs index 9abbc500..7215de3f 100644 --- a/OpenAI.SDK/Managers/OpenAIModel.cs +++ b/OpenAI.SDK/Managers/OpenAIModel.cs @@ -15,4 +15,9 @@ public async Task RetrieveModel(string model, Cancellatio { return (await _httpClient.GetFromJsonAsync(_endpointProvider.ModelRetrieve(model), cancellationToken))!; } + + public async Task DeleteModel(string modelId, CancellationToken cancellationToken = default) + { + return await (await _httpClient.DeleteAsync(_endpointProvider.ModelsDelete(modelId), cancellationToken)).Content.ReadFromJsonAsync(cancellationToken: cancellationToken); + } } \ No newline at end of file diff --git a/OpenAI.SDK/Managers/OpenAIService.cs b/OpenAI.SDK/Managers/OpenAIService.cs index 229b8abf..7ed568ae 100644 --- a/OpenAI.SDK/Managers/OpenAIService.cs +++ b/OpenAI.SDK/Managers/OpenAIService.cs @@ -5,7 +5,6 @@ namespace OpenAI.Managers; -//TODO Find a way to show default request values in documentation public partial class OpenAIService : IOpenAIService, IDisposable { private readonly bool _disposeHttpClient; diff --git a/OpenAI.SDK/ObjectModels/RequestModels/FineTuneCreateRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/FineTuneCreateRequest.cs index c9f0ee89..6e044e1d 100644 --- a/OpenAI.SDK/ObjectModels/RequestModels/FineTuneCreateRequest.cs +++ b/OpenAI.SDK/ObjectModels/RequestModels/FineTuneCreateRequest.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; using OpenAI.ObjectModels.SharedModels; namespace OpenAI.ObjectModels.RequestModels; @@ -37,8 +38,10 @@ public record FineTuneCreateRequest : IOpenAiModels.IModel /// /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. + /// Set -1 for "auto value /// [JsonPropertyName("n_epochs")] + [JsonConverter(typeof(NEpochsConverter))] public int? NEpochs { get; set; } /// diff --git a/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs index b9f87c6b..b7fe6d60 100644 --- a/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs +++ b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobCreateRequest.cs @@ -1,5 +1,6 @@ -using OpenAI.ObjectModels.SharedModels; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; +using OpenAI.ObjectModels.SharedModels; namespace OpenAI.ObjectModels.RequestModels; @@ -7,116 +8,58 @@ public record FineTuningJobCreateRequest : IOpenAiModels.IModel { /// /// The ID of an uploaded file that contains training data. - /// See upload file for how to upload a file. - /// Your dataset must be formatted as a JSONL file, where each training example is a JSON object with the keys "prompt" - /// and "completion". Additionally, you must upload your file with the purpose fine-tune. - /// See the fine-tuning guide - /// for - /// more details. + /// See upload file for how to upload a + /// file. + /// Your dataset must be formatted as a JSONL file. Additionally, you must upload your file with the purpose + /// fine-tune. + /// See the fine-tuning guide for more details. /// [JsonPropertyName("training_file")] public string TrainingFile { get; set; } /// /// The ID of an uploaded file that contains validation data. - /// If you provide this file, the data is used to generate validation metrics periodically during fine-tuning. These - /// metrics can be viewed in the - /// - /// fine-tuning results - /// file - /// - /// . Your train and validation data should be mutually exclusive. - /// Your dataset must be formatted as a JSONL file, where each validation example is a JSON object with the keys - /// "prompt" and "completion". Additionally, you must upload your file with the purpose fine-tune. - /// See the fine-tuning guide - /// for - /// more details. + /// If you provide this file, the data is used to generate validation metrics periodically during fine-tuning. + /// These metrics can be viewed in the fine-tuning results file. + /// The same data should not be present in both train and validation files. + /// Your dataset must be formatted as a JSONL file. You must upload your file with the purpose fine-tune. + /// See the fine-tuning guide for more details. /// [JsonPropertyName("validation_file")] public string? ValidationFile { get; set; } /// - /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. - /// - [JsonPropertyName("n_epochs")] - public int? NEpochs { get; set; } - - /// - /// The batch size to use for training. The batch size is the number of training examples used to train a single - /// forward and backward pass. - /// By default, the batch size will be dynamically configured to be ~0.2% of the number of examples in the training - /// set, capped at 256 - in general, we've found that larger batch sizes tend to work better for larger datasets. - /// - [JsonPropertyName("batch_size")] - public int? BatchSize { get; set; } - - /// - /// The learning rate multiplier to use for training. The fine-tuning learning rate is the original learning rate used - /// for pretraining multiplied by this value. - /// By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final batch_size(larger learning - /// rates tend to perform better with larger batch sizes). We recommend experimenting with values in the range 0.02 to - /// 0.2 to see what produces the best results. - /// - [JsonPropertyName("learning_rate_multiplier")] - public float? LearningRateMultiplier { get; set; } - - /// - /// The weight to use for loss on the prompt tokens. This controls how much the model tries to learn to generate the - /// prompt (as compared to the completion which always has a weight of 1.0), and can add a stabilizing effect to - /// training when completions are short. - /// If prompts are extremely long (relative to completions), it may make sense to reduce this weight so as to avoid - /// over-prioritizing learning the prompt. - /// - [JsonPropertyName("prompt_loss_weight")] - public float? PromptLossWeight { get; set; } - - /// - /// If set, we calculate classification-specific metrics such as accuracy and F-1 score using the validation set at the - /// end of every epoch.These metrics can be viewed in the - /// results file. - /// In order to compute classification metrics, you must provide a validation_file.Additionally, you must specify - /// classification_n_classes for multiclass classification or classification_positive_class for binary classification. + /// The hyperparameters used for the fine-tuning job. /// - [JsonPropertyName("compute_classification_metrics")] - public bool? ComputeClassificationMetrics { get; set; } + [JsonPropertyName("hyperparameters")] + public HyperparametersRequestModel? Hyperparameters { get; set; } // This can be further detailed if the properties of the hyperparameters are known. /// - /// The number of classes in a classification task. - /// This parameter is required for multiclass classification. + /// A string of up to 18 characters that will be added to your fine-tuned model name. + /// For example, a suffix of "custom-model-name" would produce a model name like + /// ft:gpt-3.5-turbo:openai:custom-model-name:7p4lURel. /// - [JsonPropertyName("classification_n_classes")] - public int? ClassificationNClasses { get; set; } - - /// - /// The positive class in binary classification. - /// This parameter is needed to generate precision, recall, and F1 metrics when doing binary classification. - /// - [JsonPropertyName("classification_positive_class")] - public string? ClassificationPositiveClass { get; set; } - - //TODO documentation wasn't clear, I don't know which type of array is expected - /// - /// If this is provided, we calculate F-beta scores at the specified beta values. The F-beta score is a generalization - /// of F-1 score. This is only used for binary classification. - /// With a beta of 1 (i.e.the F-1 score), precision and recall are given the same weight.A larger beta score puts more - /// weight on recall and less on precision. A smaller beta score puts more weight on precision and less on recall. - /// - [JsonPropertyName("classification_betas")] - public List? ClassificationBetas { get; set; } + [JsonPropertyName("suffix")] + public string? Suffix { get; set; } = null; /// - /// A string of up to 40 characters that will be added to your fine-tuned model name. - /// For example, a suffix of "custom-model-name" would produce a model name like - /// ada:ft-your-org:custom-model-name-2022-02-15-04-21-04. + /// The name of the model to fine-tune. You can select one of the + /// supported models + /// . /// - [JsonPropertyName("suffix")] - public string? Suffix { get; set; } - + [JsonPropertyName("model")] + public string Model { get; set; } +} +public class HyperparametersRequestModel +{ /// - /// The name of the base model to fine-tune. You can select one of "ada", "babbage", or "curie". To learn more about - /// these models, see the Models documentation. + /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. + /// "Auto" decides the optimal number of epochs based on the size of the dataset. If setting the number manually, we + /// support any number between 1 and 50 epochs. + /// "Auto" == -1 /// - [JsonPropertyName("model")] - public string? Model { get; set; } + [JsonPropertyName("n_epochs")] + [JsonConverter(typeof(NEpochsConverter))] + public int? NEpochs { get; set; } } \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobListEventsRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobListEventsRequest.cs new file mode 100644 index 00000000..e788c1d8 --- /dev/null +++ b/OpenAI.SDK/ObjectModels/RequestModels/FineTuningJobListEventsRequest.cs @@ -0,0 +1,29 @@ +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.RequestModels +{ + public class FineTuningJobListEventsRequest:FineTuningJobListRequest + { + /// + /// The ID of the fine-tuning job to get events for. + /// + [JsonIgnore] + public string FineTuningJobId { get; set; } + } + + public class FineTuningJobListRequest + { + /// + /// Identifier for the last job from the previous pagination request. + /// + [JsonPropertyName("after")] + public string? After { get; set; } + + /// + /// Number of fine-tuning jobs to retrieve. + /// Defaults to 20. + /// + [JsonPropertyName("limit")] + public int? Limit { get; set; } + } +} diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs index 140c1f12..be4ca12b 100644 --- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListEventsResponse.cs @@ -7,5 +7,8 @@ public record FineTuningJobListEventsResponse : BaseResponse { [JsonPropertyName("data")] public List Data { get; set; } + + [JsonPropertyName("has_more")] + public bool HasMore { get; set; } } diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs index 068121d8..3f13cd78 100644 --- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobListResponse.cs @@ -6,5 +6,8 @@ public record FineTuningJobListResponse : BaseResponse { [JsonPropertyName("data")] public List Data { get; set; } + + [JsonPropertyName("has_more")] + public bool HasMore { get; set; } } diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs index cbb4404d..dd50aaa6 100644 --- a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/FineTuningJobResponse.cs @@ -1,46 +1,97 @@ -using OpenAI.ObjectModels.SharedModels; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; +using OpenAI.ObjectModels.SharedModels; namespace OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; public record FineTuningJobResponse : BaseResponse, IOpenAiModels.IId, IOpenAiModels.IModel, IOpenAiModels.ICreatedAt { - [JsonPropertyName("id")] - public string Id { get; set; } - - [JsonPropertyName("created_at")] - public int CreatedAt { get; set; } - + /// + /// The Unix timestamp (in seconds) for when the fine-tuning job was finished. The value will be null if the + /// fine-tuning job is still running. + /// [JsonPropertyName("finished_at")] public int? FinishedAt { get; set; } - [JsonPropertyName("model")] - public string Model { get; set; } - + /// + /// The name of the fine-tuned model that is being created. The value will be null if the fine-tuning job is still + /// running. + /// [JsonPropertyName("fine_tuned_model")] public string? FineTunedModel { get; set; } + /// + /// The organization that owns the fine-tuning job. + /// [JsonPropertyName("organization_id")] - public string OrganizationId { get; set; } + public string? OrganizationId { get; set; } + /// + /// The current status of the fine-tuning job, which can be either created, pending, running, succeeded, failed, or + /// cancelled. + /// [JsonPropertyName("status")] public string Status { get; set; } + /// + /// The hyperparameters used for the fine-tuning job. See the fine-tuning guide for more details. + /// [JsonPropertyName("hyperparameters")] - public HyperParametersResponse HyperParameters { get; set; } - - [JsonPropertyName("validation_file")] - public string? ValidationFile { get; set; } + public Hyperparameters HyperparametersData { get; set; } + /// + /// The file ID used for training. You can retrieve the training data with the Files API. + /// [JsonPropertyName("training_file")] public string TrainingFile { get; set; } + /// + /// The file ID used for validation. You can retrieve the validation results with the Files API. + /// + [JsonPropertyName("validation_file")] + public string? ValidationFile { get; set; } + + /// + /// The compiled results file ID(s) for the fine-tuning job. You can retrieve the results with the Files API. + /// [JsonPropertyName("result_files")] public List ResultFiles { get; set; } + /// + /// The total number of billable tokens processed by this fine-tuning job. The value will be null if the fine-tuning + /// job is still running. + /// [JsonPropertyName("trained_tokens")] public int? TrainedTokens { get; set; } - [JsonPropertyName("updated_at")] - public int? UpdatedAt { get; set; } -} + /// + /// The Unix timestamp (in seconds) for when the fine-tuning job was created. + /// + [JsonPropertyName("created_at")] + public int CreatedAt { get; set; } + + /// + /// The object identifier, which can be referenced in the API endpoints. + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// The base model that is being fine-tuned. + /// + [JsonPropertyName("model")] + public string Model { get; set; } + + + public class Hyperparameters + { + /// + /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. + /// "Auto" decides the optimal number of epochs based on the size of the dataset. If setting the number manually, we + /// support any number between 1 and 50 epochs. + /// "Auto" == -1 + /// + [JsonPropertyName("n_epochs")] + [JsonConverter(typeof(NEpochsConverter))] + public int? NEpochs { get; set; } + } +} \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/NEpochsConverter.cs b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/NEpochsConverter.cs new file mode 100644 index 00000000..ae88f22a --- /dev/null +++ b/OpenAI.SDK/ObjectModels/ResponseModels/FineTuningJobResponseModels/NEpochsConverter.cs @@ -0,0 +1,42 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; + +public class NEpochsConverter : JsonConverter +{ + public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.String: + { + var stringValue = reader.GetString(); + if (stringValue?.ToLower() == "auto") + return -1; + break; + } + case JsonTokenType.Number: + return reader.GetInt32(); + case JsonTokenType.Null: + return null; + } + + throw new JsonException($"Unexpected token type: {reader.TokenType}"); + } + + public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options) + { + if (value.HasValue) + { + if (value.Value == -1) + writer.WriteStringValue("auto"); + else + writer.WriteNumberValue(value.Value); + } + else + { + writer.WriteNullValue(); + } + } +} \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/ResponseModels/ModelResponseModels/ModelDeleteResponse.cs b/OpenAI.SDK/ObjectModels/ResponseModels/ModelResponseModels/ModelDeleteResponse.cs new file mode 100644 index 00000000..4bc146bb --- /dev/null +++ b/OpenAI.SDK/ObjectModels/ResponseModels/ModelResponseModels/ModelDeleteResponse.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace OpenAI.ObjectModels.ResponseModels.ModelResponseModels; + +public record ModelDeleteResponse : BaseResponse +{ + [JsonPropertyName("id")] public string Id { get; set; } + + [JsonPropertyName("deleted")] public bool Deleted { get; set; } +} \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs index a6e1bbf4..9d74f2e6 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/EventResponse.cs @@ -4,11 +4,13 @@ namespace OpenAI.ObjectModels.SharedModels; public record EventResponse { - [JsonPropertyName("object")] public string Object { get; set; } + [JsonPropertyName("object")] public string? ObjectTypeName { get; set; } + [JsonPropertyName("id")] public string? Id { get; set; } [JsonPropertyName("created_at")] public int? CreatedAt { get; set; } [JsonPropertyName("level")] public string Level { get; set; } [JsonPropertyName("message")] public string Message { get; set; } + [JsonPropertyName("type")] public string Type { get; set; } } \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/SharedModels/HyperParametersResponse.cs b/OpenAI.SDK/ObjectModels/SharedModels/HyperParametersResponse.cs index ef9f0784..f64ca5a5 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/HyperParametersResponse.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/HyperParametersResponse.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using OpenAI.ObjectModels.ResponseModels.FineTuningJobResponseModels; namespace OpenAI.ObjectModels.SharedModels; @@ -9,7 +10,9 @@ public record HyperParametersResponse [JsonPropertyName("learning_rate_multiplier")] public float? LearningRateMultiplier { get; set; } - [JsonPropertyName("n_epochs")] public int? NEpochs { get; set; } + [JsonPropertyName("n_epochs")] + [JsonConverter(typeof(NEpochsConverter))] + public int? NEpochs { get; set; } [JsonPropertyName("prompt_loss_weight")] public float? PromptLossWeight { get; set; } diff --git a/OpenAI.sln.DotSettings b/OpenAI.sln.DotSettings index cfc5f601..1bc445ce 100644 --- a/OpenAI.sln.DotSettings +++ b/OpenAI.sln.DotSettings @@ -5,6 +5,7 @@ True True True + True True True From 877df2767ba5e78247c71d1e75b8d52b28fa8c52 Mon Sep 17 00:00:00 2001 From: Tolga Kayhan Date: Fri, 6 Oct 2023 21:09:01 +0100 Subject: [PATCH 13/13] Version bump and changelog update --- OpenAI.SDK/OpenAI.csproj | 2 +- Readme.md | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/OpenAI.SDK/OpenAI.csproj b/OpenAI.SDK/OpenAI.csproj index 71e72667..0cd760c9 100644 --- a/OpenAI.SDK/OpenAI.csproj +++ b/OpenAI.SDK/OpenAI.csproj @@ -11,7 +11,7 @@ OpenAI-Betalgo.png true OpenAI SDK by Betalgo - 7.1.5 + 7.2.0 Tolga Kayhan, Betalgo Betalgo Up Ltd. OpenAI ChatGPT, Whisper, GPT-4 and DALL·E dotnet SDK diff --git a/Readme.md b/Readme.md index ce18e7d2..3d854872 100644 --- a/Readme.md +++ b/Readme.md @@ -222,6 +222,10 @@ I will always be using the latest libraries, and future releases will frequently I am incredibly busy. If I forgot your name, please accept my apologies and let me know so I can add it to the list. ## Changelog +### 7.2.0 +- Added Chatgpt Finetununig support thanks to @aghimir3 +- Default Azure Openai version increased thanks to @mac8005 +- Fixed Azure Openai Audio endpoint thanks to @mac8005 ### 7.1.5 - Added error handling for PlatformNotSupportedException in PostAsStreamAsync when using HttpClient.Send, now falls back to SendRequestPreNet6 for compatibility on platforms like MAUI, Mac. Thanks to @Almis90 - We now have a function caller describe method that automatically generates function descriptions. This method is available in the utilities library. Thanks to @vbandi @@ -249,15 +253,3 @@ I am incredibly busy. If I forgot your name, please accept my apologies and let //Now var openAiService = new OpenAIService(options, httpClient); ``` -### 6.8.6 -- Updated Azure OpenAI default API version to the preview version to support ChatGPT. thanks to all [issue reporters](https://github.com/betalgo/openai/issues/181) -- Added support for an optional chat `name` field. thanks to @shanepowell -- Breaking Change - - `FineTuneCreateRequest.PromptLossWeight` converto to float thanks to @JohnJ0808 -### 6.8.5 -- Mostly bug fixes -- Fixed Moderation functions. https://github.com/betalgo/openai/issues/214 thanks to @scolmarg @AbdelAzizMohamedMousa @digitalvir -- Added File Stream support for Whisper, Thanks to @Swimburger -- Fixed Whisper default response type, Thanks to @Swimburger -- Performance improvements and code clean up,again Thanks to @Swimburger 👏 -- Code clenaup, Thanks to @WeihanLi