@umituz/react-native-ai-gemini-provider 1.10.2 → 1.10.4
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/infrastructure/services/gemini-provider.ts +14 -112
- package/src/infrastructure/services/generation-executor.ts +61 -0
- package/src/infrastructure/services/index.ts +5 -0
- package/src/infrastructure/services/job-processor.ts +62 -0
- package/src/infrastructure/services/provider-initializer.ts +52 -0
package/package.json
CHANGED
|
@@ -4,31 +4,17 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
|
-
GeminiConfig,
|
|
8
7
|
GeminiImageInput,
|
|
9
8
|
GeminiImageGenerationResult,
|
|
10
9
|
} from "../../domain/entities";
|
|
11
|
-
import { geminiClientCoreService } from "./gemini-client-core.service";
|
|
12
|
-
import { geminiTextGenerationService } from "./gemini-text-generation.service";
|
|
13
10
|
import { geminiImageGenerationService } from "./gemini-image-generation.service";
|
|
14
11
|
import { geminiImageEditService } from "./gemini-image-edit.service";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
12
|
+
import { providerInitializer, type AIProviderConfig } from "./provider-initializer";
|
|
13
|
+
import { jobProcessor } from "./job-processor";
|
|
14
|
+
import { generationExecutor } from "./generation-executor";
|
|
18
15
|
import type { JobSubmission, JobStatus } from "../job/JobManager";
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export interface AIProviderConfig {
|
|
23
|
-
apiKey: string;
|
|
24
|
-
maxRetries?: number;
|
|
25
|
-
baseDelay?: number;
|
|
26
|
-
maxDelay?: number;
|
|
27
|
-
defaultTimeoutMs?: number;
|
|
28
|
-
textModel?: string;
|
|
29
|
-
textToImageModel?: string;
|
|
30
|
-
imageEditModel?: string;
|
|
31
|
-
}
|
|
17
|
+
export type { AIProviderConfig, JobSubmission, JobStatus };
|
|
32
18
|
|
|
33
19
|
export interface SubscribeOptions<T = unknown> {
|
|
34
20
|
timeoutMs?: number;
|
|
@@ -41,59 +27,24 @@ export class GeminiProvider {
|
|
|
41
27
|
readonly providerId = "gemini";
|
|
42
28
|
readonly providerName = "Google Gemini";
|
|
43
29
|
|
|
44
|
-
private jobManager = new JobManager();
|
|
45
|
-
private contentBuilder = new ContentBuilder();
|
|
46
|
-
private responseFormatter = new ResponseFormatter();
|
|
47
|
-
|
|
48
30
|
initialize(config: AIProviderConfig): void {
|
|
49
|
-
|
|
50
|
-
// eslint-disable-next-line no-console
|
|
51
|
-
console.log("[GeminiProvider] Initializing...");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const geminiConfig: GeminiConfig = {
|
|
55
|
-
apiKey: config.apiKey,
|
|
56
|
-
maxRetries: config.maxRetries,
|
|
57
|
-
baseDelay: config.baseDelay,
|
|
58
|
-
maxDelay: config.maxDelay,
|
|
59
|
-
defaultTimeoutMs: config.defaultTimeoutMs,
|
|
60
|
-
textModel: config.textModel,
|
|
61
|
-
textToImageModel: config.textToImageModel,
|
|
62
|
-
imageEditModel: config.imageEditModel,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
geminiClientCoreService.initialize(geminiConfig);
|
|
31
|
+
providerInitializer.initialize(config);
|
|
66
32
|
}
|
|
67
33
|
|
|
68
34
|
isInitialized(): boolean {
|
|
69
|
-
return
|
|
35
|
+
return providerInitializer.isInitialized();
|
|
70
36
|
}
|
|
71
37
|
|
|
72
38
|
submitJob(model: string, input: Record<string, unknown>): Promise<JobSubmission> {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.processJobAsync(submission.requestId).catch((error) => {
|
|
76
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
77
|
-
// eslint-disable-next-line no-console
|
|
78
|
-
console.error("[GeminiProvider] Job failed:", error);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return Promise.resolve(submission);
|
|
39
|
+
return jobProcessor.submitJob(model, input);
|
|
83
40
|
}
|
|
84
41
|
|
|
85
42
|
getJobStatus(_model: string, requestId: string): Promise<JobStatus> {
|
|
86
|
-
|
|
87
|
-
return Promise.resolve(status);
|
|
43
|
+
return jobProcessor.getJobStatus(_model, requestId);
|
|
88
44
|
}
|
|
89
45
|
|
|
90
46
|
getJobResult<T = unknown>(_model: string, requestId: string): Promise<T> {
|
|
91
|
-
|
|
92
|
-
const result = this.jobManager.getJobResult<T>(requestId);
|
|
93
|
-
return Promise.resolve(result);
|
|
94
|
-
} catch (error) {
|
|
95
|
-
return Promise.reject(error);
|
|
96
|
-
}
|
|
47
|
+
return jobProcessor.getJobResult<T>(_model, requestId);
|
|
97
48
|
}
|
|
98
49
|
|
|
99
50
|
async subscribe<T = unknown>(
|
|
@@ -104,7 +55,7 @@ export class GeminiProvider {
|
|
|
104
55
|
options?.onQueueUpdate?.({ status: "IN_QUEUE" });
|
|
105
56
|
options?.onProgress?.(10);
|
|
106
57
|
|
|
107
|
-
const result = await
|
|
58
|
+
const result = await generationExecutor.executeGeneration<T>(model, input);
|
|
108
59
|
|
|
109
60
|
options?.onProgress?.(100);
|
|
110
61
|
options?.onQueueUpdate?.({ status: "COMPLETED" });
|
|
@@ -117,7 +68,7 @@ export class GeminiProvider {
|
|
|
117
68
|
model: string,
|
|
118
69
|
input: Record<string, unknown>,
|
|
119
70
|
): Promise<T> {
|
|
120
|
-
return
|
|
71
|
+
return generationExecutor.executeGeneration<T>(model, input);
|
|
121
72
|
}
|
|
122
73
|
|
|
123
74
|
async generateImage(prompt: string): Promise<GeminiImageGenerationResult> {
|
|
@@ -136,61 +87,12 @@ export class GeminiProvider {
|
|
|
136
87
|
prompt: string,
|
|
137
88
|
images: GeminiImageInput[],
|
|
138
89
|
): Promise<{ text: string; response: unknown }> {
|
|
139
|
-
|
|
140
|
-
model,
|
|
141
|
-
prompt,
|
|
142
|
-
images,
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
const text = response.candidates?.[0]?.content.parts
|
|
146
|
-
.filter((p): p is { text: string } => "text" in p)
|
|
147
|
-
.map((p) => p.text)
|
|
148
|
-
.join("") || "";
|
|
149
|
-
|
|
150
|
-
return { text, response };
|
|
90
|
+
return generationExecutor.generateWithImages(model, prompt, images);
|
|
151
91
|
}
|
|
152
92
|
|
|
153
93
|
reset(): void {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private async processJobAsync(requestId: string): Promise<void> {
|
|
159
|
-
const job = this.jobManager.getJob(requestId);
|
|
160
|
-
if (!job) return;
|
|
161
|
-
|
|
162
|
-
this.jobManager.updateJobStatus(requestId, "IN_PROGRESS");
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const result = await this.executeGeneration(job.model, job.input);
|
|
166
|
-
this.jobManager.setJobResult(requestId, result);
|
|
167
|
-
} catch (error) {
|
|
168
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
169
|
-
this.jobManager.setJobError(requestId, errorMessage);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private async executeGeneration<T>(
|
|
174
|
-
model: string,
|
|
175
|
-
input: Record<string, unknown>,
|
|
176
|
-
): Promise<T> {
|
|
177
|
-
const isImageGeneration = input.generateImage === true || input.type === "image";
|
|
178
|
-
|
|
179
|
-
if (isImageGeneration) {
|
|
180
|
-
const prompt = String(input.prompt || "");
|
|
181
|
-
const images = input.images as GeminiImageInput[] | undefined;
|
|
182
|
-
const result = await geminiImageGenerationService.generateImage(prompt, images);
|
|
183
|
-
return result as T;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const contents = this.contentBuilder.buildContents(input);
|
|
187
|
-
const response = await geminiTextGenerationService.generateContent(
|
|
188
|
-
model,
|
|
189
|
-
contents,
|
|
190
|
-
input.generationConfig as undefined,
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
return this.responseFormatter.formatResponse<T>(response, input);
|
|
94
|
+
providerInitializer.reset();
|
|
95
|
+
jobProcessor.clear();
|
|
194
96
|
}
|
|
195
97
|
}
|
|
196
98
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generation Executor
|
|
3
|
+
* Handles execution of different generation types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
GeminiImageInput,
|
|
8
|
+
} from "../../domain/entities";
|
|
9
|
+
import { geminiTextGenerationService } from "./gemini-text-generation.service";
|
|
10
|
+
import { geminiImageGenerationService } from "./gemini-image-generation.service";
|
|
11
|
+
import { ContentBuilder } from "../content/ContentBuilder";
|
|
12
|
+
import { ResponseFormatter } from "../response/ResponseFormatter";
|
|
13
|
+
|
|
14
|
+
export class GenerationExecutor {
|
|
15
|
+
private contentBuilder = new ContentBuilder();
|
|
16
|
+
private responseFormatter = new ResponseFormatter();
|
|
17
|
+
|
|
18
|
+
async executeGeneration<T>(
|
|
19
|
+
model: string,
|
|
20
|
+
input: Record<string, unknown>,
|
|
21
|
+
): Promise<T> {
|
|
22
|
+
const isImageGeneration = input.generateImage === true || input.type === "image";
|
|
23
|
+
|
|
24
|
+
if (isImageGeneration) {
|
|
25
|
+
const prompt = String(input.prompt || "");
|
|
26
|
+
const images = input.images as GeminiImageInput[] | undefined;
|
|
27
|
+
const result = await geminiImageGenerationService.generateImage(prompt, images);
|
|
28
|
+
return result as T;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const contents = this.contentBuilder.buildContents(input);
|
|
32
|
+
const response = await geminiTextGenerationService.generateContent(
|
|
33
|
+
model,
|
|
34
|
+
contents,
|
|
35
|
+
input.generationConfig as undefined,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return this.responseFormatter.formatResponse<T>(response, input);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async generateWithImages(
|
|
42
|
+
model: string,
|
|
43
|
+
prompt: string,
|
|
44
|
+
images: GeminiImageInput[],
|
|
45
|
+
): Promise<{ text: string; response: unknown }> {
|
|
46
|
+
const response = await geminiTextGenerationService.generateWithImages(
|
|
47
|
+
model,
|
|
48
|
+
prompt,
|
|
49
|
+
images,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const text = response.candidates?.[0]?.content.parts
|
|
53
|
+
.filter((p): p is { text: string } => "text" in p)
|
|
54
|
+
.map((p) => p.text)
|
|
55
|
+
.join("") || "";
|
|
56
|
+
|
|
57
|
+
return { text, response };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const generationExecutor = new GenerationExecutor();
|
|
@@ -10,6 +10,11 @@ export { geminiImageGenerationService } from "./gemini-image-generation.service"
|
|
|
10
10
|
export { geminiImageEditService } from "./gemini-image-edit.service";
|
|
11
11
|
export { geminiStreamingService } from "./gemini-streaming.service";
|
|
12
12
|
|
|
13
|
+
// Modular services
|
|
14
|
+
export { providerInitializer } from "./provider-initializer";
|
|
15
|
+
export { jobProcessor } from "./job-processor";
|
|
16
|
+
export { generationExecutor } from "./generation-executor";
|
|
17
|
+
|
|
13
18
|
// Public provider API
|
|
14
19
|
export {
|
|
15
20
|
geminiProviderService,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Processor
|
|
3
|
+
* Handles async job processing
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { JobManager } from "../job/JobManager";
|
|
7
|
+
import type { JobSubmission, JobStatus } from "../job/JobManager";
|
|
8
|
+
import { generationExecutor } from "./generation-executor";
|
|
9
|
+
|
|
10
|
+
declare const __DEV__: boolean;
|
|
11
|
+
|
|
12
|
+
export class JobProcessor {
|
|
13
|
+
private jobManager = new JobManager();
|
|
14
|
+
|
|
15
|
+
submitJob(model: string, input: Record<string, unknown>): Promise<JobSubmission> {
|
|
16
|
+
const submission = this.jobManager.submitJob(model, input);
|
|
17
|
+
|
|
18
|
+
this.processJobAsync(submission.requestId).catch((error) => {
|
|
19
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.error("[GeminiProvider] Job failed:", error);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return Promise.resolve(submission);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getJobStatus(_model: string, requestId: string): Promise<JobStatus> {
|
|
29
|
+
const status = this.jobManager.getJobStatus(requestId);
|
|
30
|
+
return Promise.resolve(status);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getJobResult<T = unknown>(_model: string, requestId: string): Promise<T> {
|
|
34
|
+
try {
|
|
35
|
+
const result = this.jobManager.getJobResult<T>(requestId);
|
|
36
|
+
return Promise.resolve(result);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return Promise.reject(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clear(): void {
|
|
43
|
+
this.jobManager.clear();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async processJobAsync(requestId: string): Promise<void> {
|
|
47
|
+
const job = this.jobManager.getJob(requestId);
|
|
48
|
+
if (!job) return;
|
|
49
|
+
|
|
50
|
+
this.jobManager.updateJobStatus(requestId, "IN_PROGRESS");
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const result = await generationExecutor.executeGeneration(job.model, job.input);
|
|
54
|
+
this.jobManager.setJobResult(requestId, result);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
57
|
+
this.jobManager.setJobError(requestId, errorMessage);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const jobProcessor = new JobProcessor();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Initializer
|
|
3
|
+
* Handles initialization logic for Gemini Provider
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GeminiConfig } from "../../domain/entities";
|
|
7
|
+
import { geminiClientCoreService } from "./gemini-client-core.service";
|
|
8
|
+
|
|
9
|
+
declare const __DEV__: boolean;
|
|
10
|
+
|
|
11
|
+
export interface AIProviderConfig {
|
|
12
|
+
apiKey: string;
|
|
13
|
+
maxRetries?: number;
|
|
14
|
+
baseDelay?: number;
|
|
15
|
+
maxDelay?: number;
|
|
16
|
+
defaultTimeoutMs?: number;
|
|
17
|
+
textModel?: string;
|
|
18
|
+
textToImageModel?: string;
|
|
19
|
+
imageEditModel?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ProviderInitializer {
|
|
23
|
+
initialize(config: AIProviderConfig): void {
|
|
24
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
25
|
+
// eslint-disable-next-line no-console
|
|
26
|
+
console.log("[GeminiProvider] Initializing...");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const geminiConfig: GeminiConfig = {
|
|
30
|
+
apiKey: config.apiKey,
|
|
31
|
+
maxRetries: config.maxRetries,
|
|
32
|
+
baseDelay: config.baseDelay,
|
|
33
|
+
maxDelay: config.maxDelay,
|
|
34
|
+
defaultTimeoutMs: config.defaultTimeoutMs,
|
|
35
|
+
textModel: config.textModel,
|
|
36
|
+
textToImageModel: config.textToImageModel,
|
|
37
|
+
imageEditModel: config.imageEditModel,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
geminiClientCoreService.initialize(geminiConfig);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
isInitialized(): boolean {
|
|
44
|
+
return geminiClientCoreService.isInitialized();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
reset(): void {
|
|
48
|
+
geminiClientCoreService.reset();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const providerInitializer = new ProviderInitializer();
|