@umituz/react-native-ai-gemini-provider 1.16.0 → 2.0.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/package.json +4 -9
- package/src/domain/constants/index.ts +1 -11
- package/src/domain/entities/index.ts +0 -1
- package/src/index.ts +2 -54
- package/src/infrastructure/job/JobManager.ts +11 -8
- package/src/infrastructure/services/gemini-provider.ts +31 -152
- package/src/infrastructure/services/generation-executor.ts +80 -141
- package/src/infrastructure/services/index.ts +1 -14
- package/src/infrastructure/services/job-processor.ts +42 -42
- package/src/infrastructure/services/provider-initializer.ts +19 -33
- package/src/infrastructure/utils/index.ts +1 -37
- package/src/infrastructure/utils/model-validation.util.ts +3 -29
- package/src/domain/constants/feature-models.constants.ts +0 -70
- package/src/domain/entities/video.types.ts +0 -149
- package/src/infrastructure/services/feature-input-builder.ts +0 -89
- package/src/infrastructure/services/feature-model-selector.ts +0 -77
- package/src/infrastructure/services/gemini-image-edit.service.ts +0 -134
- package/src/infrastructure/services/gemini-image-generation.service.ts +0 -137
- package/src/infrastructure/services/gemini-video-downloader.ts +0 -77
- package/src/infrastructure/services/gemini-video-error.ts +0 -21
- package/src/infrastructure/services/gemini-video-generation.service.ts +0 -103
- package/src/infrastructure/services/gemini-video-url-extractor.ts +0 -45
- package/src/infrastructure/services/veo-http-client.service.ts +0 -70
- package/src/infrastructure/services/veo-polling.service.ts +0 -119
- package/src/infrastructure/utils/base-input-builders.util.ts +0 -49
- package/src/infrastructure/utils/image-feature-builders.util.ts +0 -123
- package/src/infrastructure/utils/image-preparer.util.ts +0 -74
- package/src/infrastructure/utils/input-builder.types.ts +0 -44
- package/src/infrastructure/utils/input-builders.util.ts +0 -38
- package/src/infrastructure/utils/video-feature-builders.util.ts +0 -43
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-gemini-provider",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Google Gemini AI provider for React Native applications",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Google Gemini AI text generation provider for React Native applications",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -19,11 +19,8 @@
|
|
|
19
19
|
"ai",
|
|
20
20
|
"gemini",
|
|
21
21
|
"google",
|
|
22
|
-
"generation",
|
|
23
|
-
"llm"
|
|
24
|
-
"image-generation",
|
|
25
|
-
"video-generation",
|
|
26
|
-
"veo"
|
|
22
|
+
"text-generation",
|
|
23
|
+
"llm"
|
|
27
24
|
],
|
|
28
25
|
"author": "umituz",
|
|
29
26
|
"license": "MIT",
|
|
@@ -33,7 +30,6 @@
|
|
|
33
30
|
},
|
|
34
31
|
"peerDependencies": {
|
|
35
32
|
"@google/generative-ai": ">=0.21.0",
|
|
36
|
-
"@umituz/react-native-ai-generation-content": ">=1.16.0",
|
|
37
33
|
"react": ">=18.2.0",
|
|
38
34
|
"react-native": ">=0.74.0"
|
|
39
35
|
},
|
|
@@ -50,7 +46,6 @@
|
|
|
50
46
|
"@types/react": "~19.1.10",
|
|
51
47
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
52
48
|
"@typescript-eslint/parser": "^7.0.0",
|
|
53
|
-
"@umituz/react-native-ai-generation-content": "^1.58.3",
|
|
54
49
|
"@umituz/react-native-design-system": "^2.8.7",
|
|
55
50
|
"eslint": "^8.57.0",
|
|
56
51
|
"expo-apple-authentication": "^8.0.8",
|
|
@@ -2,14 +2,4 @@
|
|
|
2
2
|
* Gemini Domain Constants
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
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";
|
|
5
|
+
// No feature models needed for text-only provider
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @umituz/react-native-ai-gemini-provider
|
|
3
3
|
* Google Gemini AI provider for React Native applications
|
|
4
|
+
* Text generation only - for image/video use FAL Provider
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
// Domain Types
|
|
@@ -20,17 +21,7 @@ export type {
|
|
|
20
21
|
GeminiPromptFeedback,
|
|
21
22
|
GeminiUsageMetadata,
|
|
22
23
|
GeminiModel,
|
|
23
|
-
GeminiImageGenerationResult,
|
|
24
24
|
GeminiImageInput,
|
|
25
|
-
VideoGenerationInput,
|
|
26
|
-
VideoGenerationResult,
|
|
27
|
-
VideoGenerationProgress,
|
|
28
|
-
VideoGenerationOptions,
|
|
29
|
-
VideoGenerationError,
|
|
30
|
-
VideoAspectRatio,
|
|
31
|
-
VideoResolution,
|
|
32
|
-
VideoOperationStatus,
|
|
33
|
-
VeoOperation,
|
|
34
25
|
GeminiErrorInfo,
|
|
35
26
|
GeminiApiError,
|
|
36
27
|
ResponseModality,
|
|
@@ -38,17 +29,6 @@ export type {
|
|
|
38
29
|
|
|
39
30
|
export { GeminiErrorType, GeminiError, GEMINI_MODELS, DEFAULT_MODELS, MODEL_PRICING, RESPONSE_MODALITIES } from "./domain/entities";
|
|
40
31
|
|
|
41
|
-
// Feature Models
|
|
42
|
-
export {
|
|
43
|
-
GEMINI_IMAGE_FEATURE_MODELS,
|
|
44
|
-
GEMINI_VIDEO_FEATURE_MODELS,
|
|
45
|
-
getGeminiImageFeatureModel,
|
|
46
|
-
getGeminiVideoFeatureModel,
|
|
47
|
-
getAllFeatureModels,
|
|
48
|
-
} from "./domain/constants";
|
|
49
|
-
|
|
50
|
-
export type { FeatureModelConfig } from "./domain/constants";
|
|
51
|
-
|
|
52
32
|
// Services
|
|
53
33
|
export {
|
|
54
34
|
geminiClientCoreService,
|
|
@@ -56,23 +36,14 @@ export {
|
|
|
56
36
|
geminiTextGenerationService,
|
|
57
37
|
geminiTextService,
|
|
58
38
|
geminiStructuredTextService,
|
|
59
|
-
geminiImageGenerationService,
|
|
60
|
-
geminiImageEditService,
|
|
61
39
|
geminiStreamingService,
|
|
62
|
-
geminiVideoGenerationService,
|
|
63
40
|
geminiProviderService,
|
|
64
41
|
createGeminiProvider,
|
|
65
|
-
|
|
42
|
+
GeminiProvider,
|
|
66
43
|
} from "./infrastructure/services";
|
|
67
44
|
|
|
68
45
|
export type {
|
|
69
|
-
AIProviderConfig,
|
|
70
46
|
GeminiProviderConfig,
|
|
71
|
-
IAIProvider,
|
|
72
|
-
JobSubmission,
|
|
73
|
-
JobStatus,
|
|
74
|
-
SubscribeOptions,
|
|
75
|
-
AIJobStatusType,
|
|
76
47
|
GenerationInput,
|
|
77
48
|
GenerationResult,
|
|
78
49
|
ExecutionOptions,
|
|
@@ -89,9 +60,6 @@ export {
|
|
|
89
60
|
validateModel,
|
|
90
61
|
getSafeModel,
|
|
91
62
|
isTextModel,
|
|
92
|
-
isImageModel,
|
|
93
|
-
isImageEditModel,
|
|
94
|
-
isVideoGenerationModel,
|
|
95
63
|
getModelCategory,
|
|
96
64
|
getAllValidModels,
|
|
97
65
|
measureAsync,
|
|
@@ -101,31 +69,11 @@ export {
|
|
|
101
69
|
PerformanceTimer,
|
|
102
70
|
PerformanceTracker,
|
|
103
71
|
performanceTracker,
|
|
104
|
-
buildSingleImageInput,
|
|
105
|
-
buildDualImageInput,
|
|
106
|
-
buildUpscaleInput,
|
|
107
|
-
buildPhotoRestoreInput,
|
|
108
|
-
buildFaceSwapInput,
|
|
109
|
-
buildAnimeSelfieInput,
|
|
110
|
-
buildRemoveBackgroundInput,
|
|
111
|
-
buildRemoveObjectInput,
|
|
112
|
-
buildReplaceBackgroundInput,
|
|
113
|
-
buildHDTouchUpInput,
|
|
114
|
-
buildVideoFromDualImagesInput,
|
|
115
72
|
RateLimiter,
|
|
116
73
|
rateLimiter,
|
|
117
74
|
} from "./infrastructure/utils";
|
|
118
75
|
|
|
119
76
|
export type {
|
|
120
|
-
PreparedImage,
|
|
121
|
-
UpscaleOptions,
|
|
122
|
-
PhotoRestoreOptions,
|
|
123
|
-
FaceSwapOptions,
|
|
124
|
-
AnimeSelfieOptions,
|
|
125
|
-
RemoveBackgroundOptions,
|
|
126
|
-
RemoveObjectOptions,
|
|
127
|
-
ReplaceBackgroundOptions,
|
|
128
|
-
VideoFromImageOptions,
|
|
129
77
|
PerformanceMetrics,
|
|
130
78
|
RateLimiterOptions,
|
|
131
79
|
} from "./infrastructure/utils";
|
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
* Handles async job submission, tracking, and status management
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
JobSubmission,
|
|
8
|
-
JobStatus,
|
|
9
|
-
AIJobStatusType,
|
|
10
|
-
} from "@umituz/react-native-ai-generation-content/core";
|
|
6
|
+
declare const __DEV__: boolean;
|
|
11
7
|
|
|
12
|
-
export type
|
|
8
|
+
export type AIJobStatusType = "IN_QUEUE" | "IN_PROGRESS" | "COMPLETED" | "FAILED";
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
export interface JobSubmission {
|
|
11
|
+
requestId: string;
|
|
12
|
+
statusUrl?: string;
|
|
13
|
+
responseUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface JobStatus {
|
|
17
|
+
status: AIJobStatusType;
|
|
18
|
+
}
|
|
15
19
|
|
|
16
20
|
interface PendingJob {
|
|
17
21
|
model: string;
|
|
@@ -35,7 +39,6 @@ export class JobManager {
|
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
38
|
-
// eslint-disable-next-line no-console
|
|
39
42
|
console.log("[JobManager] Job submitted:", { requestId, model });
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -1,66 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini Provider
|
|
3
|
-
*
|
|
4
|
-
* Implements IAIProvider for unified orchestration
|
|
3
|
+
* Text-only AI provider for Google Gemini
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
AIProviderConfig,
|
|
10
|
-
JobSubmission,
|
|
11
|
-
JobStatus,
|
|
12
|
-
SubscribeOptions,
|
|
13
|
-
ImageFeatureType,
|
|
14
|
-
VideoFeatureType,
|
|
15
|
-
ImageFeatureInputData,
|
|
16
|
-
VideoFeatureInputData,
|
|
17
|
-
ProviderCapabilities,
|
|
18
|
-
RunOptions,
|
|
19
|
-
} from "@umituz/react-native-ai-generation-content/core";
|
|
20
|
-
import type {
|
|
21
|
-
GeminiImageInput,
|
|
22
|
-
GeminiImageGenerationResult,
|
|
23
|
-
} from "../../domain/entities";
|
|
24
|
-
import { geminiImageGenerationService } from "./gemini-image-generation.service";
|
|
25
|
-
import { geminiImageEditService } from "./gemini-image-edit.service";
|
|
26
|
-
import {
|
|
27
|
-
providerInitializer,
|
|
28
|
-
type GeminiProviderConfig,
|
|
29
|
-
} from "./provider-initializer";
|
|
30
|
-
import { jobProcessor } from "./job-processor";
|
|
6
|
+
import type { GeminiConfig, GeminiImageInput } from "../../domain/entities";
|
|
7
|
+
import { providerInitializer } from "./provider-initializer";
|
|
31
8
|
import { generationExecutor } from "./generation-executor";
|
|
32
|
-
import { featureInputBuilder } from "./feature-input-builder";
|
|
33
|
-
import { featureModelSelector } from "./feature-model-selector";
|
|
34
9
|
|
|
35
|
-
export type
|
|
10
|
+
export type GeminiProviderConfig = GeminiConfig;
|
|
36
11
|
|
|
37
12
|
/**
|
|
38
|
-
* Gemini
|
|
13
|
+
* Gemini Provider - Text Generation Only
|
|
14
|
+
* For image/video generation, use FAL Provider instead
|
|
39
15
|
*/
|
|
40
|
-
|
|
41
|
-
imageFeatures: [
|
|
42
|
-
"upscale",
|
|
43
|
-
"photo-restore",
|
|
44
|
-
"face-swap",
|
|
45
|
-
"anime-selfie",
|
|
46
|
-
"remove-background",
|
|
47
|
-
"remove-object",
|
|
48
|
-
"hd-touch-up",
|
|
49
|
-
"replace-background",
|
|
50
|
-
] as const,
|
|
51
|
-
videoFeatures: ["image-to-video", "text-to-video"] as const,
|
|
52
|
-
textToImage: true,
|
|
53
|
-
textToVideo: true,
|
|
54
|
-
imageToVideo: true,
|
|
55
|
-
textToVoice: false,
|
|
56
|
-
textToText: true,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export class GeminiProvider implements IAIProvider {
|
|
16
|
+
export class GeminiProvider {
|
|
60
17
|
readonly providerId = "gemini";
|
|
61
18
|
readonly providerName = "Google Gemini";
|
|
62
19
|
|
|
63
|
-
initialize(config:
|
|
20
|
+
initialize(config: GeminiProviderConfig): void {
|
|
64
21
|
providerInitializer.initialize(config);
|
|
65
22
|
}
|
|
66
23
|
|
|
@@ -68,121 +25,43 @@ export class GeminiProvider implements IAIProvider {
|
|
|
68
25
|
return providerInitializer.isInitialized();
|
|
69
26
|
}
|
|
70
27
|
|
|
71
|
-
getCapabilities(): ProviderCapabilities {
|
|
72
|
-
return GEMINI_CAPABILITIES;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
isFeatureSupported(feature: ImageFeatureType | VideoFeatureType): boolean {
|
|
76
|
-
const capabilities = this.getCapabilities();
|
|
77
|
-
return (
|
|
78
|
-
capabilities.imageFeatures.includes(feature as ImageFeatureType) ||
|
|
79
|
-
capabilities.videoFeatures.includes(feature as VideoFeatureType)
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
submitJob(
|
|
84
|
-
model: string,
|
|
85
|
-
input: Record<string, unknown>,
|
|
86
|
-
): Promise<JobSubmission> {
|
|
87
|
-
return jobProcessor.submitJob(model, input);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getJobStatus(_model: string, requestId: string): Promise<JobStatus> {
|
|
91
|
-
return jobProcessor.getJobStatus(_model, requestId);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
getJobResult<T = unknown>(_model: string, requestId: string): Promise<T> {
|
|
95
|
-
return jobProcessor.getJobResult<T>(_model, requestId);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async subscribe<T = unknown>(
|
|
99
|
-
model: string,
|
|
100
|
-
input: Record<string, unknown>,
|
|
101
|
-
options?: SubscribeOptions<T>,
|
|
102
|
-
): Promise<T> {
|
|
103
|
-
options?.onQueueUpdate?.({ status: "IN_QUEUE" });
|
|
104
|
-
|
|
105
|
-
const result = await generationExecutor.executeGeneration<T>(model, input, {
|
|
106
|
-
onProgress: (progress: number) => {
|
|
107
|
-
options?.onProgress?.({ progress, status: "IN_PROGRESS" });
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
options?.onProgress?.({ progress: 100, status: "COMPLETED" });
|
|
112
|
-
options?.onQueueUpdate?.({ status: "COMPLETED" });
|
|
113
|
-
options?.onResult?.(result);
|
|
114
|
-
|
|
115
|
-
return result;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async run<T = unknown>(
|
|
119
|
-
model: string,
|
|
120
|
-
input: Record<string, unknown>,
|
|
121
|
-
options?: RunOptions,
|
|
122
|
-
): Promise<T> {
|
|
123
|
-
return generationExecutor.executeGeneration<T>(model, input, {
|
|
124
|
-
onProgress: (progress: number) => {
|
|
125
|
-
options?.onProgress?.({ progress, status: "IN_PROGRESS" });
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async generateImage(prompt: string): Promise<GeminiImageGenerationResult> {
|
|
131
|
-
return geminiImageGenerationService.generateImage(prompt);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async editImage(
|
|
135
|
-
prompt: string,
|
|
136
|
-
images: GeminiImageInput[],
|
|
137
|
-
): Promise<GeminiImageGenerationResult> {
|
|
138
|
-
return geminiImageEditService.editImage(prompt, images);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async generateWithImages(
|
|
142
|
-
model: string,
|
|
143
|
-
prompt: string,
|
|
144
|
-
images: GeminiImageInput[],
|
|
145
|
-
): Promise<{ text: string; response: unknown }> {
|
|
146
|
-
return generationExecutor.generateWithImages(model, prompt, images);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
28
|
reset(): void {
|
|
150
29
|
providerInitializer.reset();
|
|
151
|
-
jobProcessor.clear();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get model ID for an IMAGE feature
|
|
156
|
-
*/
|
|
157
|
-
getImageFeatureModel(feature: ImageFeatureType): string {
|
|
158
|
-
return featureModelSelector.getImageFeatureModel(feature);
|
|
159
30
|
}
|
|
160
31
|
|
|
161
32
|
/**
|
|
162
|
-
*
|
|
33
|
+
* Generate text from prompt
|
|
163
34
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
data: ImageFeatureInputData,
|
|
167
|
-
): Record<string, unknown> {
|
|
168
|
-
return featureInputBuilder.buildImageFeatureInput(feature, data);
|
|
35
|
+
async generateText(prompt: string, model?: string): Promise<string> {
|
|
36
|
+
return generationExecutor.executeTextGeneration(prompt, model);
|
|
169
37
|
}
|
|
170
38
|
|
|
171
39
|
/**
|
|
172
|
-
*
|
|
40
|
+
* Generate text with images (multimodal)
|
|
41
|
+
* Useful for "describe this image" scenarios
|
|
173
42
|
*/
|
|
174
|
-
|
|
175
|
-
|
|
43
|
+
async generateTextWithImages(
|
|
44
|
+
prompt: string,
|
|
45
|
+
images: GeminiImageInput[],
|
|
46
|
+
model?: string,
|
|
47
|
+
): Promise<string> {
|
|
48
|
+
const result = await generationExecutor.generateWithImages(
|
|
49
|
+
model ?? "gemini-2.0-flash",
|
|
50
|
+
prompt,
|
|
51
|
+
images,
|
|
52
|
+
);
|
|
53
|
+
return result.text;
|
|
176
54
|
}
|
|
177
55
|
|
|
178
56
|
/**
|
|
179
|
-
*
|
|
57
|
+
* Generate structured JSON response
|
|
180
58
|
*/
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
59
|
+
async generateStructuredText<T>(
|
|
60
|
+
prompt: string,
|
|
61
|
+
schema: Record<string, unknown>,
|
|
62
|
+
model?: string,
|
|
63
|
+
): Promise<T> {
|
|
64
|
+
return generationExecutor.executeStructuredGeneration<T>(prompt, schema, model);
|
|
186
65
|
}
|
|
187
66
|
}
|
|
188
67
|
|
|
@@ -1,162 +1,101 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generation Executor
|
|
3
|
-
* Handles execution of
|
|
3
|
+
* Handles execution of text generation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
7
|
-
GeminiImageInput,
|
|
8
|
-
GeminiImageGenerationResult,
|
|
9
|
-
VideoGenerationInput,
|
|
10
|
-
VideoGenerationResult,
|
|
11
|
-
VideoGenerationProgress,
|
|
12
|
-
} from "../../domain/entities";
|
|
6
|
+
import type { GeminiImageInput } from "../../domain/entities";
|
|
13
7
|
import { geminiTextGenerationService } from "./gemini-text-generation.service";
|
|
14
|
-
import {
|
|
15
|
-
import { geminiVideoGenerationService } from "./gemini-video-generation.service";
|
|
16
|
-
import { ContentBuilder } from "../content/ContentBuilder";
|
|
17
|
-
import { ResponseFormatter } from "../response/ResponseFormatter";
|
|
8
|
+
import { geminiStructuredTextService } from "./gemini-structured-text.service";
|
|
18
9
|
|
|
19
10
|
declare const __DEV__: boolean;
|
|
20
11
|
|
|
21
12
|
export interface ExecutionOptions {
|
|
22
|
-
|
|
13
|
+
onProgress?: (progress: number) => void;
|
|
23
14
|
}
|
|
24
15
|
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
negativePrompt?: string;
|
|
33
|
-
aspect_ratio?: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type GenerationResult =
|
|
37
|
-
| string
|
|
38
|
-
| GeminiImageGenerationResult
|
|
39
|
-
| VideoGenerationResult;
|
|
16
|
+
export interface GenerationInput {
|
|
17
|
+
prompt?: string;
|
|
18
|
+
images?: GeminiImageInput[];
|
|
19
|
+
generationConfig?: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type GenerationResult = string;
|
|
40
23
|
|
|
41
24
|
export class GenerationExecutor {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
options?: ExecutionOptions,
|
|
49
|
-
): Promise<T> {
|
|
50
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
51
|
-
// eslint-disable-next-line no-console
|
|
52
|
-
console.log("[GenerationExecutor] executeGeneration() called", { model, inputType: input.type });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const isImageGeneration = input.generateImage === true || input.type === "image";
|
|
56
|
-
const isVideoGeneration = this.isVideoModel(model) || input.type === "video";
|
|
57
|
-
|
|
58
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
59
|
-
// eslint-disable-next-line no-console
|
|
60
|
-
console.log("[GenerationExecutor] Generation type:", { isImageGeneration, isVideoGeneration });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (isVideoGeneration) {
|
|
64
|
-
return this.executeVideoGeneration(input, options) as T;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (isImageGeneration) {
|
|
68
|
-
const prompt = String(input.prompt ?? "");
|
|
69
|
-
const images = input.images;
|
|
70
|
-
return geminiImageGenerationService.generateImage(prompt, images) as T;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const contents = this.contentBuilder.buildContents(input);
|
|
74
|
-
const response = await geminiTextGenerationService.generateContent(
|
|
75
|
-
model,
|
|
76
|
-
contents,
|
|
77
|
-
input.generationConfig as undefined,
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
return this.responseFormatter.formatResponse<T>(response, input);
|
|
25
|
+
/**
|
|
26
|
+
* Execute text generation
|
|
27
|
+
*/
|
|
28
|
+
async executeTextGeneration(prompt: string, model?: string): Promise<string> {
|
|
29
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
30
|
+
console.log("[GenerationExecutor] executeTextGeneration() called", { model });
|
|
81
31
|
}
|
|
82
32
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
33
|
+
const response = await geminiTextGenerationService.generateContent(
|
|
34
|
+
model ?? "gemini-2.0-flash",
|
|
35
|
+
[{ parts: [{ text: prompt }], role: "user" }],
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return this.extractTextFromResponse(response);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Execute structured text generation (JSON output)
|
|
43
|
+
*/
|
|
44
|
+
async executeStructuredGeneration<T>(
|
|
45
|
+
prompt: string,
|
|
46
|
+
schema: Record<string, unknown>,
|
|
47
|
+
model?: string,
|
|
48
|
+
): Promise<T> {
|
|
49
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
50
|
+
console.log("[GenerationExecutor] executeStructuredGeneration() called", { model });
|
|
88
51
|
}
|
|
89
52
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
53
|
+
return geminiStructuredTextService.generateStructuredContent<T>(
|
|
54
|
+
model ?? "gemini-2.0-flash",
|
|
55
|
+
prompt,
|
|
56
|
+
schema,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generate text with images (multimodal)
|
|
62
|
+
*/
|
|
63
|
+
async generateWithImages(
|
|
64
|
+
model: string,
|
|
65
|
+
prompt: string,
|
|
66
|
+
images: GeminiImageInput[],
|
|
67
|
+
): Promise<{ text: string; response: unknown }> {
|
|
68
|
+
const response = await geminiTextGenerationService.generateWithImages(
|
|
69
|
+
model,
|
|
70
|
+
prompt,
|
|
71
|
+
images,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const text = response.candidates?.[0]?.content.parts
|
|
75
|
+
.filter((p): p is { text: string } => "text" in p)
|
|
76
|
+
.map((p) => p.text)
|
|
77
|
+
.join("") || "";
|
|
78
|
+
|
|
79
|
+
return { text, response };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Extract text from Gemini response
|
|
84
|
+
*/
|
|
85
|
+
private extractTextFromResponse(response: unknown): string {
|
|
86
|
+
const resp = response as {
|
|
87
|
+
candidates?: Array<{
|
|
88
|
+
content: {
|
|
89
|
+
parts: Array<{ text?: string }>;
|
|
109
90
|
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
: undefined;
|
|
120
|
-
|
|
121
|
-
const result = await geminiVideoGenerationService.generateVideo(videoInput, onProgress);
|
|
122
|
-
|
|
123
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
124
|
-
// eslint-disable-next-line no-console
|
|
125
|
-
console.log("[GenerationExecutor] Video generation completed");
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
videoUrl: result.videoUrl,
|
|
130
|
-
metadata: result.metadata,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Normalize aspect ratio format (e.g., "16:9" stays, others default)
|
|
136
|
-
*/
|
|
137
|
-
private normalizeAspectRatio(ratio: string | undefined): "16:9" | "9:16" | "1:1" {
|
|
138
|
-
if (ratio === "9:16" || ratio === "1:1") return ratio;
|
|
139
|
-
return "16:9";
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async generateWithImages(
|
|
143
|
-
model: string,
|
|
144
|
-
prompt: string,
|
|
145
|
-
images: GeminiImageInput[],
|
|
146
|
-
): Promise<{ text: string; response: unknown }> {
|
|
147
|
-
const response = await geminiTextGenerationService.generateWithImages(
|
|
148
|
-
model,
|
|
149
|
-
prompt,
|
|
150
|
-
images,
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
const text = response.candidates?.[0]?.content.parts
|
|
154
|
-
.filter((p): p is { text: string } => "text" in p)
|
|
155
|
-
.map((p) => p.text)
|
|
156
|
-
.join("") || "";
|
|
157
|
-
|
|
158
|
-
return { text, response };
|
|
159
|
-
}
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return resp.candidates?.[0]?.content.parts
|
|
95
|
+
.filter((p): p is { text: string } => "text" in p && typeof p.text === "string")
|
|
96
|
+
.map((p) => p.text)
|
|
97
|
+
.join("") || "";
|
|
98
|
+
}
|
|
160
99
|
}
|
|
161
100
|
|
|
162
101
|
export const generationExecutor = new GenerationExecutor();
|