@umituz/react-native-ai-gemini-provider 3.0.41 → 3.0.42
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/application/builders/config-builder.ts +102 -0
- package/src/application/builders/index.ts +8 -0
- package/src/application/dtos/generation-request.dto.ts +89 -0
- package/src/application/dtos/index.ts +8 -0
- package/src/application/index.ts +16 -0
- package/src/application/providers/gemini-provider.ts +135 -0
- package/src/application/providers/index.ts +6 -0
- package/src/application/use-cases/generate-json.use-case.ts +73 -0
- package/src/application/use-cases/generate-text.use-case.ts +81 -0
- package/src/application/use-cases/index.ts +20 -0
- package/src/application/use-cases/stream-content.use-case.ts +46 -0
- package/src/domain/entities/error.types.ts +0 -5
- package/src/domain/entities/gemini.types.ts +3 -1
- package/src/domain/index.ts +16 -0
- package/src/domain/repositories/index.ts +19 -0
- package/src/domain/repositories/streaming.repository.ts +41 -0
- package/src/domain/repositories/structured-text.repository.ts +41 -0
- package/src/domain/repositories/text-generation.repository.ts +38 -0
- package/src/domain/services/validation.service.ts +157 -0
- package/src/domain/value-objects/api-key.vo.ts +55 -0
- package/src/domain/value-objects/index.ts +8 -0
- package/src/domain/value-objects/model-name.vo.ts +66 -0
- package/src/domain/value-objects/timeout.vo.ts +69 -0
- package/src/index.ts +110 -25
- package/src/infrastructure/external/gemini-client.singleton.ts +49 -0
- package/src/infrastructure/external/gemini-sdk.adapter.ts +143 -0
- package/src/infrastructure/external/index.ts +7 -0
- package/src/infrastructure/index.ts +16 -0
- package/src/infrastructure/mappers/content.mapper.ts +80 -0
- package/src/infrastructure/mappers/error.mapper.ts +152 -0
- package/src/infrastructure/mappers/index.ts +7 -0
- package/src/infrastructure/mappers/response.mapper.ts +165 -0
- package/src/infrastructure/repositories/base-gemini.repository.ts +94 -0
- package/src/infrastructure/repositories/gemini-streaming.repository.impl.ts +119 -0
- package/src/infrastructure/repositories/gemini-structured-text.repository.impl.ts +108 -0
- package/src/infrastructure/repositories/gemini-text.repository.impl.ts +76 -0
- package/src/infrastructure/repositories/index.ts +10 -0
- package/src/infrastructure/utils/index.ts +6 -0
- package/src/presentation/hooks/index.ts +8 -0
- package/src/presentation/hooks/use-gemini.hook.ts +181 -0
- package/src/presentation/hooks/use-operation-manager.hook.ts +67 -0
- package/src/presentation/index.ts +10 -0
- package/src/presentation/providers/gemini-provider.tsx +93 -0
- package/src/presentation/providers/index.ts +10 -0
- package/dist/domain/entities/error.types.d.ts +0 -96
- package/dist/domain/entities/gemini.types.d.ts +0 -128
- package/dist/domain/entities/index.d.ts +0 -6
- package/dist/domain/entities/models.d.ts +0 -23
- package/dist/index.d.ts +0 -15
- package/dist/infrastructure/services/BaseService.d.ts +0 -29
- package/dist/infrastructure/services/ChatSession.d.ts +0 -63
- package/dist/infrastructure/services/GeminiClient.d.ts +0 -16
- package/dist/infrastructure/services/GeminiProvider.d.ts +0 -10
- package/dist/infrastructure/services/Streaming.d.ts +0 -7
- package/dist/infrastructure/services/StructuredText.d.ts +0 -6
- package/dist/infrastructure/services/TextGeneration.d.ts +0 -8
- package/dist/infrastructure/services/index.d.ts +0 -6
- package/dist/infrastructure/telemetry/TelemetryHooks.d.ts +0 -41
- package/dist/infrastructure/telemetry/index.d.ts +0 -4
- package/dist/infrastructure/utils/async/execute-state.util.d.ts +0 -49
- package/dist/infrastructure/utils/async/index.d.ts +0 -4
- package/dist/infrastructure/utils/content-mapper.util.d.ts +0 -45
- package/dist/infrastructure/utils/error-mapper.util.d.ts +0 -2
- package/dist/infrastructure/utils/gemini-data-transformer.util.d.ts +0 -2
- package/dist/infrastructure/utils/json-parser.util.d.ts +0 -9
- package/dist/infrastructure/utils/stream-processor.util.d.ts +0 -14
- package/dist/presentation/hooks/index.d.ts +0 -1
- package/dist/presentation/hooks/useGemini.d.ts +0 -17
- package/dist/presentation/hooks/useOperationManager.d.ts +0 -23
- package/dist/providers/ConfigBuilder.d.ts +0 -46
- package/dist/providers/ProviderFactory.d.ts +0 -25
- package/dist/providers/index.d.ts +0 -7
- package/src/infrastructure/services/BaseService.ts +0 -53
- package/src/infrastructure/services/ChatSession.ts +0 -199
- package/src/infrastructure/services/GeminiClient.ts +0 -112
- package/src/infrastructure/services/Streaming.ts +0 -56
- package/src/infrastructure/services/StructuredText.ts +0 -57
- package/src/infrastructure/services/TextGeneration.ts +0 -57
- package/src/infrastructure/telemetry/TelemetryHooks.ts +0 -110
- package/src/infrastructure/utils/async/execute-state.util.ts +0 -93
- package/src/infrastructure/utils/content-mapper.util.ts +0 -175
- package/src/infrastructure/utils/error-mapper.util.ts +0 -145
- package/src/infrastructure/utils/gemini-data-transformer.util.ts +0 -40
- package/src/infrastructure/utils/text-calculations.util.ts +0 -51
- package/src/presentation/hooks/useGemini.ts +0 -125
- package/src/presentation/hooks/useOperationManager.ts +0 -88
- package/src/providers/ConfigBuilder.ts +0 -112
- package/src/providers/ProviderFactory.ts +0 -65
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Builder
|
|
3
|
+
* Fluent API for building Gemini configuration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { DEFAULT_MODELS } from "../../domain/entities";
|
|
7
|
+
import type { GeminiConfig } from "../../domain/entities";
|
|
8
|
+
|
|
9
|
+
export interface GeminiConfigOptions {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
strategy?: "cost" | "quality";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class GeminiConfigBuilder {
|
|
17
|
+
private apiKey?: string;
|
|
18
|
+
private model: string = DEFAULT_MODELS.TEXT;
|
|
19
|
+
private timeout = 30000;
|
|
20
|
+
private strategy?: "cost" | "quality";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Set API key (required)
|
|
24
|
+
*/
|
|
25
|
+
withApiKey(apiKey: string): this {
|
|
26
|
+
if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
|
|
27
|
+
throw new Error("API key must be a non-empty string");
|
|
28
|
+
}
|
|
29
|
+
this.apiKey = apiKey.trim();
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Set model name
|
|
35
|
+
*/
|
|
36
|
+
withModel(model: string): this {
|
|
37
|
+
if (!model || !model.startsWith("gemini-")) {
|
|
38
|
+
throw new Error("Invalid model name. Must start with 'gemini-'");
|
|
39
|
+
}
|
|
40
|
+
this.model = model;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Set request timeout (ms)
|
|
46
|
+
*/
|
|
47
|
+
withTimeout(timeout: number): this {
|
|
48
|
+
if (timeout <= 0 || timeout > 300000) {
|
|
49
|
+
throw new Error("Timeout must be between 1ms and 300000ms (5 minutes)");
|
|
50
|
+
}
|
|
51
|
+
this.timeout = timeout;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Set strategy and apply preset timeout
|
|
57
|
+
*/
|
|
58
|
+
withStrategy(strategy: "cost" | "quality"): this {
|
|
59
|
+
this.strategy = strategy;
|
|
60
|
+
|
|
61
|
+
// Apply strategy-based defaults
|
|
62
|
+
if (strategy === "quality") {
|
|
63
|
+
this.timeout = 60000; // 1 minute for quality
|
|
64
|
+
} else {
|
|
65
|
+
this.timeout = 30000; // 30 seconds for cost
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build final configuration
|
|
73
|
+
*/
|
|
74
|
+
build(): GeminiConfig {
|
|
75
|
+
if (!this.apiKey) {
|
|
76
|
+
throw new Error("API key is required. Call withApiKey() before build()");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
apiKey: this.apiKey,
|
|
81
|
+
textModel: this.model,
|
|
82
|
+
defaultTimeoutMs: this.timeout,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create a new builder instance
|
|
88
|
+
*/
|
|
89
|
+
static create(): GeminiConfigBuilder {
|
|
90
|
+
return new GeminiConfigBuilder();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create builder from existing config
|
|
95
|
+
*/
|
|
96
|
+
static from(config: GeminiConfig): GeminiConfigBuilder {
|
|
97
|
+
return new GeminiConfigBuilder()
|
|
98
|
+
.withApiKey(config.apiKey)
|
|
99
|
+
.withModel(config.textModel || DEFAULT_MODELS.TEXT)
|
|
100
|
+
.withTimeout(config.defaultTimeoutMs || 30000);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generation Request DTO
|
|
3
|
+
* Data transfer object for generation requests
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GeminiContent, GeminiGenerationConfig } from "../../domain/entities";
|
|
7
|
+
|
|
8
|
+
export class GenerationRequest {
|
|
9
|
+
constructor(
|
|
10
|
+
readonly model: string,
|
|
11
|
+
readonly contents: GeminiContent[],
|
|
12
|
+
readonly generationConfig?: GeminiGenerationConfig,
|
|
13
|
+
readonly signal?: AbortSignal
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a simple text generation request
|
|
18
|
+
*/
|
|
19
|
+
static forText(
|
|
20
|
+
model: string,
|
|
21
|
+
prompt: string,
|
|
22
|
+
config?: GeminiGenerationConfig,
|
|
23
|
+
signal?: AbortSignal
|
|
24
|
+
): GenerationRequest {
|
|
25
|
+
return new GenerationRequest(model, [], config, signal);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a streaming request
|
|
30
|
+
*/
|
|
31
|
+
static forStream(
|
|
32
|
+
model: string,
|
|
33
|
+
prompt: string,
|
|
34
|
+
onChunk: (text: string) => void,
|
|
35
|
+
config?: GeminiGenerationConfig,
|
|
36
|
+
signal?: AbortSignal
|
|
37
|
+
): GenerationRequest {
|
|
38
|
+
return new GenerationRequest(model, [], config, signal);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if request has abort signal
|
|
43
|
+
*/
|
|
44
|
+
hasSignal(): boolean {
|
|
45
|
+
return this.signal !== undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if request is aborted
|
|
50
|
+
*/
|
|
51
|
+
isAborted(): boolean {
|
|
52
|
+
return this.signal?.aborted ?? false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class StructuredGenerationRequest {
|
|
57
|
+
constructor(
|
|
58
|
+
readonly model: string,
|
|
59
|
+
readonly prompt: string,
|
|
60
|
+
readonly schema: Record<string, unknown>,
|
|
61
|
+
readonly config?: Omit<GeminiGenerationConfig, "responseMimeType" | "responseSchema">,
|
|
62
|
+
readonly signal?: AbortSignal
|
|
63
|
+
) {}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get full generation config with JSON response settings
|
|
67
|
+
*/
|
|
68
|
+
getConfig(): GeminiGenerationConfig {
|
|
69
|
+
return {
|
|
70
|
+
...this.config,
|
|
71
|
+
responseMimeType: "application/json",
|
|
72
|
+
responseSchema: this.schema as any,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check if request has abort signal
|
|
78
|
+
*/
|
|
79
|
+
hasSignal(): boolean {
|
|
80
|
+
return this.signal !== undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if request is aborted
|
|
85
|
+
*/
|
|
86
|
+
isAborted(): boolean {
|
|
87
|
+
return this.signal?.aborted ?? false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Layer
|
|
3
|
+
* Use cases and orchestration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// DTOs
|
|
7
|
+
export * from "./dtos";
|
|
8
|
+
|
|
9
|
+
// Use Cases
|
|
10
|
+
export * from "./use-cases";
|
|
11
|
+
|
|
12
|
+
// Builders
|
|
13
|
+
export * from "./builders";
|
|
14
|
+
|
|
15
|
+
// Providers
|
|
16
|
+
export * from "./providers";
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Provider
|
|
3
|
+
* Main provider for dependency injection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ValidationService } from "../../domain/services/validation.service";
|
|
7
|
+
import { ContentMapper, ResponseMapper } from "../../infrastructure/mappers";
|
|
8
|
+
import {
|
|
9
|
+
GeminiTextRepository,
|
|
10
|
+
GeminiStreamingRepository,
|
|
11
|
+
GeminiStructuredTextRepository,
|
|
12
|
+
} from "../../infrastructure/repositories";
|
|
13
|
+
import { geminiClient } from "../../infrastructure/external/gemini-client.singleton";
|
|
14
|
+
import type { GeminiConfig } from "../../domain/entities";
|
|
15
|
+
import type {
|
|
16
|
+
ITextGenerationRepository,
|
|
17
|
+
IStreamingRepository,
|
|
18
|
+
IStructuredTextRepository,
|
|
19
|
+
} from "../../domain/repositories";
|
|
20
|
+
|
|
21
|
+
export class GeminiProviderClass {
|
|
22
|
+
private static instance: GeminiProviderClass | null = null;
|
|
23
|
+
static resetCalled = false;
|
|
24
|
+
|
|
25
|
+
readonly _validator: ValidationService;
|
|
26
|
+
readonly _contentMapper: ContentMapper;
|
|
27
|
+
readonly _responseMapper: ResponseMapper;
|
|
28
|
+
|
|
29
|
+
private readonly textRepository: ITextGenerationRepository;
|
|
30
|
+
private readonly streamingRepository: IStreamingRepository;
|
|
31
|
+
private readonly structuredTextRepository: IStructuredTextRepository;
|
|
32
|
+
|
|
33
|
+
private constructor() {
|
|
34
|
+
this._validator = new ValidationService();
|
|
35
|
+
this._contentMapper = new ContentMapper();
|
|
36
|
+
this._responseMapper = new ResponseMapper();
|
|
37
|
+
|
|
38
|
+
// Initialize repositories
|
|
39
|
+
const getModel = (name: string) => geminiClient.getModel(name);
|
|
40
|
+
|
|
41
|
+
this.textRepository = new GeminiTextRepository(
|
|
42
|
+
getModel,
|
|
43
|
+
this._validator,
|
|
44
|
+
this._contentMapper,
|
|
45
|
+
this._responseMapper
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
this.streamingRepository = new GeminiStreamingRepository(
|
|
49
|
+
getModel,
|
|
50
|
+
this._validator,
|
|
51
|
+
this._contentMapper
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
this.structuredTextRepository = new GeminiStructuredTextRepository(
|
|
55
|
+
getModel,
|
|
56
|
+
this._validator,
|
|
57
|
+
this._contentMapper,
|
|
58
|
+
this._responseMapper
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get singleton instance
|
|
64
|
+
*/
|
|
65
|
+
static getInstance(): GeminiProviderClass {
|
|
66
|
+
if (!GeminiProviderClass.instance) {
|
|
67
|
+
GeminiProviderClass.instance = new GeminiProviderClass();
|
|
68
|
+
}
|
|
69
|
+
return GeminiProviderClass.instance;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Initialize with configuration
|
|
74
|
+
*/
|
|
75
|
+
initialize(config: GeminiConfig): void {
|
|
76
|
+
geminiClient.initialize(config.apiKey);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get validation service (public for use cases)
|
|
81
|
+
*/
|
|
82
|
+
getValidator(): ValidationService {
|
|
83
|
+
return this._validator;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get content mapper (public for use cases)
|
|
88
|
+
*/
|
|
89
|
+
getContentMapper(): ContentMapper {
|
|
90
|
+
return this._contentMapper;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get text generation repository
|
|
95
|
+
*/
|
|
96
|
+
getTextRepository(): ITextGenerationRepository {
|
|
97
|
+
return this.textRepository;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get streaming repository
|
|
102
|
+
*/
|
|
103
|
+
getStreamingRepository(): IStreamingRepository {
|
|
104
|
+
return this.streamingRepository;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get structured text repository
|
|
109
|
+
*/
|
|
110
|
+
getStructuredTextRepository(): IStructuredTextRepository {
|
|
111
|
+
return this.structuredTextRepository;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Reset provider (for testing)
|
|
116
|
+
*/
|
|
117
|
+
static reset(): void {
|
|
118
|
+
GeminiProviderClass.instance = null;
|
|
119
|
+
geminiClient.reset();
|
|
120
|
+
// Also expose globally for React components
|
|
121
|
+
if (typeof global !== 'undefined') {
|
|
122
|
+
(global as any).__geminiProviderReset = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Export singleton instance
|
|
129
|
+
*/
|
|
130
|
+
export const geminiProvider = GeminiProviderClass.getInstance();
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Type alias for cleaner API
|
|
134
|
+
*/
|
|
135
|
+
export type GeminiProvider = GeminiProviderClass;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate JSON Use Case
|
|
3
|
+
* Orchestrates structured JSON generation flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GeminiGenerationConfig } from "../../domain/entities";
|
|
7
|
+
import type { IStructuredTextRepository } from "../../domain/repositories/structured-text.repository";
|
|
8
|
+
import { ValidationService } from "../../domain/services/validation.service";
|
|
9
|
+
import { StructuredGenerationRequest } from "../dtos/generation-request.dto";
|
|
10
|
+
|
|
11
|
+
export interface GenerateJSONOptions<T> {
|
|
12
|
+
model: string;
|
|
13
|
+
prompt: string;
|
|
14
|
+
schema: Record<string, unknown>;
|
|
15
|
+
config?: Omit<GeminiGenerationConfig, "responseMimeType" | "responseSchema">;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface GenerateJSONResult<T> {
|
|
20
|
+
data: T;
|
|
21
|
+
text: string; // Pretty-printed JSON
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class GenerateJSONUseCase {
|
|
25
|
+
constructor(
|
|
26
|
+
private readonly repository: IStructuredTextRepository,
|
|
27
|
+
private readonly validator: ValidationService
|
|
28
|
+
) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute structured JSON generation
|
|
32
|
+
*/
|
|
33
|
+
async execute<T>(
|
|
34
|
+
options: GenerateJSONOptions<T>
|
|
35
|
+
): Promise<GenerateJSONResult<T>> {
|
|
36
|
+
// Validate inputs
|
|
37
|
+
this.validator.validatePrompt(options.prompt);
|
|
38
|
+
this.validator.validateSchema(options.schema);
|
|
39
|
+
this.validator.validateModelName(options.model);
|
|
40
|
+
this.validator.validateConfig(options.config);
|
|
41
|
+
|
|
42
|
+
// Create request
|
|
43
|
+
const request = new StructuredGenerationRequest(
|
|
44
|
+
options.model,
|
|
45
|
+
options.prompt,
|
|
46
|
+
options.schema,
|
|
47
|
+
options.config,
|
|
48
|
+
options.signal
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Execute
|
|
52
|
+
const data = await this.repository.generateStructured<T>({
|
|
53
|
+
model: request.model,
|
|
54
|
+
prompt: request.prompt,
|
|
55
|
+
schema: request.schema,
|
|
56
|
+
config: request.config,
|
|
57
|
+
signal: request.signal,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
data,
|
|
62
|
+
text: JSON.stringify(data, null, 2),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Execute simple JSON generation (returns only data)
|
|
68
|
+
*/
|
|
69
|
+
async executeSimple<T>(options: GenerateJSONOptions<T>): Promise<T> {
|
|
70
|
+
const result = await this.execute<T>(options);
|
|
71
|
+
return result.data;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Text Use Case
|
|
3
|
+
* Orchestrates text generation flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GeminiGenerationConfig, GeminiResponse } from "../../domain/entities";
|
|
7
|
+
import type { ITextGenerationRepository } from "../../domain/repositories/text-generation.repository";
|
|
8
|
+
import { ValidationService } from "../../domain/services/validation.service";
|
|
9
|
+
import { GenerationRequest } from "../dtos/generation-request.dto";
|
|
10
|
+
import { ContentMapper } from "../../infrastructure/mappers/content.mapper";
|
|
11
|
+
|
|
12
|
+
export interface GenerateTextOptions {
|
|
13
|
+
model: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
config?: GeminiGenerationConfig;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface GenerateTextResult {
|
|
20
|
+
text: string;
|
|
21
|
+
response?: GeminiResponse;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class GenerateTextUseCase {
|
|
25
|
+
constructor(
|
|
26
|
+
private readonly repository: ITextGenerationRepository,
|
|
27
|
+
private readonly validator: ValidationService,
|
|
28
|
+
private readonly contentMapper: ContentMapper
|
|
29
|
+
) {}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Execute text generation
|
|
33
|
+
*/
|
|
34
|
+
async execute(options: GenerateTextOptions): Promise<GenerateTextResult> {
|
|
35
|
+
// Validate inputs
|
|
36
|
+
this.validator.validatePrompt(options.prompt);
|
|
37
|
+
this.validator.validateModelName(options.model);
|
|
38
|
+
this.validator.validateConfig(options.config);
|
|
39
|
+
|
|
40
|
+
// Create request
|
|
41
|
+
const contents = [
|
|
42
|
+
this.contentMapper.createTextContent(options.prompt, "user"),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const request = new GenerationRequest(
|
|
46
|
+
options.model,
|
|
47
|
+
contents,
|
|
48
|
+
options.config,
|
|
49
|
+
options.signal
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Execute
|
|
53
|
+
const response = await this.repository.generate({
|
|
54
|
+
model: request.model,
|
|
55
|
+
contents: request.contents,
|
|
56
|
+
generationConfig: request.generationConfig,
|
|
57
|
+
signal: request.signal,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Extract text
|
|
61
|
+
const text = await this.repository.generateText(
|
|
62
|
+
options.model,
|
|
63
|
+
options.prompt,
|
|
64
|
+
options.config,
|
|
65
|
+
options.signal
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
text,
|
|
70
|
+
response,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execute simple text generation (returns only text)
|
|
76
|
+
*/
|
|
77
|
+
async executeSimple(options: GenerateTextOptions): Promise<string> {
|
|
78
|
+
const result = await this.execute(options);
|
|
79
|
+
return result.text;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Use Cases
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
GenerateTextUseCase,
|
|
7
|
+
type GenerateTextOptions,
|
|
8
|
+
type GenerateTextResult,
|
|
9
|
+
} from "./generate-text.use-case";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
StreamContentUseCase,
|
|
13
|
+
type StreamContentOptions,
|
|
14
|
+
} from "./stream-content.use-case";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
GenerateJSONUseCase,
|
|
18
|
+
type GenerateJSONOptions,
|
|
19
|
+
type GenerateJSONResult,
|
|
20
|
+
} from "./generate-json.use-case";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Content Use Case
|
|
3
|
+
* Orchestrates streaming flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GeminiGenerationConfig } from "../../domain/entities";
|
|
7
|
+
import type { IStreamingRepository } from "../../domain/repositories/streaming.repository";
|
|
8
|
+
import { ValidationService } from "../../domain/services/validation.service";
|
|
9
|
+
import { GenerationRequest } from "../dtos/generation-request.dto";
|
|
10
|
+
import { ContentMapper } from "../../infrastructure/mappers/content.mapper";
|
|
11
|
+
|
|
12
|
+
export interface StreamContentOptions {
|
|
13
|
+
model: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
onChunk: (text: string) => void;
|
|
16
|
+
config?: GeminiGenerationConfig;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class StreamContentUseCase {
|
|
21
|
+
constructor(
|
|
22
|
+
private readonly repository: IStreamingRepository,
|
|
23
|
+
private readonly validator: ValidationService,
|
|
24
|
+
private readonly contentMapper: ContentMapper
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Execute streaming
|
|
29
|
+
*/
|
|
30
|
+
async execute(options: StreamContentOptions): Promise<string> {
|
|
31
|
+
// Validate inputs
|
|
32
|
+
this.validator.validatePrompt(options.prompt);
|
|
33
|
+
this.validator.validateModelName(options.model);
|
|
34
|
+
this.validator.validateCallback(options.onChunk, "onChunk");
|
|
35
|
+
this.validator.validateConfig(options.config);
|
|
36
|
+
|
|
37
|
+
// Execute
|
|
38
|
+
return this.repository.streamText(
|
|
39
|
+
options.model,
|
|
40
|
+
options.prompt,
|
|
41
|
+
options.onChunk,
|
|
42
|
+
options.config,
|
|
43
|
+
options.signal
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -86,11 +86,6 @@ export class GeminiError extends Error {
|
|
|
86
86
|
this.retryable = info.retryable;
|
|
87
87
|
this.statusCode = info.statusCode;
|
|
88
88
|
this.originalError = info.originalError;
|
|
89
|
-
|
|
90
|
-
// Maintains proper stack trace (only available on V8)
|
|
91
|
-
if (Error.captureStackTrace) {
|
|
92
|
-
Error.captureStackTrace(this, GeminiError);
|
|
93
|
-
}
|
|
94
89
|
}
|
|
95
90
|
|
|
96
91
|
/**
|
|
@@ -48,7 +48,9 @@ export interface GeminiContent {
|
|
|
48
48
|
/**
|
|
49
49
|
* Individual content part
|
|
50
50
|
*/
|
|
51
|
-
export type GeminiPart =
|
|
51
|
+
export type GeminiPart =
|
|
52
|
+
| { text: string }
|
|
53
|
+
| { inlineData: { mimeType: string; data: string } };
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
56
|
* Response structure from Gemini API
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Layer
|
|
3
|
+
* Core business logic and contracts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Entities (re-export from existing)
|
|
7
|
+
export * from "./entities";
|
|
8
|
+
|
|
9
|
+
// Value Objects
|
|
10
|
+
export * from "./value-objects";
|
|
11
|
+
|
|
12
|
+
// Repository Interfaces
|
|
13
|
+
export * from "./repositories";
|
|
14
|
+
|
|
15
|
+
// Services
|
|
16
|
+
export { ValidationService, ValidationError } from "./services/validation.service";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Repository Interfaces
|
|
3
|
+
* Contracts for infrastructure implementations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
ITextGenerationRepository,
|
|
8
|
+
TextGenerationRequest,
|
|
9
|
+
} from "./text-generation.repository";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
IStreamingRepository,
|
|
13
|
+
StreamingRequest,
|
|
14
|
+
} from "./streaming.repository";
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
IStructuredTextRepository,
|
|
18
|
+
StructuredGenerationRequest,
|
|
19
|
+
} from "./structured-text.repository";
|