diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0eebf4fc3..028d2d672 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.9.2" + ".": "5.10.0" } diff --git a/.stats.yml b/.stats.yml index 571b0ee79..2b9160cf6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c7dacca97e28bceff218684bb429481a70aa47aadad983ed9178bfda75ff4cd2.yml -openapi_spec_hash: 28eb1bb901ca10d2e37db4606d2bcfa7 -config_hash: 167ad0ca036d0f023c78e6496b4311e8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-670ea0d2cc44f52a87dd3cadea45632953283e0636ba30788fdbdb22a232ccac.yml +openapi_spec_hash: d8b7d38911fead545adf3e4297956410 +config_hash: 5525bda35e48ea6387c6175c4d1651fa diff --git a/CHANGELOG.md b/CHANGELOG.md index 087c0abc5..8f3f01aac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 5.10.0 (2025-07-16) + +Full Changelog: [v5.9.2...v5.10.0](https://github.com/openai/openai-node/compare/v5.9.2...v5.10.0) + +### Features + +* **api:** manual updates ([35338b4](https://github.com/openai/openai-node/commit/35338b44ace44f0f0c0b48ea94aa96d3c81ea385)) + + +### Chores + +* **internal:** version bump ([3d9de4b](https://github.com/openai/openai-node/commit/3d9de4b2f28c80ea1f92446c092b23d69955ef30)) + ## 5.9.2 (2025-07-15) Full Changelog: [v5.9.1...v5.9.2](https://github.com/openai/openai-node/compare/v5.9.1...v5.9.2) diff --git a/api.md b/api.md index 17360e897..ef66d4e6c 100644 --- a/api.md +++ b/api.md @@ -119,6 +119,12 @@ Methods: Types: - Image +- ImageEditCompletedEvent +- ImageEditPartialImageEvent +- ImageEditStreamEvent +- ImageGenCompletedEvent +- ImageGenPartialImageEvent +- ImageGenStreamEvent - ImageModel - ImagesResponse diff --git a/examples/image-stream.ts b/examples/image-stream.ts new file mode 100755 index 000000000..62ea2a8b9 --- /dev/null +++ b/examples/image-stream.ts @@ -0,0 +1,51 @@ +#!/usr/bin/env -S npm run tsn -T + +import OpenAI from 'openai'; +import fs from 'fs'; +import path from 'path'; + +const client = new OpenAI(); + +const main = async () => { + const stream = await client.images.generate({ + model: 'gpt-image-1', + prompt: 'A cute baby sea otter', + n: 1, + size: '1024x1024', + stream: true, + partial_images: 3, + }); + + for await (const event of stream) { + let filename: string; + let imageBuffer: Buffer; + switch (event.type) { + case 'image_generation.partial_image': + console.log(` Partial image ${event.partial_image_index + 1}/3 received`); + console.log(` Size: ${event.b64_json.length} characters (base64)`); + + // Save partial image to file + filename = `partial_${event.partial_image_index + 1}.png`; + imageBuffer = Buffer.from(event.b64_json, 'base64'); + fs.writeFileSync(filename, imageBuffer); + console.log(` šŸ’¾ Saved to: ${path.resolve(filename)}`); + break; + case 'image_generation.completed': + console.log(`\nāœ… Final image completed!`); + console.log(` Size: ${event.b64_json.length} characters (base64)`); + + // Save final image to file + filename = 'final_image.png'; + imageBuffer = Buffer.from(event.b64_json, 'base64'); + fs.writeFileSync(filename, imageBuffer); + console.log(` Saved to: ${path.resolve(filename)}`); + break; + default: + console.log(`ā“ Unknown event: ${event}`); + } + } +}; + +main().catch((error) => { + console.error('Error generating image:', error); +}); diff --git a/jsr.json b/jsr.json index 739fd370b..05293a794 100644 --- a/jsr.json +++ b/jsr.json @@ -1,6 +1,6 @@ { "name": "@openai/openai", - "version": "5.9.2", + "version": "5.10.0", "exports": { ".": "./index.ts", "./helpers/zod": "./helpers/zod.ts", diff --git a/package.json b/package.json index 61159782a..79a304264 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openai", - "version": "5.9.2", + "version": "5.10.0", "description": "The official TypeScript library for the OpenAI API", "author": "OpenAI ", "types": "dist/index.d.ts", diff --git a/src/client.ts b/src/client.ts index 74ca1c51d..81102c552 100644 --- a/src/client.ts +++ b/src/client.ts @@ -57,8 +57,18 @@ import { import { Image, ImageCreateVariationParams, + ImageEditCompletedEvent, ImageEditParams, + ImageEditParamsNonStreaming, + ImageEditParamsStreaming, + ImageEditPartialImageEvent, + ImageEditStreamEvent, + ImageGenCompletedEvent, + ImageGenPartialImageEvent, + ImageGenStreamEvent, ImageGenerateParams, + ImageGenerateParamsNonStreaming, + ImageGenerateParamsStreaming, ImageModel, Images, ImagesResponse, @@ -1039,11 +1049,21 @@ export declare namespace OpenAI { export { Images as Images, type Image as Image, + type ImageEditCompletedEvent as ImageEditCompletedEvent, + type ImageEditPartialImageEvent as ImageEditPartialImageEvent, + type ImageEditStreamEvent as ImageEditStreamEvent, + type ImageGenCompletedEvent as ImageGenCompletedEvent, + type ImageGenPartialImageEvent as ImageGenPartialImageEvent, + type ImageGenStreamEvent as ImageGenStreamEvent, type ImageModel as ImageModel, type ImagesResponse as ImagesResponse, type ImageCreateVariationParams as ImageCreateVariationParams, type ImageEditParams as ImageEditParams, + type ImageEditParamsNonStreaming as ImageEditParamsNonStreaming, + type ImageEditParamsStreaming as ImageEditParamsStreaming, type ImageGenerateParams as ImageGenerateParams, + type ImageGenerateParamsNonStreaming as ImageGenerateParamsNonStreaming, + type ImageGenerateParamsStreaming as ImageGenerateParamsStreaming, }; export { Audio as Audio, type AudioModel as AudioModel, type AudioResponseFormat as AudioResponseFormat }; diff --git a/src/core/streaming.ts b/src/core/streaming.ts index 85cb598b1..475630392 100644 --- a/src/core/streaming.ts +++ b/src/core/streaming.ts @@ -57,6 +57,8 @@ export class Stream implements AsyncIterable { if ( sse.event === null || sse.event.startsWith('response.') || + sse.event.startsWith('image_edit.') || + sse.event.startsWith('image_generation.') || sse.event.startsWith('transcript.') ) { let data; diff --git a/src/resources/images.ts b/src/resources/images.ts index 4d7adbd41..8433ec22a 100644 --- a/src/resources/images.ts +++ b/src/resources/images.ts @@ -1,7 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../core/resource'; +import * as ImagesAPI from './images'; import { APIPromise } from '../core/api-promise'; +import { Stream } from '../core/streaming'; import { type Uploadable } from '../core/uploads'; import { RequestOptions } from '../internal/request-options'; import { multipartFormRequestOptions } from '../internal/uploads'; @@ -36,11 +38,20 @@ export class Images extends APIResource { * }); * ``` */ - edit(body: ImageEditParams, options?: RequestOptions): APIPromise { + edit(body: ImageEditParamsNonStreaming, options?: RequestOptions): APIPromise; + edit(body: ImageEditParamsStreaming, options?: RequestOptions): APIPromise>; + edit( + body: ImageEditParamsBase, + options?: RequestOptions, + ): APIPromise | ImagesResponse>; + edit( + body: ImageEditParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { return this._client.post( '/images/edits', - multipartFormRequestOptions({ body, ...options }, this._client), - ); + multipartFormRequestOptions({ body, ...options, stream: body.stream ?? false }, this._client), + ) as APIPromise | APIPromise>; } /** @@ -54,8 +65,22 @@ export class Images extends APIResource { * }); * ``` */ - generate(body: ImageGenerateParams, options?: RequestOptions): APIPromise { - return this._client.post('/images/generations', { body, ...options }); + generate(body: ImageGenerateParamsNonStreaming, options?: RequestOptions): APIPromise; + generate( + body: ImageGenerateParamsStreaming, + options?: RequestOptions, + ): APIPromise>; + generate( + body: ImageGenerateParamsBase, + options?: RequestOptions, + ): APIPromise | ImagesResponse>; + generate( + body: ImageGenerateParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post('/images/generations', { body, ...options, stream: body.stream ?? false }) as + | APIPromise + | APIPromise>; } } @@ -83,6 +108,284 @@ export interface Image { url?: string; } +/** + * Emitted when image editing has completed and the final image is available. + */ +export interface ImageEditCompletedEvent { + /** + * Base64-encoded final edited image data, suitable for rendering as an image. + */ + b64_json: string; + + /** + * The background setting for the edited image. + */ + background: 'transparent' | 'opaque' | 'auto'; + + /** + * The Unix timestamp when the event was created. + */ + created_at: number; + + /** + * The output format for the edited image. + */ + output_format: 'png' | 'webp' | 'jpeg'; + + /** + * The quality setting for the edited image. + */ + quality: 'low' | 'medium' | 'high' | 'auto'; + + /** + * The size of the edited image. + */ + size: '1024x1024' | '1024x1536' | '1536x1024' | 'auto'; + + /** + * The type of the event. Always `image_edit.completed`. + */ + type: 'image_edit.completed'; + + /** + * For `gpt-image-1` only, the token usage information for the image generation. + */ + usage: ImageEditCompletedEvent.Usage; +} + +export namespace ImageEditCompletedEvent { + /** + * For `gpt-image-1` only, the token usage information for the image generation. + */ + export interface Usage { + /** + * The number of tokens (images and text) in the input prompt. + */ + input_tokens: number; + + /** + * The input tokens detailed information for the image generation. + */ + input_tokens_details: Usage.InputTokensDetails; + + /** + * The number of image tokens in the output image. + */ + output_tokens: number; + + /** + * The total number of tokens (images and text) used for the image generation. + */ + total_tokens: number; + } + + export namespace Usage { + /** + * The input tokens detailed information for the image generation. + */ + export interface InputTokensDetails { + /** + * The number of image tokens in the input prompt. + */ + image_tokens: number; + + /** + * The number of text tokens in the input prompt. + */ + text_tokens: number; + } + } +} + +/** + * Emitted when a partial image is available during image editing streaming. + */ +export interface ImageEditPartialImageEvent { + /** + * Base64-encoded partial image data, suitable for rendering as an image. + */ + b64_json: string; + + /** + * The background setting for the requested edited image. + */ + background: 'transparent' | 'opaque' | 'auto'; + + /** + * The Unix timestamp when the event was created. + */ + created_at: number; + + /** + * The output format for the requested edited image. + */ + output_format: 'png' | 'webp' | 'jpeg'; + + /** + * 0-based index for the partial image (streaming). + */ + partial_image_index: number; + + /** + * The quality setting for the requested edited image. + */ + quality: 'low' | 'medium' | 'high' | 'auto'; + + /** + * The size of the requested edited image. + */ + size: '1024x1024' | '1024x1536' | '1536x1024' | 'auto'; + + /** + * The type of the event. Always `image_edit.partial_image`. + */ + type: 'image_edit.partial_image'; +} + +/** + * Emitted when a partial image is available during image editing streaming. + */ +export type ImageEditStreamEvent = ImageEditPartialImageEvent | ImageEditCompletedEvent; + +/** + * Emitted when image generation has completed and the final image is available. + */ +export interface ImageGenCompletedEvent { + /** + * Base64-encoded image data, suitable for rendering as an image. + */ + b64_json: string; + + /** + * The background setting for the generated image. + */ + background: 'transparent' | 'opaque' | 'auto'; + + /** + * The Unix timestamp when the event was created. + */ + created_at: number; + + /** + * The output format for the generated image. + */ + output_format: 'png' | 'webp' | 'jpeg'; + + /** + * The quality setting for the generated image. + */ + quality: 'low' | 'medium' | 'high' | 'auto'; + + /** + * The size of the generated image. + */ + size: '1024x1024' | '1024x1536' | '1536x1024' | 'auto'; + + /** + * The type of the event. Always `image_generation.completed`. + */ + type: 'image_generation.completed'; + + /** + * For `gpt-image-1` only, the token usage information for the image generation. + */ + usage: ImageGenCompletedEvent.Usage; +} + +export namespace ImageGenCompletedEvent { + /** + * For `gpt-image-1` only, the token usage information for the image generation. + */ + export interface Usage { + /** + * The number of tokens (images and text) in the input prompt. + */ + input_tokens: number; + + /** + * The input tokens detailed information for the image generation. + */ + input_tokens_details: Usage.InputTokensDetails; + + /** + * The number of image tokens in the output image. + */ + output_tokens: number; + + /** + * The total number of tokens (images and text) used for the image generation. + */ + total_tokens: number; + } + + export namespace Usage { + /** + * The input tokens detailed information for the image generation. + */ + export interface InputTokensDetails { + /** + * The number of image tokens in the input prompt. + */ + image_tokens: number; + + /** + * The number of text tokens in the input prompt. + */ + text_tokens: number; + } + } +} + +/** + * Emitted when a partial image is available during image generation streaming. + */ +export interface ImageGenPartialImageEvent { + /** + * Base64-encoded partial image data, suitable for rendering as an image. + */ + b64_json: string; + + /** + * The background setting for the requested image. + */ + background: 'transparent' | 'opaque' | 'auto'; + + /** + * The Unix timestamp when the event was created. + */ + created_at: number; + + /** + * The output format for the requested image. + */ + output_format: 'png' | 'webp' | 'jpeg'; + + /** + * 0-based index for the partial image (streaming). + */ + partial_image_index: number; + + /** + * The quality setting for the requested image. + */ + quality: 'low' | 'medium' | 'high' | 'auto'; + + /** + * The size of the requested image. + */ + size: '1024x1024' | '1024x1536' | '1536x1024' | 'auto'; + + /** + * The type of the event. Always `image_generation.partial_image`. + */ + type: 'image_generation.partial_image'; +} + +/** + * Emitted when a partial image is available during image generation streaming. + */ +export type ImageGenStreamEvent = ImageGenPartialImageEvent | ImageGenCompletedEvent; + export type ImageModel = 'dall-e-2' | 'dall-e-3' | 'gpt-image-1'; /** @@ -210,7 +513,9 @@ export interface ImageCreateVariationParams { user?: string; } -export interface ImageEditParams { +export type ImageEditParams = ImageEditParamsNonStreaming | ImageEditParamsStreaming; + +export interface ImageEditParamsBase { /** * The image(s) to edit. Must be a supported image file or an array of images. * @@ -239,6 +544,13 @@ export interface ImageEditParams { */ background?: 'transparent' | 'opaque' | 'auto' | null; + /** + * Control how much effort the model will exert to match the style and features, + * especially facial features, of input images. This parameter is only supported + * for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + */ + input_fidelity?: 'high' | 'low' | null; + /** * An additional image whose fully transparent areas (e.g. where alpha is zero) * indicate where `image` should be edited. If there are multiple images provided, @@ -273,6 +585,13 @@ export interface ImageEditParams { */ output_format?: 'png' | 'jpeg' | 'webp' | null; + /** + * The number of partial images to generate. This parameter is used for streaming + * responses that return partial images. Value must be between 0 and 3. When set to + * 0, the response will be a single image sent in one streaming event. + */ + partial_images?: number | null; + /** * The quality of the image that will be generated. `high`, `medium` and `low` are * only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. @@ -295,6 +614,13 @@ export interface ImageEditParams { */ size?: '256x256' | '512x512' | '1024x1024' | '1536x1024' | '1024x1536' | 'auto' | null; + /** + * Edit the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. + */ + stream?: boolean | null; + /** * A unique identifier representing your end-user, which can help OpenAI to monitor * and detect abuse. @@ -303,7 +629,32 @@ export interface ImageEditParams { user?: string; } -export interface ImageGenerateParams { +export namespace ImageEditParams { + export type ImageEditParamsNonStreaming = ImagesAPI.ImageEditParamsNonStreaming; + export type ImageEditParamsStreaming = ImagesAPI.ImageEditParamsStreaming; +} + +export interface ImageEditParamsNonStreaming extends ImageEditParamsBase { + /** + * Edit the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. + */ + stream?: false | null; +} + +export interface ImageEditParamsStreaming extends ImageEditParamsBase { + /** + * Edit the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. + */ + stream: true; +} + +export type ImageGenerateParams = ImageGenerateParamsNonStreaming | ImageGenerateParamsStreaming; + +export interface ImageGenerateParamsBase { /** * A text description of the desired image(s). The maximum length is 32000 * characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters @@ -354,6 +705,13 @@ export interface ImageGenerateParams { */ output_format?: 'png' | 'jpeg' | 'webp' | null; + /** + * The number of partial images to generate. This parameter is used for streaming + * responses that return partial images. Value must be between 0 and 3. When set to + * 0, the response will be a single image sent in one streaming event. + */ + partial_images?: number | null; + /** * The quality of the image that will be generated. * @@ -390,6 +748,13 @@ export interface ImageGenerateParams { | '1024x1792' | null; + /** + * Generate the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. This parameter is only supported for `gpt-image-1`. + */ + stream?: boolean | null; + /** * The style of the generated images. This parameter is only supported for * `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -406,13 +771,46 @@ export interface ImageGenerateParams { user?: string; } +export namespace ImageGenerateParams { + export type ImageGenerateParamsNonStreaming = ImagesAPI.ImageGenerateParamsNonStreaming; + export type ImageGenerateParamsStreaming = ImagesAPI.ImageGenerateParamsStreaming; +} + +export interface ImageGenerateParamsNonStreaming extends ImageGenerateParamsBase { + /** + * Generate the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. This parameter is only supported for `gpt-image-1`. + */ + stream?: false | null; +} + +export interface ImageGenerateParamsStreaming extends ImageGenerateParamsBase { + /** + * Generate the image in streaming mode. Defaults to `false`. See the + * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + * for more information. This parameter is only supported for `gpt-image-1`. + */ + stream: true; +} + export declare namespace Images { export { type Image as Image, + type ImageEditCompletedEvent as ImageEditCompletedEvent, + type ImageEditPartialImageEvent as ImageEditPartialImageEvent, + type ImageEditStreamEvent as ImageEditStreamEvent, + type ImageGenCompletedEvent as ImageGenCompletedEvent, + type ImageGenPartialImageEvent as ImageGenPartialImageEvent, + type ImageGenStreamEvent as ImageGenStreamEvent, type ImageModel as ImageModel, type ImagesResponse as ImagesResponse, type ImageCreateVariationParams as ImageCreateVariationParams, type ImageEditParams as ImageEditParams, + type ImageEditParamsNonStreaming as ImageEditParamsNonStreaming, + type ImageEditParamsStreaming as ImageEditParamsStreaming, type ImageGenerateParams as ImageGenerateParams, + type ImageGenerateParamsNonStreaming as ImageGenerateParamsNonStreaming, + type ImageGenerateParamsStreaming as ImageGenerateParamsStreaming, }; } diff --git a/src/resources/index.ts b/src/resources/index.ts index e494fcfcb..5b95908e7 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -67,11 +67,21 @@ export { Graders } from './graders/graders'; export { Images, type Image, + type ImageEditCompletedEvent, + type ImageEditPartialImageEvent, + type ImageEditStreamEvent, + type ImageGenCompletedEvent, + type ImageGenPartialImageEvent, + type ImageGenStreamEvent, type ImageModel, type ImagesResponse, type ImageCreateVariationParams, type ImageEditParams, + type ImageEditParamsNonStreaming, + type ImageEditParamsStreaming, type ImageGenerateParams, + type ImageGenerateParamsNonStreaming, + type ImageGenerateParamsStreaming, } from './images'; export { Models, type Model, type ModelDeleted, type ModelsPage } from './models'; export { diff --git a/src/resources/responses/responses.ts b/src/resources/responses/responses.ts index d7bfbf8cf..6d6f6ef1c 100644 --- a/src/resources/responses/responses.ts +++ b/src/resources/responses/responses.ts @@ -3349,7 +3349,7 @@ export interface ResponseOutputMessage { */ export interface ResponseOutputRefusal { /** - * The refusal explanationfrom the model. + * The refusal explanation from the model. */ refusal: string; @@ -4482,6 +4482,13 @@ export namespace Tool { */ background?: 'transparent' | 'opaque' | 'auto'; + /** + * Control how much effort the model will exert to match the style and features, + * especially facial features, of input images. This parameter is only supported + * for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + */ + input_fidelity?: 'high' | 'low' | null; + /** * Optional mask for inpainting. Contains `image_url` (string, optional) and * `file_id` (string, optional). diff --git a/src/version.ts b/src/version.ts index 75035c60e..c18a9f8dc 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '5.9.2'; // x-release-please-version +export const VERSION = '5.10.0'; // x-release-please-version diff --git a/tests/api-resources/images.test.ts b/tests/api-resources/images.test.ts index 2fcfd34c8..1079ce240 100644 --- a/tests/api-resources/images.test.ts +++ b/tests/api-resources/images.test.ts @@ -51,14 +51,17 @@ describe('resource images', () => { image: await toFile(Buffer.from('# my file contents'), 'README.md'), prompt: 'A cute baby sea otter wearing a beret', background: 'transparent', + input_fidelity: 'high', mask: await toFile(Buffer.from('# my file contents'), 'README.md'), model: 'string', n: 1, output_compression: 100, output_format: 'png', + partial_images: 1, quality: 'high', response_format: 'url', size: '1024x1024', + stream: false, user: 'user-1234', }); }); @@ -83,9 +86,11 @@ describe('resource images', () => { n: 1, output_compression: 100, output_format: 'png', + partial_images: 1, quality: 'medium', response_format: 'url', size: '1024x1024', + stream: false, style: 'vivid', user: 'user-1234', });