@umituz/react-native-ai-generation-content 1.76.1 → 1.78.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-generation-content",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.78.0",
|
|
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",
|
package/src/domains/generation/wizard/infrastructure/strategies/shared/photo-extraction.utils.ts
CHANGED
|
@@ -4,10 +4,57 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { readFileAsBase64 } from "@umituz/react-native-design-system";
|
|
7
|
+
import { manipulateAsync, SaveFormat } from "expo-image-manipulator";
|
|
8
|
+
import { Image } from "react-native";
|
|
7
9
|
import { PHOTO_KEY_PREFIX } from "../wizard-strategy.constants";
|
|
8
10
|
|
|
9
11
|
declare const __DEV__: boolean;
|
|
10
12
|
|
|
13
|
+
const MIN_IMAGE_DIMENSION = 300;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get image dimensions from URI
|
|
17
|
+
*/
|
|
18
|
+
function getImageSize(uri: string): Promise<{ width: number; height: number }> {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
Image.getSize(uri, (width, height) => resolve({ width, height }), reject);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Ensure image meets minimum dimensions (300x300) required by AI providers.
|
|
26
|
+
* Returns the original URI if already large enough, or a resized URI.
|
|
27
|
+
*/
|
|
28
|
+
async function ensureMinimumSize(uri: string): Promise<string> {
|
|
29
|
+
try {
|
|
30
|
+
const { width, height } = await getImageSize(uri);
|
|
31
|
+
|
|
32
|
+
if (width >= MIN_IMAGE_DIMENSION && height >= MIN_IMAGE_DIMENSION) {
|
|
33
|
+
return uri;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const scale = Math.max(MIN_IMAGE_DIMENSION / width, MIN_IMAGE_DIMENSION / height);
|
|
37
|
+
const newWidth = Math.ceil(width * scale);
|
|
38
|
+
const newHeight = Math.ceil(height * scale);
|
|
39
|
+
|
|
40
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
41
|
+
console.log("[PhotoExtraction] Resizing small image", {
|
|
42
|
+
from: `${width}x${height}`,
|
|
43
|
+
to: `${newWidth}x${newHeight}`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = await manipulateAsync(uri, [{ resize: { width: newWidth, height: newHeight } }], {
|
|
48
|
+
format: SaveFormat.JPEG,
|
|
49
|
+
compress: 0.9,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return result.uri;
|
|
53
|
+
} catch {
|
|
54
|
+
return uri;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
11
58
|
/**
|
|
12
59
|
* Extracts photo URIs from wizard data
|
|
13
60
|
*/
|
|
@@ -59,7 +106,8 @@ export async function extractPhotosAsBase64(
|
|
|
59
106
|
const results = await Promise.allSettled(
|
|
60
107
|
photoUris.map(async (uri, index) => {
|
|
61
108
|
try {
|
|
62
|
-
|
|
109
|
+
const resizedUri = await ensureMinimumSize(uri);
|
|
110
|
+
return await readFileAsBase64(resizedUri);
|
|
63
111
|
} catch (error) {
|
|
64
112
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
65
113
|
console.error(`[PhotoExtraction] Failed to read photo ${index}:`, error);
|
|
@@ -7,6 +7,39 @@ declare const __DEV__: boolean;
|
|
|
7
7
|
/** Max consecutive transient errors before aborting */
|
|
8
8
|
const MAX_CONSECUTIVE_ERRORS = 5;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Extract meaningful error message from various error formats.
|
|
12
|
+
* Fal AI client throws ValidationError with empty .message but details in .body/.detail
|
|
13
|
+
*/
|
|
14
|
+
function extractErrorMessage(err: unknown): string {
|
|
15
|
+
if (!err) return "Generation failed";
|
|
16
|
+
|
|
17
|
+
// Standard Error with message
|
|
18
|
+
if (err instanceof Error && err.message && err.message.length > 0) {
|
|
19
|
+
return err.message;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Fal AI ValidationError - has .body.detail array
|
|
23
|
+
const errObj = err as Record<string, unknown>;
|
|
24
|
+
if (errObj.body && typeof errObj.body === "object") {
|
|
25
|
+
const body = errObj.body as Record<string, unknown>;
|
|
26
|
+
if (Array.isArray(body.detail) && body.detail.length > 0) {
|
|
27
|
+
const first = body.detail[0] as { msg?: string; type?: string } | undefined;
|
|
28
|
+
if (first?.msg) return first.msg;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Direct .detail array on error object
|
|
33
|
+
if (Array.isArray(errObj.detail) && errObj.detail.length > 0) {
|
|
34
|
+
const first = errObj.detail[0] as { msg?: string } | undefined;
|
|
35
|
+
if (first?.msg) return first.msg;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Fallback to string conversion
|
|
39
|
+
const str = String(err);
|
|
40
|
+
return str.length > 0 && str !== "[object Object]" ? str : "Generation failed";
|
|
41
|
+
}
|
|
42
|
+
|
|
10
43
|
interface PollParams {
|
|
11
44
|
requestId: string;
|
|
12
45
|
model: string;
|
|
@@ -56,7 +89,7 @@ export const pollQueueStatus = async (params: PollParams): Promise<void> => {
|
|
|
56
89
|
}
|
|
57
90
|
await onComplete(urls);
|
|
58
91
|
} catch (resultErr) {
|
|
59
|
-
const errorMessage = resultErr
|
|
92
|
+
const errorMessage = extractErrorMessage(resultErr);
|
|
60
93
|
if (__DEV__) {
|
|
61
94
|
console.error("[VideoQueueGeneration] ❌ Result error:", errorMessage);
|
|
62
95
|
console.error("[VideoQueueGeneration] ❌ Full error:", resultErr);
|