@umituz/react-native-ai-gemini-provider 1.11.0 → 1.13.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 +4 -2
- package/src/domains/index.ts +1 -0
- package/src/domains/photo-restoration/domain/index.ts +1 -0
- package/src/domains/photo-restoration/domain/types.ts +23 -0
- package/src/domains/photo-restoration/index.ts +20 -0
- package/src/domains/photo-restoration/infrastructure/providers/gemini-photo-restore.provider.ts +111 -0
- package/src/domains/photo-restoration/infrastructure/providers/index.ts +6 -0
- package/src/domains/photo-restoration/infrastructure/services/index.ts +1 -0
- package/src/domains/photo-restoration/infrastructure/services/photo-restore.service.ts +82 -0
- package/src/domains/photo-restoration/infrastructure/utils/index.ts +4 -0
- package/src/domains/upscaling/index.ts +10 -22
- package/src/domains/upscaling/infrastructure/index.ts +1 -0
- package/src/domains/upscaling/infrastructure/providers/gemini-upscale.provider.ts +109 -0
- package/src/domains/upscaling/infrastructure/providers/index.ts +6 -0
- package/src/domains/upscaling/infrastructure/utils/index.ts +4 -1
- package/src/index.ts +8 -11
- package/src/infrastructure/job/JobManager.ts +9 -14
- package/src/infrastructure/services/gemini-provider.ts +12 -12
- package/src/infrastructure/services/index.ts +9 -4
- package/src/infrastructure/services/provider-initializer.ts +6 -10
- package/src/infrastructure/utils/image-preparer.util.ts +11 -2
- package/src/infrastructure/utils/index.ts +7 -0
- package/src/domains/upscaling/application/index.ts +0 -1
- package/src/domains/upscaling/application/use-cases/index.ts +0 -5
- package/src/domains/upscaling/application/use-cases/upscale-image.use-case.ts +0 -73
- package/src/domains/upscaling/infrastructure/utils/image-preparer.util.ts +0 -55
- package/src/domains/upscaling/presentation/hooks/index.ts +0 -1
- package/src/domains/upscaling/presentation/hooks/useUpscale.ts +0 -114
- package/src/domains/upscaling/presentation/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-gemini-provider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Google Gemini AI provider for React Native applications",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": ">=18.2.0",
|
|
34
34
|
"react-native": ">=0.74.0",
|
|
35
|
-
"@google/generative-ai": ">=0.21.0"
|
|
35
|
+
"@google/generative-ai": ">=0.21.0",
|
|
36
|
+
"@umituz/react-native-ai-generation-content": ">=1.16.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@google/generative-ai": "^0.21.0",
|
|
40
|
+
"@umituz/react-native-ai-generation-content": "latest",
|
|
39
41
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
40
42
|
"@typescript-eslint/parser": "^7.0.0",
|
|
41
43
|
"eslint": "^8.57.0",
|
package/src/domains/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restore Domain Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PhotoRestoreOptions {
|
|
6
|
+
fixScratches?: boolean;
|
|
7
|
+
enhanceFaces?: boolean;
|
|
8
|
+
colorize?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface PhotoRestoreInput {
|
|
12
|
+
base64: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
options?: PhotoRestoreOptions;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PhotoRestoreServiceResult {
|
|
18
|
+
success: boolean;
|
|
19
|
+
imageUrl?: string;
|
|
20
|
+
imageBase64?: string;
|
|
21
|
+
mimeType?: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restoration Domain - Public API
|
|
3
|
+
*
|
|
4
|
+
* Exports GeminiPhotoRestoreProvider for use with content package registry
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Provider (implements IPhotoRestoreProvider)
|
|
8
|
+
export {
|
|
9
|
+
geminiPhotoRestoreProvider,
|
|
10
|
+
type IPhotoRestoreProvider,
|
|
11
|
+
type PhotoRestoreRequest,
|
|
12
|
+
type PhotoRestoreResult,
|
|
13
|
+
} from "./infrastructure/providers";
|
|
14
|
+
|
|
15
|
+
// Internal types (for advanced usage)
|
|
16
|
+
export type {
|
|
17
|
+
PhotoRestoreOptions,
|
|
18
|
+
PhotoRestoreInput,
|
|
19
|
+
PhotoRestoreServiceResult,
|
|
20
|
+
} from "./domain/types";
|
package/src/domains/photo-restoration/infrastructure/providers/gemini-photo-restore.provider.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Photo Restore Provider
|
|
3
|
+
* Implements IPhotoRestoreProvider for content package integration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { photoRestoreService } from "../services/photo-restore.service";
|
|
7
|
+
import { prepareImage } from "../../../../infrastructure/utils/image-preparer.util";
|
|
8
|
+
|
|
9
|
+
declare const __DEV__: boolean;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Provider interface matching content package's IPhotoRestoreProvider
|
|
13
|
+
* Re-defined here to avoid cross-package dependency
|
|
14
|
+
*/
|
|
15
|
+
export interface PhotoRestoreRequest {
|
|
16
|
+
imageUri: string;
|
|
17
|
+
userId: string;
|
|
18
|
+
options?: {
|
|
19
|
+
fixScratches?: boolean;
|
|
20
|
+
enhanceFaces?: boolean;
|
|
21
|
+
colorize?: boolean;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PhotoRestoreResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
imageUrl?: string;
|
|
28
|
+
imageBase64?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
requestId?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IPhotoRestoreProvider {
|
|
34
|
+
readonly providerId: string;
|
|
35
|
+
readonly providerName: string;
|
|
36
|
+
isAvailable(): boolean;
|
|
37
|
+
restore(
|
|
38
|
+
request: PhotoRestoreRequest,
|
|
39
|
+
onProgress?: (progress: number) => void
|
|
40
|
+
): Promise<PhotoRestoreResult>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class GeminiPhotoRestoreProvider implements IPhotoRestoreProvider {
|
|
44
|
+
readonly providerId = "gemini";
|
|
45
|
+
readonly providerName = "Google Gemini";
|
|
46
|
+
|
|
47
|
+
isAvailable(): boolean {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async restore(
|
|
52
|
+
request: PhotoRestoreRequest,
|
|
53
|
+
onProgress?: (progress: number) => void
|
|
54
|
+
): Promise<PhotoRestoreResult> {
|
|
55
|
+
if (__DEV__) {
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.log("[GeminiPhotoRestoreProvider] Starting restore");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
onProgress?.(10);
|
|
62
|
+
|
|
63
|
+
const prepared = await prepareImage(request.imageUri);
|
|
64
|
+
onProgress?.(30);
|
|
65
|
+
|
|
66
|
+
const result = await photoRestoreService.restore({
|
|
67
|
+
base64: prepared.base64,
|
|
68
|
+
mimeType: prepared.mimeType,
|
|
69
|
+
options: {
|
|
70
|
+
fixScratches: request.options?.fixScratches,
|
|
71
|
+
enhanceFaces: request.options?.enhanceFaces,
|
|
72
|
+
colorize: request.options?.colorize,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
onProgress?.(90);
|
|
77
|
+
|
|
78
|
+
if (!result.success) {
|
|
79
|
+
return { success: false, error: result.error };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const imageUrl = result.imageBase64
|
|
83
|
+
? `data:${result.mimeType || "image/png"};base64,${result.imageBase64}`
|
|
84
|
+
: result.imageUrl;
|
|
85
|
+
|
|
86
|
+
onProgress?.(100);
|
|
87
|
+
|
|
88
|
+
if (__DEV__) {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.log("[GeminiPhotoRestoreProvider] Completed");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
imageUrl,
|
|
96
|
+
imageBase64: result.imageBase64,
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
|
|
101
|
+
if (__DEV__) {
|
|
102
|
+
// eslint-disable-next-line no-console
|
|
103
|
+
console.error("[GeminiPhotoRestoreProvider] Error:", message);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { success: false, error: message };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const geminiPhotoRestoreProvider = new GeminiPhotoRestoreProvider();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { photoRestoreService } from "./photo-restore.service";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restore Service
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { geminiImageEditService } from "../../../../infrastructure/services/gemini-image-edit.service";
|
|
6
|
+
import type {
|
|
7
|
+
PhotoRestoreInput,
|
|
8
|
+
PhotoRestoreServiceResult,
|
|
9
|
+
PhotoRestoreOptions,
|
|
10
|
+
} from "../../domain/types";
|
|
11
|
+
|
|
12
|
+
declare const __DEV__: boolean;
|
|
13
|
+
|
|
14
|
+
function buildPrompt(options?: PhotoRestoreOptions): string {
|
|
15
|
+
const parts = [
|
|
16
|
+
"Restore this old or damaged photo to its original quality.",
|
|
17
|
+
"Remove scratches, creases, tears, and any damage marks.",
|
|
18
|
+
"Fix faded or discolored areas.",
|
|
19
|
+
"Restore missing or damaged parts of the image.",
|
|
20
|
+
"Maintain the original style and era of the photograph.",
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
if (options?.fixScratches !== false) {
|
|
24
|
+
parts.push("Pay special attention to removing scratches and fold lines.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (options?.enhanceFaces !== false) {
|
|
28
|
+
parts.push("Carefully restore and enhance facial features while keeping them natural.");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (options?.colorize) {
|
|
32
|
+
parts.push("If the image is black and white, colorize it naturally.");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
parts.push("Preserve the authentic vintage feel while improving clarity and quality.");
|
|
36
|
+
|
|
37
|
+
return parts.join(" ");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class PhotoRestoreService {
|
|
41
|
+
async restore(input: PhotoRestoreInput): Promise<PhotoRestoreServiceResult> {
|
|
42
|
+
if (__DEV__) {
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.log("[PhotoRestoreService] Starting");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const prompt = buildPrompt(input.options);
|
|
49
|
+
|
|
50
|
+
const result = await geminiImageEditService.editImage(prompt, [
|
|
51
|
+
{ base64: input.base64, mimeType: input.mimeType },
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
if (!result.imageBase64 && !result.imageUrl) {
|
|
55
|
+
return { success: false, error: "No image returned" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (__DEV__) {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.log("[PhotoRestoreService] Completed successfully");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
success: true,
|
|
65
|
+
imageUrl: result.imageUrl,
|
|
66
|
+
imageBase64: result.imageBase64,
|
|
67
|
+
mimeType: result.mimeType,
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71
|
+
|
|
72
|
+
if (__DEV__) {
|
|
73
|
+
// eslint-disable-next-line no-console
|
|
74
|
+
console.error("[PhotoRestoreService] Error:", message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { success: false, error: message };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const photoRestoreService = new PhotoRestoreService();
|
|
@@ -1,33 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Upscaling Domain - Public API
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* - domain: Core types (no dependencies)
|
|
6
|
-
* - application: Use cases (orchestration)
|
|
7
|
-
* - infrastructure: External services
|
|
8
|
-
* - presentation: React hooks
|
|
4
|
+
* Exports GeminiUpscaleProvider for use with content package registry
|
|
9
5
|
*/
|
|
10
6
|
|
|
11
|
-
//
|
|
7
|
+
// Provider (implements IUpscaleProvider)
|
|
8
|
+
export {
|
|
9
|
+
geminiUpscaleProvider,
|
|
10
|
+
type IUpscaleProvider,
|
|
11
|
+
type UpscaleRequest,
|
|
12
|
+
type UpscaleResult,
|
|
13
|
+
} from "./infrastructure/providers";
|
|
14
|
+
|
|
15
|
+
// Internal types (for advanced usage)
|
|
12
16
|
export type {
|
|
13
17
|
UpscaleScaleFactor,
|
|
14
18
|
UpscaleOptions,
|
|
15
19
|
UpscaleInput,
|
|
16
|
-
UpscaleResult,
|
|
17
20
|
PreparedImage,
|
|
18
|
-
UseUpscaleConfig,
|
|
19
|
-
UseUpscaleReturn,
|
|
20
21
|
} from "./domain/types";
|
|
21
|
-
|
|
22
|
-
// Use Cases (Application Layer)
|
|
23
|
-
export {
|
|
24
|
-
upscaleImageUseCase,
|
|
25
|
-
type UpscaleImageRequest,
|
|
26
|
-
type UpscaleImageResponse,
|
|
27
|
-
} from "./application";
|
|
28
|
-
|
|
29
|
-
// Services (Infrastructure Layer)
|
|
30
|
-
export { upscaleService, prepareImage } from "./infrastructure";
|
|
31
|
-
|
|
32
|
-
// Hooks (Presentation Layer)
|
|
33
|
-
export { useUpscale } from "./presentation";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Upscale Provider
|
|
3
|
+
* Implements IUpscaleProvider for content package integration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { upscaleService } from "../services/upscale.service";
|
|
7
|
+
import { prepareImage } from "../../../../infrastructure/utils/image-preparer.util";
|
|
8
|
+
|
|
9
|
+
declare const __DEV__: boolean;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Provider interface matching content package's IUpscaleProvider
|
|
13
|
+
* Re-defined here to avoid cross-package dependency
|
|
14
|
+
*/
|
|
15
|
+
export interface UpscaleRequest {
|
|
16
|
+
imageUri: string;
|
|
17
|
+
userId: string;
|
|
18
|
+
options?: {
|
|
19
|
+
scaleFactor?: 2 | 4 | 8;
|
|
20
|
+
enhanceFaces?: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UpscaleResult {
|
|
25
|
+
success: boolean;
|
|
26
|
+
imageUrl?: string;
|
|
27
|
+
imageBase64?: string;
|
|
28
|
+
error?: string;
|
|
29
|
+
requestId?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface IUpscaleProvider {
|
|
33
|
+
readonly providerId: string;
|
|
34
|
+
readonly providerName: string;
|
|
35
|
+
isAvailable(): boolean;
|
|
36
|
+
upscale(
|
|
37
|
+
request: UpscaleRequest,
|
|
38
|
+
onProgress?: (progress: number) => void
|
|
39
|
+
): Promise<UpscaleResult>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class GeminiUpscaleProvider implements IUpscaleProvider {
|
|
43
|
+
readonly providerId = "gemini";
|
|
44
|
+
readonly providerName = "Google Gemini";
|
|
45
|
+
|
|
46
|
+
isAvailable(): boolean {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async upscale(
|
|
51
|
+
request: UpscaleRequest,
|
|
52
|
+
onProgress?: (progress: number) => void
|
|
53
|
+
): Promise<UpscaleResult> {
|
|
54
|
+
if (__DEV__) {
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
console.log("[GeminiUpscaleProvider] Starting upscale");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
onProgress?.(10);
|
|
61
|
+
|
|
62
|
+
const prepared = await prepareImage(request.imageUri);
|
|
63
|
+
onProgress?.(30);
|
|
64
|
+
|
|
65
|
+
const result = await upscaleService.upscale({
|
|
66
|
+
base64: prepared.base64,
|
|
67
|
+
mimeType: prepared.mimeType,
|
|
68
|
+
options: {
|
|
69
|
+
scaleFactor: request.options?.scaleFactor || 2,
|
|
70
|
+
enhanceFaces: request.options?.enhanceFaces,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
onProgress?.(90);
|
|
75
|
+
|
|
76
|
+
if (!result.success) {
|
|
77
|
+
return { success: false, error: result.error };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const imageUrl = result.imageBase64
|
|
81
|
+
? `data:${result.mimeType || "image/png"};base64,${result.imageBase64}`
|
|
82
|
+
: result.imageUrl;
|
|
83
|
+
|
|
84
|
+
onProgress?.(100);
|
|
85
|
+
|
|
86
|
+
if (__DEV__) {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.log("[GeminiUpscaleProvider] Completed");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
imageUrl,
|
|
94
|
+
imageBase64: result.imageBase64,
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
98
|
+
|
|
99
|
+
if (__DEV__) {
|
|
100
|
+
// eslint-disable-next-line no-console
|
|
101
|
+
console.error("[GeminiUpscaleProvider] Error:", message);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { success: false, error: message };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const geminiUpscaleProvider = new GeminiUpscaleProvider();
|
package/src/index.ts
CHANGED
|
@@ -79,9 +79,12 @@ export {
|
|
|
79
79
|
|
|
80
80
|
export type {
|
|
81
81
|
AIProviderConfig,
|
|
82
|
+
GeminiProviderConfig,
|
|
83
|
+
IAIProvider,
|
|
82
84
|
JobSubmission,
|
|
83
85
|
JobStatus,
|
|
84
86
|
SubscribeOptions,
|
|
87
|
+
AIJobStatusType,
|
|
85
88
|
UpscaleScaleFactor,
|
|
86
89
|
UpscaleOptions,
|
|
87
90
|
UpscaleInput,
|
|
@@ -113,19 +116,13 @@ export type {
|
|
|
113
116
|
// DOMAINS - DDD-organized features
|
|
114
117
|
// =============================================================================
|
|
115
118
|
|
|
116
|
-
// Upscaling Domain
|
|
117
|
-
export {
|
|
118
|
-
useUpscale,
|
|
119
|
-
upscaleImageUseCase,
|
|
120
|
-
upscaleService,
|
|
121
|
-
prepareImage,
|
|
122
|
-
} from "./domains/upscaling";
|
|
119
|
+
// Upscaling Domain - Provider for content package registry
|
|
120
|
+
export { geminiUpscaleProvider } from "./domains/upscaling";
|
|
123
121
|
|
|
124
122
|
export type {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
UpscaleImageResponse,
|
|
123
|
+
IUpscaleProvider,
|
|
124
|
+
UpscaleRequest as GeminiUpscaleRequest,
|
|
125
|
+
UpscaleResult as GeminiUpscaleResult,
|
|
129
126
|
PreparedImage,
|
|
130
127
|
} from "./domains/upscaling";
|
|
131
128
|
|
|
@@ -3,25 +3,20 @@
|
|
|
3
3
|
* Handles async job submission, tracking, and status management
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import type {
|
|
7
|
+
JobSubmission,
|
|
8
|
+
JobStatus,
|
|
9
|
+
AIJobStatusType,
|
|
10
|
+
} from "@umituz/react-native-ai-generation-content";
|
|
7
11
|
|
|
8
|
-
export
|
|
9
|
-
requestId: string;
|
|
10
|
-
statusUrl?: string;
|
|
11
|
-
responseUrl?: string;
|
|
12
|
-
}
|
|
12
|
+
export type { JobSubmission, JobStatus };
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
status: "IN_QUEUE" | "IN_PROGRESS" | "COMPLETED" | "FAILED";
|
|
16
|
-
logs?: Array<{ message: string; level: string; timestamp?: string }>;
|
|
17
|
-
queuePosition?: number;
|
|
18
|
-
eta?: number;
|
|
19
|
-
}
|
|
14
|
+
declare const __DEV__: boolean;
|
|
20
15
|
|
|
21
16
|
interface PendingJob {
|
|
22
17
|
model: string;
|
|
23
18
|
input: Record<string, unknown>;
|
|
24
|
-
status:
|
|
19
|
+
status: AIJobStatusType;
|
|
25
20
|
result?: unknown;
|
|
26
21
|
error?: string;
|
|
27
22
|
}
|
|
@@ -81,7 +76,7 @@ export class JobManager {
|
|
|
81
76
|
return job.result as T;
|
|
82
77
|
}
|
|
83
78
|
|
|
84
|
-
updateJobStatus(requestId: string, status:
|
|
79
|
+
updateJobStatus(requestId: string, status: AIJobStatusType): void {
|
|
85
80
|
const job = this.pendingJobs.get(requestId);
|
|
86
81
|
if (job) {
|
|
87
82
|
job.status = status;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini Provider
|
|
3
3
|
* Main AI provider implementation for Google Gemini
|
|
4
|
+
* Implements IAIProvider for unified orchestration
|
|
4
5
|
*/
|
|
5
6
|
|
|
7
|
+
import type {
|
|
8
|
+
IAIProvider,
|
|
9
|
+
AIProviderConfig,
|
|
10
|
+
JobSubmission,
|
|
11
|
+
JobStatus,
|
|
12
|
+
SubscribeOptions,
|
|
13
|
+
} from "@umituz/react-native-ai-generation-content";
|
|
6
14
|
import type {
|
|
7
15
|
GeminiImageInput,
|
|
8
16
|
GeminiImageGenerationResult,
|
|
9
17
|
} from "../../domain/entities";
|
|
10
18
|
import { geminiImageGenerationService } from "./gemini-image-generation.service";
|
|
11
19
|
import { geminiImageEditService } from "./gemini-image-edit.service";
|
|
12
|
-
import { providerInitializer, type
|
|
20
|
+
import { providerInitializer, type GeminiProviderConfig } from "./provider-initializer";
|
|
13
21
|
import { jobProcessor } from "./job-processor";
|
|
14
22
|
import { generationExecutor } from "./generation-executor";
|
|
15
|
-
import type { JobSubmission, JobStatus } from "../job/JobManager";
|
|
16
|
-
|
|
17
|
-
export type { AIProviderConfig, JobSubmission, JobStatus };
|
|
18
23
|
|
|
19
|
-
export
|
|
20
|
-
timeoutMs?: number;
|
|
21
|
-
onQueueUpdate?: (status: JobStatus) => void;
|
|
22
|
-
onProgress?: (progress: number) => void;
|
|
23
|
-
onResult?: (result: T) => void;
|
|
24
|
-
}
|
|
24
|
+
export type { GeminiProviderConfig };
|
|
25
25
|
|
|
26
|
-
export class GeminiProvider {
|
|
26
|
+
export class GeminiProvider implements IAIProvider {
|
|
27
27
|
readonly providerId = "gemini";
|
|
28
28
|
readonly providerName = "Google Gemini";
|
|
29
29
|
|
|
30
30
|
initialize(config: AIProviderConfig): void {
|
|
31
|
-
providerInitializer.initialize(config);
|
|
31
|
+
providerInitializer.initialize(config as GeminiProviderConfig);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
isInitialized(): boolean {
|
|
@@ -31,9 +31,14 @@ export {
|
|
|
31
31
|
GeminiProvider,
|
|
32
32
|
} from "./gemini-provider";
|
|
33
33
|
|
|
34
|
+
export type { GeminiProviderConfig } from "./gemini-provider";
|
|
35
|
+
export type { GeminiProviderConfig as AIProviderConfig } from "./provider-initializer";
|
|
36
|
+
|
|
37
|
+
// Re-export types from generation-content for convenience
|
|
34
38
|
export type {
|
|
35
|
-
|
|
39
|
+
IAIProvider,
|
|
40
|
+
JobSubmission,
|
|
41
|
+
JobStatus,
|
|
36
42
|
SubscribeOptions,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export type { JobSubmission, JobStatus } from "../job/JobManager";
|
|
43
|
+
AIJobStatusType,
|
|
44
|
+
} from "@umituz/react-native-ai-generation-content";
|
|
@@ -3,24 +3,20 @@
|
|
|
3
3
|
* Handles initialization logic for Gemini Provider
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { AIProviderConfig } from "@umituz/react-native-ai-generation-content";
|
|
6
7
|
import type { GeminiConfig } from "../../domain/entities";
|
|
7
8
|
import { geminiClientCoreService } from "./gemini-client-core.service";
|
|
8
9
|
|
|
9
10
|
declare const __DEV__: boolean;
|
|
10
11
|
|
|
11
|
-
export interface AIProviderConfig {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
maxDelay?: number;
|
|
16
|
-
defaultTimeoutMs?: number;
|
|
17
|
-
textModel?: string;
|
|
18
|
-
textToImageModel?: string;
|
|
19
|
-
imageEditModel?: string;
|
|
12
|
+
export interface GeminiProviderConfig extends AIProviderConfig {
|
|
13
|
+
textModel?: string;
|
|
14
|
+
textToImageModel?: string;
|
|
15
|
+
imageEditModel?: string;
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
export class ProviderInitializer {
|
|
23
|
-
initialize(config:
|
|
19
|
+
initialize(config: GeminiProviderConfig): void {
|
|
24
20
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
25
21
|
// eslint-disable-next-line no-console
|
|
26
22
|
console.log("[GeminiProvider] Initializing...");
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Image Preparer Utility
|
|
3
3
|
* Prepares images for Gemini API
|
|
4
|
+
* Shared utility - used by all image processing features
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import type { PreparedImage } from "../../domains/upscaling/domain/types";
|
|
7
|
-
|
|
8
7
|
declare const __DEV__: boolean;
|
|
9
8
|
|
|
9
|
+
export interface PreparedImage {
|
|
10
|
+
base64: string;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
function getMimeTypeFromUri(uri: string): string {
|
|
11
15
|
const extension = uri.split(".").pop()?.toLowerCase();
|
|
12
16
|
const mimeTypes: Record<string, string> = {
|
|
@@ -63,3 +67,8 @@ export function isValidBase64(str: string): boolean {
|
|
|
63
67
|
return false;
|
|
64
68
|
}
|
|
65
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Alias for prepareImageFromUri for backwards compatibility
|
|
73
|
+
*/
|
|
74
|
+
export const prepareImage = prepareImageFromUri;
|
|
@@ -12,3 +12,10 @@ export {
|
|
|
12
12
|
extractBase64Data,
|
|
13
13
|
extractTextFromResponse,
|
|
14
14
|
} from "./gemini-data-transformer.util";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
prepareImageFromUri,
|
|
18
|
+
prepareImage,
|
|
19
|
+
isValidBase64,
|
|
20
|
+
} from "./image-preparer.util";
|
|
21
|
+
export type { PreparedImage } from "./image-preparer.util";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./use-cases";
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Upscale Image Use Case
|
|
3
|
-
*
|
|
4
|
-
* Application layer: Orchestrates the upscaling flow
|
|
5
|
-
* Follows Clean Architecture - use case contains application-specific business rules
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { upscaleService, prepareImage } from "../../infrastructure";
|
|
9
|
-
import type {
|
|
10
|
-
UpscaleInput,
|
|
11
|
-
UpscaleResult,
|
|
12
|
-
UpscaleOptions,
|
|
13
|
-
} from "../../domain/types";
|
|
14
|
-
|
|
15
|
-
declare const __DEV__: boolean;
|
|
16
|
-
|
|
17
|
-
export interface UpscaleImageRequest {
|
|
18
|
-
imageUri: string;
|
|
19
|
-
options?: UpscaleOptions;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface UpscaleImageResponse {
|
|
23
|
-
success: boolean;
|
|
24
|
-
imageUrl?: string;
|
|
25
|
-
imageBase64?: string;
|
|
26
|
-
mimeType?: string;
|
|
27
|
-
error?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function upscaleImageUseCase(
|
|
31
|
-
request: UpscaleImageRequest
|
|
32
|
-
): Promise<UpscaleImageResponse> {
|
|
33
|
-
if (__DEV__) {
|
|
34
|
-
// eslint-disable-next-line no-console
|
|
35
|
-
console.log("[UpscaleImageUseCase] Starting", {
|
|
36
|
-
scaleFactor: request.options?.scaleFactor || 2,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
// Step 1: Prepare image (convert URI to base64)
|
|
42
|
-
const prepared = await prepareImage(request.imageUri);
|
|
43
|
-
|
|
44
|
-
// Step 2: Create input for service
|
|
45
|
-
const input: UpscaleInput = {
|
|
46
|
-
base64: prepared.base64,
|
|
47
|
-
mimeType: prepared.mimeType,
|
|
48
|
-
options: request.options,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Step 3: Execute upscaling
|
|
52
|
-
const result: UpscaleResult = await upscaleService.upscale(input);
|
|
53
|
-
|
|
54
|
-
if (__DEV__) {
|
|
55
|
-
// eslint-disable-next-line no-console
|
|
56
|
-
console.log("[UpscaleImageUseCase] Result:", {
|
|
57
|
-
success: result.success,
|
|
58
|
-
hasImage: !!result.imageBase64 || !!result.imageUrl,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return result;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
-
|
|
66
|
-
if (__DEV__) {
|
|
67
|
-
// eslint-disable-next-line no-console
|
|
68
|
-
console.error("[UpscaleImageUseCase] Error:", message);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return { success: false, error: message };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Image Preparer Utility
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { PreparedImage } from "../../domain/types";
|
|
6
|
-
|
|
7
|
-
declare const __DEV__: boolean;
|
|
8
|
-
|
|
9
|
-
function getMimeType(uri: string): string {
|
|
10
|
-
const ext = uri.split(".").pop()?.toLowerCase();
|
|
11
|
-
const types: Record<string, string> = {
|
|
12
|
-
jpg: "image/jpeg",
|
|
13
|
-
jpeg: "image/jpeg",
|
|
14
|
-
png: "image/png",
|
|
15
|
-
gif: "image/gif",
|
|
16
|
-
webp: "image/webp",
|
|
17
|
-
};
|
|
18
|
-
return types[ext || ""] || "image/jpeg";
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function extractBase64(dataUrl: string): string {
|
|
22
|
-
const match = dataUrl.match(/^data:[^;]+;base64,(.+)$/);
|
|
23
|
-
return match ? match[1] : dataUrl;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function prepareImage(uri: string): Promise<PreparedImage> {
|
|
27
|
-
if (__DEV__) {
|
|
28
|
-
// eslint-disable-next-line no-console
|
|
29
|
-
console.log("[ImagePreparer] Preparing image");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (uri.startsWith("data:")) {
|
|
33
|
-
const mimeMatch = uri.match(/^data:([^;]+);base64,/);
|
|
34
|
-
return {
|
|
35
|
-
base64: extractBase64(uri),
|
|
36
|
-
mimeType: mimeMatch ? mimeMatch[1] : "image/jpeg",
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const response = await fetch(uri);
|
|
41
|
-
const blob = await response.blob();
|
|
42
|
-
|
|
43
|
-
return new Promise((resolve, reject) => {
|
|
44
|
-
const reader = new FileReader();
|
|
45
|
-
reader.onloadend = () => {
|
|
46
|
-
const dataUrl = reader.result as string;
|
|
47
|
-
resolve({
|
|
48
|
-
base64: extractBase64(dataUrl),
|
|
49
|
-
mimeType: blob.type || getMimeType(uri),
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
reader.onerror = () => reject(new Error("Failed to read image"));
|
|
53
|
-
reader.readAsDataURL(blob);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useUpscale } from "./useUpscale";
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useUpscale Hook
|
|
3
|
-
*
|
|
4
|
-
* Presentation layer: React-specific abstraction for upscaling
|
|
5
|
-
* Provides a clean API hiding complexity (Deep Module pattern)
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useState, useCallback } from "react";
|
|
9
|
-
import { upscaleImageUseCase } from "../../application";
|
|
10
|
-
import type {
|
|
11
|
-
UpscaleOptions,
|
|
12
|
-
UpscaleScaleFactor,
|
|
13
|
-
UseUpscaleConfig,
|
|
14
|
-
UseUpscaleReturn,
|
|
15
|
-
} from "../../domain/types";
|
|
16
|
-
|
|
17
|
-
declare const __DEV__: boolean;
|
|
18
|
-
|
|
19
|
-
const DEFAULT_SCALE_FACTOR: UpscaleScaleFactor = 2;
|
|
20
|
-
|
|
21
|
-
export function useUpscale(config?: UseUpscaleConfig): UseUpscaleReturn {
|
|
22
|
-
const [imageUri, setImageUri] = useState<string | null>(null);
|
|
23
|
-
const [processedUrl, setProcessedUrl] = useState<string | null>(null);
|
|
24
|
-
const [isProcessing, setIsProcessing] = useState(false);
|
|
25
|
-
const [progress, setProgress] = useState(0);
|
|
26
|
-
const [error, setError] = useState<string | null>(null);
|
|
27
|
-
|
|
28
|
-
const reset = useCallback(() => {
|
|
29
|
-
setImageUri(null);
|
|
30
|
-
setProcessedUrl(null);
|
|
31
|
-
setIsProcessing(false);
|
|
32
|
-
setProgress(0);
|
|
33
|
-
setError(null);
|
|
34
|
-
}, []);
|
|
35
|
-
|
|
36
|
-
const process = useCallback(async () => {
|
|
37
|
-
if (!imageUri) {
|
|
38
|
-
setError("No image selected");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
setIsProcessing(true);
|
|
43
|
-
setProgress(10);
|
|
44
|
-
setError(null);
|
|
45
|
-
setProcessedUrl(null);
|
|
46
|
-
|
|
47
|
-
if (__DEV__) {
|
|
48
|
-
// eslint-disable-next-line no-console
|
|
49
|
-
console.log("[useUpscale] Processing started");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
setProgress(30);
|
|
54
|
-
|
|
55
|
-
const options: UpscaleOptions = {
|
|
56
|
-
scaleFactor: config?.defaultScaleFactor || DEFAULT_SCALE_FACTOR,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
setProgress(50);
|
|
60
|
-
|
|
61
|
-
const result = await upscaleImageUseCase({
|
|
62
|
-
imageUri,
|
|
63
|
-
options,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
setProgress(90);
|
|
67
|
-
|
|
68
|
-
if (!result.success) {
|
|
69
|
-
throw new Error(result.error || "Upscale failed");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const resultUrl = result.imageBase64
|
|
73
|
-
? `data:${result.mimeType || "image/png"};base64,${result.imageBase64}`
|
|
74
|
-
: result.imageUrl || null;
|
|
75
|
-
|
|
76
|
-
setProcessedUrl(resultUrl);
|
|
77
|
-
setProgress(100);
|
|
78
|
-
|
|
79
|
-
if (__DEV__) {
|
|
80
|
-
// eslint-disable-next-line no-console
|
|
81
|
-
console.log("[useUpscale] Processing completed");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (config?.onSuccess && result.success) {
|
|
85
|
-
config.onSuccess(result);
|
|
86
|
-
}
|
|
87
|
-
} catch (err) {
|
|
88
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
89
|
-
setError(message);
|
|
90
|
-
|
|
91
|
-
if (__DEV__) {
|
|
92
|
-
// eslint-disable-next-line no-console
|
|
93
|
-
console.error("[useUpscale] Error:", message);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (config?.onError) {
|
|
97
|
-
config.onError(message);
|
|
98
|
-
}
|
|
99
|
-
} finally {
|
|
100
|
-
setIsProcessing(false);
|
|
101
|
-
}
|
|
102
|
-
}, [imageUri, config]);
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
imageUri,
|
|
106
|
-
processedUrl,
|
|
107
|
-
isProcessing,
|
|
108
|
-
progress,
|
|
109
|
-
error,
|
|
110
|
-
setImageUri,
|
|
111
|
-
process,
|
|
112
|
-
reset,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./hooks";
|