@umituz/react-native-ai-generation-content 1.61.62 → 1.61.64
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/core/index.ts +1 -1
- package/src/domain/entities/index.ts +1 -1
- package/src/domain/interfaces/ai-provider.interface.ts +1 -1
- package/src/domain/interfaces/index.ts +1 -1
- package/src/domains/background/domain/entities/index.ts +1 -0
- package/src/domains/background/domain/interfaces/index.ts +1 -0
- package/src/{domain → domains/background/domain}/interfaces/provider-job-manager.interface.ts +1 -1
- package/src/domains/background/domain/types/background-generation.types.ts +28 -0
- package/src/domains/background/infrastructure/executors/backgroundJobExecutor.ts +105 -0
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller-factory.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.service.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.types.ts +2 -2
- package/src/{infrastructure → domains/background/infrastructure}/utils/polling-interval.util.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/utils/status-checker.util.ts +1 -1
- package/src/domains/background/presentation/hooks/use-background-generation.ts +97 -0
- package/src/domains/creations/presentation/components/PendingJobsSection.tsx +1 -1
- package/src/domains/generation/wizard/presentation/hooks/generationExecutor.ts +65 -0
- package/src/domains/generation/wizard/presentation/hooks/generationStateMachine.ts +35 -0
- package/src/domains/generation/wizard/presentation/hooks/typeGuards.ts +13 -0
- package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +34 -71
- package/src/domains/generation/wizard/presentation/hooks/useWizardFlowHandlers.ts +6 -84
- package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +19 -131
- package/src/domains/generation/wizard/presentation/hooks/videoQueuePoller.ts +59 -0
- package/src/domains/image-to-video/presentation/hooks/imageToVideoStrategy.ts +77 -0
- package/src/domains/image-to-video/presentation/hooks/useImageToVideoFeature.ts +102 -0
- package/src/domains/scenarios/presentation/containers/CategoryNavigationContainer.tsx +4 -80
- package/src/{features → domains}/text-to-image/infrastructure/services/text-to-image-executor.ts +2 -82
- package/src/domains/text-to-image/infrastructure/utils/imageResultExtractor.ts +58 -0
- package/src/domains/text-to-video/presentation/hooks/textToVideoStrategy.ts +75 -0
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoFeature.ts +120 -0
- package/src/exports/features.ts +12 -12
- package/src/presentation/components/PendingJobCard.tsx +1 -1
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +0 -186
- package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +0 -186
- package/src/presentation/hooks/use-background-generation.ts +0 -185
- /package/src/{domain → domains/background/domain}/entities/job.types.ts +0 -0
- /package/src/{infrastructure → domains/background/infrastructure}/utils/result-validator.util.ts +0 -0
- /package/src/{presentation → domains/background/presentation}/hooks/use-pending-jobs.ts +0 -0
- /package/src/{features → domains}/image-to-video/README.md +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/animation.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/duration.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/form.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/music.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/animation.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/duration.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/form.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/image-to-video.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/music.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/services/image-to-video-executor.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/AddMoreCard.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/AnimationStyleSelector.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/DurationSelector.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/EmptyGridState.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/GridImageItem.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/MusicMoodSelector.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/image-to-video-feature.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useFormState.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useGeneration.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useImageToVideoForm.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/screens/ImageToVideoWizardFlow.tsx +0 -0
- /package/src/{features → domains}/shared/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/components/AutoSkipPreview.tsx +0 -0
- /package/src/{features → domains}/shared/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/utils/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/utils/wizard-flow.utils.ts +0 -0
- /package/src/{features → domains}/text-to-image/README.md +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/options.constants.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/styles.constants.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/form.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/text-to-image.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useFormState.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useGeneration.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useTextToImageForm.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.tsx +0 -0
- /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/README.md +0 -0
- /package/src/{features → domains}/text-to-video/domain/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/callback.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/component.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/request.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/state.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/services/text-to-video-executor.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/FrameSelector.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/GenerationTabs.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/HeroSection.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/HintCarousel.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/OptionsPanel.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/hooks/useTextToVideoForm.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/screens/TextToVideoWizardFlow.tsx +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Main Category → Sub Category → Scenario List
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { useState, useCallback
|
|
7
|
+
import React, { useState, useCallback } from "react";
|
|
8
8
|
import type { ScenarioData } from "../../domain/scenario.types";
|
|
9
9
|
import type { MainCategory, SubCategory } from "../../domain/category.types";
|
|
10
10
|
import { MainCategoryScreen } from "../screens/MainCategoryScreen";
|
|
@@ -48,88 +48,34 @@ export const CategoryNavigationContainer: React.FC<
|
|
|
48
48
|
const [selectedMainCategoryId, setSelectedMainCategoryId] = useState<string | null>(null);
|
|
49
49
|
const [selectedSubCategoryId, setSelectedSubCategoryId] = useState<string | null>(null);
|
|
50
50
|
|
|
51
|
-
// Debug: Initial mount
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
54
|
-
console.log("[CategoryNavigationContainer] Mounted", {
|
|
55
|
-
mainCategoriesCount: mainCategories.length,
|
|
56
|
-
subCategoriesCount: subCategories.length,
|
|
57
|
-
scenariosCount: scenarios.length,
|
|
58
|
-
currentStep,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}, []);
|
|
62
|
-
|
|
63
|
-
// Debug: Step changes
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
66
|
-
console.log("[CategoryNavigationContainer] Step changed", {
|
|
67
|
-
currentStep,
|
|
68
|
-
selectedMainCategoryId,
|
|
69
|
-
selectedSubCategoryId,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}, [currentStep, selectedMainCategoryId, selectedSubCategoryId]);
|
|
73
|
-
|
|
74
51
|
const handleSelectMainCategory = useCallback((categoryId: string) => {
|
|
75
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
76
|
-
console.log("[CategoryNavigationContainer] Main category selected", {
|
|
77
|
-
categoryId,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
52
|
setSelectedMainCategoryId(categoryId);
|
|
81
53
|
setCurrentStep("sub_category");
|
|
82
|
-
|
|
83
|
-
onSelectMainCategory(categoryId);
|
|
84
|
-
}
|
|
54
|
+
onSelectMainCategory?.(categoryId);
|
|
85
55
|
}, [onSelectMainCategory]);
|
|
86
56
|
|
|
87
57
|
const handleSelectSubCategory = useCallback((subCategoryId: string) => {
|
|
88
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
89
|
-
console.log("[CategoryNavigationContainer] Sub category selected", {
|
|
90
|
-
subCategoryId,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
58
|
setSelectedSubCategoryId(subCategoryId);
|
|
94
59
|
setCurrentStep("scenario_list");
|
|
95
|
-
|
|
96
|
-
onSelectSubCategory(subCategoryId);
|
|
97
|
-
}
|
|
60
|
+
onSelectSubCategory?.(subCategoryId);
|
|
98
61
|
}, [onSelectSubCategory]);
|
|
99
62
|
|
|
100
63
|
const handleBackFromSubCategory = useCallback(() => {
|
|
101
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
102
|
-
console.log("[CategoryNavigationContainer] Back from sub category");
|
|
103
|
-
}
|
|
104
64
|
setSelectedMainCategoryId(null);
|
|
105
65
|
setCurrentStep("main_category");
|
|
106
66
|
}, []);
|
|
107
67
|
|
|
108
68
|
const handleBackFromScenarioList = useCallback(() => {
|
|
109
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
110
|
-
console.log("[CategoryNavigationContainer] Back from scenario list");
|
|
111
|
-
}
|
|
112
69
|
setSelectedSubCategoryId(null);
|
|
113
70
|
setCurrentStep("sub_category");
|
|
114
71
|
}, []);
|
|
115
72
|
|
|
116
|
-
const handleBackFromMainCategory = useCallback(() => {
|
|
117
|
-
if (onBack) {
|
|
118
|
-
onBack();
|
|
119
|
-
}
|
|
120
|
-
}, [onBack]);
|
|
121
|
-
|
|
122
73
|
if (currentStep === "main_category") {
|
|
123
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
124
|
-
console.log("[CategoryNavigationContainer] Rendering MainCategoryScreen", {
|
|
125
|
-
mainCategoriesCount: mainCategories.length,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
74
|
return (
|
|
129
75
|
<MainCategoryScreen
|
|
130
76
|
mainCategories={mainCategories}
|
|
131
77
|
onSelectCategory={handleSelectMainCategory}
|
|
132
|
-
onBack={onBack
|
|
78
|
+
onBack={onBack}
|
|
133
79
|
t={t}
|
|
134
80
|
headerTitle={headerTitle}
|
|
135
81
|
headerDescription={headerDescription}
|
|
@@ -139,14 +85,6 @@ export const CategoryNavigationContainer: React.FC<
|
|
|
139
85
|
|
|
140
86
|
if (currentStep === "sub_category" && selectedMainCategoryId) {
|
|
141
87
|
const selectedMainCategory = mainCategories.find(c => c.id === selectedMainCategoryId);
|
|
142
|
-
|
|
143
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
144
|
-
console.log("[CategoryNavigationContainer] Rendering SubCategoryScreen", {
|
|
145
|
-
selectedMainCategoryId,
|
|
146
|
-
subCategoriesCount: subCategories.length,
|
|
147
|
-
mainCategoryTitle: selectedMainCategory?.titleKey,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
88
|
return (
|
|
151
89
|
<SubCategoryScreen
|
|
152
90
|
mainCategoryId={selectedMainCategoryId}
|
|
@@ -161,12 +99,6 @@ export const CategoryNavigationContainer: React.FC<
|
|
|
161
99
|
}
|
|
162
100
|
|
|
163
101
|
if (currentStep === "scenario_list" && selectedSubCategoryId) {
|
|
164
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
165
|
-
console.log("[CategoryNavigationContainer] Rendering HierarchicalScenarioListScreen", {
|
|
166
|
-
selectedSubCategoryId,
|
|
167
|
-
scenariosCount: scenarios.length,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
102
|
return (
|
|
171
103
|
<HierarchicalScenarioListScreen
|
|
172
104
|
subCategoryId={selectedSubCategoryId}
|
|
@@ -181,13 +113,5 @@ export const CategoryNavigationContainer: React.FC<
|
|
|
181
113
|
);
|
|
182
114
|
}
|
|
183
115
|
|
|
184
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
185
|
-
console.log("[CategoryNavigationContainer] Rendering NULL - no matching condition", {
|
|
186
|
-
currentStep,
|
|
187
|
-
selectedMainCategoryId,
|
|
188
|
-
selectedSubCategoryId,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
116
|
return null;
|
|
193
117
|
};
|
package/src/{features → domains}/text-to-image/infrastructure/services/text-to-image-executor.ts
RENAMED
|
@@ -12,10 +12,8 @@ import type {
|
|
|
12
12
|
TextToImageInputBuilder,
|
|
13
13
|
TextToImageResultExtractor,
|
|
14
14
|
} from "../../domain/types";
|
|
15
|
+
import { defaultExtractImageResult, type ExtractedImageResult } from "../utils/imageResultExtractor";
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
* Options for text-to-image execution
|
|
18
|
-
*/
|
|
19
17
|
export interface ExecuteTextToImageOptions {
|
|
20
18
|
model: string;
|
|
21
19
|
buildInput: TextToImageInputBuilder;
|
|
@@ -23,84 +21,6 @@ export interface ExecuteTextToImageOptions {
|
|
|
23
21
|
onProgress?: (progress: number) => void;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
/**
|
|
27
|
-
* Extracted result structure from provider response
|
|
28
|
-
*/
|
|
29
|
-
interface ExtractedImageResult {
|
|
30
|
-
imageUrl?: string;
|
|
31
|
-
imageUrls?: string[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Extract images from provider response object
|
|
36
|
-
*/
|
|
37
|
-
function extractImagesFromObject(
|
|
38
|
-
obj: Record<string, unknown>,
|
|
39
|
-
): string[] | null {
|
|
40
|
-
// Direct images array
|
|
41
|
-
if (Array.isArray(obj.images)) {
|
|
42
|
-
const urls = obj.images
|
|
43
|
-
.map((img) => {
|
|
44
|
-
if (typeof img === "string") return img;
|
|
45
|
-
if (img && typeof img === "object" && "url" in img) {
|
|
46
|
-
return (img as { url: string }).url;
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
})
|
|
50
|
-
.filter((url): url is string => url !== null);
|
|
51
|
-
|
|
52
|
-
if (urls.length > 0) return urls;
|
|
53
|
-
}
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Default extractor for text-to-image results
|
|
59
|
-
*/
|
|
60
|
-
function defaultExtractResult(
|
|
61
|
-
result: unknown,
|
|
62
|
-
): ExtractedImageResult | undefined {
|
|
63
|
-
if (typeof result !== "object" || result === null) {
|
|
64
|
-
return undefined;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const r = result as Record<string, unknown>;
|
|
68
|
-
|
|
69
|
-
// Check nested 'data' object first (common API wrapper format)
|
|
70
|
-
if (r.data && typeof r.data === "object") {
|
|
71
|
-
const dataObj = r.data as Record<string, unknown>;
|
|
72
|
-
const urls = extractImagesFromObject(dataObj);
|
|
73
|
-
if (urls) {
|
|
74
|
-
return { imageUrl: urls[0], imageUrls: urls };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check direct 'images' array
|
|
79
|
-
const directUrls = extractImagesFromObject(r);
|
|
80
|
-
if (directUrls) {
|
|
81
|
-
return { imageUrl: directUrls[0], imageUrls: directUrls };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Check for imageUrl (data URL)
|
|
85
|
-
if (typeof r.imageUrl === "string") {
|
|
86
|
-
return { imageUrl: r.imageUrl, imageUrls: [r.imageUrl] };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Fallback: construct data URL from imageBase64
|
|
90
|
-
if (typeof r.imageBase64 === "string") {
|
|
91
|
-
const mimeType = typeof r.mimeType === "string" ? r.mimeType : "image/png";
|
|
92
|
-
const dataUrl = `data:${mimeType};base64,${r.imageBase64}`;
|
|
93
|
-
return { imageUrl: dataUrl, imageUrls: [dataUrl] };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Check for 'image' field
|
|
97
|
-
if (typeof r.image === "string") {
|
|
98
|
-
return { imageUrl: r.image, imageUrls: [r.image] };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return undefined;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
24
|
/**
|
|
105
25
|
* Text-to-Image Executor using Template Method pattern
|
|
106
26
|
* Eliminates code duplication through BaseExecutor
|
|
@@ -151,7 +71,7 @@ class TextToImageExecutor extends BaseExecutor<
|
|
|
151
71
|
protected getDefaultExtractor(): (
|
|
152
72
|
result: unknown,
|
|
153
73
|
) => ExtractedImageResult | undefined {
|
|
154
|
-
return
|
|
74
|
+
return defaultExtractImageResult;
|
|
155
75
|
}
|
|
156
76
|
}
|
|
157
77
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface ExtractedImageResult {
|
|
2
|
+
imageUrl?: string;
|
|
3
|
+
imageUrls?: string[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function extractImagesFromObject(obj: Record<string, unknown>): string[] | null {
|
|
7
|
+
if (Array.isArray(obj.images)) {
|
|
8
|
+
const urls = obj.images
|
|
9
|
+
.map((img) => {
|
|
10
|
+
if (typeof img === "string") return img;
|
|
11
|
+
if (img && typeof img === "object" && "url" in img) {
|
|
12
|
+
return (img as { url: string }).url;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
})
|
|
16
|
+
.filter((url): url is string => url !== null);
|
|
17
|
+
|
|
18
|
+
if (urls.length > 0) return urls;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function defaultExtractImageResult(result: unknown): ExtractedImageResult | undefined {
|
|
24
|
+
if (typeof result !== "object" || result === null) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const r = result as Record<string, unknown>;
|
|
29
|
+
|
|
30
|
+
if (r.data && typeof r.data === "object") {
|
|
31
|
+
const dataObj = r.data as Record<string, unknown>;
|
|
32
|
+
const urls = extractImagesFromObject(dataObj);
|
|
33
|
+
if (urls) {
|
|
34
|
+
return { imageUrl: urls[0], imageUrls: urls };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const directUrls = extractImagesFromObject(r);
|
|
39
|
+
if (directUrls) {
|
|
40
|
+
return { imageUrl: directUrls[0], imageUrls: directUrls };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof r.imageUrl === "string") {
|
|
44
|
+
return { imageUrl: r.imageUrl, imageUrls: [r.imageUrl] };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof r.imageBase64 === "string") {
|
|
48
|
+
const mimeType = typeof r.mimeType === "string" ? r.mimeType : "image/png";
|
|
49
|
+
const dataUrl = `data:${mimeType};base64,${r.imageBase64}`;
|
|
50
|
+
return { imageUrl: dataUrl, imageUrls: [dataUrl] };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof r.image === "string") {
|
|
54
|
+
return { imageUrl: r.image, imageUrls: [r.image] };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { executeTextToVideo } from "../../infrastructure/services";
|
|
2
|
+
import type { GenerationStrategy } from "../../../../presentation/hooks/generation";
|
|
3
|
+
import type {
|
|
4
|
+
TextToVideoConfig,
|
|
5
|
+
TextToVideoCallbacks,
|
|
6
|
+
TextToVideoResult,
|
|
7
|
+
TextToVideoOptions,
|
|
8
|
+
TextToVideoInputBuilder,
|
|
9
|
+
TextToVideoResultExtractor,
|
|
10
|
+
} from "../../domain/types";
|
|
11
|
+
|
|
12
|
+
interface VideoGenerationInput {
|
|
13
|
+
prompt: string;
|
|
14
|
+
options?: TextToVideoOptions;
|
|
15
|
+
creationId: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CreateStrategyParams {
|
|
19
|
+
config: TextToVideoConfig;
|
|
20
|
+
callbacks: TextToVideoCallbacks;
|
|
21
|
+
buildInput: TextToVideoInputBuilder;
|
|
22
|
+
extractResult?: TextToVideoResultExtractor;
|
|
23
|
+
userId: string;
|
|
24
|
+
currentPrompt: string;
|
|
25
|
+
creationIdRef: React.MutableRefObject<string>;
|
|
26
|
+
updateState: (videoUrl: string | null, thumbnailUrl: string | null) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const createTextToVideoStrategy = (
|
|
30
|
+
params: CreateStrategyParams,
|
|
31
|
+
): GenerationStrategy<VideoGenerationInput, TextToVideoResult> => {
|
|
32
|
+
const { config, callbacks, buildInput, extractResult, userId, currentPrompt, creationIdRef, updateState } = params;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
execute: async (input) => {
|
|
36
|
+
creationIdRef.current = input.creationId;
|
|
37
|
+
|
|
38
|
+
callbacks.onGenerationStart?.({
|
|
39
|
+
creationId: input.creationId,
|
|
40
|
+
type: "text-to-video",
|
|
41
|
+
prompt: input.prompt,
|
|
42
|
+
metadata: input.options as Record<string, unknown> | undefined,
|
|
43
|
+
}).catch(() => {});
|
|
44
|
+
|
|
45
|
+
const result = await executeTextToVideo(
|
|
46
|
+
{ prompt: input.prompt, userId, options: input.options },
|
|
47
|
+
{ model: config.model, buildInput, extractResult },
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!result.success || !result.videoUrl) {
|
|
51
|
+
throw new Error(result.error || "Generation failed");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
updateState(result.videoUrl ?? null, result.thumbnailUrl ?? null);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
videoUrl: result.videoUrl,
|
|
59
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
getCreditCost: () => config.creditCost,
|
|
63
|
+
save: async (result) => {
|
|
64
|
+
if (result.success && result.videoUrl && creationIdRef.current) {
|
|
65
|
+
await callbacks.onCreationSave?.({
|
|
66
|
+
creationId: creationIdRef.current,
|
|
67
|
+
type: "text-to-video",
|
|
68
|
+
videoUrl: result.videoUrl,
|
|
69
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
70
|
+
prompt: currentPrompt,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo, useRef } from "react";
|
|
2
|
+
import { useGenerationOrchestrator } from "../../../../presentation/hooks/generation";
|
|
3
|
+
import { DEFAULT_ALERT_MESSAGES } from "../../../../presentation/constants/alert-messages";
|
|
4
|
+
import { generateCreationId } from "../../../../infrastructure/utils/id-generator.util";
|
|
5
|
+
import { createTextToVideoStrategy } from "./textToVideoStrategy";
|
|
6
|
+
import type {
|
|
7
|
+
TextToVideoFeatureState,
|
|
8
|
+
TextToVideoConfig,
|
|
9
|
+
TextToVideoCallbacks,
|
|
10
|
+
TextToVideoResult,
|
|
11
|
+
TextToVideoOptions,
|
|
12
|
+
TextToVideoInputBuilder,
|
|
13
|
+
TextToVideoResultExtractor,
|
|
14
|
+
} from "../../domain/types";
|
|
15
|
+
|
|
16
|
+
export interface UseTextToVideoFeatureProps {
|
|
17
|
+
config: TextToVideoConfig;
|
|
18
|
+
callbacks: TextToVideoCallbacks;
|
|
19
|
+
userId: string;
|
|
20
|
+
buildInput: TextToVideoInputBuilder;
|
|
21
|
+
extractResult?: TextToVideoResultExtractor;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TextToVideoGenerateParams extends TextToVideoOptions {
|
|
25
|
+
prompt?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UseTextToVideoFeatureReturn {
|
|
29
|
+
state: TextToVideoFeatureState;
|
|
30
|
+
setPrompt: (prompt: string) => void;
|
|
31
|
+
generate: (params?: TextToVideoGenerateParams) => Promise<TextToVideoResult>;
|
|
32
|
+
reset: () => void;
|
|
33
|
+
isReady: boolean;
|
|
34
|
+
canGenerate: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const INITIAL_STATE: TextToVideoFeatureState = {
|
|
38
|
+
prompt: "",
|
|
39
|
+
videoUrl: null,
|
|
40
|
+
thumbnailUrl: null,
|
|
41
|
+
isProcessing: false,
|
|
42
|
+
progress: 0,
|
|
43
|
+
error: null,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function useTextToVideoFeature(props: UseTextToVideoFeatureProps): UseTextToVideoFeatureReturn {
|
|
47
|
+
const { config, callbacks, userId, buildInput, extractResult } = props;
|
|
48
|
+
const [state, setState] = useState<TextToVideoFeatureState>(INITIAL_STATE);
|
|
49
|
+
const creationIdRef = useRef("");
|
|
50
|
+
|
|
51
|
+
const updateState = useCallback((videoUrl: string | null, thumbnailUrl: string | null) => {
|
|
52
|
+
setState((prev) => ({ ...prev, videoUrl, thumbnailUrl }));
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const strategy = useMemo(
|
|
56
|
+
() =>
|
|
57
|
+
createTextToVideoStrategy({
|
|
58
|
+
config,
|
|
59
|
+
callbacks,
|
|
60
|
+
buildInput,
|
|
61
|
+
extractResult,
|
|
62
|
+
userId,
|
|
63
|
+
currentPrompt: state.prompt,
|
|
64
|
+
creationIdRef,
|
|
65
|
+
updateState,
|
|
66
|
+
}),
|
|
67
|
+
[config, callbacks, buildInput, extractResult, userId, state.prompt, updateState],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const orchestrator = useGenerationOrchestrator(strategy, {
|
|
71
|
+
userId,
|
|
72
|
+
alertMessages: DEFAULT_ALERT_MESSAGES,
|
|
73
|
+
onCreditsExhausted: () => callbacks.onShowPaywall?.(config.creditCost),
|
|
74
|
+
onSuccess: (result) => callbacks.onGenerate?.(result as TextToVideoResult),
|
|
75
|
+
onError: (err) => callbacks.onError?.(err.message),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const setPrompt = useCallback((prompt: string) => {
|
|
79
|
+
setState((prev) => ({ ...prev, prompt, error: null }));
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
const generate = useCallback(
|
|
83
|
+
async (params?: TextToVideoGenerateParams): Promise<TextToVideoResult> => {
|
|
84
|
+
const prompt = params?.prompt || state.prompt;
|
|
85
|
+
if (!prompt.trim()) {
|
|
86
|
+
const error = "Prompt is required";
|
|
87
|
+
setState((prev) => ({ ...prev, error }));
|
|
88
|
+
return { success: false, error };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setState((prev) => ({ ...prev, isProcessing: true, error: null, progress: 0 }));
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const result = await orchestrator.generate({
|
|
95
|
+
prompt: prompt.trim(),
|
|
96
|
+
options: params,
|
|
97
|
+
creationId: generateCreationId("text-to-video"),
|
|
98
|
+
});
|
|
99
|
+
setState((prev) => ({ ...prev, isProcessing: false }));
|
|
100
|
+
return { success: true, videoUrl: (result as TextToVideoResult)?.videoUrl };
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : "Generation failed";
|
|
103
|
+
setState((prev) => ({ ...prev, isProcessing: false, error: message }));
|
|
104
|
+
return { success: false, error: message };
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
[state.prompt, orchestrator],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const reset = useCallback(() => setState(INITIAL_STATE), []);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
state,
|
|
114
|
+
setPrompt,
|
|
115
|
+
generate,
|
|
116
|
+
reset,
|
|
117
|
+
isReady: !orchestrator.isGenerating && !state.isProcessing,
|
|
118
|
+
canGenerate: !orchestrator.isGenerating && !state.isProcessing && state.prompt.trim().length > 0,
|
|
119
|
+
};
|
|
120
|
+
}
|
package/src/exports/features.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type {
|
|
|
18
18
|
UseTextToImageFormOptions, UseTextToImageFormReturn,
|
|
19
19
|
TextToImagePromptInputProps, TextToImageExamplePromptsProps, TextToImageStyleSelectorProps,
|
|
20
20
|
TextToImageAspectRatioSelectorProps, TextToImageGenerateButtonProps, TextToImageSettingsSheetProps,
|
|
21
|
-
} from "../
|
|
21
|
+
} from "../domains/text-to-image";
|
|
22
22
|
export {
|
|
23
23
|
DEFAULT_IMAGE_STYLES, DEFAULT_NUM_IMAGES_OPTIONS, ASPECT_RATIO_VALUES, IMAGE_SIZE_VALUES,
|
|
24
24
|
OUTPUT_FORMAT_VALUES, DEFAULT_FORM_VALUES, DEFAULT_TEXT_TO_IMAGE_PROMPTS, DEFAULT_TEXT_TO_VOICE_PROMPTS,
|
|
@@ -29,7 +29,7 @@ export {
|
|
|
29
29
|
TextToImagePromptInput, TextToImageExamplePrompts, TextToImageNumImagesSelector,
|
|
30
30
|
TextToImageStyleSelector, TextToImageAspectRatioSelector, TextToImageSizeSelector,
|
|
31
31
|
TextToImageOutputFormatSelector, TextToImageGenerateButton, TextToImageSettingsSheet,
|
|
32
|
-
} from "../
|
|
32
|
+
} from "../domains/text-to-image";
|
|
33
33
|
|
|
34
34
|
// Text-to-Video Feature
|
|
35
35
|
export type {
|
|
@@ -45,13 +45,13 @@ export type {
|
|
|
45
45
|
ExamplePrompt,
|
|
46
46
|
UseTextToVideoFeatureProps, UseTextToVideoFeatureReturn, TextToVideoGenerateParams,
|
|
47
47
|
UseTextToVideoFormProps, UseTextToVideoFormReturn, ExecuteTextToVideoOptions,
|
|
48
|
-
} from "../
|
|
48
|
+
} from "../domains/text-to-video";
|
|
49
49
|
export {
|
|
50
50
|
INITIAL_FORM_STATE, INITIAL_GENERATION_STATE,
|
|
51
51
|
executeTextToVideo, hasTextToVideoSupport,
|
|
52
52
|
useTextToVideoFeature, useTextToVideoForm,
|
|
53
53
|
GenerationTabs, FrameSelector, OptionsPanel, HeroSection, HintCarousel,
|
|
54
|
-
} from "../
|
|
54
|
+
} from "../domains/text-to-video";
|
|
55
55
|
|
|
56
56
|
// Image-to-Video Feature
|
|
57
57
|
export type {
|
|
@@ -70,7 +70,7 @@ export type {
|
|
|
70
70
|
ImageToVideoAnimationStyleSelectorProps, ImageToVideoDurationSelectorProps,
|
|
71
71
|
ImageToVideoMusicMoodSelectorProps, ImageToVideoSelectionGridProps,
|
|
72
72
|
ImageToVideoSelectionGridTranslations, ImageToVideoGenerateButtonProps,
|
|
73
|
-
} from "../
|
|
73
|
+
} from "../domains/image-to-video";
|
|
74
74
|
export {
|
|
75
75
|
IMAGE_TO_VIDEO_ANIMATION_STYLES, IMAGE_TO_VIDEO_DEFAULT_ANIMATION,
|
|
76
76
|
IMAGE_TO_VIDEO_MUSIC_MOODS, IMAGE_TO_VIDEO_DEFAULT_MUSIC,
|
|
@@ -80,12 +80,12 @@ export {
|
|
|
80
80
|
useImageToVideoFormState, useImageToVideoGeneration, useImageToVideoForm, useImageToVideoFeature,
|
|
81
81
|
ImageToVideoAnimationStyleSelector, ImageToVideoDurationSelector,
|
|
82
82
|
ImageToVideoMusicMoodSelector, ImageToVideoSelectionGrid, ImageToVideoGenerateButton,
|
|
83
|
-
} from "../
|
|
83
|
+
} from "../domains/image-to-video";
|
|
84
84
|
|
|
85
85
|
// Wizard Flows
|
|
86
|
-
export { TextToImageWizardFlow } from "../
|
|
87
|
-
export type { TextToImageWizardFlowProps } from "../
|
|
88
|
-
export { TextToVideoWizardFlow } from "../
|
|
89
|
-
export type { TextToVideoWizardFlowProps } from "../
|
|
90
|
-
export { ImageToVideoWizardFlow } from "../
|
|
91
|
-
export type { ImageToVideoWizardFlowProps } from "../
|
|
86
|
+
export { TextToImageWizardFlow } from "../domains/text-to-image/presentation/screens/TextToImageWizardFlow";
|
|
87
|
+
export type { TextToImageWizardFlowProps } from "../domains/text-to-image/presentation/screens/TextToImageWizardFlow";
|
|
88
|
+
export { TextToVideoWizardFlow } from "../domains/text-to-video/presentation/screens/TextToVideoWizardFlow";
|
|
89
|
+
export type { TextToVideoWizardFlowProps } from "../domains/text-to-video/presentation/screens/TextToVideoWizardFlow";
|
|
90
|
+
export { ImageToVideoWizardFlow } from "../domains/image-to-video/presentation/screens/ImageToVideoWizardFlow";
|
|
91
|
+
export type { ImageToVideoWizardFlowProps } from "../domains/image-to-video/presentation/screens/ImageToVideoWizardFlow";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicText, AtomicSpinner, useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
-
import type { BackgroundJob } from "../../domain/entities/job.types";
|
|
9
|
+
import type { BackgroundJob } from "../../domains/background/domain/entities/job.types";
|
|
10
10
|
import { PendingJobProgressBar } from "./PendingJobProgressBar";
|
|
11
11
|
import { PendingJobCardActions } from "./PendingJobCardActions";
|
|
12
12
|
|