@umituz/react-native-ai-generation-content 1.90.2 → 1.90.4
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 +3 -3
- package/src/domain/interfaces/app-services-auth.interface.ts +27 -0
- package/src/domain/interfaces/app-services-composite.interface.ts +29 -0
- package/src/domain/interfaces/app-services-optional.interface.ts +42 -0
- package/src/domain/interfaces/app-services.interface.ts +0 -79
- package/src/domain/interfaces/index.ts +3 -0
- package/src/domains/background/infrastructure/services/job-poller-index.ts +7 -0
- package/src/domains/background/infrastructure/services/job-poller-utils.ts +127 -0
- package/src/domains/background/infrastructure/services/job-poller.service.ts +85 -140
- package/src/domains/background/infrastructure/utils/polling-interval.util.ts +1 -1
- package/src/domains/background/presentation/hooks/use-background-generation.ts +1 -1
- package/src/domains/content-moderation/index.ts +7 -13
- package/src/domains/content-moderation/infrastructure/services/content-moderation.service.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +15 -4
- package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +19 -8
- package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
- package/src/domains/creations/domain/types/creation-categories.constants.ts +57 -0
- package/src/domains/creations/domain/types/creation-categories.helpers.ts +67 -0
- package/src/domains/creations/domain/types/creation-categories.ts +7 -114
- package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
- package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
- package/src/domains/creations/presentation/hooks/creation-validators.ts +31 -29
- package/src/domains/creations/presentation/hooks/job-poller-index.ts +10 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.filters.ts +34 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.logger.ts +76 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.stale-handlers.ts +52 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.ts +8 -0
- package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
- package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +18 -235
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +1 -2
- package/src/domains/creations/presentation-exports.ts +2 -2
- package/src/domains/face-detection/domain/entities/FaceDetection.ts +4 -3
- package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +24 -21
- package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +58 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +69 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +77 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +54 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +112 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder.ts +7 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/index.ts +20 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +44 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-end-logger.ts +18 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-start-logger.ts +57 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-step-logger.ts +106 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/types.ts +49 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +8 -0
- package/src/domains/generation/infrastructure/flow/flow-store-actions.ts +105 -0
- package/src/domains/generation/infrastructure/flow/flow-store-initial-state.ts +26 -0
- package/src/domains/generation/infrastructure/flow/useFlowStore.ts +4 -116
- package/src/domains/generation/presentation/useAIGeneration.hook.ts +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation-strategy-index.ts +7 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +2 -12
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.types.ts +11 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.utils.ts +12 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +1 -220
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-builder.ts +66 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +88 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +74 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-style-enhancements.ts +35 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +41 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +10 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor.ts +76 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-input-builder.ts +46 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-result-types.ts +17 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +61 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.audio-extractor.ts +27 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +2 -176
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.input-builder.ts +90 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts +3 -108
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -130
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.validation.ts +136 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +40 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +37 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/usePhotoUploadStateLogic.ts +142 -0
- package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +102 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.handlers.ts +97 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.saver.ts +54 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.ts +22 -87
- package/src/domains/generation/wizard/presentation/hooks/usePhotoUploadState.ts +8 -177
- package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +1 -295
- package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +1 -1
- package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +77 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/use-video-queue-utils.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationCallbacks.ts +119 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +75 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationRefs.ts +65 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue-index.ts +9 -0
- package/src/domains/image-to-video/domain/types/image-to-video-state.types.ts +11 -4
- package/src/domains/text-to-image/domain/constants/index.ts +5 -6
- package/src/domains/text-to-image/domain/types/text-to-image.types.ts +43 -22
- package/src/domains/text-to-video/domain/types/request.types.ts +32 -9
- package/src/domains/text-to-video/domain/types/state.types.ts +22 -22
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.handlers.ts +44 -0
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.ts +5 -51
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.types.ts +33 -0
- package/src/exports/features.ts +1 -1
- package/src/infrastructure/services/generation-orchestrator.service.ts +2 -2
- package/src/infrastructure/utils/couple-input-context.ts +13 -0
- package/src/infrastructure/utils/couple-input-index.ts +9 -0
- package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
- package/src/infrastructure/utils/couple-input-refiner.ts +101 -0
- package/src/infrastructure/utils/couple-input-resolver.ts +71 -0
- package/src/infrastructure/utils/couple-input-types.ts +11 -0
- package/src/infrastructure/utils/couple-input.util.ts +3 -176
- package/src/infrastructure/utils/photo-generation/photo-preparation.util.ts +1 -1
- package/src/infrastructure/validation/base-validator.ts +3 -26
- package/src/infrastructure/validation/base-validator.types.ts +32 -0
- package/src/presentation/hooks/generation/index.ts +1 -1
- package/src/presentation/hooks/generation/orchestrator-abort-logs.ts +48 -0
- package/src/presentation/hooks/generation/orchestrator-execution-logs.ts +67 -0
- package/src/presentation/hooks/generation/orchestrator-index.ts +14 -0
- package/src/presentation/hooks/generation/orchestrator-start-logs.ts +65 -0
- package/src/presentation/hooks/generation/orchestrator-state-utils.ts +17 -0
- package/src/presentation/hooks/generation/orchestrator-types.ts +55 -0
- package/src/presentation/hooks/generation/orchestrator-utils-index.ts +29 -0
- package/src/presentation/hooks/generation/orchestrator-utils.ts +25 -0
- package/src/presentation/hooks/generation/useDualImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useVideoGeneration.ts +1 -1
- package/src/shared/hooks/factories/generation-hook-index.ts +12 -0
- package/src/shared/hooks/factories/generation-hook-types.ts +47 -0
- package/src/shared/hooks/factories/generation-hook-utils.ts +94 -0
- package/src/shared/hooks/factories/index.ts +1 -1
- package/src/shared/index.ts +1 -1
- package/src/shared/utils/calculations/aspect-ratio-calculations.ts +30 -0
- package/src/shared/utils/calculations/base64-calculations.ts +26 -0
- package/src/shared/utils/calculations/confidence-calculations.ts +21 -0
- package/src/shared/utils/calculations/cost-calculations-index.ts +43 -0
- package/src/shared/utils/calculations/cost-calculations.ts +25 -0
- package/src/shared/utils/calculations/credit-calculations.ts +37 -0
- package/src/shared/utils/calculations/index.ts +46 -0
- package/src/shared/utils/calculations/math-utilities.ts +32 -0
- package/src/shared/utils/calculations/memory-calculations.ts +33 -0
- package/src/shared/utils/calculations/pagination-calculations.ts +38 -0
- package/src/shared/utils/calculations/percentage-calculations.ts +33 -0
- package/src/shared/utils/calculations/time-calculations.ts +99 -0
- package/src/shared/utils/credit.ts +1 -1
- package/src/shared-kernel/application/hooks/index.ts +8 -0
- package/src/shared-kernel/application/hooks/use-feature-state.ts +106 -0
- package/src/shared-kernel/application/hooks/use-generation-handler.ts +110 -0
- package/src/shared-kernel/base-types/base-callbacks.types.ts +73 -0
- package/src/shared-kernel/base-types/base-feature-state.types.ts +77 -0
- package/src/shared-kernel/base-types/base-generation.types.ts +69 -0
- package/src/shared-kernel/base-types/index.ts +30 -0
- package/src/shared-kernel/domain/base-generation-strategy.ts +146 -0
- package/src/shared-kernel/domain/index.ts +7 -0
- package/src/shared-kernel/index.ts +17 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.ts +126 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.types.ts +33 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.ts +52 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.types.ts +38 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +79 -0
- package/src/shared-kernel/infrastructure/validation/index.ts +70 -0
- package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
- package/src/domains/creations/domain/constants/index.ts +0 -12
- package/src/domains/creations/domain/utils/index.ts +0 -12
- package/src/domains/generation/infrastructure/couple-generation-builder.ts +0 -374
- package/src/domains/image-to-video/domain/index.ts +0 -2
- package/src/domains/image-to-video/infrastructure/index.ts +0 -1
- package/src/domains/image-to-video/presentation/index.ts +0 -5
- package/src/domains/text-to-video/domain/index.ts +0 -1
- package/src/domains/text-to-video/presentation/index.ts +0 -7
- package/src/presentation/hooks/generation/orchestrator.ts +0 -276
- package/src/shared/hooks/factories/createGenerationHook.ts +0 -253
- package/src/shared/utils/calculations.util.ts +0 -366
|
@@ -4,180 +4,11 @@
|
|
|
4
4
|
* Uses design system's useMedia hook for media picking with built-in validation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface PhotoUploadTranslations {
|
|
17
|
-
readonly fileTooLarge: string;
|
|
18
|
-
readonly maxFileSize: string;
|
|
19
|
-
readonly error: string;
|
|
20
|
-
readonly uploadFailed: string;
|
|
21
|
-
readonly permissionDenied?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface PhotoUploadError {
|
|
25
|
-
readonly title: string;
|
|
26
|
-
readonly message: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface UsePhotoUploadStateProps {
|
|
30
|
-
readonly config?: PhotoUploadConfig;
|
|
31
|
-
readonly translations: PhotoUploadTranslations;
|
|
32
|
-
readonly initialImage?: UploadedImage;
|
|
33
|
-
readonly stepId?: string;
|
|
34
|
-
readonly onError?: (error: PhotoUploadError) => void;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface UsePhotoUploadStateReturn {
|
|
38
|
-
readonly image: UploadedImage | null;
|
|
39
|
-
readonly handlePickImage: () => Promise<void>;
|
|
40
|
-
readonly canContinue: boolean;
|
|
41
|
-
readonly clearImage: () => void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const usePhotoUploadState = ({
|
|
45
|
-
config,
|
|
46
|
-
translations,
|
|
47
|
-
initialImage,
|
|
48
|
-
stepId,
|
|
49
|
-
onError,
|
|
50
|
-
}: UsePhotoUploadStateProps): UsePhotoUploadStateReturn => {
|
|
51
|
-
const [image, setImage] = useState<UploadedImage | null>(initialImage || null);
|
|
52
|
-
const { pickImage, isLoading } = useMedia();
|
|
53
|
-
const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
54
|
-
|
|
55
|
-
// Use refs to avoid effect re-runs on callback changes
|
|
56
|
-
const onErrorRef = useRef(onError);
|
|
57
|
-
const translationsRef = useRef(translations);
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
onErrorRef.current = onError;
|
|
61
|
-
translationsRef.current = translations;
|
|
62
|
-
}, [onError, translations]);
|
|
63
|
-
|
|
64
|
-
const maxFileSizeMB = config?.maxFileSizeMB ?? MEDIA_CONSTANTS.MAX_IMAGE_SIZE_MB;
|
|
65
|
-
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
68
|
-
console.log("[usePhotoUploadState] Step changed, resetting image", { stepId, hasInitialImage: !!initialImage });
|
|
69
|
-
}
|
|
70
|
-
setImage(initialImage || null);
|
|
71
|
-
}, [stepId, initialImage]);
|
|
72
|
-
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
// Clear any existing timeout first
|
|
75
|
-
if (timeoutRef.current) {
|
|
76
|
-
clearTimeout(timeoutRef.current);
|
|
77
|
-
timeoutRef.current = undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (isLoading) {
|
|
81
|
-
timeoutRef.current = setTimeout(() => {
|
|
82
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
83
|
-
console.warn("[usePhotoUploadState] Image picker timeout - possible stuck state (DEV warning only)");
|
|
84
|
-
}
|
|
85
|
-
// NOTE: Do NOT call onError here — the picker may still complete successfully.
|
|
86
|
-
// Showing a modal alert while the picker is open blocks the UI.
|
|
87
|
-
}, 30000);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return () => {
|
|
91
|
-
if (timeoutRef.current) {
|
|
92
|
-
clearTimeout(timeoutRef.current);
|
|
93
|
-
timeoutRef.current = undefined;
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
}, [isLoading]);
|
|
97
|
-
|
|
98
|
-
const clearImage = useCallback(() => {
|
|
99
|
-
setImage(null);
|
|
100
|
-
}, []);
|
|
101
|
-
|
|
102
|
-
const handlePickImage = useCallback(async () => {
|
|
103
|
-
try {
|
|
104
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
105
|
-
console.log("[usePhotoUploadState] Starting image pick");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const result = await pickImage({
|
|
109
|
-
allowsEditing: true,
|
|
110
|
-
aspect: [1, 1],
|
|
111
|
-
quality: MediaQuality.MEDIUM,
|
|
112
|
-
maxFileSizeMB,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
if (result.error) {
|
|
116
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
117
|
-
console.log("[usePhotoUploadState] Validation error", result.error);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (result.error === MediaValidationError.FILE_TOO_LARGE) {
|
|
121
|
-
onErrorRef.current?.({
|
|
122
|
-
title: translationsRef.current.fileTooLarge,
|
|
123
|
-
message: translationsRef.current.maxFileSize.replace("{size}", maxFileSizeMB.toString()),
|
|
124
|
-
});
|
|
125
|
-
} else if (result.error === MediaValidationError.PERMISSION_DENIED) {
|
|
126
|
-
onErrorRef.current?.({
|
|
127
|
-
title: translationsRef.current.error,
|
|
128
|
-
message: translationsRef.current.permissionDenied ?? "Permission to access media library is required",
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (result.canceled || !result.assets || result.assets.length === 0) {
|
|
135
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
136
|
-
console.log("[usePhotoUploadState] Image pick canceled");
|
|
137
|
-
}
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const selectedAsset = result.assets[0];
|
|
142
|
-
if (!selectedAsset) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const uploadedImage: UploadedImage = {
|
|
147
|
-
uri: selectedAsset.uri,
|
|
148
|
-
previewUrl: selectedAsset.uri,
|
|
149
|
-
width: selectedAsset.width,
|
|
150
|
-
height: selectedAsset.height,
|
|
151
|
-
fileSize: selectedAsset.fileSize,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
setImage(uploadedImage);
|
|
155
|
-
|
|
156
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
157
|
-
const fileSizeMB = (selectedAsset.fileSize ?? 0) / (1024 * 1024);
|
|
158
|
-
console.log("[usePhotoUploadState] Image selected", {
|
|
159
|
-
width: uploadedImage.width,
|
|
160
|
-
height: uploadedImage.height,
|
|
161
|
-
fileSizeMB: fileSizeMB.toFixed(2),
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
} catch (error) {
|
|
165
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
166
|
-
console.error("[usePhotoUploadState] Error picking image", error);
|
|
167
|
-
}
|
|
168
|
-
onErrorRef.current?.({
|
|
169
|
-
title: translationsRef.current.error,
|
|
170
|
-
message: translationsRef.current.uploadFailed,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}, [pickImage, maxFileSizeMB]);
|
|
174
|
-
|
|
175
|
-
const canContinue = image !== null && !isLoading;
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
image,
|
|
179
|
-
handlePickImage,
|
|
180
|
-
canContinue,
|
|
181
|
-
clearImage,
|
|
182
|
-
};
|
|
183
|
-
};
|
|
7
|
+
export { usePhotoUploadState } from "./photo-upload";
|
|
8
|
+
export type {
|
|
9
|
+
PhotoUploadConfig,
|
|
10
|
+
PhotoUploadTranslations,
|
|
11
|
+
PhotoUploadError,
|
|
12
|
+
UsePhotoUploadStateProps,
|
|
13
|
+
UsePhotoUploadStateReturn,
|
|
14
|
+
} from "./photo-upload";
|
|
@@ -2,298 +2,4 @@
|
|
|
2
2
|
* Video Queue Generation Hook
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { pollQueueStatus } from "./videoQueuePoller";
|
|
8
|
-
import {
|
|
9
|
-
DEFAULT_POLL_INTERVAL_MS,
|
|
10
|
-
DEFAULT_MAX_POLL_TIME_MS,
|
|
11
|
-
} from "../../../../../infrastructure/constants/polling.constants";
|
|
12
|
-
import type { GenerationUrls } from "./generation-result.utils";
|
|
13
|
-
import type {
|
|
14
|
-
UseVideoQueueGenerationProps,
|
|
15
|
-
UseVideoQueueGenerationReturn,
|
|
16
|
-
} from "./use-video-queue-generation.types";
|
|
17
|
-
|
|
18
|
-
export function useVideoQueueGeneration(props: UseVideoQueueGenerationProps): UseVideoQueueGenerationReturn {
|
|
19
|
-
const { userId, scenario, persistence, strategy, creditCost, deductCredits, onSuccess, onError } = props;
|
|
20
|
-
|
|
21
|
-
const creationIdRef = useRef<string | null>(null);
|
|
22
|
-
const requestIdRef = useRef<string | null>(null);
|
|
23
|
-
const modelRef = useRef<string | null>(null);
|
|
24
|
-
const pollingRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
25
|
-
const isGeneratingRef = useRef(false);
|
|
26
|
-
const isPollingRef = useRef(false);
|
|
27
|
-
const consecutiveErrorsRef = useRef(0);
|
|
28
|
-
const pollStartTimeRef = useRef<number | null>(null);
|
|
29
|
-
const [isGenerating, setIsGenerating] = useState(false);
|
|
30
|
-
|
|
31
|
-
const clearPolling = useCallback(() => {
|
|
32
|
-
if (pollingRef.current) {
|
|
33
|
-
clearInterval(pollingRef.current);
|
|
34
|
-
pollingRef.current = null;
|
|
35
|
-
}
|
|
36
|
-
}, []);
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
return () => {
|
|
40
|
-
clearPolling();
|
|
41
|
-
isGeneratingRef.current = false;
|
|
42
|
-
isPollingRef.current = false;
|
|
43
|
-
consecutiveErrorsRef.current = 0;
|
|
44
|
-
pollStartTimeRef.current = null;
|
|
45
|
-
// NOTE: Do NOT null creationIdRef/requestIdRef/modelRef here.
|
|
46
|
-
// In-flight poll callbacks may still resolve after unmount and need
|
|
47
|
-
// these refs to properly save the completed generation to Firestore.
|
|
48
|
-
// They are cleaned up by resetRefs() after handleComplete/handleError.
|
|
49
|
-
setIsGenerating(false);
|
|
50
|
-
};
|
|
51
|
-
}, [clearPolling]);
|
|
52
|
-
|
|
53
|
-
const resetRefs = useCallback(() => {
|
|
54
|
-
clearPolling();
|
|
55
|
-
creationIdRef.current = null;
|
|
56
|
-
requestIdRef.current = null;
|
|
57
|
-
modelRef.current = null;
|
|
58
|
-
isGeneratingRef.current = false;
|
|
59
|
-
isPollingRef.current = false;
|
|
60
|
-
consecutiveErrorsRef.current = 0;
|
|
61
|
-
pollStartTimeRef.current = null;
|
|
62
|
-
setIsGenerating(false);
|
|
63
|
-
}, [clearPolling]);
|
|
64
|
-
|
|
65
|
-
const handleComplete = useCallback(
|
|
66
|
-
async (urls: GenerationUrls) => {
|
|
67
|
-
clearPolling();
|
|
68
|
-
|
|
69
|
-
const creationId = creationIdRef.current;
|
|
70
|
-
const uri = (urls.videoUrl || urls.imageUrl) ?? "";
|
|
71
|
-
|
|
72
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
73
|
-
console.log("[VideoQueue] ✅ handleComplete called", {
|
|
74
|
-
creationId,
|
|
75
|
-
userId,
|
|
76
|
-
hasVideoUrl: !!urls.videoUrl,
|
|
77
|
-
hasImageUrl: !!urls.imageUrl,
|
|
78
|
-
hasOnSuccess: !!onSuccess
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!creationId || !userId || !uri || uri.trim() === "") {
|
|
83
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
84
|
-
console.error("[VideoQueue] ❌ Invalid completion data:", { creationId, userId, uri });
|
|
85
|
-
}
|
|
86
|
-
resetRefs();
|
|
87
|
-
onError?.("Invalid completion data - no valid URL received");
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
let persistenceSucceeded = true;
|
|
92
|
-
if (creationId && userId) {
|
|
93
|
-
try {
|
|
94
|
-
await persistence.updateToCompleted(userId, creationId, {
|
|
95
|
-
uri,
|
|
96
|
-
imageUrl: urls.imageUrl,
|
|
97
|
-
videoUrl: urls.videoUrl,
|
|
98
|
-
thumbnailUrl: urls.thumbnailUrl,
|
|
99
|
-
generationStartedAt: pollStartTimeRef.current ?? undefined,
|
|
100
|
-
});
|
|
101
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
102
|
-
console.log("[VideoQueue] ✅ Updated completion status in Firestore");
|
|
103
|
-
}
|
|
104
|
-
} catch (error) {
|
|
105
|
-
persistenceSucceeded = false;
|
|
106
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
107
|
-
console.error("[VideoQueue] ❌ Failed to update completion status:", error);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
resetRefs();
|
|
113
|
-
|
|
114
|
-
// Deduct credits after successful generation
|
|
115
|
-
if (deductCredits && creditCost) {
|
|
116
|
-
await deductCredits(creditCost).catch((err) => {
|
|
117
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
118
|
-
console.error("[VideoQueue] deductCredits error:", err);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
124
|
-
console.log("[VideoQueue] 🎯 Calling onSuccess callback now...", { persistenceSucceeded });
|
|
125
|
-
}
|
|
126
|
-
onSuccess?.(urls);
|
|
127
|
-
|
|
128
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
129
|
-
console.log("[VideoQueue] ✅ onSuccess callback completed");
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
[userId, persistence, deductCredits, creditCost, onSuccess, onError, resetRefs, clearPolling],
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
const handleError = useCallback(
|
|
136
|
-
async (errorMsg: string) => {
|
|
137
|
-
clearPolling();
|
|
138
|
-
const creationId = creationIdRef.current;
|
|
139
|
-
if (creationId && userId) {
|
|
140
|
-
try {
|
|
141
|
-
await persistence.updateToFailed(userId, creationId, errorMsg);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
144
|
-
console.error("[VideoQueue] Failed to update error status:", error);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
resetRefs();
|
|
149
|
-
onError?.(errorMsg);
|
|
150
|
-
},
|
|
151
|
-
[userId, persistence, onError, resetRefs, clearPolling],
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
// Use a ref to hold the latest handleComplete/handleError to avoid stale closures
|
|
155
|
-
// in the setInterval callback
|
|
156
|
-
const handleCompleteRef = useRef(handleComplete);
|
|
157
|
-
const handleErrorRef = useRef(handleError);
|
|
158
|
-
useEffect(() => { handleCompleteRef.current = handleComplete; }, [handleComplete]);
|
|
159
|
-
useEffect(() => { handleErrorRef.current = handleError; }, [handleError]);
|
|
160
|
-
|
|
161
|
-
const pollStatus = useCallback(async () => {
|
|
162
|
-
const requestId = requestIdRef.current;
|
|
163
|
-
const model = modelRef.current;
|
|
164
|
-
if (!requestId || !model) return;
|
|
165
|
-
|
|
166
|
-
// Check max poll time
|
|
167
|
-
if (pollStartTimeRef.current !== null) {
|
|
168
|
-
const elapsed = Date.now() - pollStartTimeRef.current;
|
|
169
|
-
if (elapsed >= DEFAULT_MAX_POLL_TIME_MS) {
|
|
170
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
171
|
-
console.warn("[VideoQueue] ⏰ Max poll time exceeded, aborting");
|
|
172
|
-
}
|
|
173
|
-
await handleErrorRef.current("Generation timed out. Please try again.");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
try {
|
|
179
|
-
await pollQueueStatus({
|
|
180
|
-
requestId,
|
|
181
|
-
model,
|
|
182
|
-
isPollingRef,
|
|
183
|
-
pollingRef,
|
|
184
|
-
consecutiveErrorsRef,
|
|
185
|
-
onComplete: handleCompleteRef.current,
|
|
186
|
-
onError: handleErrorRef.current,
|
|
187
|
-
});
|
|
188
|
-
} catch (error) {
|
|
189
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
190
|
-
console.error("[VideoQueue] Unexpected poll error:", error);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}, []);
|
|
194
|
-
|
|
195
|
-
// Keep a stable ref to pollStatus for the setInterval closure
|
|
196
|
-
const pollStatusRef = useRef(pollStatus);
|
|
197
|
-
useEffect(() => { pollStatusRef.current = pollStatus; }, [pollStatus]);
|
|
198
|
-
|
|
199
|
-
const startGeneration = useCallback(
|
|
200
|
-
async (input: unknown, prompt: string) => {
|
|
201
|
-
if (!strategy.submitToQueue) {
|
|
202
|
-
onError?.("Queue submission not available");
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
if (isGeneratingRef.current) return;
|
|
206
|
-
|
|
207
|
-
isGeneratingRef.current = true;
|
|
208
|
-
setIsGenerating(true);
|
|
209
|
-
|
|
210
|
-
let creationId: string | null = null;
|
|
211
|
-
if (userId && prompt) {
|
|
212
|
-
try {
|
|
213
|
-
const inputData = input as Record<string, unknown>;
|
|
214
|
-
const duration = typeof inputData?.duration === "number" ? inputData.duration : undefined;
|
|
215
|
-
const resolution = typeof inputData?.resolution === "string" ? inputData.resolution : undefined;
|
|
216
|
-
const aspectRatio = typeof inputData?.aspectRatio === "string" ? inputData.aspectRatio : undefined;
|
|
217
|
-
|
|
218
|
-
const result = await persistence.saveAsProcessing(userId, {
|
|
219
|
-
scenarioId: scenario.id,
|
|
220
|
-
scenarioTitle: scenario.title || scenario.id,
|
|
221
|
-
prompt,
|
|
222
|
-
duration,
|
|
223
|
-
resolution,
|
|
224
|
-
creditCost,
|
|
225
|
-
aspectRatio,
|
|
226
|
-
provider: "fal",
|
|
227
|
-
outputType: scenario.outputType,
|
|
228
|
-
});
|
|
229
|
-
creationId = result.creationId;
|
|
230
|
-
creationIdRef.current = creationId;
|
|
231
|
-
// Record the actual DB-level start time for accurate durationMs
|
|
232
|
-
pollStartTimeRef.current = result.startedAt.getTime();
|
|
233
|
-
} catch (error) {
|
|
234
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
235
|
-
console.error("[VideoQueue] Failed to save processing creation:", error);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
let queueResult;
|
|
241
|
-
try {
|
|
242
|
-
queueResult = await strategy.submitToQueue(input);
|
|
243
|
-
} catch (error) {
|
|
244
|
-
if (creationId && userId) {
|
|
245
|
-
try {
|
|
246
|
-
await persistence.updateToFailed(userId, creationId, error instanceof Error ? error.message : "Queue submission failed");
|
|
247
|
-
} catch (persistError) {
|
|
248
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
249
|
-
console.error("[VideoQueue] Failed to persist submission error:", persistError);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
isGeneratingRef.current = false;
|
|
254
|
-
setIsGenerating(false);
|
|
255
|
-
onError?.(error instanceof Error ? error.message : "Queue submission failed");
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (!queueResult.success || !queueResult.requestId || !queueResult.model) {
|
|
260
|
-
if (creationId && userId) {
|
|
261
|
-
try {
|
|
262
|
-
await persistence.updateToFailed(userId, creationId, queueResult.error || "Queue submission failed");
|
|
263
|
-
} catch (persistError) {
|
|
264
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
265
|
-
console.error("[VideoQueue] Failed to persist queue failure:", persistError);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
isGeneratingRef.current = false;
|
|
270
|
-
setIsGenerating(false);
|
|
271
|
-
onError?.(queueResult.error || "Queue submission failed");
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
requestIdRef.current = queueResult.requestId;
|
|
276
|
-
modelRef.current = queueResult.model;
|
|
277
|
-
|
|
278
|
-
if (creationId && userId && queueResult.requestId && queueResult.model) {
|
|
279
|
-
try {
|
|
280
|
-
await persistence.updateRequestId(userId, creationId, queueResult.requestId, queueResult.model);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
283
|
-
console.error("[VideoQueue] Failed to update request ID:", error);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Start polling: use DB-level startedAt if available, otherwise fallback to now
|
|
289
|
-
if (pollStartTimeRef.current === null) {
|
|
290
|
-
pollStartTimeRef.current = Date.now();
|
|
291
|
-
}
|
|
292
|
-
pollingRef.current = setInterval(() => void pollStatusRef.current(), DEFAULT_POLL_INTERVAL_MS);
|
|
293
|
-
void pollStatusRef.current();
|
|
294
|
-
},
|
|
295
|
-
[userId, scenario, persistence, strategy, creditCost, onError],
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
return { isGenerating, startGeneration };
|
|
299
|
-
}
|
|
5
|
+
export { useVideoQueueGeneration } from "./video-queue";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { useEffect, useReducer, useMemo, useRef } from "react";
|
|
7
7
|
import { createWizardStrategy } from "../../infrastructure/strategies";
|
|
8
8
|
import { createCreationPersistence } from "../../infrastructure/utils/creation-persistence.util";
|
|
9
|
-
import { useVideoQueueGeneration } from "./
|
|
9
|
+
import { useVideoQueueGeneration } from "./video-queue-index";
|
|
10
10
|
import { usePhotoBlockingGeneration } from "./usePhotoBlockingGeneration";
|
|
11
11
|
import { generationReducer, INITIAL_STATE } from "./generationStateMachine";
|
|
12
12
|
import { executeWizardGeneration } from "./generationExecutor";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video Queue Generation Hook
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import type {
|
|
7
|
+
UseVideoQueueGenerationProps,
|
|
8
|
+
UseVideoQueueGenerationReturn,
|
|
9
|
+
} from "../use-video-queue-generation.types";
|
|
10
|
+
import { useVideoQueueGenerationRefs, useVideoQueueGenerationState } from "./useVideoQueueGenerationRefs";
|
|
11
|
+
import { useCompletionHandler, useErrorHandler } from "./useVideoQueueGenerationCallbacks";
|
|
12
|
+
import { usePollStatus, useCallbackRefs } from "./useVideoQueueGenerationPolling";
|
|
13
|
+
import { useStartGeneration } from "./useVideoQueueGenerationStart";
|
|
14
|
+
|
|
15
|
+
export function useVideoQueueGeneration(props: UseVideoQueueGenerationProps): UseVideoQueueGenerationReturn {
|
|
16
|
+
const refs = useVideoQueueGenerationRefs();
|
|
17
|
+
const state = useVideoQueueGenerationState();
|
|
18
|
+
|
|
19
|
+
const clearPolling = (() => {
|
|
20
|
+
const { pollingRef } = refs;
|
|
21
|
+
return () => {
|
|
22
|
+
if (pollingRef.current) {
|
|
23
|
+
clearInterval(pollingRef.current);
|
|
24
|
+
pollingRef.current = null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
return () => {
|
|
31
|
+
clearPolling();
|
|
32
|
+
refs.isGeneratingRef.current = false;
|
|
33
|
+
refs.isPollingRef.current = false;
|
|
34
|
+
refs.consecutiveErrorsRef.current = 0;
|
|
35
|
+
refs.pollStartTimeRef.current = null;
|
|
36
|
+
// NOTE: Do NOT null creationIdRef/requestIdRef/modelRef here.
|
|
37
|
+
// In-flight poll callbacks may still resolve after unmount and need
|
|
38
|
+
// these refs to properly save the completed generation to Firestore.
|
|
39
|
+
// They are cleaned up by resetRefs() after handleComplete/handleError.
|
|
40
|
+
state.setIsGenerating(false);
|
|
41
|
+
};
|
|
42
|
+
}, [clearPolling, refs, state]);
|
|
43
|
+
|
|
44
|
+
const resetRefs = (() => {
|
|
45
|
+
const {
|
|
46
|
+
creationIdRef,
|
|
47
|
+
requestIdRef,
|
|
48
|
+
modelRef,
|
|
49
|
+
isGeneratingRef,
|
|
50
|
+
isPollingRef,
|
|
51
|
+
consecutiveErrorsRef,
|
|
52
|
+
pollStartTimeRef,
|
|
53
|
+
} = refs;
|
|
54
|
+
const { setIsGenerating } = state;
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
creationIdRef.current = null;
|
|
58
|
+
requestIdRef.current = null;
|
|
59
|
+
modelRef.current = null;
|
|
60
|
+
isGeneratingRef.current = false;
|
|
61
|
+
isPollingRef.current = false;
|
|
62
|
+
consecutiveErrorsRef.current = 0;
|
|
63
|
+
pollStartTimeRef.current = null;
|
|
64
|
+
setIsGenerating(false);
|
|
65
|
+
};
|
|
66
|
+
})();
|
|
67
|
+
|
|
68
|
+
const handleComplete = useCompletionHandler(props, refs, state, clearPolling, resetRefs);
|
|
69
|
+
const handleError = useErrorHandler(props, refs, clearPolling, resetRefs);
|
|
70
|
+
const pollStatus = usePollStatus(refs);
|
|
71
|
+
const startGeneration = useStartGeneration(props, refs, state, clearPolling);
|
|
72
|
+
|
|
73
|
+
// Sync callback refs
|
|
74
|
+
useCallbackRefs(handleComplete, handleError, pollStatus, refs);
|
|
75
|
+
|
|
76
|
+
return { isGenerating: state.isGenerating, startGeneration };
|
|
77
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video Queue Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface VideoQueueUtils {
|
|
6
|
+
isQueueFull: () => boolean;
|
|
7
|
+
getQueueSize: () => number;
|
|
8
|
+
clearQueue: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createVideoQueueUtils(): VideoQueueUtils {
|
|
12
|
+
return {
|
|
13
|
+
isQueueFull: () => false,
|
|
14
|
+
getQueueSize: () => 0,
|
|
15
|
+
clearQueue: () => {},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
import type { VideoQueueRefs } from "./useVideoQueueGenerationRefs";
|
|
20
|
+
import type { VideoQueueState } from "./useVideoQueueGenerationRefs";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a clear polling function
|
|
24
|
+
*/
|
|
25
|
+
export function createClearPolling(refs: VideoQueueRefs): () => void {
|
|
26
|
+
const { pollingRef } = refs;
|
|
27
|
+
return () => {
|
|
28
|
+
if (pollingRef.current) {
|
|
29
|
+
clearInterval(pollingRef.current);
|
|
30
|
+
pollingRef.current = null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a reset refs function
|
|
37
|
+
*/
|
|
38
|
+
export function createResetRefs(
|
|
39
|
+
refs: VideoQueueRefs,
|
|
40
|
+
state: VideoQueueState
|
|
41
|
+
): () => void {
|
|
42
|
+
const {
|
|
43
|
+
creationIdRef,
|
|
44
|
+
requestIdRef,
|
|
45
|
+
modelRef,
|
|
46
|
+
isGeneratingRef,
|
|
47
|
+
isPollingRef,
|
|
48
|
+
consecutiveErrorsRef,
|
|
49
|
+
pollStartTimeRef,
|
|
50
|
+
} = refs;
|
|
51
|
+
const { setIsGenerating } = state;
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
creationIdRef.current = null;
|
|
55
|
+
requestIdRef.current = null;
|
|
56
|
+
modelRef.current = null;
|
|
57
|
+
isGeneratingRef.current = false;
|
|
58
|
+
isPollingRef.current = false;
|
|
59
|
+
consecutiveErrorsRef.current = 0;
|
|
60
|
+
pollStartTimeRef.current = null;
|
|
61
|
+
setIsGenerating(false);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Log completion event
|
|
67
|
+
*/
|
|
68
|
+
export function logCompletion(
|
|
69
|
+
creationId: string | null,
|
|
70
|
+
userId: string | undefined,
|
|
71
|
+
urls: { videoUrl?: string; imageUrl?: string },
|
|
72
|
+
hasCallback: boolean
|
|
73
|
+
): void {
|
|
74
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
75
|
+
console.log("[VideoQueue] ✅ Generation completed", {
|
|
76
|
+
creationId,
|
|
77
|
+
userId,
|
|
78
|
+
hasVideoUrl: !!urls.videoUrl,
|
|
79
|
+
hasImageUrl: !!urls.imageUrl,
|
|
80
|
+
hasCallback,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log error event
|
|
87
|
+
*/
|
|
88
|
+
export function logError(message: string, data?: Record<string, unknown>): void {
|
|
89
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
90
|
+
console.error("[VideoQueue] ❌ Error:", message, data);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Validate completion data
|
|
96
|
+
*/
|
|
97
|
+
export function validateCompletionData(
|
|
98
|
+
creationId: string | null,
|
|
99
|
+
userId: string | undefined,
|
|
100
|
+
uri: string
|
|
101
|
+
): boolean {
|
|
102
|
+
return !!(creationId && userId && uri);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract input metadata for generation
|
|
107
|
+
*/
|
|
108
|
+
export function extractInputMetadata(params: {
|
|
109
|
+
readonly model: string;
|
|
110
|
+
readonly prompt: string;
|
|
111
|
+
readonly imageUrls?: string[];
|
|
112
|
+
}): {
|
|
113
|
+
readonly model: string;
|
|
114
|
+
readonly prompt: string;
|
|
115
|
+
readonly imageUrls: string[];
|
|
116
|
+
} {
|
|
117
|
+
return {
|
|
118
|
+
model: params.model,
|
|
119
|
+
prompt: params.prompt,
|
|
120
|
+
imageUrls: params.imageUrls || [],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|