@loonylabs/tti-middleware 1.9.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -1
- package/dist/middleware/services/tti/providers/base-tti-provider.js +32 -0
- package/dist/middleware/services/tti/providers/google-cloud-provider.d.ts +4 -0
- package/dist/middleware/services/tti/providers/google-cloud-provider.js +136 -2
- package/dist/middleware/types/index.d.ts +56 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
- [Configuration](#%EF%B8%8F-configuration)
|
|
25
25
|
- [Providers & Models](#-providers--models)
|
|
26
26
|
- [Character Consistency](#-character-consistency)
|
|
27
|
+
- [Inpainting / Image Editing](#inpainting--image-editing)
|
|
27
28
|
- [GDPR / Compliance](#-gdpr--compliance)
|
|
28
29
|
- [API Reference](#-api-reference)
|
|
29
30
|
- [Advanced Features](#-advanced-features)
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
- **Eden AI**: Aggregator with access to OpenAI, Stability AI, Replicate (experimental)
|
|
45
46
|
- **IONOS**: German cloud provider with OpenAI-compatible API (experimental)
|
|
46
47
|
- **Character Consistency**: Generate consistent characters across multiple images (perfect for children's book illustrations)
|
|
48
|
+
- **Inpainting**: Fix specific areas of a generated image without regenerating the entire scene — via Vertex AI `imagen-capability` model. Supports optional subject reference images (`maskReferenceImages`) to guide *what* gets inserted into the masked area
|
|
47
49
|
- **GDPR/DSGVO Compliance**: Built-in EU region support with automatic fallback
|
|
48
50
|
- **Region Rotation**: Opt-in region rotation on quota errors (429) for Google Cloud — rotate through regions instead of retrying the same exhausted region
|
|
49
51
|
- **Retry Logic**: Exponential backoff with jitter for transient errors (429, 408, 5xx, timeouts)
|
|
@@ -307,6 +309,72 @@ const duelScene = await service.generate({
|
|
|
307
309
|
|
|
308
310
|
- Model must be `gemini-flash-image` (only model supporting character consistency)
|
|
309
311
|
|
|
312
|
+
## Inpainting / Image Editing
|
|
313
|
+
|
|
314
|
+
The `imagen-capability` model supports mask-based inpainting via Vertex AI. This is the **only** model that supports pixel-precise editing with a mask image.
|
|
315
|
+
|
|
316
|
+
### Basic Inpainting
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
const result = await service.generate({
|
|
320
|
+
model: 'imagen-capability',
|
|
321
|
+
prompt: 'Remove the extra arm and fill with matching forest background',
|
|
322
|
+
baseImage: { base64: originalImageBase64, mimeType: 'image/png' },
|
|
323
|
+
maskImage: { base64: maskBase64, mimeType: 'image/png' },
|
|
324
|
+
editMode: 'inpainting-remove', // default: 'inpainting-insert'
|
|
325
|
+
maskDilation: 0.02, // optional, 0.0–1.0, default 0.01
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**How the mask works:**
|
|
330
|
+
- White pixels = area the model will regenerate
|
|
331
|
+
- Black pixels = area preserved exactly as-is
|
|
332
|
+
- Mask must have identical dimensions to `baseImage`
|
|
333
|
+
|
|
334
|
+
### Guided Inpainting with Subject References
|
|
335
|
+
|
|
336
|
+
Use `maskReferenceImages` to provide a reference photo of the subject to insert — e.g. "place **this** character into the masked region":
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
const result = await service.generate({
|
|
340
|
+
model: 'imagen-capability',
|
|
341
|
+
prompt: 'The character standing in a bright forest clearing, photorealistic',
|
|
342
|
+
baseImage: { base64: sceneBase64, mimeType: 'image/png' },
|
|
343
|
+
maskImage: { base64: maskBase64, mimeType: 'image/png' },
|
|
344
|
+
editMode: 'inpainting-insert',
|
|
345
|
+
maskReferenceImages: [
|
|
346
|
+
{
|
|
347
|
+
base64: characterRefBase64,
|
|
348
|
+
mimeType: 'image/png',
|
|
349
|
+
subjectType: 'person', // 'person' | 'animal' | 'product' | 'default'
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Subject types:**
|
|
356
|
+
|
|
357
|
+
| `subjectType` | Use case |
|
|
358
|
+
|---------------|----------|
|
|
359
|
+
| `'person'` | Human character |
|
|
360
|
+
| `'animal'` | Animal or creature |
|
|
361
|
+
| `'product'` | Object, item, product |
|
|
362
|
+
| `'default'` | Let the model decide (safe fallback) |
|
|
363
|
+
|
|
364
|
+
**Notes:**
|
|
365
|
+
- `maskReferenceImages` only works with `editMode: 'inpainting-insert'`
|
|
366
|
+
- Gemini models do **not** support mask-based inpainting or `maskReferenceImages`
|
|
367
|
+
- `maskReferenceImages` without `baseImage` throws a validation error
|
|
368
|
+
|
|
369
|
+
### Supported `editMode` Values
|
|
370
|
+
|
|
371
|
+
| Value | Description |
|
|
372
|
+
|-------|-------------|
|
|
373
|
+
| `'inpainting-insert'` | Add or replace content in masked area (default) |
|
|
374
|
+
| `'inpainting-remove'` | Remove content and fill with matching background |
|
|
375
|
+
| `'background-swap'` | Replace background, preserve foreground |
|
|
376
|
+
| `'outpainting'` | Extend image beyond its boundaries into the masked area |
|
|
377
|
+
|
|
310
378
|
## GDPR / Compliance
|
|
311
379
|
|
|
312
380
|
### Provider Compliance Overview
|
|
@@ -365,15 +433,30 @@ interface TTIRequest {
|
|
|
365
433
|
n?: number; // Number of images (default: 1)
|
|
366
434
|
aspectRatio?: string; // '1:1', '16:9', '4:3', etc.
|
|
367
435
|
|
|
368
|
-
// Character consistency
|
|
436
|
+
// Character consistency (Gemini models only)
|
|
369
437
|
referenceImages?: TTIReferenceImage[];
|
|
370
438
|
subjectDescription?: string;
|
|
371
439
|
|
|
440
|
+
// Inpainting / image editing (imagen-capability only)
|
|
441
|
+
baseImage?: TTIReferenceImage; // Activates edit mode when set
|
|
442
|
+
maskImage?: TTIReferenceImage; // Required when baseImage is set
|
|
443
|
+
maskDilation?: number; // 0.0–1.0, default 0.01
|
|
444
|
+
editMode?: 'inpainting-insert' | 'inpainting-remove' | 'background-swap' | 'outpainting';
|
|
445
|
+
maskReferenceImages?: TTIMaskReferenceImage[]; // Subject refs for guided inpainting
|
|
446
|
+
|
|
372
447
|
// Retry configuration
|
|
373
448
|
retry?: boolean | RetryOptions; // true (default), false, or custom config
|
|
374
449
|
|
|
375
450
|
providerOptions?: Record<string, unknown>;
|
|
376
451
|
}
|
|
452
|
+
|
|
453
|
+
type TTISubjectType = 'person' | 'animal' | 'product' | 'default';
|
|
454
|
+
|
|
455
|
+
interface TTIMaskReferenceImage {
|
|
456
|
+
base64: string;
|
|
457
|
+
mimeType?: string;
|
|
458
|
+
subjectType?: TTISubjectType; // defaults to 'default'
|
|
459
|
+
}
|
|
377
460
|
```
|
|
378
461
|
|
|
379
462
|
### TTIResponse
|
|
@@ -196,6 +196,38 @@ class BaseTTIProvider {
|
|
|
196
196
|
if (!request.prompt || request.prompt.trim().length === 0) {
|
|
197
197
|
throw new InvalidConfigError(this.providerName, 'Prompt cannot be empty');
|
|
198
198
|
}
|
|
199
|
+
// If baseImage is provided, validate inpainting requirements
|
|
200
|
+
if (request.baseImage) {
|
|
201
|
+
if (!request.baseImage.base64 || request.baseImage.base64.trim().length === 0) {
|
|
202
|
+
throw new InvalidConfigError(this.providerName, 'baseImage has empty base64 data');
|
|
203
|
+
}
|
|
204
|
+
const modelId = request.model || this.getDefaultModel();
|
|
205
|
+
if (!this.modelSupportsCapability(modelId, 'imageEditing')) {
|
|
206
|
+
throw new CapabilityNotSupportedError(this.providerName, 'imageEditing', modelId);
|
|
207
|
+
}
|
|
208
|
+
if (!request.maskImage) {
|
|
209
|
+
throw new InvalidConfigError(this.providerName, 'maskImage is required when baseImage is set');
|
|
210
|
+
}
|
|
211
|
+
if (!request.maskImage.base64 || request.maskImage.base64.trim().length === 0) {
|
|
212
|
+
throw new InvalidConfigError(this.providerName, 'maskImage has empty base64 data');
|
|
213
|
+
}
|
|
214
|
+
if (request.maskDilation !== undefined) {
|
|
215
|
+
if (request.maskDilation < 0 || request.maskDilation > 1) {
|
|
216
|
+
throw new InvalidConfigError(this.providerName, 'maskDilation must be between 0.0 and 1.0');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (request.maskReferenceImages && request.maskReferenceImages.length > 0) {
|
|
220
|
+
for (let i = 0; i < request.maskReferenceImages.length; i++) {
|
|
221
|
+
const ref = request.maskReferenceImages[i];
|
|
222
|
+
if (!ref.base64 || ref.base64.trim().length === 0) {
|
|
223
|
+
throw new InvalidConfigError(this.providerName, `maskReferenceImages[${i}] has empty base64 data`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (request.maskReferenceImages && request.maskReferenceImages.length > 0 && !request.baseImage) {
|
|
229
|
+
throw new InvalidConfigError(this.providerName, 'maskReferenceImages requires baseImage to be set');
|
|
230
|
+
}
|
|
199
231
|
// If reference images are provided, validate them
|
|
200
232
|
if (request.referenceImages && request.referenceImages.length > 0) {
|
|
201
233
|
const modelId = request.model || this.getDefaultModel();
|
|
@@ -63,6 +63,10 @@ export declare class GoogleCloudTTIProvider extends BaseTTIProvider {
|
|
|
63
63
|
private generateWithImagen;
|
|
64
64
|
private getAiplatformClient;
|
|
65
65
|
private processImagenResponse;
|
|
66
|
+
/** Maps our editMode values to the Vertex AI API constants */
|
|
67
|
+
private static readonly EDIT_MODE_MAP;
|
|
68
|
+
private static readonly SUBJECT_TYPE_MAP;
|
|
69
|
+
private editWithImagen;
|
|
66
70
|
private generateWithGemini;
|
|
67
71
|
private getGenaiClient;
|
|
68
72
|
private buildCharacterConsistencyPrompt;
|
|
@@ -131,6 +131,27 @@ const GOOGLE_CLOUD_MODELS = [
|
|
|
131
131
|
availableRegions: IMAGEN_4_REGIONS,
|
|
132
132
|
pricingUrl: 'https://cloud.google.com/vertex-ai/generative-ai/pricing',
|
|
133
133
|
},
|
|
134
|
+
// ── Imagen Capability model (Vertex AI editing / inpainting) ──
|
|
135
|
+
{
|
|
136
|
+
id: 'imagen-capability',
|
|
137
|
+
displayName: 'Imagen 3 Capability (Editing)',
|
|
138
|
+
capabilities: {
|
|
139
|
+
textToImage: false,
|
|
140
|
+
characterConsistency: false,
|
|
141
|
+
imageEditing: true,
|
|
142
|
+
maxImagesPerRequest: 4,
|
|
143
|
+
},
|
|
144
|
+
availableRegions: [
|
|
145
|
+
'europe-west1',
|
|
146
|
+
'europe-west2',
|
|
147
|
+
'europe-west3',
|
|
148
|
+
'europe-west4',
|
|
149
|
+
'europe-west9',
|
|
150
|
+
'us-central1',
|
|
151
|
+
'us-east4',
|
|
152
|
+
],
|
|
153
|
+
pricingUrl: 'https://cloud.google.com/vertex-ai/generative-ai/pricing',
|
|
154
|
+
},
|
|
134
155
|
// ── Gemini models (Vertex AI generateContent API) ──────────
|
|
135
156
|
{
|
|
136
157
|
id: 'gemini-flash-image',
|
|
@@ -185,6 +206,7 @@ const MODEL_ID_MAP = {
|
|
|
185
206
|
'imagen-4': 'imagen-4.0-generate-001',
|
|
186
207
|
'imagen-4-fast': 'imagen-4.0-fast-generate-001',
|
|
187
208
|
'imagen-4-ultra': 'imagen-4.0-ultra-generate-001',
|
|
209
|
+
'imagen-capability': 'imagen-3.0-capability-001',
|
|
188
210
|
'gemini-flash-image': 'gemini-2.5-flash-image',
|
|
189
211
|
'gemini-pro-image': 'gemini-3-pro-image-preview',
|
|
190
212
|
'gemini-flash-image-2': 'gemini-3.1-flash-image-preview',
|
|
@@ -296,10 +318,18 @@ class GoogleCloudTTIProvider extends base_tti_provider_1.BaseTTIProvider {
|
|
|
296
318
|
hasReferenceImages: (0, base_tti_provider_1.hasReferenceImages)(request),
|
|
297
319
|
});
|
|
298
320
|
const isGeminiModel = GEMINI_API_MODELS.has(modelId);
|
|
299
|
-
const
|
|
321
|
+
const isEditRequest = !!request.baseImage;
|
|
322
|
+
const operationName = isEditRequest
|
|
323
|
+
? 'Imagen edit API call'
|
|
324
|
+
: isGeminiModel
|
|
325
|
+
? 'Gemini API call'
|
|
326
|
+
: 'Imagen API call';
|
|
300
327
|
// Operation lambda reads currentRegion from closure
|
|
301
328
|
const operation = () => {
|
|
302
|
-
if (
|
|
329
|
+
if (isEditRequest) {
|
|
330
|
+
return this.editWithImagen(request, modelId, currentRegion);
|
|
331
|
+
}
|
|
332
|
+
else if (isGeminiModel) {
|
|
303
333
|
return this.generateWithGemini(request, modelId, currentRegion);
|
|
304
334
|
}
|
|
305
335
|
else {
|
|
@@ -528,6 +558,94 @@ class GoogleCloudTTIProvider extends base_tti_provider_1.BaseTTIProvider {
|
|
|
528
558
|
usage,
|
|
529
559
|
};
|
|
530
560
|
}
|
|
561
|
+
async editWithImagen(request, modelId, region) {
|
|
562
|
+
const startTime = Date.now();
|
|
563
|
+
const internalModelId = MODEL_ID_MAP[modelId];
|
|
564
|
+
this.lastUsedRegion = region;
|
|
565
|
+
try {
|
|
566
|
+
const { client, helpers } = await this.getAiplatformClient(region);
|
|
567
|
+
const endpoint = `projects/${this.config.projectId}/locations/${region}/publishers/google/models/${internalModelId}`;
|
|
568
|
+
// Build referenceImages array: [RAW base image, MASK image]
|
|
569
|
+
const referenceImages = [
|
|
570
|
+
{
|
|
571
|
+
referenceType: 'REFERENCE_TYPE_RAW',
|
|
572
|
+
referenceId: 1,
|
|
573
|
+
referenceImage: {
|
|
574
|
+
bytesBase64Encoded: request.baseImage.base64,
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
referenceType: 'REFERENCE_TYPE_MASK',
|
|
579
|
+
referenceId: 2,
|
|
580
|
+
referenceImage: {
|
|
581
|
+
bytesBase64Encoded: request.maskImage.base64,
|
|
582
|
+
},
|
|
583
|
+
maskImageConfig: {
|
|
584
|
+
maskMode: 'MASK_MODE_USER_PROVIDED',
|
|
585
|
+
dilation: request.maskDilation ?? 0.01,
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
];
|
|
589
|
+
// Append optional subject reference images for guided inpainting
|
|
590
|
+
if (request.maskReferenceImages && request.maskReferenceImages.length > 0) {
|
|
591
|
+
for (const [i, ref] of request.maskReferenceImages.entries()) {
|
|
592
|
+
const subjectType = GoogleCloudTTIProvider.SUBJECT_TYPE_MAP[ref.subjectType ?? 'default'] ??
|
|
593
|
+
'SUBJECT_TYPE_DEFAULT';
|
|
594
|
+
referenceImages.push({
|
|
595
|
+
referenceType: 'REFERENCE_TYPE_SUBJECT',
|
|
596
|
+
referenceId: 3 + i,
|
|
597
|
+
referenceImage: {
|
|
598
|
+
bytesBase64Encoded: ref.base64,
|
|
599
|
+
},
|
|
600
|
+
subjectImageConfig: {
|
|
601
|
+
subjectType,
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
const instanceValue = {
|
|
607
|
+
prompt: request.prompt,
|
|
608
|
+
referenceImages,
|
|
609
|
+
};
|
|
610
|
+
const instance = helpers.toValue(instanceValue);
|
|
611
|
+
// Map editMode to Vertex AI constant, default to inpainting-insert
|
|
612
|
+
const editModeKey = request.editMode ?? 'inpainting-insert';
|
|
613
|
+
const vertexEditMode = GoogleCloudTTIProvider.EDIT_MODE_MAP[editModeKey] ?? 'EDIT_MODE_INPAINT_INSERTION';
|
|
614
|
+
const parameterValue = {
|
|
615
|
+
editMode: vertexEditMode,
|
|
616
|
+
sampleCount: request.n || 1,
|
|
617
|
+
editConfig: {
|
|
618
|
+
baseSteps: request.providerOptions?.baseSteps ?? 35,
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
const parameters = helpers.toValue(parameterValue);
|
|
622
|
+
this.log('info', 'Sending Imagen edit request to Vertex AI', {
|
|
623
|
+
endpoint,
|
|
624
|
+
editMode: vertexEditMode,
|
|
625
|
+
dilation: request.maskDilation ?? 0.01,
|
|
626
|
+
});
|
|
627
|
+
const [response] = await client.predict({
|
|
628
|
+
endpoint,
|
|
629
|
+
instances: [instance],
|
|
630
|
+
parameters,
|
|
631
|
+
});
|
|
632
|
+
const duration = Date.now() - startTime;
|
|
633
|
+
this.log('info', `Imagen edit response received in ${duration}ms`, {
|
|
634
|
+
duration,
|
|
635
|
+
hasPredictions: !!response.predictions?.length,
|
|
636
|
+
});
|
|
637
|
+
if (!response.predictions || response.predictions.length === 0) {
|
|
638
|
+
throw new base_tti_provider_1.GenerationFailedError(this.providerName, 'No images returned from Imagen edit API');
|
|
639
|
+
}
|
|
640
|
+
return this.processImagenResponse(response.predictions, helpers, modelId, duration);
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
if (error instanceof base_tti_provider_1.InvalidConfigError || error instanceof base_tti_provider_1.GenerationFailedError) {
|
|
644
|
+
throw error;
|
|
645
|
+
}
|
|
646
|
+
throw this.handleError(error, 'during Imagen edit API call');
|
|
647
|
+
}
|
|
648
|
+
}
|
|
531
649
|
// ============================================================
|
|
532
650
|
// PRIVATE: GEMINI IMAGE IMPLEMENTATION
|
|
533
651
|
// ============================================================
|
|
@@ -702,3 +820,19 @@ IMPORTANT: Maintain exact visual consistency with the subject in the reference -
|
|
|
702
820
|
}
|
|
703
821
|
}
|
|
704
822
|
exports.GoogleCloudTTIProvider = GoogleCloudTTIProvider;
|
|
823
|
+
// ============================================================
|
|
824
|
+
// PRIVATE: IMAGEN EDITING / INPAINTING IMPLEMENTATION
|
|
825
|
+
// ============================================================
|
|
826
|
+
/** Maps our editMode values to the Vertex AI API constants */
|
|
827
|
+
GoogleCloudTTIProvider.EDIT_MODE_MAP = {
|
|
828
|
+
'inpainting-insert': 'EDIT_MODE_INPAINT_INSERTION',
|
|
829
|
+
'inpainting-remove': 'EDIT_MODE_INPAINT_REMOVAL',
|
|
830
|
+
'background-swap': 'EDIT_MODE_BGSWAP',
|
|
831
|
+
'outpainting': 'EDIT_MODE_OUTPAINT',
|
|
832
|
+
};
|
|
833
|
+
GoogleCloudTTIProvider.SUBJECT_TYPE_MAP = {
|
|
834
|
+
person: 'SUBJECT_TYPE_PERSON',
|
|
835
|
+
animal: 'SUBJECT_TYPE_ANIMAL',
|
|
836
|
+
product: 'SUBJECT_TYPE_PRODUCT',
|
|
837
|
+
default: 'SUBJECT_TYPE_DEFAULT',
|
|
838
|
+
};
|
|
@@ -82,6 +82,30 @@ export interface TTIReferenceImage {
|
|
|
82
82
|
/** MIME type of the image (e.g., 'image/png', 'image/jpeg') */
|
|
83
83
|
mimeType?: string;
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Subject type hint for mask reference images.
|
|
87
|
+
* Helps the model understand what kind of subject is shown in the reference image.
|
|
88
|
+
* - 'person' — a human character
|
|
89
|
+
* - 'animal' — an animal or creature
|
|
90
|
+
* - 'product' — an object, product, or item
|
|
91
|
+
* - 'default' — let the model decide (fallback)
|
|
92
|
+
*/
|
|
93
|
+
export type TTISubjectType = 'person' | 'animal' | 'product' | 'default';
|
|
94
|
+
/**
|
|
95
|
+
* Reference image for mask-based inpainting (subject reference).
|
|
96
|
+
* Used with maskReferenceImages to guide what the model inserts into the masked area.
|
|
97
|
+
*/
|
|
98
|
+
export interface TTIMaskReferenceImage {
|
|
99
|
+
/** Base64-encoded image data of the subject to insert */
|
|
100
|
+
base64: string;
|
|
101
|
+
/** MIME type of the image (e.g., 'image/png', 'image/jpeg') */
|
|
102
|
+
mimeType?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Subject type hint for the model.
|
|
105
|
+
* Defaults to 'default' if omitted.
|
|
106
|
+
*/
|
|
107
|
+
subjectType?: TTISubjectType;
|
|
108
|
+
}
|
|
85
109
|
/**
|
|
86
110
|
* Unified TTI generation request
|
|
87
111
|
* Works for both simple text-to-image and character consistency
|
|
@@ -105,6 +129,38 @@ export interface TTIRequest {
|
|
|
105
129
|
* Required when using referenceImages (e.g., "cute cartoon bear with red hat")
|
|
106
130
|
*/
|
|
107
131
|
subjectDescription?: string;
|
|
132
|
+
/**
|
|
133
|
+
* Base image to edit. When present, activates "edit mode" instead of text-to-image generation.
|
|
134
|
+
* Requires maskImage and a model that supports imageEditing capability.
|
|
135
|
+
*/
|
|
136
|
+
baseImage?: TTIReferenceImage;
|
|
137
|
+
/**
|
|
138
|
+
* Mask image for inpainting. White pixels = regenerate, black pixels = preserve.
|
|
139
|
+
* Must have identical dimensions to baseImage.
|
|
140
|
+
* Required when baseImage is set.
|
|
141
|
+
*/
|
|
142
|
+
maskImage?: TTIReferenceImage;
|
|
143
|
+
/**
|
|
144
|
+
* Mask dilation: expands the mask boundary to smooth hard edges (0.0–1.0, default 0.01).
|
|
145
|
+
* Useful when hand-drawn masks have jagged edges.
|
|
146
|
+
*/
|
|
147
|
+
maskDilation?: number;
|
|
148
|
+
/**
|
|
149
|
+
* Edit operation to perform on the masked region.
|
|
150
|
+
* - 'inpainting-insert': add or replace content in the masked area (default)
|
|
151
|
+
* - 'inpainting-remove': remove content and fill with matching background
|
|
152
|
+
* - 'background-swap': replace background while preserving foreground
|
|
153
|
+
* - 'outpainting': extend image beyond its boundaries into the masked area
|
|
154
|
+
*/
|
|
155
|
+
editMode?: 'inpainting-insert' | 'inpainting-remove' | 'background-swap' | 'outpainting';
|
|
156
|
+
/**
|
|
157
|
+
* Optional subject reference images for mask-based inpainting.
|
|
158
|
+
* Only valid when baseImage and maskImage are set.
|
|
159
|
+
* Each entry guides the model to insert a specific subject into the masked area
|
|
160
|
+
* (e.g., "place the character from this reference image into the mask").
|
|
161
|
+
* Only supported by the 'imagen-capability' model.
|
|
162
|
+
*/
|
|
163
|
+
maskReferenceImages?: TTIMaskReferenceImage[];
|
|
108
164
|
/** Additional provider-specific options */
|
|
109
165
|
providerOptions?: Record<string, unknown>;
|
|
110
166
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loonylabs/tti-middleware",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Provider-agnostic Text-to-Image middleware with GDPR compliance. Supports Google Cloud (Imagen, Gemini), Eden AI, and IONOS.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|