@umituz/react-native-ai-gemini-provider 1.10.7 → 1.12.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-gemini-provider",
3
- "version": "1.10.7",
3
+ "version": "1.12.0",
4
4
  "description": "Google Gemini AI provider for React Native applications",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Domains - DDD-organized features
3
+ */
4
+
5
+ export * from "./upscaling";
@@ -0,0 +1 @@
1
+ export * from "./types";
@@ -0,0 +1,9 @@
1
+ export type {
2
+ UpscaleScaleFactor,
3
+ UpscaleOptions,
4
+ UpscaleInput,
5
+ UpscaleResult,
6
+ PreparedImage,
7
+ UseUpscaleConfig,
8
+ UseUpscaleReturn,
9
+ } from "./upscale.types";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Upscale Types
3
+ */
4
+
5
+ export type UpscaleScaleFactor = 2 | 4 | 8;
6
+
7
+ export interface UpscaleOptions {
8
+ scaleFactor?: UpscaleScaleFactor;
9
+ enhanceFaces?: boolean;
10
+ enhanceDetails?: boolean;
11
+ }
12
+
13
+ export interface UpscaleInput {
14
+ base64: string;
15
+ mimeType: string;
16
+ options?: UpscaleOptions;
17
+ }
18
+
19
+ export interface UpscaleResult {
20
+ success: boolean;
21
+ imageUrl?: string;
22
+ imageBase64?: string;
23
+ mimeType?: string;
24
+ error?: string;
25
+ }
26
+
27
+ export interface PreparedImage {
28
+ base64: string;
29
+ mimeType: string;
30
+ }
31
+
32
+ export interface UseUpscaleConfig {
33
+ defaultScaleFactor?: UpscaleScaleFactor;
34
+ onSuccess?: (result: UpscaleResult) => void;
35
+ onError?: (error: string) => void;
36
+ }
37
+
38
+ export interface UseUpscaleReturn {
39
+ imageUri: string | null;
40
+ processedUrl: string | null;
41
+ isProcessing: boolean;
42
+ progress: number;
43
+ error: string | null;
44
+ setImageUri: (uri: string) => void;
45
+ process: () => Promise<void>;
46
+ reset: () => void;
47
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Upscaling Domain - Public API
3
+ *
4
+ * Exports GeminiUpscaleProvider for use with content package registry
5
+ */
6
+
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)
16
+ export type {
17
+ UpscaleScaleFactor,
18
+ UpscaleOptions,
19
+ UpscaleInput,
20
+ PreparedImage,
21
+ } from "./domain/types";
@@ -0,0 +1,3 @@
1
+ export * from "./services";
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 "../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";
@@ -0,0 +1 @@
1
+ export { upscaleService } from "./upscale.service";
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Upscale Service
3
+ */
4
+
5
+ import { geminiImageEditService } from "../../../../infrastructure/services/gemini-image-edit.service";
6
+ import type {
7
+ UpscaleInput,
8
+ UpscaleResult,
9
+ UpscaleOptions,
10
+ } from "../../domain/types";
11
+
12
+ declare const __DEV__: boolean;
13
+
14
+ function buildPrompt(options?: UpscaleOptions): string {
15
+ const scale = options?.scaleFactor || 2;
16
+ const parts = [
17
+ `Upscale this image by ${scale}x while maintaining quality.`,
18
+ "Preserve all original details and colors.",
19
+ "Enhance sharpness and clarity.",
20
+ ];
21
+
22
+ if (options?.enhanceFaces) {
23
+ parts.push("Pay special attention to enhancing facial features.");
24
+ }
25
+
26
+ if (options?.enhanceDetails) {
27
+ parts.push("Enhance fine details and textures.");
28
+ }
29
+
30
+ return parts.join(" ");
31
+ }
32
+
33
+ class UpscaleService {
34
+ async upscale(input: UpscaleInput): Promise<UpscaleResult> {
35
+ if (__DEV__) {
36
+ // eslint-disable-next-line no-console
37
+ console.log("[UpscaleService] Starting", {
38
+ scaleFactor: input.options?.scaleFactor || 2,
39
+ });
40
+ }
41
+
42
+ try {
43
+ const prompt = buildPrompt(input.options);
44
+
45
+ const result = await geminiImageEditService.editImage(prompt, [
46
+ { base64: input.base64, mimeType: input.mimeType },
47
+ ]);
48
+
49
+ if (!result.imageBase64 && !result.imageUrl) {
50
+ return { success: false, error: "No image returned" };
51
+ }
52
+
53
+ if (__DEV__) {
54
+ // eslint-disable-next-line no-console
55
+ console.log("[UpscaleService] Completed successfully");
56
+ }
57
+
58
+ return {
59
+ success: true,
60
+ imageUrl: result.imageUrl,
61
+ imageBase64: result.imageBase64,
62
+ mimeType: result.mimeType,
63
+ };
64
+ } catch (error) {
65
+ const message = error instanceof Error ? error.message : String(error);
66
+
67
+ if (__DEV__) {
68
+ // eslint-disable-next-line no-console
69
+ console.error("[UpscaleService] Error:", message);
70
+ }
71
+
72
+ return { success: false, error: message };
73
+ }
74
+ }
75
+ }
76
+
77
+ export const upscaleService = new UpscaleService();
@@ -0,0 +1,55 @@
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
+ }
@@ -0,0 +1 @@
1
+ export { prepareImage } from "./image-preparer.util";
package/src/index.ts CHANGED
@@ -109,6 +109,20 @@ export type {
109
109
  UseGeminiReturn,
110
110
  } from "./presentation/hooks";
