How to Create Your Own AI Provider
This tutorial will guide you through creating a custom AI-powered image generation provider for CreativeEditor SDK (CE.SDK) using the @imgly/plugin-ai-generation-web
package. You'll learn how to implement an AI provider from scratch using the schema-based approach and how to seamlessly integrate sophisticated AI image generation capabilities with CE.SDK.
Prerequisites#
- Basic knowledge of TypeScript and React
- Familiarity with CreativeEditor SDK
- An image generation API to integrate with
1. Project Setup#
First, set up your project and install the necessary packages:
# Create a new project or use an existing onemkdir my-image-providercd my-image-provider# Initialize package.jsonnpm init -y# Install required dependenciesnpm install @imgly/plugin-ai-generation-web @cesdk/cesdk-js typescript
2. Understanding the Provider Interface#
The core of the AI generation system is the Provider
interface. For image generation, we implement this interface with kind: 'image'
.
Key components of an image provider:
- id: Unique identifier for your provider
- kind: Always 'image' for image generation
- initialize: Setup function for any necessary configuration
- input: Configuration for the input UI panel and parameters
- output: Configuration for generation behavior and result handling
3. Creating an OpenAPI Schema#
For schema-based input, you need an OpenAPI schema that defines your input parameters. Create a file called myApiSchema.json
:
{"openapi": "3.0.0","info": {"title": "My Image Generator API","version": "1.0.0"},"components": {"schemas": {"GenerationInput": {"type": "object","required": ["prompt"],"properties": {"prompt": {"type": "string","title": "Description","description": "Describe the image you want to generate","x-imgly-builder": {"component": "TextArea"}},"width": {"type": "integer","title": "Width","default": 512,"enum": [256, 512, 768, 1024],"x-imgly-builder": {"component": "Select"}},"height": {"type": "integer","title": "Height","default": 512,"enum": [256, 512, 768, 1024],"x-imgly-builder": {"component": "Select"}},"style": {"type": "string","title": "Style","default": "photorealistic","enum": ["photorealistic", "cartoon", "sketch", "painting"],"x-imgly-builder": {"component": "Select"}}},"x-order-properties": ["prompt", "width", "height", "style"]}}}}
4. 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
:
import {Provider,ImageOutput,loggingMiddleware,uploadMiddleware} from '@imgly/plugin-ai-generation-web';import type CreativeEditorSDK from '@cesdk/cesdk-js';import apiSchema from './myApiSchema.json';// Define your input type based on your schemainterface MyProviderInput {prompt: string;width: number;height: number;style: string;}// Create a function that returns your providerexport function MyImageProvider({apiKey,apiUrl = 'https://your-api-url.com'}: {apiKey: string;apiUrl?: string;}): (context: {cesdk: CreativeEditorSDK;}) => Promise<Provider<'image', MyProviderInput, ImageOutput>> {// Return a function that returns the providerreturn async ({ cesdk }) => {// Create and return the providerconst provider: Provider<'image', MyProviderInput, ImageOutput> = {// Unique identifier for your providerid: 'my-image-provider',// Define output type as 'image'kind: 'image',// Initialize your providerinitialize: async ({ engine, cesdk }) => {console.log('Initializing my image provider');// Any setup needed (e.g., API client initialization)},// Define input panel and UI using schemainput: {panel: {type: 'schema',document: apiSchema, // Your OpenAPI schemainputReference: '#/components/schemas/GenerationInput', // Reference to your input schemauserFlow: 'placeholder', // Creates a block first, then updates it with the generated contentorderExtensionKeyword: 'x-order-properties', // Used to control property display order// Convert API input to block parametersgetBlockInput: async (input) => ({image: {width: input.width || 512,height: input.height || 512,label: `AI: ${input.prompt?.substring(0, 20)}...`}})}},// Define output generation behavioroutput: {// Allow cancellation of generationabortable: true,// Store generated assets in browser's IndexedDBhistory: '@imgly/indexedDB',// Add middleware for logging and uploadingmiddleware: [loggingMiddleware(),// Example of upload middleware that stores generated images on your serveruploadMiddleware(async (output) => {// Upload the image to your serverconst response = await fetch('https://your-server.com/api/upload', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({url: output.url,type: 'ai-generated-image'})});const result = await response.json();// Return the output with the updated URL from your serverreturn {...output,url: result.storedImageUrl};})],// Configure success/error notificationsnotification: {success: {show: true,message: 'Image generated successfully!'},error: {show: true,message: (context) => `Generation failed: ${context.error}`}},// The core generation functiongenerate: async (input, { abortSignal }) => {try {// Call your API to generate an imageconst response = await fetch(apiUrl, {method: 'POST',headers: {'Content-Type': 'application/json',Authorization: `Bearer ${apiKey}`},body: JSON.stringify({prompt: input.prompt,width: input.width,height: input.height,style: input.style}),signal: abortSignal});if (!response.ok) {throw new Error(`API error: ${response.statusText}`);}const data = await response.json();// Return the image URLreturn {kind: 'image',url: data.imageUrl // Replace with the actual property from your API response};} catch (error) {console.error('Image generation failed:', error);throw error;}}}};return provider;};}
5. Integrating with CE.SDK#
Now let's integrate your provider with CE.SDK using the @imgly/plugin-ai-image-generation-web
package.
Create an index.ts
file:
import CreativeEditorSDK from '@cesdk/cesdk-js';import ImageGeneration from '@imgly/plugin-ai-image-generation-web';import { MyImageProvider } from './MyImageProvider';// Initialize the editorasync function initializeEditor(container: HTMLElement) {const cesdk = await CreativeEditorSDK.create(container, {license: 'your-cesdk-license-key'});// Add default asset sourcesawait cesdk.addDefaultAssetSources();// Add your image generation providercesdk.addPlugin(ImageGeneration({text2image: MyImageProvider({apiKey: 'your-api-key',apiUrl: 'https://your-api-url.com'}),debug: true}));// Create a design sceneawait cesdk.createDesignScene();// Add the dock component to open the AI image generation panelcesdk.ui.setDockOrder(['ly.img.ai/image-generation.dock',...cesdk.ui.getDockOrder()]);return cesdk;}// Start the editor when the DOM is loadeddocument.addEventListener('DOMContentLoaded', () => {const container = document.getElementById('cesdk-container');if (container) {initializeEditor(container);}});
6. Create an HTML Page#
Create an index.html
file to host your editor:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>AI Image Generation with CE.SDK</title><style>body,html {margin: 0;padding: 0;height: 100%;width: 100%;overflow: hidden;}#cesdk-container {width: 100%;height: 100vh;}</style></head><body><div id="cesdk-container"></div><script src="./dist/index.js"></script></body></html>
7. 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.
Setting up TypeScript#
Create a basic TypeScript configuration:
# Create a tsconfig.json filenpx tsc --init
Edit the generated tsconfig.json
to include these recommended settings:
{"compilerOptions": {"target": "ES2020","module": "ESNext","moduleResolution": "node","esModuleInterop": true,"strict": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"resolveJsonModule": true,"outDir": "./dist","jsx": "react"},"include": ["src/**/*"],"exclude": ["node_modules", "dist"]}
Setting up esbuild#
Install esbuild as a development dependency:
npm install --save-dev esbuild
Create a build script in your package.json
:
{"name": "my-image-provider","version": "1.0.0","scripts": {"build": "esbuild index.ts --bundle --outfile=dist/index.js --platform=browser","dev": "esbuild index.ts --bundle --outfile=dist/index.js --platform=browser --watch --servedir=."},"dependencies": {"@cesdk/cesdk-js": "^1.48.0","@imgly/plugin-ai-generation-web": "^0.1.0","@imgly/plugin-ai-image-generation-web": "^0.1.0"},"devDependencies": {"esbuild": "^0.19.0","typescript": "^5.0.0"}}
Project Structure#
Make sure your files are organized as follows:
my-image-provider/├── index.html├── index.ts├── MyImageProvider.ts├── myApiSchema.json├── package.json└── tsconfig.json
Running the Example#
Now you can build and run your example:
# For production buildnpm run build# For development with live reloadnpm run dev
If you use npm run dev
, esbuild will start a development server and you can view your project at http://localhost:8000.
Alternatively, you can use any static file server after building:
# Using serve (you might need to install it first with: npm install -g serve)serve# Or with Python's built-in HTTP serverpython -m http.server# Or with PHP's built-in serverphp -S localhost:8000
Troubleshooting#
If you encounter issues:
- Check browser console for errors
- Verify that your API endpoint is correctly configured
- Make sure the CE.SDK license key is valid
- Check that all dependencies are installed correctly
Remember that this build setup is just an example - feel free to adapt it to your existing workflow or preferred build tools. The key components are:
- TypeScript compilation
- Bundling your code
- Serving the HTML and bundled JavaScript
Conclusion#
You've now created a custom image generation provider for CE.SDK using the schema-based approach! Your provider integrates with the AI image generation plugin and provides a seamless user experience for generating images.
The schema-based approach offers several advantages:
- Automatic UI generation based on your schema
- Built-in validation of input parameters
- Consistent UI experience that matches the CE.SDK style
- Easy ordering of properties using the
x-order-properties
extension
Next steps:
- Customize specific property renderers using the
renderCustomProperty
option - Add more advanced validation in your schema
- Implement proper error handling and retry logic
- Add custom asset sources for generated images