From 74c8e83611c29dc993b5802a404c46d86f07088e Mon Sep 17 00:00:00 2001 From: joyqi Date: Wed, 8 Mar 2023 18:04:34 +0800 Subject: [PATCH] add edits and images api --- README.md | 54 +++++++++++++++++++++++++++++++ package.json | 5 +-- pnpm-lock.yaml | 2 ++ src/index.ts | 8 +++++ src/v1/edits.ts | 29 +++++++++++++++++ src/v1/images.ts | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ src/v1/index.ts | 4 ++- 7 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 src/v1/edits.ts create mode 100644 src/v1/images.ts diff --git a/README.md b/README.md index 2fc8615..a4ecb28 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ An elegant Node.js library written in TypeScript for the OpenAI API. +- [Installation](#installation) +- [Example](#example) +- [V1 API](#v1-api) + - [Models](#models) + - [Completions](#completions) + - [Chat](#chat) + - [Edits](#edits) + - [Images](#images) + ## Installation ```bash @@ -46,6 +55,8 @@ To use the OpenAI V1 API, you must call the `v1()` method on the client instance const v1 = client.v1(); ``` +Check out the [OpenAI V1 API docs](https://platform.openai.com/docs/api-reference/introduction) for more information. + ### Models List all available models: @@ -88,3 +99,46 @@ const chat = await v1.chat.create({ ] }); ``` + +### Edits + +Create an edit: + +```javascript +const edit = await v1.edits.create({ + model: 'text-davinci-edit-001', + input: 'I am a test', + instruction: 'Make this text funny', +}); +``` + +### Images + +Create an image: + +```javascript +const image = await v1.images.create({ + prompt: 'A cute baby sea otter', + n: 1, + size: '512x512', +}); +``` + +Create image edit: + +```javascript +const imageEdit = await v1.images.edit({ + prompt: 'Make this image funny', + n: 1, + size: '512x512', +}, '/path/to/image.png'); +``` + +Create image variation: + +```javascript +const imageVariation = await v1.images.variation({ + n: 1, + size: '512x512', +}, '/path/to/image.png'); +``` \ No newline at end of file diff --git a/package.json b/package.json index f7d420e..21c9fe4 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "test": "npx mocha" }, "devDependencies": { - "@types/node": "latest", "@types/mocha": "latest", + "@types/node": "latest", "assert": "latest", "mocha": "latest", "ts-node": "latest", @@ -43,6 +43,7 @@ "typescript": "latest" }, "dependencies": { - "axios": "^1.3.4" + "axios": "^1.3.4", + "form-data": "^4.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5619464..bdf473c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ specifiers: '@types/node': latest assert: latest axios: ^1.3.4 + form-data: ^4.0.0 mocha: latest ts-node: latest tsc-esm-fix: latest @@ -12,6 +13,7 @@ specifiers: dependencies: axios: 1.3.4 + form-data: 4.0.0 devDependencies: '@types/mocha': 10.0.1 diff --git a/src/index.ts b/src/index.ts index 06f4255..ff9678f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -43,6 +43,14 @@ export class OpenAI { }, chat: { create: v1.createChat(client) + }, + edits: { + create: v1.createEdit(client) + }, + images: { + create: v1.createImage(client), + edit: v1.editImage(client), + createVariation: v1.createImageVariation(client) } }; } diff --git a/src/v1/edits.ts b/src/v1/edits.ts new file mode 100644 index 0000000..f7e8a14 --- /dev/null +++ b/src/v1/edits.ts @@ -0,0 +1,29 @@ +import { Usage } from "."; +import { ApiClient } from ".."; + +type EditRequest = { + model: string; + input?: string; + instruction: string; + n?: number; + temperature?: number; + top_p?: number; +}; + +type Choice = { + index: number; + text: string; +} + +type Edit = { + object: string; + created: number; + choices: Choice[]; + usage: Usage; +} + +export function createEdit(client: ApiClient) { + return async (request: EditRequest): Promise => { + return await client("edits", { method: "POST", data: request }); + } +} diff --git a/src/v1/images.ts b/src/v1/images.ts new file mode 100644 index 0000000..b769736 --- /dev/null +++ b/src/v1/images.ts @@ -0,0 +1,83 @@ +import { createReadStream } from "fs"; +import { ApiClient } from ".."; +import FormData from "form-data"; + +type ImageSize = '256x256' | '512x512' | '1024x1024'; + +type ImageResponseFormat = 'url' | 'b64_json'; + +type CreateImageRequest = { + prompt: string; + n?: number; + size?: ImageSize; + response_format?: ImageResponseFormat; + user?: string; +}; + +type EditImageRequest = { + prompt: string; + n?: number; + size?: ImageSize; + response_format?: ImageResponseFormat; + user?: string; +}; + +type CreateImageVariationRequest = { + n?: number; + size?: ImageSize; + response_format?: ImageResponseFormat; + user?: string; +}; + +type UrlImage = { + url: string; +}; + +type B64JsonImage = { + b64_json: string; +}; + +type ImageData = UrlImage | B64JsonImage; + +type Image = { + created: number; + data: ImageData[]; +}; + +export function createImage(client: ApiClient) { + return async (request: CreateImageRequest): Promise => { + return await client("images/generations", { method: "POST", data: request }); + } +} + +export function editImage(client: ApiClient) { + return async (request: EditImageRequest, image: string, mask?: string): Promise => { + const form = new FormData(); + + for (const key in request) { + form.append(key, '' + request[key as keyof EditImageRequest]); + } + + form.append('image', createReadStream(image)); + + if (mask) { + form.append('mask', createReadStream(mask)); + } + + return await client("images/edits", { method: "POST", data: form }); + } +} + +export function createImageVariation(client: ApiClient) { + return async (request: CreateImageVariationRequest, image: string): Promise => { + const form = new FormData(); + + for (const key in request) { + form.append(key, '' + request[key as keyof CreateImageVariationRequest]); + } + + form.append('image', createReadStream(image)); + + return await client("images/variations", { method: "POST", data: form }); + } +} \ No newline at end of file diff --git a/src/v1/index.ts b/src/v1/index.ts index 68b4ac4..e5aabf5 100644 --- a/src/v1/index.ts +++ b/src/v1/index.ts @@ -6,4 +6,6 @@ export type Usage = { export * from "./models"; export * from "./completions"; -export * from "./chat"; \ No newline at end of file +export * from "./chat"; +export * from "./edits"; +export * from "./images"; \ No newline at end of file