@umituz/react-native-ai-generation-content 1.17.220 → 1.17.221
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 +1 -1
- package/src/features/image-to-video/presentation/hooks/useGenerationExecution.ts +142 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.constants.ts +15 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +26 -178
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.types.ts +27 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoValidation.ts +46 -0
package/package.json
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGenerationExecution Hook
|
|
3
|
+
* Handles the core generation execution logic for image-to-video
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import { executeImageToVideo } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
ImageToVideoFeatureConfig,
|
|
10
|
+
ImageToVideoFeatureCallbacks,
|
|
11
|
+
ImageToVideoResult,
|
|
12
|
+
ImageToVideoGenerateParams,
|
|
13
|
+
} from "../../domain/types";
|
|
14
|
+
|
|
15
|
+
declare const __DEV__: boolean;
|
|
16
|
+
|
|
17
|
+
interface UseGenerationExecutionParams {
|
|
18
|
+
userId: string;
|
|
19
|
+
config: ImageToVideoFeatureConfig;
|
|
20
|
+
callbacks?: ImageToVideoFeatureCallbacks;
|
|
21
|
+
setState: React.Dispatch<React.SetStateAction<any>>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useGenerationExecution({
|
|
25
|
+
userId,
|
|
26
|
+
config,
|
|
27
|
+
callbacks,
|
|
28
|
+
setState,
|
|
29
|
+
}: UseGenerationExecutionParams) {
|
|
30
|
+
return useCallback(
|
|
31
|
+
async (
|
|
32
|
+
imageUri: string,
|
|
33
|
+
motionPrompt: string,
|
|
34
|
+
options?: Omit<ImageToVideoGenerateParams, "imageUri" | "motionPrompt">,
|
|
35
|
+
): Promise<ImageToVideoResult> => {
|
|
36
|
+
const creationId = `image-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
37
|
+
|
|
38
|
+
setState((prev: any) => ({
|
|
39
|
+
...prev,
|
|
40
|
+
imageUri,
|
|
41
|
+
isProcessing: true,
|
|
42
|
+
progress: 0,
|
|
43
|
+
error: null,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
47
|
+
console.log("[ImageToVideoFeature] Starting generation, creationId:", creationId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
config.onProcessingStart?.();
|
|
51
|
+
|
|
52
|
+
if (callbacks?.onGenerationStart) {
|
|
53
|
+
callbacks.onGenerationStart({
|
|
54
|
+
creationId,
|
|
55
|
+
type: "image-to-video",
|
|
56
|
+
imageUri,
|
|
57
|
+
metadata: options as Record<string, unknown> | undefined,
|
|
58
|
+
}).catch((err) => {
|
|
59
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
60
|
+
console.warn("[ImageToVideoFeature] onGenerationStart failed:", err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const imageBase64 = await config.prepareImage(imageUri);
|
|
67
|
+
|
|
68
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
69
|
+
console.log("[ImageToVideoFeature] Image prepared, calling executeImageToVideo");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const result = await executeImageToVideo(
|
|
73
|
+
{
|
|
74
|
+
imageUri,
|
|
75
|
+
imageBase64,
|
|
76
|
+
userId,
|
|
77
|
+
motionPrompt: motionPrompt || undefined,
|
|
78
|
+
options,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
model: config.model,
|
|
82
|
+
buildInput: config.buildInput,
|
|
83
|
+
extractResult: config.extractResult,
|
|
84
|
+
onProgress: (progress) => {
|
|
85
|
+
setState((prev: any) => ({ ...prev, progress }));
|
|
86
|
+
callbacks?.onProgress?.(progress);
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (result.success && result.videoUrl) {
|
|
92
|
+
setState((prev: any) => ({
|
|
93
|
+
...prev,
|
|
94
|
+
videoUrl: result.videoUrl ?? null,
|
|
95
|
+
thumbnailUrl: result.thumbnailUrl ?? null,
|
|
96
|
+
isProcessing: false,
|
|
97
|
+
progress: 100,
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
if (callbacks?.onCreditDeduct && config.creditCost) {
|
|
101
|
+
await callbacks.onCreditDeduct(config.creditCost);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (callbacks?.onCreationSave) {
|
|
105
|
+
await callbacks.onCreationSave({
|
|
106
|
+
creationId,
|
|
107
|
+
type: "image-to-video",
|
|
108
|
+
videoUrl: result.videoUrl,
|
|
109
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
110
|
+
imageUri,
|
|
111
|
+
metadata: options as Record<string, unknown> | undefined,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
callbacks?.onGenerate?.(result);
|
|
116
|
+
} else {
|
|
117
|
+
const error = result.error || "Generation failed";
|
|
118
|
+
setState((prev: any) => ({ ...prev, isProcessing: false, error }));
|
|
119
|
+
config.onError?.(error);
|
|
120
|
+
callbacks?.onError?.(error);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
config.onProcessingComplete?.(result);
|
|
124
|
+
return result;
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
127
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
128
|
+
console.error("[ImageToVideoFeature] Generation error:", errorMessage);
|
|
129
|
+
}
|
|
130
|
+
setState((prev: any) => ({
|
|
131
|
+
...prev,
|
|
132
|
+
isProcessing: false,
|
|
133
|
+
error: errorMessage,
|
|
134
|
+
}));
|
|
135
|
+
config.onError?.(errorMessage);
|
|
136
|
+
callbacks?.onError?.(errorMessage);
|
|
137
|
+
return { success: false, error: errorMessage };
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[userId, config, callbacks],
|
|
141
|
+
);
|
|
142
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useImageToVideoFeature Constants
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ImageToVideoFeatureState } from "../../domain/types";
|
|
6
|
+
|
|
7
|
+
export const INITIAL_IMAGE_TO_VIDEO_STATE: ImageToVideoFeatureState = {
|
|
8
|
+
imageUri: null,
|
|
9
|
+
motionPrompt: "",
|
|
10
|
+
videoUrl: null,
|
|
11
|
+
thumbnailUrl: null,
|
|
12
|
+
isProcessing: false,
|
|
13
|
+
progress: 0,
|
|
14
|
+
error: null,
|
|
15
|
+
};
|
|
@@ -4,48 +4,33 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback, useMemo } from "react";
|
|
7
|
-
import {
|
|
7
|
+
import { useGenerationExecution } from "./useGenerationExecution";
|
|
8
|
+
import { validateImageToVideoGeneration } from "./useImageToVideoValidation";
|
|
9
|
+
import { INITIAL_IMAGE_TO_VIDEO_STATE } from "./useImageToVideoFeature.constants";
|
|
10
|
+
import type {
|
|
11
|
+
UseImageToVideoFeatureProps,
|
|
12
|
+
UseImageToVideoFeatureReturn,
|
|
13
|
+
} from "./useImageToVideoFeature.types";
|
|
8
14
|
import type {
|
|
9
15
|
ImageToVideoFeatureState,
|
|
10
|
-
ImageToVideoFeatureConfig,
|
|
11
|
-
ImageToVideoResult,
|
|
12
|
-
ImageToVideoFeatureCallbacks,
|
|
13
16
|
ImageToVideoGenerateParams,
|
|
17
|
+
ImageToVideoResult,
|
|
14
18
|
} from "../../domain/types";
|
|
15
19
|
|
|
16
20
|
declare const __DEV__: boolean;
|
|
17
21
|
|
|
18
|
-
export interface UseImageToVideoFeatureProps {
|
|
19
|
-
config: ImageToVideoFeatureConfig;
|
|
20
|
-
callbacks?: ImageToVideoFeatureCallbacks;
|
|
21
|
-
userId: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface UseImageToVideoFeatureReturn {
|
|
25
|
-
state: ImageToVideoFeatureState;
|
|
26
|
-
setImageUri: (uri: string) => void;
|
|
27
|
-
setMotionPrompt: (prompt: string) => void;
|
|
28
|
-
generate: (params?: ImageToVideoGenerateParams) => Promise<ImageToVideoResult>;
|
|
29
|
-
reset: () => void;
|
|
30
|
-
isReady: boolean;
|
|
31
|
-
canGenerate: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const INITIAL_STATE: ImageToVideoFeatureState = {
|
|
35
|
-
imageUri: null,
|
|
36
|
-
motionPrompt: "",
|
|
37
|
-
videoUrl: null,
|
|
38
|
-
thumbnailUrl: null,
|
|
39
|
-
isProcessing: false,
|
|
40
|
-
progress: 0,
|
|
41
|
-
error: null,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
22
|
export function useImageToVideoFeature(
|
|
45
23
|
props: UseImageToVideoFeatureProps,
|
|
46
24
|
): UseImageToVideoFeatureReturn {
|
|
47
25
|
const { config, callbacks, userId } = props;
|
|
48
|
-
const [state, setState] = useState<ImageToVideoFeatureState>(
|
|
26
|
+
const [state, setState] = useState<ImageToVideoFeatureState>(INITIAL_IMAGE_TO_VIDEO_STATE);
|
|
27
|
+
|
|
28
|
+
const executeGeneration = useGenerationExecution({
|
|
29
|
+
userId,
|
|
30
|
+
config,
|
|
31
|
+
callbacks,
|
|
32
|
+
setState,
|
|
33
|
+
});
|
|
49
34
|
|
|
50
35
|
const setImageUri = useCallback(
|
|
51
36
|
(uri: string) => {
|
|
@@ -59,123 +44,6 @@ export function useImageToVideoFeature(
|
|
|
59
44
|
setState((prev) => ({ ...prev, motionPrompt: prompt }));
|
|
60
45
|
}, []);
|
|
61
46
|
|
|
62
|
-
const executeGeneration = useCallback(
|
|
63
|
-
async (
|
|
64
|
-
imageUri: string,
|
|
65
|
-
motionPrompt: string,
|
|
66
|
-
options?: Omit<ImageToVideoGenerateParams, "imageUri" | "motionPrompt">,
|
|
67
|
-
): Promise<ImageToVideoResult> => {
|
|
68
|
-
const creationId = `image-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
69
|
-
|
|
70
|
-
setState((prev) => ({
|
|
71
|
-
...prev,
|
|
72
|
-
imageUri,
|
|
73
|
-
isProcessing: true,
|
|
74
|
-
progress: 0,
|
|
75
|
-
error: null,
|
|
76
|
-
}));
|
|
77
|
-
|
|
78
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
79
|
-
|
|
80
|
-
console.log("[ImageToVideoFeature] Starting generation, creationId:", creationId);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
config.onProcessingStart?.();
|
|
84
|
-
|
|
85
|
-
if (callbacks?.onGenerationStart) {
|
|
86
|
-
callbacks.onGenerationStart({
|
|
87
|
-
creationId,
|
|
88
|
-
type: "image-to-video",
|
|
89
|
-
imageUri,
|
|
90
|
-
metadata: options as Record<string, unknown> | undefined,
|
|
91
|
-
}).catch((err) => {
|
|
92
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
93
|
-
|
|
94
|
-
console.warn("[ImageToVideoFeature] onGenerationStart failed:", err);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
const imageBase64 = await config.prepareImage(imageUri);
|
|
101
|
-
|
|
102
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
103
|
-
|
|
104
|
-
console.log("[ImageToVideoFeature] Image prepared, calling executeImageToVideo");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const result = await executeImageToVideo(
|
|
108
|
-
{
|
|
109
|
-
imageUri,
|
|
110
|
-
imageBase64,
|
|
111
|
-
userId,
|
|
112
|
-
motionPrompt: motionPrompt || undefined,
|
|
113
|
-
options,
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
model: config.model,
|
|
117
|
-
buildInput: config.buildInput,
|
|
118
|
-
extractResult: config.extractResult,
|
|
119
|
-
onProgress: (progress) => {
|
|
120
|
-
setState((prev) => ({ ...prev, progress }));
|
|
121
|
-
callbacks?.onProgress?.(progress);
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
if (result.success && result.videoUrl) {
|
|
127
|
-
setState((prev) => ({
|
|
128
|
-
...prev,
|
|
129
|
-
videoUrl: result.videoUrl ?? null,
|
|
130
|
-
thumbnailUrl: result.thumbnailUrl ?? null,
|
|
131
|
-
isProcessing: false,
|
|
132
|
-
progress: 100,
|
|
133
|
-
}));
|
|
134
|
-
|
|
135
|
-
if (callbacks?.onCreditDeduct && config.creditCost) {
|
|
136
|
-
await callbacks.onCreditDeduct(config.creditCost);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (callbacks?.onCreationSave) {
|
|
140
|
-
await callbacks.onCreationSave({
|
|
141
|
-
creationId,
|
|
142
|
-
type: "image-to-video",
|
|
143
|
-
videoUrl: result.videoUrl,
|
|
144
|
-
thumbnailUrl: result.thumbnailUrl,
|
|
145
|
-
imageUri,
|
|
146
|
-
metadata: options as Record<string, unknown> | undefined,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
callbacks?.onGenerate?.(result);
|
|
151
|
-
} else {
|
|
152
|
-
const error = result.error || "Generation failed";
|
|
153
|
-
setState((prev) => ({ ...prev, isProcessing: false, error }));
|
|
154
|
-
config.onError?.(error);
|
|
155
|
-
callbacks?.onError?.(error);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
config.onProcessingComplete?.(result);
|
|
159
|
-
return result;
|
|
160
|
-
} catch (err) {
|
|
161
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
162
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
163
|
-
|
|
164
|
-
console.error("[ImageToVideoFeature] Generation error:", errorMessage);
|
|
165
|
-
}
|
|
166
|
-
setState((prev) => ({
|
|
167
|
-
...prev,
|
|
168
|
-
isProcessing: false,
|
|
169
|
-
error: errorMessage,
|
|
170
|
-
}));
|
|
171
|
-
config.onError?.(errorMessage);
|
|
172
|
-
callbacks?.onError?.(errorMessage);
|
|
173
|
-
return { success: false, error: errorMessage };
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
[userId, config, callbacks],
|
|
177
|
-
);
|
|
178
|
-
|
|
179
47
|
const generate = useCallback(
|
|
180
48
|
async (params?: ImageToVideoGenerateParams): Promise<ImageToVideoResult> => {
|
|
181
49
|
const { imageUri: paramImageUri, motionPrompt: paramMotionPrompt, ...options } = params || {};
|
|
@@ -183,43 +51,21 @@ export function useImageToVideoFeature(
|
|
|
183
51
|
const effectiveMotionPrompt = paramMotionPrompt ?? state.motionPrompt;
|
|
184
52
|
|
|
185
53
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
186
|
-
|
|
187
54
|
console.log("[ImageToVideoFeature] generate called, hasImage:", !!effectiveImageUri);
|
|
188
55
|
}
|
|
189
56
|
|
|
190
|
-
if (!effectiveImageUri) {
|
|
191
|
-
const error = "Image is required";
|
|
192
|
-
setState((prev) => ({ ...prev, error }));
|
|
193
|
-
callbacks?.onError?.(error);
|
|
194
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
195
|
-
|
|
196
|
-
console.log("[ImageToVideoFeature] Generate failed: Image is required");
|
|
197
|
-
}
|
|
198
|
-
return { success: false, error };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
57
|
if (paramImageUri) {
|
|
202
58
|
setState((prev) => ({ ...prev, imageUri: paramImageUri }));
|
|
203
59
|
}
|
|
204
60
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return { success: false, error: "Authentication required" };
|
|
211
|
-
}
|
|
61
|
+
const validation = await validateImageToVideoGeneration(
|
|
62
|
+
effectiveImageUri,
|
|
63
|
+
callbacks,
|
|
64
|
+
config.creditCost,
|
|
65
|
+
);
|
|
212
66
|
|
|
213
|
-
if (
|
|
214
|
-
|
|
215
|
-
if (!hasCredits) {
|
|
216
|
-
callbacks?.onShowPaywall?.(config.creditCost);
|
|
217
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
218
|
-
|
|
219
|
-
console.log("[ImageToVideoFeature] Generate failed: Insufficient credits");
|
|
220
|
-
}
|
|
221
|
-
return { success: false, error: "Insufficient credits" };
|
|
222
|
-
}
|
|
67
|
+
if (!validation.shouldProceed) {
|
|
68
|
+
return validation;
|
|
223
69
|
}
|
|
224
70
|
|
|
225
71
|
return executeGeneration(effectiveImageUri, effectiveMotionPrompt, options);
|
|
@@ -228,7 +74,7 @@ export function useImageToVideoFeature(
|
|
|
228
74
|
);
|
|
229
75
|
|
|
230
76
|
const reset = useCallback(() => {
|
|
231
|
-
setState(
|
|
77
|
+
setState(INITIAL_IMAGE_TO_VIDEO_STATE);
|
|
232
78
|
}, []);
|
|
233
79
|
|
|
234
80
|
const isReady = useMemo(
|
|
@@ -243,3 +89,5 @@ export function useImageToVideoFeature(
|
|
|
243
89
|
|
|
244
90
|
return { state, setImageUri, setMotionPrompt, generate, reset, isReady, canGenerate };
|
|
245
91
|
}
|
|
92
|
+
|
|
93
|
+
export type { UseImageToVideoFeatureProps, UseImageToVideoFeatureReturn } from "./useImageToVideoFeature.types";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useImageToVideoFeature Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ImageToVideoFeatureState,
|
|
7
|
+
ImageToVideoFeatureConfig,
|
|
8
|
+
ImageToVideoResult,
|
|
9
|
+
ImageToVideoFeatureCallbacks,
|
|
10
|
+
ImageToVideoGenerateParams,
|
|
11
|
+
} from "../../domain/types";
|
|
12
|
+
|
|
13
|
+
export interface UseImageToVideoFeatureProps {
|
|
14
|
+
config: ImageToVideoFeatureConfig;
|
|
15
|
+
callbacks?: ImageToVideoFeatureCallbacks;
|
|
16
|
+
userId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UseImageToVideoFeatureReturn {
|
|
20
|
+
state: ImageToVideoFeatureState;
|
|
21
|
+
setImageUri: (uri: string) => void;
|
|
22
|
+
setMotionPrompt: (prompt: string) => void;
|
|
23
|
+
generate: (params?: ImageToVideoGenerateParams) => Promise<ImageToVideoResult>;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
isReady: boolean;
|
|
26
|
+
canGenerate: boolean;
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image-to-Video Validation Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ImageToVideoFeatureCallbacks, ImageToVideoGenerateParams, ImageToVideoResult } from "../../domain/types";
|
|
6
|
+
|
|
7
|
+
declare const __DEV__: boolean;
|
|
8
|
+
|
|
9
|
+
export interface ValidationResult extends ImageToVideoResult {
|
|
10
|
+
shouldProceed: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function validateImageToVideoGeneration(
|
|
14
|
+
effectiveImageUri: string | null,
|
|
15
|
+
callbacks?: ImageToVideoFeatureCallbacks,
|
|
16
|
+
creditCost?: number,
|
|
17
|
+
): Promise<ValidationResult> {
|
|
18
|
+
if (!effectiveImageUri) {
|
|
19
|
+
const error = "Image is required";
|
|
20
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
21
|
+
console.log("[ImageToVideoFeature] Generate failed: Image is required");
|
|
22
|
+
}
|
|
23
|
+
callbacks?.onError?.(error);
|
|
24
|
+
return { success: false, error, shouldProceed: false };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (callbacks?.onAuthCheck && !callbacks.onAuthCheck()) {
|
|
28
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
29
|
+
console.log("[ImageToVideoFeature] Generate failed: Authentication required");
|
|
30
|
+
}
|
|
31
|
+
return { success: false, error: "Authentication required", shouldProceed: false };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (callbacks?.onCreditCheck && creditCost) {
|
|
35
|
+
const hasCredits = await callbacks.onCreditCheck(creditCost);
|
|
36
|
+
if (!hasCredits) {
|
|
37
|
+
callbacks?.onShowPaywall?.(creditCost);
|
|
38
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
39
|
+
console.log("[ImageToVideoFeature] Generate failed: Insufficient credits");
|
|
40
|
+
}
|
|
41
|
+
return { success: false, error: "Insufficient credits", shouldProceed: false };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { success: true, shouldProceed: true };
|
|
46
|
+
}
|