@umituz/react-native-ai-generation-content 1.89.33 → 1.89.34

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-generation-content",
3
- "version": "1.89.33",
3
+ "version": "1.89.34",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -3,9 +3,11 @@
3
3
  * Shared photo extraction logic for wizard strategies
4
4
  *
5
5
  * Resize strategy:
6
- * - Small images (<300px): scale UP to 300px minimum (AI provider requirement)
6
+ * - Small images (<768px): scale UP to 768px minimum (good face preservation)
7
7
  * - Large images (>1536px): scale DOWN to 1536px maximum (reduces upload size ~10x)
8
8
  * - Normal images: pass through unchanged
9
+ *
10
+ * IMPORTANT: 768px minimum ensures AI models have enough detail for face preservation
9
11
  */
10
12
 
11
13
  import { readFileAsBase64 } from "@umituz/react-native-design-system/filesystem";
@@ -14,7 +16,7 @@ import { Image } from "react-native";
14
16
  import { PHOTO_KEY_PREFIX } from "../wizard-strategy.constants";
15
17
 
16
18
 
17
- const MIN_IMAGE_DIMENSION = 300;
19
+ const MIN_IMAGE_DIMENSION = 768; // Minimum for good face preservation
18
20
  const MAX_IMAGE_DIMENSION = 1536;
19
21
 
20
22
  /**
@@ -28,7 +30,7 @@ function getImageSize(uri: string): Promise<{ width: number; height: number }> {
28
30
 
29
31
  /**
30
32
  * Ensure image is within optimal dimensions for AI generation.
31
- * - Too small (<300px): scale up (AI providers require minimum dimensions)
33
+ * - Too small (<768px): scale up (good face preservation)
32
34
  * - Too large (>1536px): scale down (reduces upload size, prevents timeouts)
33
35
  * - Within range: return as-is
34
36
  */
@@ -37,41 +39,76 @@ async function ensureOptimalSize(uri: string): Promise<string> {
37
39
  const { width, height } = await getImageSize(uri);
38
40
  const maxDim = Math.max(width, height);
39
41
 
42
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
43
+ console.log("[PhotoExtraction] Analyzing image", {
44
+ originalDimensions: `${width}x${height}`,
45
+ maxDim,
46
+ minDim: Math.min(width, height),
47
+ isTooSmall: width < MIN_IMAGE_DIMENSION || height < MIN_IMAGE_DIMENSION,
48
+ isTooLarge: maxDim > MAX_IMAGE_DIMENSION,
49
+ });
50
+ }
51
+
40
52
  // Already within optimal range
41
53
  if (width >= MIN_IMAGE_DIMENSION && height >= MIN_IMAGE_DIMENSION && maxDim <= MAX_IMAGE_DIMENSION) {
54
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
55
+ console.log("[PhotoExtraction] Image already optimal, skipping resize", {
56
+ dimensions: `${width}x${height}`,
57
+ minRequired: MIN_IMAGE_DIMENSION,
58
+ maxAllowed: MAX_IMAGE_DIMENSION,
59
+ });
60
+ }
42
61
  return uri;
43
62
  }
44
63
 
45
64
  let newWidth: number;
46
65
  let newHeight: number;
66
+ let direction: string;
47
67
 
48
68
  if (maxDim > MAX_IMAGE_DIMENSION) {
49
69
  // Scale DOWN — largest dimension becomes MAX_IMAGE_DIMENSION
50
70
  const scale = MAX_IMAGE_DIMENSION / maxDim;
51
71
  newWidth = Math.round(width * scale);
52
72
  newHeight = Math.round(height * scale);
73
+ direction = "down";
53
74
  } else {
54
75
  // Scale UP — smallest dimension becomes MIN_IMAGE_DIMENSION
55
76
  const scale = Math.max(MIN_IMAGE_DIMENSION / width, MIN_IMAGE_DIMENSION / height);
56
77
  newWidth = Math.ceil(width * scale);
57
78
  newHeight = Math.ceil(height * scale);
79
+ direction = "up";
58
80
  }
59
81
 
82
+ const compressQuality = maxDim > MAX_IMAGE_DIMENSION ? 0.8 : 1.0; // Lossless for scale-up
83
+
60
84
  if (typeof __DEV__ !== "undefined" && __DEV__) {
61
- const direction = maxDim > MAX_IMAGE_DIMENSION ? "down" : "up";
62
85
  console.log(`[PhotoExtraction] Resizing ${direction}`, {
63
86
  from: `${width}x${height}`,
64
87
  to: `${newWidth}x${newHeight}`,
88
+ scaleChange: `${((Math.max(newWidth, newHeight) / maxDim - 1) * 100).toFixed(0)}%`,
89
+ compressQuality,
65
90
  });
66
91
  }
67
92
 
68
93
  const result = await manipulateAsync(uri, [{ resize: { width: newWidth, height: newHeight } }], {
69
94
  format: SaveFormat.JPEG,
70
- compress: maxDim > MAX_IMAGE_DIMENSION ? 0.8 : 0.9,
95
+ compress: compressQuality,
71
96
  });
