Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Decart API Key to run the examples with `pnpm run:examples`
DECART_API_KEY=
73 changes: 73 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install pnpm
uses: pnpm/action-setup@v4.1.0
with:
version: 10.7.1

- name: Set node LTS
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: pnpm

- name: Install
run: pnpm install

- name: Build
run: pnpm build

- name: Lint
run: pnpm lint

- name: Format
run: pnpm format:check

- name: Typecheck
run: pnpm typecheck

- name: Test
run: pnpm test

release:
needs: test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install pnpm
uses: pnpm/action-setup@v4.1.0
with:
version: 10.7.1

- name: Set node LTS
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: pnpm

- name: Install
run: pnpm install

- name: Build
run: pnpm build

- run: pnpm dlx pkg-pr-new publish
46 changes: 46 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Release

permissions:
contents: write
id-token: write

on:
push:
tags:
- "v*"

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install pnpm
uses: pnpm/action-setup@v4.1.0
with:
version: 10.7.1

- name: Set node LTS
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: pnpm
registry-url: "https://registry.npmjs.org"

- name: Install
run: pnpm install

- name: Build
run: pnpm build

- name: Publish
run: pnpm publish --no-git-checks
env:
NPM_CONFIG_PROVENANCE: true
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- run: npx changelogithub
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.env
node_modules
dist
*.log
.DS_Store
examples/output
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.6
16 changes: 16 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.sortMembers": "explicit"
},
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.formatOnSaveMode": "file"
}
123 changes: 123 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# AI SDK - Decart Provider

The **Decart provider** for the [AI SDK](https://ai-sdk.dev/docs) contains support for [Decart](https://decart.ai)'s image generation models.

## Setup

The Decart provider is available in the `@decartai/ai-sdk-provider` module. You can install it with:

```bash
npm i @decartai/ai-sdk-provider
```

## Provider Instance

You can import the default provider instance `decart` from `@decartai/ai-sdk-provider`:

```ts
import { decart } from '@decartai/ai-sdk-provider';
```

If you need a customized setup, you can import `createDecart` and create a provider instance with your settings:

```ts
import { createDecart } from '@decartai/ai-sdk-provider';

const decart = createDecart({
apiKey: 'your-api-key', // optional, defaults to DECART_API_KEY environment variable
baseURL: 'custom-url', // optional
headers: {
/* custom headers */
}, // optional
});
```

You can use the following optional settings to customize the Decart provider instance:

- **baseURL** _string_

Use a different URL prefix for API calls, e.g. to use proxy servers.
The default prefix is `https://api.decart.ai`.

- **apiKey** _string_

API key that is being sent using the `X-API-KEY` header.
It defaults to the `DECART_API_KEY` environment variable.

- **headers** _Record<string,string>_

Custom headers to include in the requests.

- **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_

Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation.
You can use it as a middleware to intercept requests,
or to provide a custom fetch implementation for e.g. testing.

## Image Models

You can create Decart image models using the `.image()` factory method.
For more on image generation with the AI SDK see [generateImage()](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-image).

### Basic Usage

```ts
import { decart } from '@decartai/ai-sdk-provider';
import { experimental_generateImage as generateImage } from 'ai';
import fs from 'fs';

const { image } = await generateImage({
model: decart.image('lucy-pro-t2i'),
prompt: 'Three dogs playing in the snow',
});

const filename = `image-${Date.now()}.png`;
fs.writeFileSync(filename, image.uint8Array);
console.log(`Image saved to ${filename}`);
```

### Model Capabilities

Decart currently offers:

| Model | Description |
| -------------- | ------------------------------------------- |
| `lucy-pro-t2i` | High-quality text-to-image generation model |

The model supports the following aspect ratios:

- 16:9 (landscape)
- 9:16 (portrait)

<Note>
Other aspect ratios will generate a warning and fall back to the default
behavior.
</Note>

### Image Model Settings

You can customize the generation behavior with optional settings:

```ts
const { image } = await generateImage({
model: decart.image('lucy-pro-t2i'),
prompt: 'Three dogs playing in the snow',
aspectRatio: '16:9',
seed: 42,
});
```

Supported settings:

- **aspectRatio** _string_

Control the aspect ratio of the generated image. Supported values: `16:9` (landscape) and `9:16` (portrait).

- **seed** _number_

Set a seed value for reproducible results.


## Learn More

For more details about Decart's capabilities and features, visit [Decart AI](https://decart.ai).
47 changes: 47 additions & 0 deletions examples/lib/present-image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import fs from "node:fs";
import path from "node:path";
import type { Experimental_GeneratedImage as GeneratedImage } from "ai";
import imageType from "image-type";
import sharp from "sharp";
import terminalImage from "terminal-image";

const OUTPUT_DIR = path.resolve(__dirname, "../output");

/**
* Displays images in the terminal using a downsampled preview and saves the
* original, full-resolution files to the output directory with unique
* timestamps.
* @param images - An array of generated images to process and display.
*/
export async function presentImages(images: GeneratedImage[]) {
const timestamp = Date.now();
for (const [index, image] of images.entries()) {
let srcBuffer = image.uint8Array;

// Determine the format of the image.
const format = await imageType(srcBuffer);
const extension = format?.ext;
if (!extension) {
throw new Error("Unknown image format");
}

if (extension === "webp") {
// `terminal-image` doesn't support WebP, so convert to PNG.
srcBuffer = await sharp(srcBuffer).png().toBuffer();
}

// Render the image to the terminal.
console.log(await terminalImage.buffer(Buffer.from(srcBuffer)));

// Save the original image to a file.
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
const filePath = path.join(
OUTPUT_DIR,
`image-${timestamp}-${index}.${extension}`,
);
await fs.promises.writeFile(filePath, srcBuffer);
console.log(`Saved image to ${filePath}`);
}

console.log(`Processed ${images.length} images`);
}
13 changes: 13 additions & 0 deletions examples/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import "dotenv/config";
import { presentImages } from "./lib/present-image";

export async function runAll() {
const tasks = [await import("./tasks/image-generation")];

for (const task of tasks) {
const result = await task.run();
await presentImages(result.images);
}
}

runAll().catch(console.error);
10 changes: 10 additions & 0 deletions examples/tasks/image-generation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { decart } from "@decartai/ai-sdk-provider";
import { experimental_generateImage as generateImage } from "ai";

export async function run() {
const result = await generateImage({
model: decart.image("lucy-pro-t2i"),
prompt: "Three dogs playing in the snow",
});
return result;
}
Loading
Loading