@umituz/react-native-ai-gemini-provider 1.14.0 → 1.14.2
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/package.json +6 -6
- package/src/domain/constants/feature-models.constants.ts +70 -0
- package/src/domain/constants/index.ts +15 -0
- package/src/index.ts +41 -0
- package/src/infrastructure/services/gemini-provider.ts +92 -0
- package/src/infrastructure/utils/index.ts +29 -0
- package/src/infrastructure/utils/input-builders.util.ts +265 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-gemini-provider",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.2",
|
|
4
4
|
"description": "Google Gemini AI provider for React Native applications",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -30,18 +30,18 @@
|
|
|
30
30
|
"url": "https://github.com/umituz/react-native-ai-gemini-provider"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"react": ">=18.2.0",
|
|
34
|
-
"react-native": ">=0.74.0",
|
|
35
33
|
"@google/generative-ai": ">=0.21.0",
|
|
36
|
-
"@umituz/react-native-ai-generation-content": ">=1.16.0"
|
|
34
|
+
"@umituz/react-native-ai-generation-content": ">=1.16.0",
|
|
35
|
+
"react": ">=18.2.0",
|
|
36
|
+
"react-native": ">=0.74.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@google/generative-ai": "^0.21.0",
|
|
40
|
-
"@
|
|
40
|
+
"@types/react": "~19.1.10",
|
|
41
41
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
42
42
|
"@typescript-eslint/parser": "^7.0.0",
|
|
43
|
+
"@umituz/react-native-ai-generation-content": "^1.17.26",
|
|
43
44
|
"eslint": "^8.57.0",
|
|
44
|
-
"@types/react": "~19.1.10",
|
|
45
45
|
"react": "19.1.0",
|
|
46
46
|
"react-native": "0.81.5",
|
|
47
47
|
"typescript": "^5.3.0"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Feature Models Catalog
|
|
3
|
+
* Provider-specific model IDs for image and video processing features
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
ImageFeatureType,
|
|
8
|
+
VideoFeatureType,
|
|
9
|
+
} from "@umituz/react-native-ai-generation-content";
|
|
10
|
+
|
|
11
|
+
export interface FeatureModelConfig {
|
|
12
|
+
id: string;
|
|
13
|
+
feature: ImageFeatureType | VideoFeatureType;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gemini model IDs for IMAGE processing features
|
|
19
|
+
* Using gemini-2.0-flash-exp for image editing capabilities
|
|
20
|
+
*/
|
|
21
|
+
export const GEMINI_IMAGE_FEATURE_MODELS: Record<ImageFeatureType, string> = {
|
|
22
|
+
"upscale": "gemini-2.0-flash-exp",
|
|
23
|
+
"photo-restore": "gemini-2.0-flash-exp",
|
|
24
|
+
"face-swap": "gemini-2.0-flash-exp",
|
|
25
|
+
"anime-selfie": "gemini-2.0-flash-exp",
|
|
26
|
+
"remove-background": "gemini-2.0-flash-exp",
|
|
27
|
+
"remove-object": "gemini-2.0-flash-exp",
|
|
28
|
+
"hd-touch-up": "gemini-2.0-flash-exp",
|
|
29
|
+
"replace-background": "gemini-2.0-flash-exp",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gemini model IDs for VIDEO generation features
|
|
34
|
+
* Using gemini-2.0-flash-exp for video generation capabilities
|
|
35
|
+
*/
|
|
36
|
+
export const GEMINI_VIDEO_FEATURE_MODELS: Record<VideoFeatureType, string> = {
|
|
37
|
+
"ai-hug": "gemini-2.0-flash-exp",
|
|
38
|
+
"ai-kiss": "gemini-2.0-flash-exp",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get Gemini model ID for an image feature
|
|
43
|
+
*/
|
|
44
|
+
export function getGeminiImageFeatureModel(feature: ImageFeatureType): string {
|
|
45
|
+
return GEMINI_IMAGE_FEATURE_MODELS[feature];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get Gemini model ID for a video feature
|
|
50
|
+
*/
|
|
51
|
+
export function getGeminiVideoFeatureModel(feature: VideoFeatureType): string {
|
|
52
|
+
return GEMINI_VIDEO_FEATURE_MODELS[feature];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get all feature model configs
|
|
57
|
+
*/
|
|
58
|
+
export function getAllFeatureModels(): FeatureModelConfig[] {
|
|
59
|
+
const imageModels = Object.entries(GEMINI_IMAGE_FEATURE_MODELS).map(([feature, id]) => ({
|
|
60
|
+
id,
|
|
61
|
+
feature: feature as ImageFeatureType,
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
const videoModels = Object.entries(GEMINI_VIDEO_FEATURE_MODELS).map(([feature, id]) => ({
|
|
65
|
+
id,
|
|
66
|
+
feature: feature as VideoFeatureType,
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
return [...imageModels, ...videoModels];
|
|
70
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Domain Constants
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
GEMINI_IMAGE_FEATURE_MODELS,
|
|
7
|
+
GEMINI_VIDEO_FEATURE_MODELS,
|
|
8
|
+
getGeminiImageFeatureModel,
|
|
9
|
+
getGeminiVideoFeatureModel,
|
|
10
|
+
getAllFeatureModels,
|
|
11
|
+
} from "./feature-models.constants";
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
FeatureModelConfig,
|
|
15
|
+
} from "./feature-models.constants";
|
package/src/index.ts
CHANGED
|
@@ -60,6 +60,22 @@ export {
|
|
|
60
60
|
|
|
61
61
|
export type { ResponseModality } from "./domain/entities";
|
|
62
62
|
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// DOMAIN LAYER - Feature Models
|
|
65
|
+
// =============================================================================
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
GEMINI_IMAGE_FEATURE_MODELS,
|
|
69
|
+
GEMINI_VIDEO_FEATURE_MODELS,
|
|
70
|
+
getGeminiImageFeatureModel,
|
|
71
|
+
getGeminiVideoFeatureModel,
|
|
72
|
+
getAllFeatureModels,
|
|
73
|
+
} from "./domain/constants";
|
|
74
|
+
|
|
75
|
+
export type {
|
|
76
|
+
FeatureModelConfig,
|
|
77
|
+
} from "./domain/constants";
|
|
78
|
+
|
|
63
79
|
// =============================================================================
|
|
64
80
|
// INFRASTRUCTURE LAYER - Services
|
|
65
81
|
// =============================================================================
|
|
@@ -94,6 +110,31 @@ export {
|
|
|
94
110
|
mapGeminiError,
|
|
95
111
|
isGeminiErrorRetryable,
|
|
96
112
|
categorizeGeminiError,
|
|
113
|
+
// Input builders
|
|
114
|
+
buildSingleImageInput,
|
|
115
|
+
buildDualImageInput,
|
|
116
|
+
buildUpscaleInput,
|
|
117
|
+
buildPhotoRestoreInput,
|
|
118
|
+
buildAIHugInput,
|
|
119
|
+
buildAIKissInput,
|
|
120
|
+
buildFaceSwapInput,
|
|
121
|
+
buildAnimeSelfieInput,
|
|
122
|
+
buildRemoveBackgroundInput,
|
|
123
|
+
buildRemoveObjectInput,
|
|
124
|
+
buildReplaceBackgroundInput,
|
|
125
|
+
buildHDTouchUpInput,
|
|
126
|
+
buildVideoFromDualImagesInput,
|
|
127
|
+
} from "./infrastructure/utils";
|
|
128
|
+
|
|
129
|
+
export type {
|
|
130
|
+
UpscaleOptions as GeminiUpscaleOptions,
|
|
131
|
+
PhotoRestoreOptions as GeminiPhotoRestoreOptions,
|
|
132
|
+
FaceSwapOptions as GeminiFaceSwapOptions,
|
|
133
|
+
AnimeSelfieOptions as GeminiAnimeSelfieOptions,
|
|
134
|
+
RemoveBackgroundOptions as GeminiRemoveBackgroundOptions,
|
|
135
|
+
RemoveObjectOptions as GeminiRemoveObjectOptions,
|
|
136
|
+
ReplaceBackgroundOptions as GeminiReplaceBackgroundOptions,
|
|
137
|
+
VideoFromImageOptions as GeminiVideoFromImageOptions,
|
|
97
138
|
} from "./infrastructure/utils";
|
|
98
139
|
|
|
99
140
|
// =============================================================================
|
|
@@ -10,6 +10,10 @@ import type {
|
|
|
10
10
|
JobSubmission,
|
|
11
11
|
JobStatus,
|
|
12
12
|
SubscribeOptions,
|
|
13
|
+
ImageFeatureType,
|
|
14
|
+
VideoFeatureType,
|
|
15
|
+
ImageFeatureInputData,
|
|
16
|
+
VideoFeatureInputData,
|
|
13
17
|
} from "@umituz/react-native-ai-generation-content";
|
|
14
18
|
import type {
|
|
15
19
|
GeminiImageInput,
|
|
@@ -20,6 +24,21 @@ import { geminiImageEditService } from "./gemini-image-edit.service";
|
|
|
20
24
|
import { providerInitializer, type GeminiProviderConfig } from "./provider-initializer";
|
|
21
25
|
import { jobProcessor } from "./job-processor";
|
|
22
26
|
import { generationExecutor } from "./generation-executor";
|
|
27
|
+
import {
|
|
28
|
+
GEMINI_IMAGE_FEATURE_MODELS,
|
|
29
|
+
GEMINI_VIDEO_FEATURE_MODELS,
|
|
30
|
+
} from "../../domain/constants/feature-models.constants";
|
|
31
|
+
import {
|
|
32
|
+
buildUpscaleInput,
|
|
33
|
+
buildPhotoRestoreInput,
|
|
34
|
+
buildFaceSwapInput,
|
|
35
|
+
buildAnimeSelfieInput,
|
|
36
|
+
buildRemoveBackgroundInput,
|
|
37
|
+
buildRemoveObjectInput,
|
|
38
|
+
buildReplaceBackgroundInput,
|
|
39
|
+
buildHDTouchUpInput,
|
|
40
|
+
buildVideoFromDualImagesInput,
|
|
41
|
+
} from "../utils/input-builders.util";
|
|
23
42
|
|
|
24
43
|
export type { GeminiProviderConfig };
|
|
25
44
|
|
|
@@ -94,6 +113,79 @@ export class GeminiProvider implements IAIProvider {
|
|
|
94
113
|
providerInitializer.reset();
|
|
95
114
|
jobProcessor.clear();
|
|
96
115
|
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get model ID for an IMAGE feature
|
|
119
|
+
*/
|
|
120
|
+
getImageFeatureModel(feature: ImageFeatureType): string {
|
|
121
|
+
return GEMINI_IMAGE_FEATURE_MODELS[feature];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Build input for an IMAGE feature
|
|
126
|
+
*/
|
|
127
|
+
buildImageFeatureInput(
|
|
128
|
+
feature: ImageFeatureType,
|
|
129
|
+
data: ImageFeatureInputData,
|
|
130
|
+
): Record<string, unknown> {
|
|
131
|
+
const { imageBase64, targetImageBase64, prompt, options } = data;
|
|
132
|
+
|
|
133
|
+
switch (feature) {
|
|
134
|
+
case "upscale":
|
|
135
|
+
return buildUpscaleInput(imageBase64, options);
|
|
136
|
+
case "photo-restore":
|
|
137
|
+
return buildPhotoRestoreInput(imageBase64, options);
|
|
138
|
+
case "face-swap":
|
|
139
|
+
if (!targetImageBase64) {
|
|
140
|
+
throw new Error("Face swap requires target image");
|
|
141
|
+
}
|
|
142
|
+
return buildFaceSwapInput(imageBase64, targetImageBase64, options);
|
|
143
|
+
case "anime-selfie":
|
|
144
|
+
return buildAnimeSelfieInput(imageBase64, options);
|
|
145
|
+
case "remove-background":
|
|
146
|
+
return buildRemoveBackgroundInput(imageBase64, options);
|
|
147
|
+
case "remove-object":
|
|
148
|
+
return buildRemoveObjectInput(imageBase64, { prompt, ...options });
|
|
149
|
+
case "hd-touch-up":
|
|
150
|
+
return buildHDTouchUpInput(imageBase64, options);
|
|
151
|
+
case "replace-background":
|
|
152
|
+
if (!prompt) {
|
|
153
|
+
throw new Error("Replace background requires prompt");
|
|
154
|
+
}
|
|
155
|
+
return buildReplaceBackgroundInput(imageBase64, { prompt });
|
|
156
|
+
default:
|
|
157
|
+
throw new Error(`Unknown image feature: ${feature}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get model ID for a VIDEO feature
|
|
163
|
+
*/
|
|
164
|
+
getVideoFeatureModel(feature: VideoFeatureType): string {
|
|
165
|
+
return GEMINI_VIDEO_FEATURE_MODELS[feature];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Build input for a VIDEO feature
|
|
170
|
+
*/
|
|
171
|
+
buildVideoFeatureInput(
|
|
172
|
+
feature: VideoFeatureType,
|
|
173
|
+
data: VideoFeatureInputData,
|
|
174
|
+
): Record<string, unknown> {
|
|
175
|
+
const { sourceImageBase64, targetImageBase64, prompt, options } = data;
|
|
176
|
+
|
|
177
|
+
switch (feature) {
|
|
178
|
+
case "ai-hug":
|
|
179
|
+
case "ai-kiss":
|
|
180
|
+
return buildVideoFromDualImagesInput(sourceImageBase64, {
|
|
181
|
+
target_image: targetImageBase64,
|
|
182
|
+
motion_prompt: prompt,
|
|
183
|
+
...options,
|
|
184
|
+
});
|
|
185
|
+
default:
|
|
186
|
+
throw new Error(`Unknown video feature: ${feature}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
97
189
|
}
|
|
98
190
|
|
|
99
191
|
export const geminiProviderService = new GeminiProvider();
|
|
@@ -19,3 +19,32 @@ export {
|
|
|
19
19
|
isValidBase64,
|
|
20
20
|
} from "./image-preparer.util";
|
|
21
21
|
export type { PreparedImage } from "./image-preparer.util";
|
|
22
|
+
|
|
23
|
+
// Input builders
|
|
24
|
+
export {
|
|
25
|
+
buildSingleImageInput,
|
|
26
|
+
buildDualImageInput,
|
|
27
|
+
buildUpscaleInput,
|
|
28
|
+
buildPhotoRestoreInput,
|
|
29
|
+
buildAIHugInput,
|
|
30
|
+
buildAIKissInput,
|
|
31
|
+
buildFaceSwapInput,
|
|
32
|
+
buildAnimeSelfieInput,
|
|
33
|
+
buildRemoveBackgroundInput,
|
|
34
|
+
buildRemoveObjectInput,
|
|
35
|
+
buildReplaceBackgroundInput,
|
|
36
|
+
buildHDTouchUpInput,
|
|
37
|
+
buildVideoFromDualImagesInput,
|
|
38
|
+
} from "./input-builders.util";
|
|
39
|
+
|
|
40
|
+
export type {
|
|
41
|
+
UpscaleOptions,
|
|
42
|
+
PhotoRestoreOptions,
|
|
43
|
+
FaceSwapOptions,
|
|
44
|
+
AnimeSelfieOptions,
|
|
45
|
+
RemoveBackgroundOptions,
|
|
46
|
+
RemoveObjectOptions,
|
|
47
|
+
ReplaceBackgroundOptions,
|
|
48
|
+
VideoFromImageOptions,
|
|
49
|
+
VideoFromDualImageOptions,
|
|
50
|
+
} from "./input-builders.util";
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Input Builders
|
|
3
|
+
* Constructs Gemini API input from normalized data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// TYPES
|
|
8
|
+
// =============================================================================
|
|
9
|
+
|
|
10
|
+
export interface UpscaleOptions {
|
|
11
|
+
scaleFactor?: number;
|
|
12
|
+
enhanceFaces?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PhotoRestoreOptions {
|
|
16
|
+
enhanceFaces?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FaceSwapOptions {
|
|
20
|
+
// No additional options
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AnimeSelfieOptions {
|
|
24
|
+
style?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface RemoveBackgroundOptions {
|
|
28
|
+
// No additional options
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface RemoveObjectOptions {
|
|
32
|
+
mask?: string;
|
|
33
|
+
prompt?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ReplaceBackgroundOptions {
|
|
37
|
+
prompt: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface VideoFromImageOptions {
|
|
41
|
+
motion_prompt?: string;
|
|
42
|
+
duration?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// BASE BUILDERS
|
|
47
|
+
// =============================================================================
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build Gemini single image input format
|
|
51
|
+
*/
|
|
52
|
+
export function buildSingleImageInput(
|
|
53
|
+
base64: string,
|
|
54
|
+
prompt: string,
|
|
55
|
+
): Record<string, unknown> {
|
|
56
|
+
// Remove data: prefix if present
|
|
57
|
+
const cleanBase64 = base64.replace(/^data:image\/\w+;base64,/, "");
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
contents: [
|
|
61
|
+
{
|
|
62
|
+
parts: [
|
|
63
|
+
{ text: prompt },
|
|
64
|
+
{ inlineData: { mimeType: "image/jpeg", data: cleanBase64 } },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build Gemini dual image input format
|
|
73
|
+
*/
|
|
74
|
+
export function buildDualImageInput(
|
|
75
|
+
sourceBase64: string,
|
|
76
|
+
targetBase64: string,
|
|
77
|
+
prompt: string,
|
|
78
|
+
): Record<string, unknown> {
|
|
79
|
+
const cleanSource = sourceBase64.replace(/^data:image\/\w+;base64,/, "");
|
|
80
|
+
const cleanTarget = targetBase64.replace(/^data:image\/\w+;base64,/, "");
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
contents: [
|
|
84
|
+
{
|
|
85
|
+
parts: [
|
|
86
|
+
{ text: prompt },
|
|
87
|
+
{ inlineData: { mimeType: "image/jpeg", data: cleanSource } },
|
|
88
|
+
{ inlineData: { mimeType: "image/jpeg", data: cleanTarget } },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// =============================================================================
|
|
96
|
+
// FEATURE-SPECIFIC BUILDERS
|
|
97
|
+
// =============================================================================
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Build upscale input for Gemini
|
|
101
|
+
*/
|
|
102
|
+
export function buildUpscaleInput(
|
|
103
|
+
base64: string,
|
|
104
|
+
options?: UpscaleOptions,
|
|
105
|
+
): Record<string, unknown> {
|
|
106
|
+
const scale = options?.scaleFactor || 2;
|
|
107
|
+
const faceEnhance = options?.enhanceFaces
|
|
108
|
+
? " Enhance facial features."
|
|
109
|
+
: "";
|
|
110
|
+
|
|
111
|
+
const prompt = `Upscale this image by ${scale}x. Preserve all details, colors and enhance clarity.${faceEnhance}`;
|
|
112
|
+
|
|
113
|
+
return buildSingleImageInput(base64, prompt);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build photo restore input for Gemini
|
|
118
|
+
*/
|
|
119
|
+
export function buildPhotoRestoreInput(
|
|
120
|
+
base64: string,
|
|
121
|
+
options?: PhotoRestoreOptions,
|
|
122
|
+
): Record<string, unknown> {
|
|
123
|
+
const faceEnhance = options?.enhanceFaces !== false
|
|
124
|
+
? " Enhance facial features and expressions."
|
|
125
|
+
: "";
|
|
126
|
+
|
|
127
|
+
const prompt = `Restore this photo. Remove noise, scratches, and damage while preserving original content.${faceEnhance}`;
|
|
128
|
+
|
|
129
|
+
return buildSingleImageInput(base64, prompt);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Build AI hug video input for Gemini
|
|
134
|
+
*/
|
|
135
|
+
export function buildAIHugInput(
|
|
136
|
+
base64: string,
|
|
137
|
+
options?: VideoFromImageOptions,
|
|
138
|
+
): Record<string, unknown> {
|
|
139
|
+
const motionPrompt = options?.motion_prompt || "Create a warm hugging animation";
|
|
140
|
+
|
|
141
|
+
const prompt = `Transform this image into a video. ${motionPrompt}. Make it natural and emotional.`;
|
|
142
|
+
|
|
143
|
+
return buildSingleImageInput(base64, prompt);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Build AI kiss video input for Gemini
|
|
148
|
+
*/
|
|
149
|
+
export function buildAIKissInput(
|
|
150
|
+
base64: string,
|
|
151
|
+
options?: VideoFromImageOptions,
|
|
152
|
+
): Record<string, unknown> {
|
|
153
|
+
const motionPrompt = options?.motion_prompt || "Create a kissing animation";
|
|
154
|
+
|
|
155
|
+
const prompt = `Transform this image into a video. ${motionPrompt}. Make it romantic and natural.`;
|
|
156
|
+
|
|
157
|
+
return buildSingleImageInput(base64, prompt);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Build face swap input for Gemini
|
|
162
|
+
*/
|
|
163
|
+
export function buildFaceSwapInput(
|
|
164
|
+
sourceBase64: string,
|
|
165
|
+
targetBase64: string,
|
|
166
|
+
_options?: FaceSwapOptions,
|
|
167
|
+
): Record<string, unknown> {
|
|
168
|
+
const prompt = "Swap the face from the first image onto the person in the second image. Preserve lighting, expression, and natural appearance.";
|
|
169
|
+
|
|
170
|
+
return buildDualImageInput(sourceBase64, targetBase64, prompt);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Build anime selfie input for Gemini
|
|
175
|
+
*/
|
|
176
|
+
export function buildAnimeSelfieInput(
|
|
177
|
+
base64: string,
|
|
178
|
+
options?: AnimeSelfieOptions,
|
|
179
|
+
): Record<string, unknown> {
|
|
180
|
+
const style = options?.style || "anime";
|
|
181
|
+
|
|
182
|
+
const prompt = `Convert this photo into ${style} style. Preserve facial features and expression while applying artistic transformation.`;
|
|
183
|
+
|
|
184
|
+
return buildSingleImageInput(base64, prompt);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Build remove background input for Gemini
|
|
189
|
+
*/
|
|
190
|
+
export function buildRemoveBackgroundInput(
|
|
191
|
+
base64: string,
|
|
192
|
+
_options?: RemoveBackgroundOptions,
|
|
193
|
+
): Record<string, unknown> {
|
|
194
|
+
const prompt = "Remove the background from this image. Keep only the main subject with transparent background.";
|
|
195
|
+
|
|
196
|
+
return buildSingleImageInput(base64, prompt);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Build remove object (inpaint) input for Gemini
|
|
201
|
+
*/
|
|
202
|
+
export function buildRemoveObjectInput(
|
|
203
|
+
base64: string,
|
|
204
|
+
options?: RemoveObjectOptions,
|
|
205
|
+
): Record<string, unknown> {
|
|
206
|
+
const objectDescription = options?.prompt || "the unwanted object";
|
|
207
|
+
|
|
208
|
+
const prompt = `Remove ${objectDescription} from this image and fill the area naturally with the surrounding background.`;
|
|
209
|
+
|
|
210
|
+
return buildSingleImageInput(base64, prompt);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Build replace background input for Gemini
|
|
215
|
+
*/
|
|
216
|
+
export function buildReplaceBackgroundInput(
|
|
217
|
+
base64: string,
|
|
218
|
+
options: ReplaceBackgroundOptions,
|
|
219
|
+
): Record<string, unknown> {
|
|
220
|
+
const prompt = `Replace the background with: ${options.prompt}. Keep the main subject intact and blend naturally.`;
|
|
221
|
+
|
|
222
|
+
return buildSingleImageInput(base64, prompt);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Build HD touch up input (same as upscale with face enhancement)
|
|
227
|
+
*/
|
|
228
|
+
export function buildHDTouchUpInput(
|
|
229
|
+
base64: string,
|
|
230
|
+
options?: UpscaleOptions,
|
|
231
|
+
): Record<string, unknown> {
|
|
232
|
+
return buildUpscaleInput(base64, { ...options, enhanceFaces: true });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// =============================================================================
|
|
236
|
+
// VIDEO FEATURE BUILDERS
|
|
237
|
+
// =============================================================================
|
|
238
|
+
|
|
239
|
+
export interface VideoFromDualImageOptions {
|
|
240
|
+
target_image?: string;
|
|
241
|
+
motion_prompt?: string;
|
|
242
|
+
duration?: number;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Build video from dual images input for Gemini
|
|
247
|
+
* Used for ai-hug and ai-kiss features that need source and target images
|
|
248
|
+
*/
|
|
249
|
+
export function buildVideoFromDualImagesInput(
|
|
250
|
+
sourceBase64: string,
|
|
251
|
+
options?: VideoFromDualImageOptions,
|
|
252
|
+
): Record<string, unknown> {
|
|
253
|
+
const targetBase64 = options?.target_image || "";
|
|
254
|
+
const motionPrompt = options?.motion_prompt || "Create an animated interaction between the two people";
|
|
255
|
+
|
|
256
|
+
if (!targetBase64) {
|
|
257
|
+
// Single image case (fallback)
|
|
258
|
+
const prompt = `Transform this image into a video. ${motionPrompt}. Make it natural and emotional.`;
|
|
259
|
+
return buildSingleImageInput(sourceBase64, prompt);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const prompt = `Transform these two images into a video. ${motionPrompt}. Make it natural and emotional. The first image is the source person, the second is the target person.`;
|
|
263
|
+
|
|
264
|
+
return buildDualImageInput(sourceBase64, targetBase64, prompt);
|
|
265
|
+
}
|