Skip to content

Add Support for Custom Headers #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 5, 2025
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 CHANGELOG-AI.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

- [all] Add support for custom headers

## [0.1.8] - 2025-05-26

- [ai-apps] Handle `sceneMode` change in upcoming CE.SDK version 1.52.0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
type Provider,
type AudioOutput,
Middleware
CommonProviderConfiguration
} from '@imgly/plugin-ai-generation-web';
import CreativeEditorSDK from '@cesdk/cesdk-js';
import schema from './ElevenMultilingualV2.json';
Expand All @@ -19,19 +19,16 @@ type ElevenlabsInput = {
speed: number;
};

type ProviderConfiguration = {
proxyUrl: string;
debug?: boolean;
middleware?: Middleware<ElevenlabsInput, AudioOutput>[];

interface ProviderConfiguration
extends CommonProviderConfiguration<ElevenlabsInput, AudioOutput> {
/**
* Base URL used for the UI assets used in the plugin.
*
* By default, we load the assets from the IMG.LY CDN You can copy the assets.
* from the `/assets` folder to your own server and set the base URL to your server.
*/
baseURL?: string;
};
}

export function ElevenMultilingualV2(
config: ProviderConfiguration
Expand Down Expand Up @@ -216,7 +213,8 @@ export async function generateSpeech(
method: 'POST',
headers: {
Accept: 'audio/mpeg',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
...(config.headers ?? {})
},
body: JSON.stringify({
text,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
type Provider,
type AudioOutput,
Middleware
CommonProviderConfiguration
} from '@imgly/plugin-ai-generation-web';
import CreativeEditorSDK from '@cesdk/cesdk-js';
import schema from './ElevenSoundEffects.json';
Expand All @@ -12,11 +12,8 @@ type ElevenlabsInput = {
duration_seconds: number;
};

type ProviderConfiguration = {
proxyUrl: string;
debug?: boolean;
middleware?: Middleware<ElevenlabsInput, AudioOutput>[];
};
interface ProviderConfiguration
extends CommonProviderConfiguration<ElevenlabsInput, AudioOutput> {}

export function ElevenSoundEffects(
config: ProviderConfiguration
Expand Down Expand Up @@ -116,7 +113,8 @@ export async function generateSound(
method: 'POST',
headers: {
Accept: 'audio/mpeg',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
...(config.headers ?? {})
},
body: JSON.stringify({
text,
Expand Down
102 changes: 94 additions & 8 deletions packages/plugin-ai-generation-web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,20 @@ import {
Provider,
ImageOutput,
initProvider,
loggingMiddleware
loggingMiddleware,
CommonProviderConfiguration
} from '@imgly/plugin-ai-generation-web';

// Create your image generation provider
const myImageProvider: Provider<'image', MyInputType, ImageOutput> = {
// Define your provider configuration interface
interface MyProviderConfiguration
extends CommonProviderConfiguration<MyInputType, ImageOutput> {
// Add any provider-specific configuration here
baseURL?: string;
}

// Create a provider factory function
function createMyImageProvider(config: MyProviderConfiguration): Provider<'image', MyInputType, ImageOutput> {
return {
// Unique identifier for this provider
id: 'my-image-provider',

Expand All @@ -40,7 +49,10 @@ const myImageProvider: Provider<'image', MyInputType, ImageOutput> = {
// Initialize the provider
initialize: async ({ engine, cesdk }) => {
// Setup APIs, register further components, etc.
myAIApi.configure({ apiKey: 'YOUR_API_KEY' });
myAIApi.configure({
apiKey: 'YOUR_API_KEY',
headers: config.headers // Use custom headers if provided
});
},

// Define input panel and UI components
Expand Down Expand Up @@ -97,15 +109,30 @@ const myImageProvider: Provider<'image', MyInputType, ImageOutput> = {
// Core generation function
generate: async (input, { abortSignal, engine }) => {
// Call your AI API and return result
const response = await myAIApi.generateImage(input);
const response = await myAIApi.generateImage(input, {
headers: config.headers // Pass custom headers to API
});

return {
kind: 'image',
url: response.imageUrl
};
}
}
};
};
}

// Usage example
const myImageProvider = createMyImageProvider({
proxyUrl: 'https://your-api-proxy.example.com',
headers: {
'x-client-version': '1.0.0',
'x-request-source': 'cesdk-plugin'
},
debug: false,
middleware: [loggingMiddleware()],
baseURL: 'https://assets.example.com'
});
```

## Provider Interface
Expand All @@ -120,6 +147,61 @@ The Provider interface is generic and type-safe, supporting four output kinds:
interface Provider<K extends OutputKind, I, O extends Output, C = O> { ... }
```

## Common Provider Configuration

All providers should extend the `CommonProviderConfiguration` interface, which provides standardized configuration options:

```typescript
interface CommonProviderConfiguration<I, O extends Output> {
// The proxy URL to use for the provider
proxyUrl: string;

// Enable debug mode for additional logging
debug?: boolean;

// Middleware for request/response processing
middleware?: Middleware<I, O>[];

// Custom headers to include in all API requests
headers?: Record<string, string>;
}
```

The `headers` property allows you to include custom HTTP headers in all API requests made by your provider. This is useful for:
- Adding custom client identification headers
- Including version information
- Passing through metadata required by your API
- Adding correlation IDs for request tracing

**Implementation Note:** When implementing your provider's `generate` function, ensure you merge the custom headers with any required headers for your API. For example:

```typescript
// In your generate function
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
...config.headers // Spread custom headers
},
body: JSON.stringify(requestData)
});
```

Example provider configuration:

```typescript
const myProvider = createMyProvider({
proxyUrl: 'https://api.example.com',
headers: {
'x-client-version': '1.0.0',
'x-request-source': 'cesdk-plugin'
},
debug: false,
middleware: [loggingMiddleware()]
});
```

### Key Provider Options

- **id**: Unique identifier for your provider
Expand Down Expand Up @@ -759,9 +841,13 @@ The most basic way is to use the `initProvider` function to register your provid
```typescript
import { initProvider } from '@imgly/plugin-ai-generation-web';

// Create your provider
// Create your provider with custom headers
const myProvider = createMyProvider({
proxyUrl: 'https://your-api-proxy.example.com'
proxyUrl: 'https://your-api-proxy.example.com',
headers: {
'x-custom-header': 'value',
'x-client-version': '1.0.0'
}
});

// Initialize the provider with CreativeEditor SDK
Expand Down
59 changes: 46 additions & 13 deletions packages/plugin-ai-generation-web/TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,33 @@ For schema-based input, you need an OpenAPI schema that defines your input param
}
```

## 4. Creating a Schema-Based Image Provider
## 4. Understanding CommonProviderConfiguration

Before creating your provider, it's important to understand the `CommonProviderConfiguration` interface. This interface provides standardized configuration options that all providers should extend:

```typescript
interface CommonProviderConfiguration<I, O extends Output> {
// The proxy URL to use for the provider
proxyUrl: string;

// Enable debug mode for additional logging
debug?: boolean;

// Middleware for request/response processing
middleware?: Middleware<I, O>[];

// Custom headers to include in all API requests
headers?: Record<string, string>;
}
```

The `headers` property is particularly useful for:
- Adding custom client identification headers
- Including version information
- Passing through metadata required by your API
- Adding correlation IDs for request tracing

## 5. Creating a Schema-Based Image Provider

Let's create a simple provider that generates images by calling your API. Create a file called `MyImageProvider.ts`:

Expand All @@ -111,6 +137,7 @@ import {
ImageOutput,
loggingMiddleware,
uploadMiddleware,
CommonProviderConfiguration,
// Quick action helper components
QuickActionChangeImage,
QuickActionSwapImageBackground,
Expand All @@ -128,14 +155,14 @@ interface MyProviderInput {
image_url?: string; // For image-to-image operations
}

// Create a function that returns your provider
export function MyImageProvider({
apiKey,
apiUrl = 'https://your-api-url.com'
}: {
// Define provider configuration interface extending CommonProviderConfiguration
interface MyProviderConfiguration extends CommonProviderConfiguration<MyProviderInput, ImageOutput> {
apiKey: string;
apiUrl?: string;
}): (context: {
}

// Create a function that returns your provider
export function MyImageProvider(config: MyProviderConfiguration): (context: {
cesdk: CreativeEditorSDK;
}) => Promise<Provider<'image', MyProviderInput, ImageOutput>> {
// Return a function that returns the provider
Expand Down Expand Up @@ -286,11 +313,12 @@ export function MyImageProvider({
}

// Call your API to generate an image
const response = await fetch(apiUrl, {
const response = await fetch(config.apiUrl || 'https://your-api-url.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
Authorization: `Bearer ${config.apiKey}`,
...config.headers // Include custom headers
},
body: JSON.stringify(requestBody),
signal: abortSignal
Expand Down Expand Up @@ -322,7 +350,7 @@ export function MyImageProvider({
}
```

## 5. Integrating with CE.SDK
## 6. Integrating with CE.SDK

Now let's integrate your provider with CE.SDK using the `@imgly/plugin-ai-image-generation-web` package.

Expand All @@ -347,7 +375,12 @@ async function initializeEditor(container: HTMLElement) {
ImageGeneration({
text2image: MyImageProvider({
apiKey: 'your-api-key',
apiUrl: 'https://your-api-url.com'
apiUrl: 'https://your-api-url.com',
proxyUrl: 'https://your-proxy-url.com',
headers: {
'x-client-version': '1.0.0',
'x-request-source': 'cesdk-tutorial'
}
}),
debug: true
})
Expand All @@ -374,7 +407,7 @@ document.addEventListener('DOMContentLoaded', () => {
});
```

## 6. Create an HTML Page
## 7. Create an HTML Page

Create an `index.html` file to host your editor:

Expand Down Expand Up @@ -407,7 +440,7 @@ Create an `index.html` file to host your editor:
</html>
```

## 7. Build and Run the Example
## 8. Build and Run the Example

Let's set up a complete build and run process using esbuild. Note that you're free to use whatever build setup you're most comfortable with (webpack, Vite, Parcel, etc.) - the following is just an example to get you started quickly.

Expand Down
27 changes: 27 additions & 0 deletions packages/plugin-ai-generation-web/src/generation/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type CreativeEditorSDK from '@cesdk/cesdk-js';
import { type CreativeEngine } from '@cesdk/cesdk-js';
import type Provider from './provider';
import { Output } from './provider';
import { Middleware } from './middleware/middleware';

/**
* Configuration options for provider initialization
Expand Down Expand Up @@ -36,6 +38,31 @@ export type InitProviderConfiguration = {
middleware?: GenerationMiddleware;
};

/**
* Common provider configuration that all providers should provide.
*/
export interface CommonProviderConfiguration<I, O extends Output> {
/**
* The proxy URL to use for the provider.
*/
proxyUrl: string;

/**
* Indicates whether the provider is in debug mode and should log additional information.
*/
debug?: boolean;

/**
* Middleware that shall be executed during the generation process.
*/
middleware?: Middleware<I, O>[];

/**
* Headers that shall be sent with the request of the provider.
*/
headers?: Record<string, string>;
}

export type GenerationMiddleware = (
generate: () => Promise<void>,
context: {
Expand Down
Loading