@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.
Files changed (30) hide show
  1. package/package.json +4 -9
  2. package/src/domain/constants/index.ts +1 -11
  3. package/src/domain/entities/index.ts +0 -1
  4. package/src/index.ts +2 -54
  5. package/src/infrastructure/job/JobManager.ts +11 -8
  6. package/src/infrastructure/services/gemini-provider.ts +31 -152
  7. package/src/infrastructure/services/generation-executor.ts +80 -141
  8. package/src/infrastructure/services/index.ts +1 -14
  9. package/src/infrastructure/services/job-processor.ts +42 -42
  10. package/src/infrastructure/services/provider-initializer.ts +19 -33
  11. package/src/infrastructure/utils/index.ts +1 -37
  12. package/src/infrastructure/utils/model-validation.util.ts +3 -29
  13. package/src/domain/constants/feature-models.constants.ts +0 -70
  14. package/src/domain/entities/video.types.ts +0 -149
  15. package/src/infrastructure/services/feature-input-builder.ts +0 -89
  16. package/src/infrastructure/services/feature-model-selector.ts +0 -77
  17. package/src/infrastructure/services/gemini-image-edit.service.ts +0 -134
  18. package/src/infrastructure/services/gemini-image-generation.service.ts +0 -137
  19. package/src/infrastructure/services/gemini-video-downloader.ts +0 -77
  20. package/src/infrastructure/services/gemini-video-error.ts +0 -21
  21. package/src/infrastructure/services/gemini-video-generation.service.ts +0 -103
  22. package/src/infrastructure/services/gemini-video-url-extractor.ts +0 -45
  23. package/src/infrastructure/services/veo-http-client.service.ts +0 -70
  24. package/src/infrastructure/services/veo-polling.service.ts +0 -119
  25. package/src/infrastructure/utils/base-input-builders.util.ts +0 -49
  26. package/src/infrastructure/utils/image-feature-builders.util.ts +0 -123
  27. package/src/infrastructure/utils/image-preparer.util.ts +0 -74
  28. package/src/infrastructure/utils/input-builder.types.ts +0 -44
  29. package/src/infrastructure/utils/input-builders.util.ts +0 -38
  30. 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": "1.16.0",
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
- 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";
5
+ // No feature models needed for text-only provider
@@ -5,4 +5,3 @@
5
5
  export * from "./gemini.types";
6
6
  export * from "./error.types";
7
7
  export * from "./models";
8
- export * from "./video.types";
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
- featureModelSelector,
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
- import type {
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 { JobSubmission, JobStatus };
8
+ export type AIJobStatusType = "IN_QUEUE" | "IN_PROGRESS" | "COMPLETED" | "FAILED";
13
9
 
14
- declare const __DEV__: boolean;
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
- * Main AI provider implementation for Google Gemini
4
- * Implements IAIProvider for unified orchestration
3
+ * Text-only AI provider for Google Gemini
5
4
  */
6
5
 
7
- import type {
8
- IAIProvider,
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 { GeminiProviderConfig };
10
+ export type GeminiProviderConfig = GeminiConfig;
36
11
 
37
12
  /**
38
- * Gemini provider capabilities
13
+ * Gemini Provider - Text Generation Only
14
+ * For image/video generation, use FAL Provider instead
39
15
  */
40
- const GEMINI_CAPABILITIES: ProviderCapabilities = {
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: AIProviderConfig): void {
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
- * Build input for an IMAGE feature
33
+ * Generate text from prompt
163
34
  */
164
- buildImageFeatureInput(
165
- feature: ImageFeatureType,
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
- * Get model ID for a VIDEO feature
40
+ * Generate text with images (multimodal)
41
+ * Useful for "describe this image" scenarios
173
42
  */
174
- getVideoFeatureModel(feature: VideoFeatureType): string {
175
- return featureModelSelector.getVideoFeatureModel(feature);
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
- * Build input for a VIDEO feature
57
+ * Generate structured JSON response
180
58
  */
181
- buildVideoFeatureInput(
182
- feature: VideoFeatureType,
183
- data: VideoFeatureInputData,
184
- ): Record<string, unknown> {
185
- return featureInputBuilder.buildVideoFeatureInput(feature, data);
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 different generation types
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 { geminiImageGenerationService } from "./gemini-image-generation.service";
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
- onProgress?: (progress: number) => void;
13
+ onProgress?: (progress: number) => void;
23
14
  }
24
15
 
25
- export type GenerationInput = {
26
- type?: "text" | "image" | "video";
27
- generateImage?: boolean;
28
- prompt?: string;
29
- images?: GeminiImageInput[];
30
- generationConfig?: unknown;
31
- image?: string;
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
- private contentBuilder = new ContentBuilder();
43
- private responseFormatter = new ResponseFormatter();
44
-
45
- async executeGeneration<T = GenerationResult>(
46
- model: string,
47
- input: GenerationInput,
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
- * Check if model is a video generation model (Veo)
85
- */
86
- private isVideoModel(model: string): boolean {
87
- return model.toLowerCase().includes("veo");
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
- * Execute video generation using Veo API
92
- */
93
- private async executeVideoGeneration(
94
- input: GenerationInput,
95
- options?: ExecutionOptions,
96
- ): Promise<VideoGenerationResult> {
97
- if (typeof __DEV__ !== "undefined" && __DEV__) {
98
- // eslint-disable-next-line no-console
99
- console.log("[GenerationExecutor] executeVideoGeneration() called");
100
- }
101
-
102
- const videoInput: VideoGenerationInput = {
103
- prompt: String(input.prompt ?? ""),
104
- image: input.image,
105
- negativePrompt: input.negativePrompt,
106
- options: {
107
- aspectRatio: this.normalizeAspectRatio(input.aspect_ratio),
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
- const onProgress = options?.onProgress
112
- ? (p: VideoGenerationProgress) => {
113
- if (typeof __DEV__ !== "undefined" && __DEV__) {
114
- // eslint-disable-next-line no-console
115
- console.log("[GenerationExecutor] Progress update:", p.progress);
116
- }
117
- options.onProgress?.(p.progress);
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();