@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-gemini-provider",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Google Gemini AI provider for React Native applications",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -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 {
@@ -4,3 +4,4 @@
4
4
 
5
5
  export * from "./gemini.types";
6
6
  export * from "./error.types";
7
+ export * from "./models";
@@ -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: "gemini-2.0-flash",
25
- imageModel: "gemini-2.0-flash-preview-image-generation",
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("[Gemini] Client initialized with official SDK");
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 Gemini 2.0 Flash with image generation capability
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 || "gemini-2.0-flash-preview-image-generation";
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("[Gemini] Generate image:", { model: imageModel, hasInputImages: !!images?.length });
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
- const response = await this.generateContent(imageModel, contents, config);
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