Skip to content

Commit

Permalink
feat(client): add auto-pagination to fine tuning list endpoints (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-bot authored Aug 25, 2023
1 parent 294727a commit 5f89c5e
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 32 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,37 @@ On timeout, an `APIConnectionTimeoutError` is thrown.

Note that requests which time out will be [retried twice by default](#retries).

## Auto-pagination

List methods in the OpenAI API are paginated.
You can use `for await … of` syntax to iterate through items across all pages:

```ts
async function fetchAllFineTuningJobs(params) {
const allFineTuningJobs = [];
// Automatically fetches more pages as needed.
for await (const job of openai.fineTuning.jobs.list({ limit: 20 })) {
allFineTuningJobs.push(job);
}
return allFineTuningJobs;
}
```

Alternatively, you can make request a single page at a time:

```ts
let page = await openai.fineTuning.jobs.list({ limit: 20 });
for (const job of page.data) {
console.log(job);
}

// Convenience methods are provided for manually paginating:
while (page.hasNextPage()) {
page = page.getNextPage();
// ...
}
```

## Advanced Usage

### Accessing raw Response data (e.g., headers)
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ export namespace OpenAI {
export import Page = Pagination.Page;
export import PageResponse = Pagination.PageResponse;

export import CursorPage = Pagination.CursorPage;
export import CursorPageParams = Pagination.CursorPageParams;
export import CursorPageResponse = Pagination.CursorPageResponse;

export import Completions = API.Completions;
export import Completion = API.Completion;
export import CompletionChoice = API.CompletionChoice;
Expand Down
60 changes: 59 additions & 1 deletion src/pagination.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// File generated from our OpenAPI spec by Stainless.

import { AbstractPage, Response, APIClient, FinalRequestOptions } from './core';
import { AbstractPage, Response, APIClient, FinalRequestOptions, PageInfo } from './core';

export interface PageResponse<Item> {
data: Array<Item>;
Expand Down Expand Up @@ -40,3 +40,61 @@ export class Page<Item> extends AbstractPage<Item> implements PageResponse<Item>
return null;
}
}

export interface CursorPageResponse<Item> {
data: Array<Item>;
}

export interface CursorPageParams {
/**
* Identifier for the last job from the previous pagination request.
*/
after?: string;

/**
* Number of fine-tuning jobs to retrieve.
*/
limit?: number;
}

export class CursorPage<Item extends { id: string }>
extends AbstractPage<Item>
implements CursorPageResponse<Item>
{
data: Array<Item>;

constructor(
client: APIClient,
response: Response,
body: CursorPageResponse<Item>,
options: FinalRequestOptions,
) {
super(client, response, body, options);

this.data = body.data;
}

getPaginatedItems(): Item[] {
return this.data;
}

// @deprecated Please use `nextPageInfo()` instead
nextPageParams(): Partial<CursorPageParams> | null {
const info = this.nextPageInfo();
if (!info) return null;
if ('params' in info) return info.params;
const params = Object.fromEntries(info.url.searchParams);
if (!Object.keys(params).length) return null;
return params;
}

nextPageInfo(): PageInfo | null {
if (!this.data?.length) {
return null;
}

const next = this.data[this.data.length - 1]?.id;
if (!next) return null;
return { params: { after: next } };
}
}
36 changes: 5 additions & 31 deletions src/resources/fine-tuning/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { APIResource } from 'openai/resource';
import { isRequestOptions } from 'openai/core';
import * as Files from 'openai/resources/files';
import * as API from './index';
import { Page } from 'openai/pagination';
import { CursorPage, CursorPageParams } from 'openai/pagination';

export class Jobs extends APIResource {
/**
Expand Down Expand Up @@ -81,17 +81,11 @@ export class Jobs extends APIResource {
}
}

/**
* Note: no pagination actually occurs yet, this is for forwards-compatibility.
*/
export class FineTuningJobsPage extends Page<FineTuningJob> {}
export class FineTuningJobsPage extends CursorPage<FineTuningJob> {}
// alias so we can export it in the namespace
type _FineTuningJobsPage = FineTuningJobsPage;

/**
* Note: no pagination actually occurs yet, this is for forwards-compatibility.
*/
export class FineTuningJobEventsPage extends Page<FineTuningJobEvent> {}
export class FineTuningJobEventsPage extends CursorPage<FineTuningJobEvent> {}
// alias so we can export it in the namespace
type _FineTuningJobEventsPage = FineTuningJobEventsPage;

Expand Down Expand Up @@ -258,29 +252,9 @@ export namespace JobCreateParams {
}
}

export interface JobListParams {
/**
* Identifier for the last job from the previous pagination request.
*/
after?: string;

/**
* Number of fine-tuning jobs to retrieve.
*/
limit?: number;
}

export interface JobListEventsParams {
/**
* Identifier for the last event from the previous pagination request.
*/
after?: string;
export interface JobListParams extends CursorPageParams {}

/**
* Number of events to retrieve.
*/
limit?: number;
}
export interface JobListEventsParams extends CursorPageParams {}

export namespace Jobs {
export import FineTuningJob = API.FineTuningJob;
Expand Down

0 comments on commit 5f89c5e

Please sign in to comment.