Skip to content

Commit

Permalink
Move service methods for paginated endpoints to use SCM based paginat…
Browse files Browse the repository at this point in the history
…ion pattern (#188)
  • Loading branch information
ShivangiReja authored Aug 27, 2024
1 parent 9664ef8 commit 5773292
Show file tree
Hide file tree
Showing 10 changed files with 575 additions and 56 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Release History

## 2.0.0-beta.11 (Unreleased)

### Features Added

### Breaking Changes

- Updated fine-tuning pagination methods `GetJobs`, `GetEvents`, and `GetJobCheckpoints` to return `IEnumerable<ClientResult>` instead of `ClientResult`. (commit_hash)
- Updated the batching pagination method `GetBatches` to return `IEnumerable<ClientResult>` instead of `ClientResult`. (commit_hash)

### Bugs Fixed

### Other Changes

## 2.0.0-beta.10 (2024-08-26)

### Breaking Changes
Expand Down
16 changes: 8 additions & 8 deletions api/OpenAI.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,8 +1170,8 @@ public class BatchClient {
public virtual Task<ClientResult> CreateBatchAsync(BinaryContent content, RequestOptions options = null);
public virtual ClientResult GetBatch(string batchId, RequestOptions options);
public virtual Task<ClientResult> GetBatchAsync(string batchId, RequestOptions options);
public virtual ClientResult GetBatches(string after, int? limit, RequestOptions options);
public virtual Task<ClientResult> GetBatchesAsync(string after, int? limit, RequestOptions options);
public virtual IEnumerable<ClientResult> GetBatches(string after, int? limit, RequestOptions options);
public virtual IAsyncEnumerable<ClientResult> GetBatchesAsync(string after, int? limit, RequestOptions options);
}
}
namespace OpenAI.Chat {
Expand Down Expand Up @@ -1792,12 +1792,12 @@ public class FineTuningClient {
public virtual Task<ClientResult> CreateJobAsync(BinaryContent content, RequestOptions options = null);
public virtual ClientResult GetJob(string jobId, RequestOptions options);
public virtual Task<ClientResult> GetJobAsync(string jobId, RequestOptions options);
public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options);
public virtual Task<ClientResult> GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options);
public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options);
public virtual Task<ClientResult> GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options);
public virtual ClientResult GetJobs(string after, int? limit, RequestOptions options);
public virtual Task<ClientResult> GetJobsAsync(string after, int? limit, RequestOptions options);
public virtual IEnumerable<ClientResult> GetJobCheckpoints(string jobId, string after, int? limit, RequestOptions options);
public virtual IAsyncEnumerable<ClientResult> GetJobCheckpointsAsync(string jobId, string after, int? limit, RequestOptions options);
public virtual IEnumerable<ClientResult> GetJobEvents(string jobId, string after, int? limit, RequestOptions options);
public virtual IAsyncEnumerable<ClientResult> GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options);
public virtual IEnumerable<ClientResult> GetJobs(string after, int? limit, RequestOptions options);
public virtual IAsyncEnumerable<ClientResult> GetJobsAsync(string after, int? limit, RequestOptions options);
}
}
namespace OpenAI.Images {
Expand Down
13 changes: 7 additions & 6 deletions src/Custom/Batch/BatchClient.Protocol.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace OpenAI.Batch;
Expand Down Expand Up @@ -49,10 +50,10 @@ public virtual ClientResult CreateBatch(BinaryContent content, RequestOptions op
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> GetBatchesAsync(string after, int? limit, RequestOptions options)
public virtual IAsyncEnumerable<ClientResult> GetBatchesAsync(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetBatchesRequest(after, limit, options);
return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
BatchesPageEnumerator enumerator = new BatchesPageEnumerator(_pipeline, _endpoint, after, limit, options);
return PageCollectionHelpers.CreateAsync(enumerator);
}

/// <summary>
Expand All @@ -63,10 +64,10 @@ public virtual async Task<ClientResult> GetBatchesAsync(string after, int? limit
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult GetBatches(string after, int? limit, RequestOptions options)
public virtual IEnumerable<ClientResult> GetBatches(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetBatchesRequest(after, limit, options);
return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options));
BatchesPageEnumerator enumerator = new BatchesPageEnumerator(_pipeline, _endpoint, after, limit, options);
return PageCollectionHelpers.Create(enumerator);
}

/// <summary>
Expand Down
108 changes: 108 additions & 0 deletions src/Custom/Batch/Internal/Pagination/BatchesPageEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Text.Json;
using System.Threading.Tasks;

#nullable enable

namespace OpenAI.Batch;

internal partial class BatchesPageEnumerator : PageResultEnumerator
{
private readonly ClientPipeline _pipeline;
private readonly Uri _endpoint;

private readonly int? _limit;
private readonly RequestOptions _options;

private string _after;

public BatchesPageEnumerator(
ClientPipeline pipeline,
Uri endpoint,
string after, int? limit,
RequestOptions options)
{
_pipeline = pipeline;
_endpoint = endpoint;

_after = after;
_limit = limit;
_options = options;
}

public override async Task<ClientResult> GetFirstAsync()
=> await GetBatchesAsync(_after, _limit, _options).ConfigureAwait(false);

public override ClientResult GetFirst()
=> GetBatches(_after, _limit, _options);

public override async Task<ClientResult> GetNextAsync(ClientResult result)
{
PipelineResponse response = result.GetRawResponse();

using JsonDocument doc = JsonDocument.Parse(response.Content);
_after = doc.RootElement.GetProperty("last_id"u8).GetString()!;

return await GetBatchesAsync(_after, _limit, _options).ConfigureAwait(false);
}

public override ClientResult GetNext(ClientResult result)
{
PipelineResponse response = result.GetRawResponse();

using JsonDocument doc = JsonDocument.Parse(response.Content);
_after = doc.RootElement.GetProperty("last_id"u8).GetString()!;

return GetBatches(_after, _limit, _options);
}

public override bool HasNext(ClientResult result)
{
PipelineResponse response = result.GetRawResponse();

using JsonDocument doc = JsonDocument.Parse(response.Content);
bool hasMore = doc.RootElement.GetProperty("has_more"u8).GetBoolean();

return hasMore;
}

internal virtual async Task<ClientResult> GetBatchesAsync(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetBatchesRequest(after, limit, options);
return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}

internal virtual ClientResult GetBatches(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetBatchesRequest(after, limit, options);
return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options));
}

