feat: new package generate-image (#123)
* feat: new package `generate-image` * fix(generate-image): url path * fix: lint errors * docs: add generate-image * chore(xsai): update exports --------- Co-authored-by: Neko <neko@ayaka.moe>
This commit is contained in:
1 parent
b2d4ba5fea
commit
f51578f9b0
16 files changed
+208
-44
No files matched your search
@@ -3,17 +3,20 @@ ignorePaths: []
|
||||
dictionaryDefinitions: []
|
||||
dictionaries: []
|
||||
words:
|
||||
- AAAAIGZ
|
||||
- agentic
|
||||
- all-minilm
|
||||
- arktype
|
||||
- automd
|
||||
- BAAI
|
||||
- Bhdmlm
|
||||
- bumpp
|
||||
- Cerebras
|
||||
- changelogithub
|
||||
- codestral
|
||||
- cognitivecomputations
|
||||
- composio
|
||||
- dall
|
||||
- deepinfra
|
||||
- deepseek
|
||||
- elevenlabs
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Image
|
||||
description: Creates an image given a prompt.
|
||||
---
|
||||
|
||||
import { PkgSizeBadge } from '@/components/pkg-size-badge'
|
||||
|
||||
<PkgSizeBadge pkg="@xsai/generate-image" />
|
||||
|
||||
```package-install
|
||||
npm i @xsai/generate-image
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```ts twoslash
|
||||
import { generateImage } from '@xsai/generate-image'
|
||||
import { env } from 'node:process'
|
||||
|
||||
const { image } = await generateImage({
|
||||
apiKey: env.OPENAI_API_KEY!,
|
||||
baseURL: 'http://api.openai.com/v1/',
|
||||
model: 'dall-e-3',
|
||||
prompt: 'A cute baby sea otter'
|
||||
})
|
||||
|
||||
const { images } = await generateImage({
|
||||
apiKey: env.OPENAI_API_KEY!,
|
||||
baseURL: 'http://api.openai.com/v1/',
|
||||
n: 4, // [!code highlight]
|
||||
model: 'dall-e-3',
|
||||
prompt: 'A cute baby sea otter'
|
||||
})
|
||||
```
|
||||
@@ -5,6 +5,7 @@
|
||||
"text",
|
||||
"object",
|
||||
"speech",
|
||||
"transcription"
|
||||
"transcription",
|
||||
"image"
|
||||
]
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
"defaultOpen": false,
|
||||
"pages": [
|
||||
"[@xsai/embed](https://tsdocs.dev/search/docs/@xsai/embed)",
|
||||
"[@xsai/generate-image](https://tsdocs.dev/search/docs/@xsai/generate-image)",
|
||||
"[@xsai/generate-object](https://tsdocs.dev/search/docs/@xsai/generate-object)",
|
||||
"[@xsai/generate-speech](https://tsdocs.dev/search/docs/@xsai/generate-speech)",
|
||||
"[@xsai/generate-text](https://tsdocs.dev/search/docs/@xsai/generate-text)",
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"@xsai-ext/providers-cloud": "workspace:^",
|
||||
"@xsai-ext/providers-local": "workspace:^",
|
||||
"@xsai/embed": "workspace:^",
|
||||
"@xsai/generate-image": "workspace:^",
|
||||
"@xsai/generate-object": "workspace:^",
|
||||
"@xsai/generate-speech": "workspace:^",
|
||||
"@xsai/generate-text": "workspace:^",
|
||||
|
||||
+26
-35
@@ -1,36 +1,27 @@
|
||||
// import { defineConfig } from '@importantimport/eslint-config'
|
||||
import { GLOB_MARKDOWN_CODE, GLOB_TESTS } from '@antfu/eslint-config'
|
||||
import { defineConfig } from '@importantimport/eslint-config'
|
||||
|
||||
// export default defineConfig({
|
||||
// typescript: { tsconfigPath: './tsconfig.json' },
|
||||
// })
|
||||
|
||||
import antfu, { GLOB_MARKDOWN_CODE, GLOB_TESTS } from '@antfu/eslint-config'
|
||||
import { ii } from '@importantimport/eslint-config'
|
||||
|
||||
export default antfu({ typescript: { tsconfigPath: './tsconfig.json' } })
|
||||
.append(ii({ typescript: { tsconfigPath: './tsconfig.json' } }))
|
||||
.append({
|
||||
ignores: [
|
||||
'docs/components/ui/**/*.tsx',
|
||||
],
|
||||
})
|
||||
.append({
|
||||
rules: {
|
||||
'@masknet/no-default-error': 'off',
|
||||
'@masknet/no-then': 'off',
|
||||
'sonarjs/todo-tag': 'warn',
|
||||
},
|
||||
})
|
||||
.append({
|
||||
files: [...GLOB_TESTS, GLOB_MARKDOWN_CODE],
|
||||
rules: {
|
||||
'@masknet/no-top-level': 'off',
|
||||
'@masknet/unicode-specific-set': 'off',
|
||||
},
|
||||
})
|
||||
.append({
|
||||
ignores: [
|
||||
'cspell.config.yaml',
|
||||
'cspell.config.yml',
|
||||
],
|
||||
})
|
||||
export default defineConfig({
|
||||
typescript: { tsconfigPath: './tsconfig.json' },
|
||||
}, [{
|
||||
ignores: [
|
||||
'docs/components/ui/**/*.tsx',
|
||||
],
|
||||
}, {
|
||||
rules: {
|
||||
'@masknet/no-default-error': 'off',
|
||||
'@masknet/no-then': 'off',
|
||||
'sonarjs/todo-tag': 'warn',
|
||||
},
|
||||
}, {
|
||||
files: [...GLOB_TESTS, GLOB_MARKDOWN_CODE],
|
||||
rules: {
|
||||
'@masknet/no-top-level': 'off',
|
||||
'@masknet/unicode-specific-set': 'off',
|
||||
},
|
||||
}, {
|
||||
ignores: [
|
||||
'cspell.config.yaml',
|
||||
'cspell.config.yml',
|
||||
],
|
||||
}])
|
||||
@@ -42,6 +42,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@xsai/embed": "workspace:",
|
||||
"@xsai/generate-image": "workspace:",
|
||||
"@xsai/generate-object": "workspace:",
|
||||
"@xsai/generate-speech": "workspace:",
|
||||
"@xsai/generate-text": "workspace:",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from '@xsai/embed'
|
||||
export * from '@xsai/generate-image'
|
||||
export * from '@xsai/generate-object'
|
||||
export * from '@xsai/generate-speech'
|
||||
export * from '@xsai/generate-text'
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
https://xsai.js.org/docs/packages/generate/image
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@xsai/generate-image",
|
||||
"type": "module",
|
||||
"version": "0.2.0-beta.1",
|
||||
"description": "extra-small AI SDK for Browser, Node.js, Deno, Bun or Edge Runtime.",
|
||||
"author": "Moeru AI",
|
||||
"license": "MIT",
|
||||
"homepage": "https://xsai.js.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/moeru-ai/xsai.git",
|
||||
"directory": "packages/generate-image"
|
||||
},
|
||||
"bugs": "https://github.com/moeru-ai/xsai/issues",
|
||||
"keywords": [
|
||||
"xsai",
|
||||
"openai",
|
||||
"ai"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"exports": "./src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup"
|
||||
},
|
||||
"dependencies": {
|
||||
"@xsai/shared": "workspace:"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import type { CommonRequestOptions } from '@xsai/shared'
|
||||
|
||||
import { requestBody, requestHeaders, requestURL, responseJSON } from '@xsai/shared'
|
||||
|
||||
export interface GenerateImageOptions extends CommonRequestOptions {
|
||||
[key: string]: unknown
|
||||
/**
|
||||
* The number of images to generate.
|
||||
* @default `1`
|
||||
*/
|
||||
n?: number
|
||||
/** A text description of the desired image(s). */
|
||||
prompt: string
|
||||
/**
|
||||
* The size of the generated images.
|
||||
* @default `1024x1024`
|
||||
*/
|
||||
size?: `${number}x${number}`
|
||||
}
|
||||
|
||||
export interface GenerateImageResponse {
|
||||
created: number
|
||||
data: {
|
||||
b64_json: string
|
||||
revised_prompt?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface GenerateImageResult {
|
||||
image: GenerateImageResultImage
|
||||
images: GenerateImageResultImage[]
|
||||
}
|
||||
|
||||
export interface GenerateImageResultImage {
|
||||
base64: string
|
||||
mimeType: string
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
const mimeTypes = {
|
||||
'/9j/': 'image/jpg',
|
||||
'AAAAIGZ0eXBhdmlm': 'image/avif',
|
||||
'iVBORw0KGgo': 'image/png',
|
||||
'R0lGOD': 'image/gif',
|
||||
'UklGRg==': 'image/webp',
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
const convertImage = (b64_json: string) => {
|
||||
const key = Object.keys(mimeTypes).find(prefix => b64_json.startsWith(prefix)) as keyof typeof mimeTypes | undefined
|
||||
const mimeType = mimeTypes[key ?? 'iVBORw0KGgo']
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line @masknet/string-no-data-url
|
||||
base64: `data:${mimeType};base64,${b64_json}`,
|
||||
mimeType,
|
||||
}
|
||||
}
|
||||
|
||||
/** @experimental */
|
||||
export const generateImage = async (options: GenerateImageOptions): Promise<GenerateImageResult> =>
|
||||
(options.fetch ?? globalThis.fetch)(requestURL('images/generations', options.baseURL), {
|
||||
body: requestBody({
|
||||
...options,
|
||||
responseFormat: 'b64_json',
|
||||
}),
|
||||
headers: requestHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
}, options.apiKey),
|
||||
method: 'POST',
|
||||
signal: options.abortSignal,
|
||||
})
|
||||
.then(responseJSON<GenerateImageResponse>)
|
||||
.then(({ data }) => {
|
||||
const images: GenerateImageResultImage[] = data.map(({ b64_json }) => convertImage(b64_json))
|
||||
|
||||
return { image: images[0], images }
|
||||
})
|
||||
@@ -19,6 +19,7 @@ type GenerateObjectOutputOption = 'array' | 'object'
|
||||
export async function generateObject<T extends Schema>(options: GenerateObjectOptions<T> & { output: 'array' }): Promise<GenerateObjectResult<Array<Infer<T>>>>
|
||||
export async function generateObject<T extends Schema>(options: GenerateObjectOptions<T> & { output: 'object' }): Promise<GenerateObjectResult<Infer<T>>>
|
||||
export async function generateObject<T extends Schema>(options: GenerateObjectOptions<T>): Promise<GenerateObjectResult<Infer<T>>>
|
||||
// eslint-disable-next-line func-style
|
||||
export async function generateObject<T extends Schema>(options: GenerateObjectOptions<T> & { output?: GenerateObjectOutputOption }) {
|
||||
const { schema: schemaValidator } = options
|
||||
|
||||
|
||||
@@ -43,18 +43,16 @@ export async function streamObject<T extends Schema>(
|
||||
& StreamObjectOptions<T>
|
||||
& { output: 'array' }
|
||||
): Promise<StreamObjectResult<T> & { elementStream: ReadableStream<Infer<T>>, partialObjectStream: undefined }>
|
||||
|
||||
export async function streamObject<T extends Schema>(
|
||||
options: StreamObjectExtraOptions<T>
|
||||
& StreamObjectOptions<T>
|
||||
& { output: 'object' }
|
||||
): Promise<StreamObjectResult<T> & { elementStream: undefined, partialObjectStream: ReadableStream<PartialDeep<Infer<T>>> }>
|
||||
|
||||
export async function streamObject<T extends Schema>(
|
||||
options: StreamObjectExtraOptions<T>
|
||||
& StreamObjectOptions<T>
|
||||
): Promise<StreamObjectResult<T> & { elementStream: undefined, partialObjectStream: ReadableStream<PartialDeep<Infer<T>>> }>
|
||||
|
||||
// eslint-disable-next-line func-style
|
||||
export async function streamObject<T extends Schema>(
|
||||
options: StreamObjectExtraOptions<T>
|
||||
& StreamObjectOptions<T>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#browser_compatibility} */
|
||||
// eslint-disable-next-line func-style
|
||||
export async function* toAsyncIterator<T>(
|
||||
stream: ReadableStream<T>,
|
||||
): AsyncGenerator<T, void, unknown> {
|
||||
|
||||
Generated
+12
@@ -145,6 +145,9 @@ importers:
|
||||
'@xsai/embed':
|
||||
specifier: workspace:^
|
||||
version: link:../packages/embed
|
||||
'@xsai/generate-image':
|
||||
specifier: workspace:^
|
||||
version: link:../packages/generate-image
|
||||
'@xsai/generate-object':
|
||||
specifier: workspace:^
|
||||
version: link:../packages/generate-object
|
||||
@@ -258,6 +261,9 @@ importers:
|
||||
'@xsai/embed':
|
||||
specifier: 'workspace:'
|
||||
version: link:../../packages/embed
|
||||
'@xsai/generate-image':
|
||||
specifier: 'workspace:'
|
||||
version: link:../../packages/generate-image
|
||||
'@xsai/generate-object':
|
||||
specifier: 'workspace:'
|
||||
version: link:../../packages/generate-object
|
||||
@@ -330,6 +336,12 @@ importers:
|
||||
specifier: 'workspace:'
|
||||
version: link:../shared
|
||||
|
||||
packages/generate-image:
|
||||
dependencies:
|
||||
'@xsai/shared':
|
||||
specifier: 'workspace:'
|
||||
version: link:../shared
|
||||
|
||||
packages/generate-object:
|
||||
dependencies:
|
||||
'@xsai/generate-text':
|
||||
|
||||
+2
-5
@@ -10,12 +10,9 @@ catalog:
|
||||
|
||||
catalogs:
|
||||
schema:
|
||||
'@valibot/to-json-schema': ^1.0.0
|
||||
valibot: ^1.0.0
|
||||
|
||||
'@valibot/to-json-schema': &valibot ^1.0.0
|
||||
arktype: ^2.1.13
|
||||
|
||||
effect: ^3.14.2
|
||||
|
||||
valibot: *valibot
|
||||
zod: ^3.24.2
|
||||
zod-to-json-schema: ^3.24.5
|
||||
Reference in new issue
Block a user