72
97
 
98
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
99
+ console.log("[PhotoExtraction] Resize complete", {
100
+ original: `${width}x${height}`,
101
+ resized: `${newWidth}x${newHeight}`,
102
+ action: direction,
103
+ quality: compressQuality === 1.0 ? "lossless" : `${compressQuality * 100}%`,
104
+ });
105
+ }
106
+
73
107
  return result.uri;
74
- } catch {
108
+ } catch (error) {
109
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
110
+ console.error("[PhotoExtraction] Resize failed, using original", error);
111
+ }
75
112
  return uri;
76
113
  }
77
114
  }
@@ -108,18 +145,27 @@ export async function extractPhotosAsBase64(
108
145
  enableDebugLogs = false,
109
146
  ): Promise<string[]> {
110
147
  if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
111
- console.log("[PhotoExtraction] Starting extraction", {
148
+ console.log("[PhotoExtraction] >>> extractPhotosAsBase64 START", {
112
149
  wizardDataKeys: Object.keys(wizardData),
150
+ photoKeyPrefix: PHOTO_KEY_PREFIX,
151
+ minDimension: MIN_IMAGE_DIMENSION,
152
+ maxDimension: MAX_IMAGE_DIMENSION,
113
153
  });
114
154
  }
115
155
 
116
156
  const photoUris = extractPhotoUris(wizardData);
117
157
 
118
158
  if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
119
- console.log("[PhotoExtraction] Found photo URIs", { count: photoUris.length });
159
+ console.log("[PhotoExtraction] Photo URIs extracted", {
160
+ count: photoUris.length,
161
+ keys: Object.keys(wizardData).filter(k => k.includes(PHOTO_KEY_PREFIX)),
162
+ });
120
163
  }
121
164
 
122
165
  if (photoUris.length === 0) {
166
+ if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
167
+ console.log("[PhotoExtraction] No photos found, returning empty array");
168
+ }
123
169
  return [];
124
170
  }
125
171
 
@@ -127,11 +173,29 @@ export async function extractPhotosAsBase64(
127
173
  const results = await Promise.allSettled(
128
174
  photoUris.map(async (uri, index) => {
129
175
  try {
176
+ if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
177
+ console.log(`[PhotoExtraction] Processing photo ${index + 1}/${photoUris.length}`, {
178
+ uri: uri.substring(0, 50) + "...",
179
+ });
180
+ }
181
+
130
182
  const optimizedUri = await ensureOptimalSize(uri);
131
- return await readFileAsBase64(optimizedUri);
183
+ const base64 = await readFileAsBase64(optimizedUri);
184
+
185
+ if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
186
+ console.log(`[PhotoExtraction] Photo ${index + 1} processed`, {
187
+ sizeKB: (base64.length / 1024).toFixed(1),
188
+ originalUri: uri.substring(0, 30) + "...",
189
+ });
190
+ }
191
+
192
+ return base64;
132
193
  } catch (error) {
133
194
  if (typeof __DEV__ !== "undefined" && __DEV__) {
134
- console.error(`[PhotoExtraction] Failed to read photo ${index}:`, error);
195
+ console.error(`[PhotoExtraction] Failed to process photo ${index + 1}:`, {
196
+ uri: uri.substring(0, 50) + "...",
197
+ error: error instanceof Error ? error.message : String(error),
198
+ });
135
199
  }
136
200
  return null;
137
201
  }
@@ -143,15 +207,21 @@ export async function extractPhotosAsBase64(
143
207
  .map((result) => (result.status === "fulfilled" ? result.value : null))
144
208
  .filter((photo): photo is string => typeof photo === "string" && photo.length > 0);
145
209
 
210
+ const failedCount = results.filter((r) => r.status === "rejected").length;
211
+
146
212
  if (enableDebugLogs && typeof __DEV__ !== "undefined" && __DEV__) {
147
- const failedCount = results.filter((r) => r.status === "rejected").length;
148
- console.log("[PhotoExtraction] Converted photos", {
213
+ console.log("[PhotoExtraction] <<< extractPhotosAsBase64 COMPLETE", {
149
214
  total: photoUris.length,
150
- valid: validPhotos.length,
215
+ successful: validPhotos.length,
151
216
  failed: failedCount,
152
- sizes: validPhotos.map((p) => `${(p.length / 1024).toFixed(1)}KB`),
217
+ sizes: validPhotos.map((p, i) => `Photo ${i + 1}: ${(p.length / 1024).toFixed(1)}KB`),
218
+ totalSizeMB: ((validPhotos.reduce((sum, p) => sum + p.length, 0) / 1024 / 1024).toFixed(2)),
153
219
  });
154
220
  }
155
221
 
222
+ if (failedCount > 0 && typeof __DEV__ !== "undefined" && __DEV__) {
223
+ console.warn(`[PhotoExtraction] ⚠️ ${failedCount} photo(s) failed to process`);
224
+ }
225
+
156
226
  return validPhotos;
157
227
  }