111
111
 
112
+ // =============================================================================
113
+ // DOMAINS - DDD-organized features
114
+ // =============================================================================
115
+
116
+ // Upscaling Domain - Provider for content package registry
117
+ export { geminiUpscaleProvider } from "./domains/upscaling";
118
+
119
+ export type {
120
+ IUpscaleProvider,
121
+ UpscaleRequest as GeminiUpscaleRequest,
122
+ UpscaleResult as GeminiUpscaleResult,
123
+ PreparedImage,
124
+ } from "./domains/upscaling";
125
+
112
126
  // =============================================================================
113
127
  // PROVIDER CONFIGURATION - Tier-based Setup
114
128
  // =============================================================================
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Image Preparer Utility
3
+ * Prepares images for Gemini API
4
+ */
5
+
6
+ import type { PreparedImage } from "../../domains/upscaling/domain/types";
7
+
8
+ declare const __DEV__: boolean;
9
+
10
+ function getMimeTypeFromUri(uri: string): string {
11
+ const extension = uri.split(".").pop()?.toLowerCase();
12
+ const mimeTypes: Record<string, string> = {
13
+ jpg: "image/jpeg",
14
+ jpeg: "image/jpeg",
15
+ png: "image/png",
16
+ gif: "image/gif",
17
+ webp: "image/webp",
18
+ };
19
+ return mimeTypes[extension || ""] || "image/jpeg";
20
+ }
21
+
22
+ function extractBase64FromDataUrl(dataUrl: string): string {
23
+ const match = dataUrl.match(/^data:[^;]+;base64,(.+)$/);
24
+ return match ? match[1] : dataUrl;
25
+ }
26
+
27
+ export async function prepareImageFromUri(
28
+ uri: string,
29
+ ): Promise<PreparedImage> {
30
+ if (__DEV__) {
31
+ // eslint-disable-next-line no-console
32
+ console.log("[ImagePreparer] Preparing image from URI");
33
+ }
34
+
35
+ if (uri.startsWith("data:")) {
36
+ const mimeMatch = uri.match(/^data:([^;]+);base64,/);
37
+ const mimeType = mimeMatch ? mimeMatch[1] : "image/jpeg";
38
+ const base64 = extractBase64FromDataUrl(uri);
39
+ return { base64, mimeType };
40
+ }
41
+
42
+ const response = await fetch(uri);
43
+ const blob = await response.blob();
44
+
45
+ return new Promise((resolve, reject) => {
46
+ const reader = new FileReader();
47
+ reader.onloadend = () => {
48
+ const dataUrl = reader.result as string;
49
+ const base64 = extractBase64FromDataUrl(dataUrl);
50
+ const mimeType = blob.type || getMimeTypeFromUri(uri);
51
+ resolve({ base64, mimeType });
52
+ };
53
+ reader.onerror = () => reject(new Error("Failed to read image"));
54
+ reader.readAsDataURL(blob);
55
+ });
56
+ }
57
+
58
+ export function isValidBase64(str: string): boolean {
59
+ if (!str || str.length === 0) return false;
60
+ try {
61
+ return btoa(atob(str)) === str;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }