@umituz/react-native-ai-gemini-provider 1.14.23 → 1.14.25
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/error.types.ts +45 -0
- package/src/index.ts +7 -0
- package/src/infrastructure/services/feature-model-selector.ts +48 -2
- package/src/infrastructure/services/generation-executor.ts +32 -16
- package/src/infrastructure/services/index.ts +8 -0
- package/src/infrastructure/utils/error-mapper.util.ts +9 -0
- package/src/infrastructure/utils/index.ts +1 -0
package/package.json
CHANGED
|
@@ -37,3 +37,48 @@ export interface GeminiApiError {
|
|
|
37
37
|
}>;
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Custom error class for Gemini API errors
|
|
43
|
+
*/
|
|
44
|
+
export class GeminiError extends Error {
|
|
45
|
+
readonly type: GeminiErrorType;
|
|
46
|
+
readonly retryable: boolean;
|
|
47
|
+
readonly statusCode?: number;
|
|
48
|
+
readonly originalError?: unknown;
|
|
49
|
+
|
|
50
|
+
constructor(info: GeminiErrorInfo) {
|
|
51
|
+
super(info.messageKey);
|
|
52
|
+
this.name = "GeminiError";
|
|
53
|
+
this.type = info.type;
|
|
54
|
+
this.retryable = info.retryable;
|
|
55
|
+
this.statusCode = info.statusCode;
|
|
56
|
+
this.originalError = info.originalError;
|
|
57
|
+
|
|
58
|
+
// Maintains proper stack trace (only available on V8)
|
|
59
|
+
if (Error.captureStackTrace) {
|
|
60
|
+
Error.captureStackTrace(this, GeminiError);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if error is retryable
|
|
66
|
+
*/
|
|
67
|
+
isRetryable(): boolean {
|
|
68
|
+
return this.retryable;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get error type
|
|
73
|
+
*/
|
|
74
|
+
getErrorType(): GeminiErrorType {
|
|
75
|
+
return this.type;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create GeminiError from unknown error
|
|
80
|
+
*/
|
|
81
|
+
static fromError(_error: unknown, info: GeminiErrorInfo): GeminiError {
|
|
82
|
+
return new GeminiError(info);
|
|
83
|
+
}
|
|
84
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -51,6 +51,8 @@ export type {
|
|
|
51
51
|
GeminiApiError,
|
|
52
52
|
} from "./domain/entities";
|
|
53
53
|
|
|
54
|
+
export { GeminiError } from "./domain/entities";
|
|
55
|
+
|
|
54
56
|
// Model Constants
|
|
55
57
|
export {
|
|
56
58
|
GEMINI_MODELS,
|
|
@@ -90,6 +92,7 @@ export {
|
|
|
90
92
|
geminiVideoGenerationService,
|
|
91
93
|
geminiProviderService,
|
|
92
94
|
createGeminiProvider,
|
|
95
|
+
featureModelSelector,
|
|
93
96
|
} from "./infrastructure/services";
|
|
94
97
|
|
|
95
98
|
export type {
|
|
@@ -100,6 +103,9 @@ export type {
|
|
|
100
103
|
JobStatus,
|
|
101
104
|
SubscribeOptions,
|
|
102
105
|
AIJobStatusType,
|
|
106
|
+
GenerationInput,
|
|
107
|
+
GenerationResult,
|
|
108
|
+
ExecutionOptions,
|
|
103
109
|
} from "./infrastructure/services";
|
|
104
110
|
|
|
105
111
|
// =============================================================================
|
|
@@ -110,6 +116,7 @@ export {
|
|
|
110
116
|
mapGeminiError,
|
|
111
117
|
isGeminiErrorRetryable,
|
|
112
118
|
categorizeGeminiError,
|
|
119
|
+
createGeminiError,
|
|
113
120
|
// Input builders
|
|
114
121
|
buildSingleImageInput,
|
|
115
122
|
buildDualImageInput,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Feature Model Selector
|
|
3
3
|
* Returns the appropriate model ID for a given feature
|
|
4
|
+
* Supports runtime model overrides for flexibility
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import type {
|
|
@@ -12,19 +13,64 @@ import {
|
|
|
12
13
|
GEMINI_VIDEO_FEATURE_MODELS,
|
|
13
14
|
} from "../../domain/constants/feature-models.constants";
|
|
14
15
|
|
|
16
|
+
declare const __DEV__: boolean;
|
|
17
|
+
|
|
18
|
+
type ModelOverrideMap = Partial<Record<ImageFeatureType | VideoFeatureType, string>>;
|
|
19
|
+
|
|
15
20
|
class FeatureModelSelector {
|
|
21
|
+
private overrides: ModelOverrideMap = {};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set model override for a specific feature
|
|
25
|
+
* This allows runtime configuration without modifying constants
|
|
26
|
+
*/
|
|
27
|
+
setModelOverride(feature: ImageFeatureType | VideoFeatureType, model: string): void {
|
|
28
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
29
|
+
// eslint-disable-next-line no-console
|
|
30
|
+
console.log("[FeatureModelSelector] Model override set:", { feature, model });
|
|
31
|
+
}
|
|
32
|
+
this.overrides[feature] = model;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Clear all model overrides
|
|
37
|
+
*/
|
|
38
|
+
clearOverrides(): void {
|
|
39
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.log("[FeatureModelSelector] All model overrides cleared");
|
|
42
|
+
}
|
|
43
|
+
this.overrides = {};
|
|
44
|
+
}
|
|
45
|
+
|
|
16
46
|
/**
|
|
17
47
|
* Get model ID for an IMAGE feature
|
|
48
|
+
* Returns override if set, otherwise returns default model
|
|
18
49
|
*/
|
|
19
50
|
getImageFeatureModel(feature: ImageFeatureType): string {
|
|
20
|
-
return GEMINI_IMAGE_FEATURE_MODELS[feature];
|
|
51
|
+
return this.overrides[feature] ?? GEMINI_IMAGE_FEATURE_MODELS[feature];
|
|
21
52
|
}
|
|
22
53
|
|
|
23
54
|
/**
|
|
24
55
|
* Get model ID for a VIDEO feature
|
|
56
|
+
* Returns override if set, otherwise returns default model
|
|
25
57
|
*/
|
|
26
58
|
getVideoFeatureModel(feature: VideoFeatureType): string {
|
|
27
|
-
return GEMINI_VIDEO_FEATURE_MODELS[feature];
|
|
59
|
+
return this.overrides[feature] ?? GEMINI_VIDEO_FEATURE_MODELS[feature];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if a feature has a custom override
|
|
64
|
+
*/
|
|
65
|
+
hasOverride(feature: ImageFeatureType | VideoFeatureType): boolean {
|
|
66
|
+
return feature in this.overrides;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get all current overrides
|
|
71
|
+
*/
|
|
72
|
+
getOverrides(): ModelOverrideMap {
|
|
73
|
+
return { ...this.overrides };
|
|
28
74
|
}
|
|
29
75
|
}
|
|
30
76
|
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
GeminiImageInput,
|
|
8
|
+
GeminiImageGenerationResult,
|
|
8
9
|
VideoGenerationInput,
|
|
10
|
+
VideoGenerationResult,
|
|
9
11
|
VideoGenerationProgress,
|
|
10
12
|
} from "../../domain/entities";
|
|
11
13
|
import { geminiTextGenerationService } from "./gemini-text-generation.service";
|
|
@@ -20,13 +22,29 @@ export interface ExecutionOptions {
|
|
|
20
22
|
onProgress?: (progress: number) => void;
|
|
21
23
|
}
|
|
22
24
|
|
|
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;
|
|
40
|
+
|
|
23
41
|
export class GenerationExecutor {
|
|
24
42
|
private contentBuilder = new ContentBuilder();
|
|
25
43
|
private responseFormatter = new ResponseFormatter();
|
|
26
44
|
|
|
27
|
-
async executeGeneration<T>(
|
|
45
|
+
async executeGeneration<T = GenerationResult>(
|
|
28
46
|
model: string,
|
|
29
|
-
input:
|
|
47
|
+
input: GenerationInput,
|
|
30
48
|
options?: ExecutionOptions,
|
|
31
49
|
): Promise<T> {
|
|
32
50
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
@@ -43,14 +61,13 @@ export class GenerationExecutor {
|
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
if (isVideoGeneration) {
|
|
46
|
-
return this.executeVideoGeneration
|
|
64
|
+
return this.executeVideoGeneration(input, options) as T;
|
|
47
65
|
}
|
|
48
66
|
|
|
49
67
|
if (isImageGeneration) {
|
|
50
|
-
const prompt = String(input.prompt
|
|
51
|
-
const images = input.images
|
|
52
|
-
|
|
53
|
-
return result as T;
|
|
68
|
+
const prompt = String(input.prompt ?? "");
|
|
69
|
+
const images = input.images;
|
|
70
|
+
return geminiImageGenerationService.generateImage(prompt, images) as T;
|
|
54
71
|
}
|
|
55
72
|
|
|
56
73
|
const contents = this.contentBuilder.buildContents(input);
|
|
@@ -73,21 +90,21 @@ export class GenerationExecutor {
|
|
|
73
90
|
/**
|
|
74
91
|
* Execute video generation using Veo API
|
|
75
92
|
*/
|
|
76
|
-
private async executeVideoGeneration
|
|
77
|
-
input:
|
|
93
|
+
private async executeVideoGeneration(
|
|
94
|
+
input: GenerationInput,
|
|
78
95
|
options?: ExecutionOptions,
|
|
79
|
-
): Promise<
|
|
96
|
+
): Promise<VideoGenerationResult> {
|
|
80
97
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
81
98
|
// eslint-disable-next-line no-console
|
|
82
99
|
console.log("[GenerationExecutor] executeVideoGeneration() called");
|
|
83
100
|
}
|
|
84
101
|
|
|
85
102
|
const videoInput: VideoGenerationInput = {
|
|
86
|
-
prompt: String(input.prompt
|
|
87
|
-
image: input.image
|
|
88
|
-
negativePrompt: input.negativePrompt
|
|
103
|
+
prompt: String(input.prompt ?? ""),
|
|
104
|
+
image: input.image,
|
|
105
|
+
negativePrompt: input.negativePrompt,
|
|
89
106
|
options: {
|
|
90
|
-
aspectRatio: this.normalizeAspectRatio(input.aspect_ratio
|
|
107
|
+
aspectRatio: this.normalizeAspectRatio(input.aspect_ratio),
|
|
91
108
|
},
|
|
92
109
|
};
|
|
93
110
|
|
|
@@ -109,10 +126,9 @@ export class GenerationExecutor {
|
|
|
109
126
|
}
|
|
110
127
|
|
|
111
128
|
return {
|
|
112
|
-
video: { url: result.videoUrl },
|
|
113
129
|
videoUrl: result.videoUrl,
|
|
114
130
|
metadata: result.metadata,
|
|
115
|
-
}
|
|
131
|
+
};
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
/**
|
|
@@ -15,6 +15,7 @@ export { geminiVideoGenerationService } from "./gemini-video-generation.service"
|
|
|
15
15
|
export { providerInitializer } from "./provider-initializer";
|
|
16
16
|
export { jobProcessor } from "./job-processor";
|
|
17
17
|
export { generationExecutor } from "./generation-executor";
|
|
18
|
+
export { featureModelSelector } from "./feature-model-selector";
|
|
18
19
|
|
|
19
20
|
// Public provider API
|
|
20
21
|
export {
|
|
@@ -26,6 +27,13 @@ export {
|
|
|
26
27
|
export type { GeminiProviderConfig } from "./gemini-provider";
|
|
27
28
|
export type { GeminiProviderConfig as AIProviderConfig } from "./provider-initializer";
|
|
28
29
|
|
|
30
|
+
// Generation executor types
|
|
31
|
+
export type {
|
|
32
|
+
GenerationInput,
|
|
33
|
+
GenerationResult,
|
|
34
|
+
ExecutionOptions,
|
|
35
|
+
} from "./generation-executor";
|
|
36
|
+
|
|
29
37
|
// Re-export types from generation-content for convenience
|
|
30
38
|
export type {
|
|
31
39
|
IAIProvider,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
GeminiErrorType,
|
|
8
8
|
type GeminiErrorInfo,
|
|
9
9
|
type GeminiApiError,
|
|
10
|
+
GeminiError,
|
|
10
11
|
} from "../../domain/entities";
|
|
11
12
|
|
|
12
13
|
const ERROR_PATTERNS: Array<{
|
|
@@ -112,3 +113,11 @@ export function isGeminiErrorRetryable(error: unknown): boolean {
|
|
|
112
113
|
export function categorizeGeminiError(error: unknown): GeminiErrorType {
|
|
113
114
|
return mapGeminiError(error).type;
|
|
114
115
|
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create a GeminiError instance from an unknown error
|
|
119
|
+
*/
|
|
120
|
+
export function createGeminiError(error: unknown): GeminiError {
|
|
121
|
+
const errorInfo = mapGeminiError(error);
|
|
122
|
+
return GeminiError.fromError(error, errorInfo);
|
|
123
|
+
}
|