@umituz/react-native-ai-gemini-provider 1.4.0 → 1.6.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 +1 -1
- package/src/domain/entities/gemini.types.ts +2 -0
- package/src/domain/entities/index.ts +1 -0
- package/src/domain/entities/models.ts +47 -0
- package/src/index.ts +9 -0
- package/src/infrastructure/services/gemini-client.service.ts +61 -7
- package/src/infrastructure/services/gemini-provider.service.ts +30 -0
package/package.json
CHANGED
|
@@ -21,6 +21,8 @@ export interface GeminiGenerationConfig {
|
|
|
21
21
|
topP?: number;
|
|
22
22
|
maxOutputTokens?: number;
|
|
23
23
|
stopSequences?: string[];
|
|
24
|
+
/** Response modalities for multimodal output (TEXT, IMAGE) */
|
|
25
|
+
responseModalities?: Array<"TEXT" | "IMAGE">;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface GeminiSafetySettings {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Model Constants
|
|
3
|
+
* Centralized model configuration for all AI operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Available Gemini models
|
|
8
|
+
*/
|
|
9
|
+
export const GEMINI_MODELS = {
|
|
10
|
+
// Text generation models
|
|
11
|
+
TEXT: {
|
|
12
|
+
FLASH: "gemini-2.0-flash",
|
|
13
|
+
FLASH_LITE: "gemini-2.0-flash-lite",
|
|
14
|
+
PRO: "gemini-1.5-pro",
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Image generation models
|
|
18
|
+
IMAGE: {
|
|
19
|
+
FLASH: "gemini-2.5-flash-preview-image-generation",
|
|
20
|
+
FLASH_STABLE: "gemini-2.0-flash-preview-image-generation",
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Video understanding models
|
|
24
|
+
VIDEO: {
|
|
25
|
+
FLASH: "gemini-2.0-flash",
|
|
26
|
+
},
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Default models for each operation type
|
|
31
|
+
*/
|
|
32
|
+
export const DEFAULT_MODELS = {
|
|
33
|
+
TEXT: GEMINI_MODELS.TEXT.FLASH,
|
|
34
|
+
IMAGE: GEMINI_MODELS.IMAGE.FLASH,
|
|
35
|
+
VIDEO: GEMINI_MODELS.VIDEO.FLASH,
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Response modalities for different generation types
|
|
40
|
+
*/
|
|
41
|
+
export const RESPONSE_MODALITIES = {
|
|
42
|
+
TEXT_ONLY: ["TEXT"] as const,
|
|
43
|
+
IMAGE_ONLY: ["IMAGE"] as const,
|
|
44
|
+
TEXT_AND_IMAGE: ["TEXT", "IMAGE"] as const,
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
export type ResponseModality = "TEXT" | "IMAGE";
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,15 @@ export type {
|
|
|
42
42
|
GeminiApiError,
|
|
43
43
|
} from "./domain/entities";
|
|
44
44
|
|
|
45
|
+
// Model Constants
|
|
46
|
+
export {
|
|
47
|
+
GEMINI_MODELS,
|
|
48
|
+
DEFAULT_MODELS,
|
|
49
|
+
RESPONSE_MODALITIES,
|
|
50
|
+
} from "./domain/entities";
|
|
51
|
+
|
|
52
|
+
export type { ResponseModality } from "./domain/entities";
|
|
53
|
+
|
|
45
54
|
// =============================================================================
|
|
46
55
|
// INFRASTRUCTURE LAYER - Services
|
|
47
56
|
// =============================================================================
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { GoogleGenerativeAI, type GenerativeModel } from "@google/generative-ai";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_MODELS,
|
|
9
|
+
RESPONSE_MODALITIES,
|
|
10
|
+
} from "../../domain/entities";
|
|
7
11
|
import type {
|
|
8
12
|
GeminiConfig,
|
|
9
13
|
GeminiContent,
|
|
@@ -21,8 +25,8 @@ const DEFAULT_CONFIG: Partial<GeminiConfig> = {
|
|
|
21
25
|
baseDelay: 1000,
|
|
22
26
|
maxDelay: 10000,
|
|
23
27
|
defaultTimeoutMs: 60000,
|
|
24
|
-
defaultModel:
|
|
25
|
-
imageModel:
|
|
28
|
+
defaultModel: DEFAULT_MODELS.TEXT,
|
|
29
|
+
imageModel: DEFAULT_MODELS.IMAGE,
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
const RETRYABLE_ERROR_PATTERNS = [
|
|
@@ -62,13 +66,26 @@ class GeminiClientService {
|
|
|
62
66
|
private initialized = false;
|
|
63
67
|
|
|
64
68
|
initialize(config: GeminiConfig): void {
|
|
69
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
70
|
+
// eslint-disable-next-line no-console
|
|
71
|
+
console.log("[GeminiClient] initialize() called", {
|
|
72
|
+
hasApiKey: !!config.apiKey,
|
|
73
|
+
defaultModel: config.defaultModel,
|
|
74
|
+
imageModel: config.imageModel,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
this.client = new GoogleGenerativeAI(config.apiKey);
|
|
66
79
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
67
80
|
this.initialized = true;
|
|
68
81
|
|
|
69
82
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
70
83
|
// eslint-disable-next-line no-console
|
|
71
|
-
console.log("[
|
|
84
|
+
console.log("[GeminiClient] initialized successfully", {
|
|
85
|
+
defaultModel: this.config.defaultModel,
|
|
86
|
+
imageModel: this.config.imageModel,
|
|
87
|
+
maxRetries: this.config.maxRetries,
|
|
88
|
+
});
|
|
72
89
|
}
|
|
73
90
|
}
|
|
74
91
|
|
|
@@ -208,6 +225,16 @@ class GeminiClientService {
|
|
|
208
225
|
images: Array<{ base64: string; mimeType: string }>,
|
|
209
226
|
config?: GeminiGenerationConfig,
|
|
210
227
|
): Promise<GeminiResponse> {
|
|
228
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
229
|
+
// eslint-disable-next-line no-console
|
|
230
|
+
console.log("[GeminiClient] generateWithImages() called", {
|
|
231
|
+
model,
|
|
232
|
+
promptLength: prompt.length,
|
|
233
|
+
imagesCount: images.length,
|
|
234
|
+
imageMimeTypes: images.map(i => i.mimeType),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
211
238
|
const parts: GeminiContent["parts"] = [{ text: prompt }];
|
|
212
239
|
|
|
213
240
|
for (const image of images) {
|
|
@@ -221,23 +248,33 @@ class GeminiClientService {
|
|
|
221
248
|
|
|
222
249
|
const contents: GeminiContent[] = [{ parts, role: "user" }];
|
|
223
250
|
|
|
251
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
252
|
+
// eslint-disable-next-line no-console
|
|
253
|
+
console.log("[GeminiClient] generateWithImages() → calling generateContent()");
|
|
254
|
+
}
|
|
255
|
+
|
|
224
256
|
return this.generateContent(model, contents, config);
|
|
225
257
|
}
|
|
226
258
|
|
|
227
259
|
/**
|
|
228
260
|
* Generate image from prompt and/or input images
|
|
229
|
-
* Uses
|
|
261
|
+
* Uses centralized model config with responseModalities for image output
|
|
230
262
|
*/
|
|
231
263
|
async generateImage(
|
|
232
264
|
prompt: string,
|
|
233
265
|
images?: Array<{ base64: string; mimeType: string }>,
|
|
234
266
|
config?: GeminiGenerationConfig,
|
|
235
267
|
): Promise<GeminiImageGenerationResult> {
|
|
236
|
-
const imageModel = this.config?.imageModel ||
|
|
268
|
+
const imageModel = this.config?.imageModel || DEFAULT_MODELS.IMAGE;
|
|
237
269
|
|
|
238
270
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
239
271
|
// eslint-disable-next-line no-console
|
|
240
|
-
console.log("[
|
|
272
|
+
console.log("[GeminiClient] generateImage() called", {
|
|
273
|
+
model: imageModel,
|
|
274
|
+
promptLength: prompt.length,
|
|
275
|
+
hasInputImages: !!images?.length,
|
|
276
|
+
inputImagesCount: images?.length ?? 0,
|
|
277
|
+
});
|
|
241
278
|
}
|
|
242
279
|
|
|
243
280
|
const parts: GeminiContent["parts"] = [{ text: prompt }];
|
|
@@ -259,7 +296,14 @@ class GeminiClientService {
|
|
|
259
296
|
}
|
|
260
297
|
|
|
261
298
|
const contents: GeminiContent[] = [{ parts, role: "user" }];
|
|
262
|
-
|
|
299
|
+
|
|
300
|
+
// Image generation requires responseModalities to include IMAGE
|
|
301
|
+
const imageConfig: GeminiGenerationConfig = {
|
|
302
|
+
...config,
|
|
303
|
+
responseModalities: [...RESPONSE_MODALITIES.TEXT_AND_IMAGE],
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const response = await this.generateContent(imageModel, contents, imageConfig);
|
|
263
307
|
|
|
264
308
|
// Extract generated image from response
|
|
265
309
|
const result: GeminiImageGenerationResult = {
|
|
@@ -284,6 +328,16 @@ class GeminiClientService {
|
|
|
284
328
|
}
|
|
285
329
|
}
|
|
286
330
|
|
|
331
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
332
|
+
// eslint-disable-next-line no-console
|
|
333
|
+
console.log("[GeminiClient] generateImage() completed", {
|
|
334
|
+
hasText: !!result.text,
|
|
335
|
+
hasImage: !!result.imageBase64,
|
|
336
|
+
mimeType: result.mimeType,
|
|
337
|
+
imageDataLength: result.imageBase64?.length ?? 0,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
287
341
|
return result;
|
|
288
342
|
}
|
|
289
343
|
|
|
@@ -67,6 +67,14 @@ class GeminiProviderService {
|
|
|
67
67
|
private jobCounter = 0;
|
|
68
68
|
|
|
69
69
|
initialize(config: AIProviderConfig): void {
|
|
70
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.log("[GeminiProvider] initialize() called", {
|
|
73
|
+
hasApiKey: !!config.apiKey,
|
|
74
|
+
imageModel: config.imageModel,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
const geminiConfig: GeminiConfig = {
|
|
71
79
|
apiKey: config.apiKey,
|
|
72
80
|
maxRetries: config.maxRetries,
|
|
@@ -77,6 +85,11 @@ class GeminiProviderService {
|
|
|
77
85
|
};
|
|
78
86
|
|
|
79
87
|
geminiClientService.initialize(geminiConfig);
|
|
88
|
+
|
|
89
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
91
|
+
console.log("[GeminiProvider] initialized successfully");
|
|
92
|
+
}
|
|
80
93
|
}
|
|
81
94
|
|
|
82
95
|
isInitialized(): boolean {
|
|
@@ -206,6 +219,15 @@ class GeminiProviderService {
|
|
|
206
219
|
prompt: string,
|
|
207
220
|
images: GeminiImageInput[],
|
|
208
221
|
): Promise<{ text: string; response: unknown }> {
|
|
222
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
223
|
+
// eslint-disable-next-line no-console
|
|
224
|
+
console.log("[GeminiProvider] generateWithImages() called", {
|
|
225
|
+
model,
|
|
226
|
+
promptLength: prompt.length,
|
|
227
|
+
imagesCount: images.length,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
209
231
|
const response = await geminiClientService.generateWithImages(
|
|
210
232
|
model,
|
|
211
233
|
prompt,
|
|
@@ -217,6 +239,14 @@ class GeminiProviderService {
|
|
|
217
239
|
.map((p) => p.text)
|
|
218
240
|
.join("") || "";
|
|
219
241
|
|
|
242
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
243
|
+
// eslint-disable-next-line no-console
|
|
244
|
+
console.log("[GeminiProvider] generateWithImages() completed", {
|
|
245
|
+
hasText: !!text,
|
|
246
|
+
textLength: text.length,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
220
250
|
return { text, response };
|
|
221
251
|
}
|
|
222
252
|
|