@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.
Files changed (29) hide show
  1. package/package.json +4 -2
  2. package/src/domains/index.ts +1 -0
  3. package/src/domains/photo-restoration/domain/index.ts +1 -0
  4. package/src/domains/photo-restoration/domain/types.ts +23 -0
  5. package/src/domains/photo-restoration/index.ts +20 -0
  6. package/src/domains/photo-restoration/infrastructure/providers/gemini-photo-restore.provider.ts +111 -0
  7. package/src/domains/photo-restoration/infrastructure/providers/index.ts +6 -0
  8. package/src/domains/photo-restoration/infrastructure/services/index.ts +1 -0
  9. package/src/domains/photo-restoration/infrastructure/services/photo-restore.service.ts +82 -0
  10. package/src/domains/photo-restoration/infrastructure/utils/index.ts +4 -0
  11. package/src/domains/upscaling/index.ts +10 -22
  12. package/src/domains/upscaling/infrastructure/index.ts +1 -0
  13. package/src/domains/upscaling/infrastructure/providers/gemini-upscale.provider.ts +109 -0
  14. package/src/domains/upscaling/infrastructure/providers/index.ts +6 -0
  15. package/src/domains/upscaling/infrastructure/utils/index.ts +4 -1
  16. package/src/index.ts +8 -11
  17. package/src/infrastructure/job/JobManager.ts +9 -14
  18. package/src/infrastructure/services/gemini-provider.ts +12 -12
  19. package/src/infrastructure/services/index.ts +9 -4
  20. package/src/infrastructure/services/provider-initializer.ts +6 -10
  21. package/src/infrastructure/utils/image-preparer.util.ts +11 -2
  22. package/src/infrastructure/utils/index.ts +7 -0
  23. package/src/domains/upscaling/application/index.ts +0 -1
  24. package/src/domains/upscaling/application/use-cases/index.ts +0 -5
  25. package/src/domains/upscaling/application/use-cases/upscale-image.use-case.ts +0 -73
  26. package/src/domains/upscaling/infrastructure/utils/image-preparer.util.ts +0 -55
  27. package/src/domains/upscaling/presentation/hooks/index.ts +0 -1
  28. package/src/domains/upscaling/presentation/hooks/useUpscale.ts +0 -114
  29. 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.11.0",
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",
@@ -3,3 +3,4 @@
3
3
  */
4
4
 
5
5
  export * from "./upscaling";
6
+ export * from "./photo-restoration";
@@ -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";
@@ -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,6 @@
1
+ export {
2
+ geminiPhotoRestoreProvider,
3
+ type IPhotoRestoreProvider,
4
+ type PhotoRestoreRequest,
5
+ type PhotoRestoreResult,
6
+ } from "./gemini-photo-restore.provider";
@@ -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();
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Re-export from shared utils for backwards compatibility
3
+ */
4
+ export { prepareImage, type PreparedImage } from "../../../../infrastructure/utils/image-preparer.util";
@@ -1,33 +1,21 @@
1
1
  /**
2
2
  * Upscaling Domain - Public API
3
3
  *
4
- * Clean Architecture:
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
- // Types (Domain Layer)
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";
@@ -1,2 +1,3 @@
1
1
  export * from "./services";
2
2
  export * from "./utils";
3
+ export * from "./providers";
@@ -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();
@@ -0,0 +1,6 @@
1
+ export {
2
+ geminiUpscaleProvider,
3
+ type IUpscaleProvider,
4
+ type UpscaleRequest,
5
+ type UpscaleResult,
6
+ } from "./gemini-upscale.provider";
@@ -1 +1,4 @@
1
- export { prepareImage } from "./image-preparer.util";
1
+ /**
2
+ * Re-export from shared utils for backwards compatibility
3
+ */
4
+ export { prepareImage, type PreparedImage } from "../../../../infrastructure/utils/image-preparer.util";
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
- UseUpscaleConfig,
126
- UseUpscaleReturn,
127
- UpscaleImageRequest,
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
- declare const __DEV__: boolean;
6
+ import type {
7
+ JobSubmission,
8
+ JobStatus,
9
+ AIJobStatusType,
10
+ } from "@umituz/react-native-ai-generation-content";
7
11
 
8
- export interface JobSubmission {
9
- requestId: string;
10
- statusUrl?: string;
11
- responseUrl?: string;
12
- }
12
+ export type { JobSubmission, JobStatus };
13
13
 
14
- export interface JobStatus {
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: JobStatus["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: JobStatus["status"]): void {
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 AIProviderConfig } from "./provider-initializer";
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 interface SubscribeOptions<T = unknown> {
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
- AIProviderConfig,
39
+ IAIProvider,
40
+ JobSubmission,
41
+ JobStatus,
36
42
  SubscribeOptions,
37
- } from "./gemini-provider";
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
- apiKey: string;
13
- maxRetries?: number;
14
- baseDelay?: number;
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: AIProviderConfig): void {
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,5 +0,0 @@
1
- export {
2
- upscaleImageUseCase,
3
- type UpscaleImageRequest,
4
- type UpscaleImageResponse,
5
- } from "./upscale-image.use-case";
@@ -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";