@loonylabs/tti-middleware 1.10.0 → 1.12.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
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,7 +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)
|
|
47
|
-
- **Inpainting**: Fix specific areas of a generated image without regenerating the entire scene — via Vertex AI `imagen-capability` model
|
|
48
|
+
- **Inpainting**: Fix specific areas of a generated image without regenerating the entire scene — via Vertex AI `imagen-capability` model.
|
|
48
49
|
- **GDPR/DSGVO Compliance**: Built-in EU region support with automatic fallback
|
|
49
50
|
- **Region Rotation**: Opt-in region rotation on quota errors (429) for Google Cloud — rotate through regions instead of retrying the same exhausted region
|
|
50
51
|
- **Retry Logic**: Exponential backoff with jitter for transient errors (429, 408, 5xx, timeouts)
|
|
@@ -308,6 +309,37 @@ const duelScene = await service.generate({
|
|
|
308
309
|
|
|
309
310
|
- Model must be `gemini-flash-image` (only model supporting character consistency)
|
|
310
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
|
+
### Supported `editMode` Values
|
|
335
|
+
|
|
336
|
+
| Value | Description |
|
|
337
|
+
|-------|-------------|
|
|
338
|
+
| `'inpainting-insert'` | Add or replace content in masked area (default) |
|
|
339
|
+
| `'inpainting-remove'` | Remove content and fill with matching background |
|
|
340
|
+
| `'background-swap'` | Replace background, preserve foreground |
|
|
341
|
+
| `'outpainting'` | Extend image beyond its boundaries into the masked area |
|
|
342
|
+
|
|
311
343
|
## GDPR / Compliance
|
|
312
344
|
|
|
313
345
|
### Provider Compliance Overview
|
|
@@ -366,10 +398,16 @@ interface TTIRequest {
|
|
|
366
398
|
n?: number; // Number of images (default: 1)
|
|
367
399
|
aspectRatio?: string; // '1:1', '16:9', '4:3', etc.
|
|
368
400
|
|
|
369
|
-
// Character consistency
|
|
401
|
+
// Character consistency (Gemini models only)
|
|
370
402
|
referenceImages?: TTIReferenceImage[];
|
|
371
403
|
subjectDescription?: string;
|
|
372
404
|
|
|
405
|
+
// Inpainting / image editing (imagen-capability only)
|
|
406
|
+
baseImage?: TTIReferenceImage; // Activates edit mode when set
|
|
407
|
+
maskImage?: TTIReferenceImage; // Required when baseImage is set
|
|
408
|
+
maskDilation?: number; // 0.0–1.0, default 0.01
|
|
409
|
+
editMode?: 'inpainting-insert' | 'inpainting-remove' | 'background-swap' | 'outpainting';
|
|
410
|
+
|
|
373
411
|
// Retry configuration
|
|
374
412
|
retry?: boolean | RetryOptions; // true (default), false, or custom config
|
|
375
413
|
|
|
@@ -65,6 +65,7 @@ export declare class GoogleCloudTTIProvider extends BaseTTIProvider {
|
|
|
65
65
|
private processImagenResponse;
|
|
66
66
|
/** Maps our editMode values to the Vertex AI API constants */
|
|
67
67
|
private static readonly EDIT_MODE_MAP;
|
|
68
|
+
private static readonly SUBJECT_TYPE_MAP;
|
|
68
69
|
private editWithImagen;
|
|
69
70
|
private generateWithGemini;
|
|
70
71
|
private getGenaiClient;
|
|
@@ -565,18 +565,31 @@ class GoogleCloudTTIProvider extends base_tti_provider_1.BaseTTIProvider {
|
|
|
565
565
|
try {
|
|
566
566
|
const { client, helpers } = await this.getAiplatformClient(region);
|
|
567
567
|
const endpoint = `projects/${this.config.projectId}/locations/${region}/publishers/google/models/${internalModelId}`;
|
|
568
|
-
// Build referenceImages array
|
|
568
|
+
// Build referenceImages array.
|
|
569
|
+
//
|
|
570
|
+
// Vertex AI uses sequential, distinct referenceId values for each entry.
|
|
571
|
+
// RAW and MASK have separate IDs — the API pairs them by type/order, not by shared ID.
|
|
572
|
+
// SUBJECT gets the next ID after MASK and MUST be cited in the prompt as [N].
|
|
573
|
+
//
|
|
574
|
+
// Correct layout (confirmed by official Vertex AI docs):
|
|
575
|
+
// REFERENCE_TYPE_RAW referenceId: 1
|
|
576
|
+
// REFERENCE_TYPE_MASK referenceId: 2
|
|
577
|
+
// REFERENCE_TYPE_SUBJECT referenceId: 3 ← referenced in prompt as [3]
|
|
578
|
+
//
|
|
579
|
+
// See: https://cloud.google.com/vertex-ai/generative-ai/docs/image/edit-insert-objects
|
|
580
|
+
const RAW_REFERENCE_ID = 1;
|
|
581
|
+
const MASK_REFERENCE_ID = 2;
|
|
569
582
|
const referenceImages = [
|
|
570
583
|
{
|
|
571
584
|
referenceType: 'REFERENCE_TYPE_RAW',
|
|
572
|
-
referenceId:
|
|
585
|
+
referenceId: RAW_REFERENCE_ID,
|
|
573
586
|
referenceImage: {
|
|
574
587
|
bytesBase64Encoded: request.baseImage.base64,
|
|
575
588
|
},
|
|
576
589
|
},
|
|
577
590
|
{
|
|
578
591
|
referenceType: 'REFERENCE_TYPE_MASK',
|
|
579
|
-
referenceId:
|
|
592
|
+
referenceId: MASK_REFERENCE_ID,
|
|
580
593
|
referenceImage: {
|
|
581
594
|
bytesBase64Encoded: request.maskImage.base64,
|
|
582
595
|
},
|
|
@@ -813,3 +826,10 @@ GoogleCloudTTIProvider.EDIT_MODE_MAP = {
|
|
|
813
826
|
'background-swap': 'EDIT_MODE_BGSWAP',
|
|
814
827
|
'outpainting': 'EDIT_MODE_OUTPAINT',
|
|
815
828
|
};
|
|
829
|
+
GoogleCloudTTIProvider.SUBJECT_TYPE_MAP = {
|
|
830
|
+
person: 'SUBJECT_TYPE_PERSON',
|
|
831
|
+
// Vertex AI API uses ANIMAL_COMPANION, not ANIMAL
|
|
832
|
+
animal: 'SUBJECT_TYPE_ANIMAL_COMPANION',
|
|
833
|
+
product: 'SUBJECT_TYPE_PRODUCT',
|
|
834
|
+
default: 'SUBJECT_TYPE_DEFAULT',
|
|
835
|
+
};
|
package/package.json
CHANGED
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@loonylabs/tti-middleware",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Provider-agnostic Text-to-Image middleware with GDPR compliance. Supports Google Cloud (Imagen, Gemini), Eden AI, and IONOS.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist",
|
|
9
|
-
"LICENSE",
|
|
10
|
-
"README.md",
|
|
11
|
-
".env.example"
|
|
12
|
-
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsc",
|
|
15
|
-
"test": "npm run test:unit",
|
|
16
|
-
"test:unit": "jest --testPathPattern=tests/unit",
|
|
17
|
-
"test:unit:watch": "jest --testPathPattern=tests/unit --watch",
|
|
18
|
-
"test:unit:coverage": "jest --testPathPattern=tests/unit --coverage",
|
|
19
|
-
"test:integration": "cross-env TTI_INTEGRATION_TESTS=true jest --testPathPattern=tests/integration",
|
|
20
|
-
"test:ci": "jest --runInBand --ci --coverage --testPathPattern=tests/unit",
|
|
21
|
-
"test:live": "TTI_INTEGRATION_TESTS=true jest tests/integration/*.integration.test.ts --testTimeout=120000",
|
|
22
|
-
"test:manual": "ts-node scripts/manual-test-edenai.ts",
|
|
23
|
-
"test:manual:google-cloud": "ts-node scripts/manual-test-google-cloud.ts",
|
|
24
|
-
"lint": "eslint src/**/*.ts",
|
|
25
|
-
"format": "prettier --write \"src/**/*.ts\"",
|
|
26
|
-
"clean": "node -e \"const fs=require('fs');if(fs.existsSync('dist'))fs.rmSync('dist',{recursive:true})\"",
|
|
27
|
-
"prepare": "npm run build",
|
|
28
|
-
"prepublishOnly": "npm run clean && npm run build && npm run test"
|
|
29
|
-
},
|
|
30
|
-
"keywords": [
|
|
31
|
-
"tti",
|
|
32
|
-
"text-to-image",
|
|
33
|
-
"image-generation",
|
|
34
|
-
"ai",
|
|
35
|
-
"vertex-ai",
|
|
36
|
-
"google-cloud",
|
|
37
|
-
"gemini",
|
|
38
|
-
"imagen",
|
|
39
|
-
"middleware",
|
|
40
|
-
"provider-agnostic",
|
|
41
|
-
"typescript",
|
|
42
|
-
"gdpr",
|
|
43
|
-
"dsgvo",
|
|
44
|
-
"character-consistency"
|
|
45
|
-
],
|
|
46
|
-
"author": "loonylabs-dev",
|
|
47
|
-
"license": "MIT",
|
|
48
|
-
"repository": {
|
|
49
|
-
"type": "git",
|
|
50
|
-
"url": "https://github.com/loonylabs-dev/tti-middleware.git"
|
|
51
|
-
},
|
|
52
|
-
"bugs": {
|
|
53
|
-
"url": "https://github.com/loonylabs-dev/tti-middleware/issues"
|
|
54
|
-
},
|
|
55
|
-
"homepage": "https://github.com/loonylabs-dev/tti-middleware#readme",
|
|
56
|
-
"peerDependencies": {
|
|
57
|
-
"@google-cloud/aiplatform": ">=3.0.0",
|
|
58
|
-
"@google/genai": ">=1.40.0"
|
|
59
|
-
},
|
|
60
|
-
"peerDependenciesMeta": {
|
|
61
|
-
"@google-cloud/aiplatform": {
|
|
62
|
-
"optional": true
|
|
63
|
-
},
|
|
64
|
-
"@google/genai": {
|
|
65
|
-
"optional": true
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
"devDependencies": {
|
|
69
|
-
"@google-cloud/aiplatform": "^3.29.0",
|
|
70
|
-
"@google/genai": "^1.40.0",
|
|
71
|
-
"@types/jest": "^29.5.8",
|
|
72
|
-
"@types/node": "^20.10.0",
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
74
|
-
"@typescript-eslint/parser": "^6.13.0",
|
|
75
|
-
"cross-env": "^10.1.0",
|
|
76
|
-
"dotenv": "^17.2.3",
|
|
77
|
-
"eslint": "^8.54.0",
|
|
78
|
-
"jest": "^29.7.0",
|
|
79
|
-
"prettier": "^3.1.0",
|
|
80
|
-
"ts-jest": "^29.1.1",
|
|
81
|
-
"ts-node": "^10.9.2",
|
|
82
|
-
"typescript": "^5.3.2"
|
|
83
|
-
},
|
|
84
|
-
"engines": {
|
|
85
|
-
"node": ">=18.0.0"
|
|
86
|
-
},
|
|
87
|
-
"publishConfig": {
|
|
88
|
-
"access": "public"
|
|
89
|
-
}
|
|
90
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@loonylabs/tti-middleware",
|
|
3
|
+
"version": "1.12.0",
|
|
4
|
+
"description": "Provider-agnostic Text-to-Image middleware with GDPR compliance. Supports Google Cloud (Imagen, Gemini), Eden AI, and IONOS.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"README.md",
|
|
11
|
+
".env.example"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "npm run test:unit",
|
|
16
|
+
"test:unit": "jest --testPathPattern=tests/unit",
|
|
17
|
+
"test:unit:watch": "jest --testPathPattern=tests/unit --watch",
|
|
18
|
+
"test:unit:coverage": "jest --testPathPattern=tests/unit --coverage",
|
|
19
|
+
"test:integration": "cross-env TTI_INTEGRATION_TESTS=true jest --testPathPattern=tests/integration",
|
|
20
|
+
"test:ci": "jest --runInBand --ci --coverage --testPathPattern=tests/unit",
|
|
21
|
+
"test:live": "TTI_INTEGRATION_TESTS=true jest tests/integration/*.integration.test.ts --testTimeout=120000",
|
|
22
|
+
"test:manual": "ts-node scripts/manual-test-edenai.ts",
|
|
23
|
+
"test:manual:google-cloud": "ts-node scripts/manual-test-google-cloud.ts",
|
|
24
|
+
"lint": "eslint src/**/*.ts",
|
|
25
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
26
|
+
"clean": "node -e \"const fs=require('fs');if(fs.existsSync('dist'))fs.rmSync('dist',{recursive:true})\"",
|
|
27
|
+
"prepare": "npm run build",
|
|
28
|
+
"prepublishOnly": "npm run clean && npm run build && npm run test"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"tti",
|
|
32
|
+
"text-to-image",
|
|
33
|
+
"image-generation",
|
|
34
|
+
"ai",
|
|
35
|
+
"vertex-ai",
|
|
36
|
+
"google-cloud",
|
|
37
|
+
"gemini",
|
|
38
|
+
"imagen",
|
|
39
|
+
"middleware",
|
|
40
|
+
"provider-agnostic",
|
|
41
|
+
"typescript",
|
|
42
|
+
"gdpr",
|
|
43
|
+
"dsgvo",
|
|
44
|
+
"character-consistency"
|
|
45
|
+
],
|
|
46
|
+
"author": "loonylabs-dev",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/loonylabs-dev/tti-middleware.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/loonylabs-dev/tti-middleware/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/loonylabs-dev/tti-middleware#readme",
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@google-cloud/aiplatform": ">=3.0.0",
|
|
58
|
+
"@google/genai": ">=1.40.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"@google-cloud/aiplatform": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@google/genai": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@google-cloud/aiplatform": "^3.29.0",
|
|
70
|
+
"@google/genai": "^1.40.0",
|
|
71
|
+
"@types/jest": "^29.5.8",
|
|
72
|
+
"@types/node": "^20.10.0",
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
74
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
75
|
+
"cross-env": "^10.1.0",
|
|
76
|
+
"dotenv": "^17.2.3",
|
|
77
|
+
"eslint": "^8.54.0",
|
|
78
|
+
"jest": "^29.7.0",
|
|
79
|
+
"prettier": "^3.1.0",
|
|
80
|
+
"ts-jest": "^29.1.1",
|
|
81
|
+
"ts-node": "^10.9.2",
|
|
82
|
+
"typescript": "^5.3.2"
|
|
83
|
+
},
|
|
84
|
+
"engines": {
|
|
85
|
+
"node": ">=18.0.0"
|
|
86
|
+
},
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"access": "public"
|
|
89
|
+
}
|
|
90
|
+
}
|