internal PipelineMessage CreateGetBatchesRequest(string after, int? limit, RequestOptions options)
{
var message = _pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
var request = message.Request;
request.Method = "GET";
var uri = new ClientUriBuilder();
uri.Reset(_endpoint);
uri.AppendPath("/v1/batches", false);
if (after != null)
{
uri.AppendQuery("after", after, true);
}
if (limit != null)
{
uri.AppendQuery("limit", limit.Value, true);
}
request.Uri = uri.ToUri();
request.Headers.Set("Accept", "application/json");
message.Apply(options);
return message;
}

private static PipelineMessageClassifier? _pipelineMessageClassifier200;
private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 });
}
53 changes: 27 additions & 26 deletions src/Custom/FineTuning/FineTuningClient.Protocol.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace OpenAI.FineTuning;
Expand Down Expand Up @@ -76,10 +77,10 @@ public virtual ClientResult CreateJob(BinaryContent content, RequestOptions opti
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> GetJobsAsync(string after, int? limit, RequestOptions options)
public virtual IAsyncEnumerable<ClientResult> GetJobsAsync(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetPaginatedFineTuningJobsRequest(after, limit, options);
return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
FineTuningJobsPageEnumerator enumerator = new FineTuningJobsPageEnumerator(_pipeline, _endpoint, after, limit, options);
return PageCollectionHelpers.CreateAsync(enumerator);
}

// CUSTOM:
Expand All @@ -93,10 +94,10 @@ public virtual async Task<ClientResult> GetJobsAsync(string after, int? limit, R
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult GetJobs(string after, int? limit, RequestOptions options)
public virtual IEnumerable<ClientResult> GetJobs(string after, int? limit, RequestOptions options)
{
using PipelineMessage message = CreateGetPaginatedFineTuningJobsRequest(after, limit, options);
return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options));
FineTuningJobsPageEnumerator enumerator = new FineTuningJobsPageEnumerator(_pipeline, _endpoint, after, limit, options);
return PageCollectionHelpers.Create(enumerator);
}

// CUSTOM:
Expand Down Expand Up @@ -197,12 +198,12 @@ public virtual ClientResult CancelJob(string jobId, RequestOptions options)
/// <exception cref="ArgumentException"> <paramref name="jobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options)
public virtual IAsyncEnumerable<ClientResult> GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(jobId, nameof(jobId));

using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options);
return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
FineTuningJobEventsPageEnumerator enumerator = new FineTuningJobEventsPageEnumerator(_pipeline, _endpoint, jobId, after, limit, options);
return PageCollectionHelpers.CreateAsync(enumerator);
}

// CUSTOM:
Expand All @@ -219,49 +220,49 @@ public virtual async Task<ClientResult> GetJobEventsAsync(string jobId, string a
/// <exception cref="ArgumentException"> <paramref name="jobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options)
public virtual IEnumerable<ClientResult> GetJobEvents(string jobId, string after, int? limit, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(jobId, nameof(jobId));

using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options);
return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options));
FineTuningJobEventsPageEnumerator enumerator = new FineTuningJobEventsPageEnumerator(_pipeline, _endpoint, jobId, after, limit, options);
return PageCollectionHelpers.Create(enumerator);
}

/// <summary>
/// [Protocol Method] List the checkpoints for a fine-tuning job.
/// </summary>
/// <param name="fineTuningJobId"> The ID of the fine-tuning job to get checkpoints for. </param>
/// <param name="jobId"> The ID of the fine-tuning job to get checkpoints for. </param>
/// <param name="after"> Identifier for the last checkpoint ID from the previous pagination request. </param>
/// <param name="limit"> Number of checkpoints to retrieve. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="fineTuningJobId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="fineTuningJobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="jobId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="jobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options)
public virtual IAsyncEnumerable<ClientResult> GetJobCheckpointsAsync(string jobId, string after, int? limit, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId));
Argument.AssertNotNullOrEmpty(jobId, nameof(jobId));

using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options);
return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
FineTuningJobCheckpointsPageEnumerator enumerator = new FineTuningJobCheckpointsPageEnumerator(_pipeline, _endpoint, jobId, after, limit, options);
return PageCollectionHelpers.CreateAsync(enumerator);
}

/// <summary>
/// [Protocol Method] List the checkpoints for a fine-tuning job.
/// </summary>
/// <param name="fineTuningJobId"> The ID of the fine-tuning job to get checkpoints for. </param>
/// <param name="jobId"> The ID of the fine-tuning job to get checkpoints for. </param>
/// <param name="after"> Identifier for the last checkpoint ID from the previous pagination request. </param>
/// <param name="limit"> Number of checkpoints to retrieve. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="fineTuningJobId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="fineTuningJobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="jobId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="jobId"/> is an empty string, and was expected to be non-empty. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options)
public virtual IEnumerable<ClientResult> GetJobCheckpoints(string jobId, string after, int? limit, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId));
Argument.AssertNotNullOrEmpty(jobId, nameof(jobId));

using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options);
return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options));
FineTuningJobCheckpointsPageEnumerator enumerator = new FineTuningJobCheckpointsPageEnumerator(_pipeline, _endpoint, jobId, after, limit, options);
return PageCollectionHelpers.Create(enumerator);
}
}
Loading

0 comments on commit 5773292

Please sign in to comment.