@umituz/react-native-ai-generation-content 1.88.7 → 1.88.9
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/domains/creations/presentation/components/CreationCard.tsx +6 -0
- package/src/domains/creations/presentation/components/CreationPreview.tsx +4 -0
- package/src/domains/creations/presentation/components/CreationVideoPreview.tsx +10 -4
- package/src/domains/generation/wizard/presentation/components/GenericWizardFlow.tsx +3 -0
- package/src/domains/generation/wizard/presentation/components/IndeterminateProgressBar.tsx +3 -1
- package/src/domains/generation/wizard/presentation/components/WizardFlow.types.ts +2 -0
- package/src/domains/generation/wizard/presentation/components/WizardFlowContent.tsx +3 -0
- package/src/domains/generation/wizard/presentation/components/WizardStepRenderer.tsx +10 -1
- package/src/domains/generation/wizard/presentation/components/WizardStepRenderer.types.ts +1 -0
- package/src/domains/generation/wizard/presentation/screens/GeneratingScreen.tsx +79 -46
- package/src/domains/image-to-video/presentation/screens/ImageToVideoWizardFlow.tsx +2 -0
- package/src/domains/prompts/domain/base/constants.ts +45 -10
- package/src/domains/text-to-image/presentation/screens/TextToImageWizardFlow.tsx +2 -0
- package/src/domains/text-to-video/presentation/screens/TextToVideoWizardFlow.tsx +2 -0
- package/src/infrastructure/config/env.config.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.88.
|
|
3
|
+
"version": "1.88.9",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -59,6 +59,11 @@ export function CreationCard({
|
|
|
59
59
|
canPostToFeed,
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
// Determine if video is downloading (has video URL but no thumbnail yet)
|
|
63
|
+
const hasVideoOutput = !!creation.output?.videoUrl;
|
|
64
|
+
const hasThumbnail = !!creation.output?.thumbnailUrl;
|
|
65
|
+
const isVideoDownloading = hasVideoOutput && !hasThumbnail && creation.status === 'completed';
|
|
66
|
+
|
|
62
67
|
const handlePress = useCallback(() => {
|
|
63
68
|
if (__DEV__) {
|
|
64
69
|
console.log("[CreationCard] handlePress TRIGGERED", {
|
|
@@ -127,6 +132,7 @@ export function CreationCard({
|
|
|
127
132
|
thumbnailUrl={creation.output?.thumbnailUrl}
|
|
128
133
|
status={creation.status}
|
|
129
134
|
type={creation.type as CreationTypeId}
|
|
135
|
+
showDownloadLoading={isVideoDownloading}
|
|
130
136
|
/>
|
|
131
137
|
{showBadges && creation.status && (
|
|
132
138
|
<CreationBadges
|
|
@@ -25,6 +25,8 @@ interface CreationPreviewProps {
|
|
|
25
25
|
readonly height?: number;
|
|
26
26
|
/** Show loading indicator when in progress */
|
|
27
27
|
readonly showLoadingIndicator?: boolean;
|
|
28
|
+
/** Show loading when video is downloading but no thumbnail yet */
|
|
29
|
+
readonly showDownloadLoading?: boolean;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export function CreationPreview({
|
|
@@ -35,6 +37,7 @@ export function CreationPreview({
|
|
|
35
37
|
aspectRatio = 16 / 9,
|
|
36
38
|
height,
|
|
37
39
|
showLoadingIndicator = true,
|
|
40
|
+
showDownloadLoading = false,
|
|
38
41
|
}: CreationPreviewProps) {
|
|
39
42
|
// Determine preview type based on URI content, not creation type
|
|
40
43
|
// This handles scenario-based videos (solo_martial_artist, ski_resort, etc.)
|
|
@@ -51,6 +54,7 @@ export function CreationPreview({
|
|
|
51
54
|
aspectRatio={aspectRatio}
|
|
52
55
|
height={height}
|
|
53
56
|
showLoadingIndicator={showLoadingIndicator}
|
|
57
|
+
showDownloadLoading={showDownloadLoading}
|
|
54
58
|
/>
|
|
55
59
|
);
|
|
56
60
|
}
|
|
@@ -26,6 +26,8 @@ interface CreationVideoPreviewProps {
|
|
|
26
26
|
readonly height?: number;
|
|
27
27
|
/** Show loading indicator when in progress */
|
|
28
28
|
readonly showLoadingIndicator?: boolean;
|
|
29
|
+
/** Show loading when video is downloading but no thumbnail yet */
|
|
30
|
+
readonly showDownloadLoading?: boolean;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export function CreationVideoPreview({
|
|
@@ -35,10 +37,12 @@ export function CreationVideoPreview({
|
|
|
35
37
|
aspectRatio = 16 / 9,
|
|
36
38
|
height,
|
|
37
39
|
showLoadingIndicator = true,
|
|
40
|
+
showDownloadLoading = false,
|
|
38
41
|
}: CreationVideoPreviewProps) {
|
|
39
42
|
const tokens = useAppDesignTokens();
|
|
40
43
|
const inProgress = isInProgress(status);
|
|
41
44
|
const hasThumbnail = shouldShowThumbnail(thumbnailUrl, inProgress);
|
|
45
|
+
const isDownloading = showDownloadLoading && !hasThumbnail && !inProgress && _videoUrl;
|
|
42
46
|
|
|
43
47
|
// Debug logging
|
|
44
48
|
if (__DEV__) {
|
|
@@ -47,9 +51,11 @@ export function CreationVideoPreview({
|
|
|
47
51
|
status,
|
|
48
52
|
inProgress,
|
|
49
53
|
hasThumbnail,
|
|
50
|
-
|
|
54
|
+
isDownloading,
|
|
55
|
+
videoUrl: _videoUrl,
|
|
56
|
+
willShowSpinner: (inProgress && showLoadingIndicator) || isDownloading,
|
|
51
57
|
willShowThumbnail: hasThumbnail,
|
|
52
|
-
willShowPlaceholder: !inProgress && !hasThumbnail,
|
|
58
|
+
willShowPlaceholder: !inProgress && !hasThumbnail && !isDownloading,
|
|
53
59
|
});
|
|
54
60
|
}
|
|
55
61
|
|
|
@@ -106,8 +112,8 @@ export function CreationVideoPreview({
|
|
|
106
112
|
[tokens, aspectRatio, height]
|
|
107
113
|
);
|
|
108
114
|
|
|
109
|
-
// Show loading state
|
|
110
|
-
if (inProgress && showLoadingIndicator) {
|
|
115
|
+
// Show loading state (progress or downloading)
|
|
116
|
+
if ((inProgress && showLoadingIndicator) || isDownloading) {
|
|
111
117
|
return (
|
|
112
118
|
<View style={styles.container}>
|
|
113
119
|
<View style={styles.loadingContainer}>
|
|
@@ -53,6 +53,7 @@ export interface GenericWizardFlowProps {
|
|
|
53
53
|
readonly renderPreview?: (onContinue: () => void) => React.ReactElement | null;
|
|
54
54
|
readonly renderGenerating?: (progress: number) => React.ReactElement | null;
|
|
55
55
|
readonly renderResult?: (result: unknown) => React.ReactElement | null;
|
|
56
|
+
readonly renderMascot?: () => React.ReactNode;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
|
|
@@ -79,6 +80,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
|
|
|
79
80
|
renderPreview,
|
|
80
81
|
renderGenerating,
|
|
81
82
|
renderResult,
|
|
83
|
+
renderMascot,
|
|
82
84
|
} = props;
|
|
83
85
|
|
|
84
86
|
// Resolve scenario from prop or registry
|
|
@@ -139,6 +141,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
|
|
|
139
141
|
renderPreview={renderPreview}
|
|
140
142
|
renderGenerating={renderGenerating}
|
|
141
143
|
renderResult={renderResult}
|
|
144
|
+
renderMascot={renderMascot}
|
|
142
145
|
/>
|
|
143
146
|
);
|
|
144
147
|
};
|
|
@@ -10,11 +10,13 @@ import { View, StyleSheet } from "react-native";
|
|
|
10
10
|
interface IndeterminateProgressBarProps {
|
|
11
11
|
readonly backgroundColor: string;
|
|
12
12
|
readonly fillColor: string;
|
|
13
|
+
readonly height?: number;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export const IndeterminateProgressBar: React.FC<IndeterminateProgressBarProps> = ({
|
|
16
17
|
backgroundColor,
|
|
17
18
|
fillColor,
|
|
19
|
+
height = 8,
|
|
18
20
|
}) => {
|
|
19
21
|
const [position, setPosition] = useState(0);
|
|
20
22
|
const directionRef = useRef(1);
|
|
@@ -39,7 +41,7 @@ export const IndeterminateProgressBar: React.FC<IndeterminateProgressBarProps> =
|
|
|
39
41
|
}, []);
|
|
40
42
|
|
|
41
43
|
return (
|
|
42
|
-
<View style={[styles.progressBar, { backgroundColor }]}>
|
|
44
|
+
<View style={[styles.progressBar, { backgroundColor, height }]}>
|
|
43
45
|
<View
|
|
44
46
|
style={[
|
|
45
47
|
styles.progressFill,
|
|
@@ -54,6 +54,7 @@ interface WizardFlowContentProps {
|
|
|
54
54
|
readonly renderPreview?: (onContinue: () => void) => React.ReactElement | null;
|
|
55
55
|
readonly renderGenerating?: (progress: number) => React.ReactElement | null;
|
|
56
56
|
readonly renderResult?: (result: unknown) => React.ReactElement | null;
|
|
57
|
+
readonly renderMascot?: () => React.ReactNode;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
|
|
@@ -80,6 +81,7 @@ export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
|
|
|
80
81
|
renderPreview,
|
|
81
82
|
renderGenerating,
|
|
82
83
|
renderResult,
|
|
84
|
+
renderMascot,
|
|
83
85
|
} = props;
|
|
84
86
|
|
|
85
87
|
const tokens = useAppDesignTokens();
|
|
@@ -249,6 +251,7 @@ export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
|
|
|
249
251
|
renderPreview={renderPreview}
|
|
250
252
|
renderGenerating={renderGenerating}
|
|
251
253
|
renderResult={renderResult}
|
|
254
|
+
renderMascot={renderMascot}
|
|
252
255
|
/>
|
|
253
256
|
<StarRatingPicker
|
|
254
257
|
visible={showRatingPicker}
|
|
@@ -39,6 +39,7 @@ export const WizardStepRenderer: React.FC<WizardStepRendererProps> = ({
|
|
|
39
39
|
renderPreview,
|
|
40
40
|
renderGenerating,
|
|
41
41
|
renderResult,
|
|
42
|
+
renderMascot,
|
|
42
43
|
}) => {
|
|
43
44
|
if (!step) {
|
|
44
45
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
@@ -53,7 +54,15 @@ export const WizardStepRenderer: React.FC<WizardStepRendererProps> = ({
|
|
|
53
54
|
|
|
54
55
|
case StepType.GENERATING: {
|
|
55
56
|
if (renderGenerating) return renderGenerating(generationProgress);
|
|
56
|
-
return
|
|
57
|
+
return (
|
|
58
|
+
<GeneratingScreen
|
|
59
|
+
progress={generationProgress}
|
|
60
|
+
scenario={scenario}
|
|
61
|
+
t={t}
|
|
62
|
+
onDismiss={onDismissGenerating}
|
|
63
|
+
renderMascot={renderMascot}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
case StepType.RESULT_PREVIEW: {
|
|
@@ -30,4 +30,5 @@ export interface WizardStepRendererProps {
|
|
|
30
30
|
readonly renderPreview?: (onContinue: () => void) => React.ReactElement | null;
|
|
31
31
|
readonly renderGenerating?: (progress: number) => React.ReactElement | null;
|
|
32
32
|
readonly renderResult?: (result: unknown) => React.ReactElement | null;
|
|
33
|
+
readonly renderMascot?: () => React.ReactNode;
|
|
33
34
|
}
|
|
@@ -28,6 +28,7 @@ interface GeneratingScreenProps {
|
|
|
28
28
|
};
|
|
29
29
|
readonly t: (key: string) => string;
|
|
30
30
|
readonly onDismiss?: () => void;
|
|
31
|
+
readonly renderMascot?: () => React.ReactNode;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const PHASES = [
|
|
@@ -47,6 +48,7 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
47
48
|
scenario,
|
|
48
49
|
t,
|
|
49
50
|
onDismiss,
|
|
51
|
+
renderMascot,
|
|
50
52
|
}) => {
|
|
51
53
|
const tokens = useAppDesignTokens();
|
|
52
54
|
const phase = useGenerationPhase();
|
|
@@ -100,8 +102,8 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
100
102
|
<View style={styles.container}>
|
|
101
103
|
<View style={styles.content}>
|
|
102
104
|
{/* Scanning Animation Container */}
|
|
103
|
-
<View style={[styles.scanFrame, { borderColor: tokens.colors.primary + "
|
|
104
|
-
<View style={[styles.scanOverlay, { backgroundColor: tokens.colors.primary + "
|
|
105
|
+
<View style={[styles.scanFrame, { borderColor: tokens.colors.primary + "20" }]}>
|
|
106
|
+
<View style={[styles.scanOverlay, { backgroundColor: tokens.colors.primary + "05" }]}>
|
|
105
107
|
<Animated.View
|
|
106
108
|
style={[
|
|
107
109
|
styles.scanLine,
|
|
@@ -109,18 +111,24 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
109
111
|
backgroundColor: tokens.colors.primary,
|
|
110
112
|
transform: [{ translateY: scanTranslateY }],
|
|
111
113
|
shadowColor: tokens.colors.primary,
|
|
112
|
-
shadowOpacity: 0.
|
|
114
|
+
shadowOpacity: 0.6,
|
|
113
115
|
shadowRadius: 10,
|
|
114
116
|
}
|
|
115
117
|
]}
|
|
116
118
|
/>
|
|
117
119
|
</View>
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
<View style={styles.mascotContainer}>
|
|
121
|
+
{renderMascot ? (
|
|
122
|
+
renderMascot()
|
|
123
|
+
) : (
|
|
124
|
+
<Animated.View style={[styles.spinnerOverlay, { opacity: pulseAnim }]}>
|
|
125
|
+
<ActivityIndicator size="large" color={tokens.colors.primary} />
|
|
126
|
+
</Animated.View>
|
|
127
|
+
)}
|
|
128
|
+
</View>
|
|
121
129
|
</View>
|
|
122
130
|
|
|
123
|
-
<AtomicText type="
|
|
131
|
+
<AtomicText type="headlineSmall" style={[styles.title, { color: tokens.colors.textPrimary }]}>
|
|
124
132
|
{messages.title}
|
|
125
133
|
</AtomicText>
|
|
126
134
|
|
|
@@ -181,17 +189,20 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
181
189
|
{statusMessage}
|
|
182
190
|
</AtomicText>
|
|
183
191
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
{/* Combined Progress section */}
|
|
193
|
+
<View style={styles.progressSection}>
|
|
194
|
+
<View style={styles.progressWrapper}>
|
|
195
|
+
<IndeterminateProgressBar
|
|
196
|
+
backgroundColor={tokens.colors.surfaceVariant}
|
|
197
|
+
fillColor={tokens.colors.primary}
|
|
198
|
+
height={4}
|
|
199
|
+
/>
|
|
200
|
+
</View>
|
|
201
|
+
<AtomicText type="bodySmall" style={[styles.hint, { color: tokens.colors.textSecondary, opacity: 0.7 }]}>
|
|
202
|
+
{messages.hint}
|
|
203
|
+
</AtomicText>
|
|
189
204
|
</View>
|
|
190
205
|
|
|
191
|
-
<AtomicText type="bodySmall" style={[styles.hint, { color: tokens.colors.textSecondary }]}>
|
|
192
|
-
{messages.hint}
|
|
193
|
-
</AtomicText>
|
|
194
|
-
|
|
195
206
|
{onDismiss && (
|
|
196
207
|
<TouchableOpacity
|
|
197
208
|
style={[styles.backgroundHintButton, { borderColor: tokens.colors.primary }]}
|
|
@@ -218,17 +229,16 @@ const styles = StyleSheet.create({
|
|
|
218
229
|
width: "85%",
|
|
219
230
|
maxWidth: 400,
|
|
220
231
|
alignItems: "center",
|
|
221
|
-
gap: 16,
|
|
222
232
|
},
|
|
223
233
|
scanFrame: {
|
|
224
|
-
width:
|
|
225
|
-
height:
|
|
226
|
-
borderRadius:
|
|
227
|
-
borderWidth:
|
|
234
|
+
width: 160,
|
|
235
|
+
height: 160,
|
|
236
|
+
borderRadius: 80, // Circular for better look
|
|
237
|
+
borderWidth: 1,
|
|
228
238
|
overflow: "hidden",
|
|
229
239
|
justifyContent: "center",
|
|
230
240
|
alignItems: "center",
|
|
231
|
-
marginBottom:
|
|
241
|
+
marginBottom: 24,
|
|
232
242
|
},
|
|
233
243
|
scanOverlay: {
|
|
234
244
|
...StyleSheet.absoluteFillObject,
|
|
@@ -236,70 +246,93 @@ const styles = StyleSheet.create({
|
|
|
236
246
|
alignItems: "center",
|
|
237
247
|
},
|
|
238
248
|
scanLine: {
|
|
239
|
-
width: "
|
|
240
|
-
height:
|
|
249
|
+
width: "140%",
|
|
250
|
+
height: 2,
|
|
241
251
|
position: "absolute",
|
|
242
|
-
left: "-
|
|
243
|
-
|
|
252
|
+
left: "-20%",
|
|
253
|
+
},
|
|
254
|
+
mascotContainer: {
|
|
255
|
+
zIndex: 5,
|
|
256
|
+
justifyContent: "center",
|
|
257
|
+
alignItems: "center",
|
|
244
258
|
},
|
|
245
259
|
spinnerOverlay: {
|
|
246
260
|
zIndex: 10,
|
|
247
261
|
},
|
|
248
262
|
title: {
|
|
249
263
|
textAlign: "center",
|
|
264
|
+
fontWeight: "900",
|
|
265
|
+
letterSpacing: -0.5,
|
|
266
|
+
marginBottom: 20,
|
|
250
267
|
},
|
|
251
268
|
stepsRow: {
|
|
252
269
|
flexDirection: "row",
|
|
253
270
|
alignItems: "center",
|
|
254
271
|
justifyContent: "center",
|
|
255
|
-
marginVertical:
|
|
272
|
+
marginVertical: 12,
|
|
273
|
+
width: "100%",
|
|
256
274
|
},
|
|
257
275
|
stepItem: {
|
|
258
276
|
alignItems: "center",
|
|
259
|
-
|
|
277
|
+
width: 70,
|
|
260
278
|
},
|
|
261
279
|
stepBubble: {
|
|
262
|
-
width:
|
|
263
|
-
height:
|
|
264
|
-
borderRadius:
|
|
280
|
+
width: 36,
|
|
281
|
+
height: 36,
|
|
282
|
+
borderRadius: 18,
|
|
265
283
|
justifyContent: "center",
|
|
266
284
|
alignItems: "center",
|
|
267
|
-
borderWidth:
|
|
285
|
+
borderWidth: 1,
|
|
286
|
+
marginBottom: 8,
|
|
268
287
|
},
|
|
269
288
|
stepNumber: {
|
|
270
|
-
fontSize:
|
|
271
|
-
fontWeight: "
|
|
289
|
+
fontSize: 14,
|
|
290
|
+
fontWeight: "800",
|
|
272
291
|
},
|
|
273
292
|
stepLabel: {
|
|
274
|
-
fontSize:
|
|
293
|
+
fontSize: 10,
|
|
294
|
+
textTransform: "uppercase",
|
|
295
|
+
letterSpacing: 0.5,
|
|
275
296
|
},
|
|
276
297
|
stepConnector: {
|
|
277
|
-
|
|
278
|
-
height:
|
|
298
|
+
flex: 1,
|
|
299
|
+
height: 1,
|
|
300
|
+
maxWidth: 30,
|
|
279
301
|
borderRadius: 1,
|
|
280
|
-
|
|
302
|
+
marginTop: -18, // Align with bubble center
|
|
281
303
|
marginHorizontal: 4,
|
|
282
304
|
},
|
|
283
305
|
message: {
|
|
284
306
|
textAlign: "center",
|
|
307
|
+
marginTop: 20,
|
|
308
|
+
fontSize: 16,
|
|
309
|
+
fontWeight: "600",
|
|
310
|
+
},
|
|
311
|
+
progressSection: {
|
|
312
|
+
width: "100%",
|
|
313
|
+
alignItems: "center",
|
|
314
|
+
marginTop: 24,
|
|
315
|
+
gap: 12,
|
|
285
316
|
},
|
|
286
|
-
|
|
317
|
+
progressWrapper: {
|
|
287
318
|
width: "100%",
|
|
288
|
-
|
|
319
|
+
height: 4, // Slimmer progress bar
|
|
289
320
|
},
|
|
290
321
|
hint: {
|
|
291
322
|
textAlign: "center",
|
|
292
|
-
marginTop: 4,
|
|
293
323
|
},
|
|
294
324
|
backgroundHintButton: {
|
|
295
|
-
marginTop:
|
|
296
|
-
paddingVertical:
|
|
297
|
-
paddingHorizontal:
|
|
325
|
+
marginTop: 40,
|
|
326
|
+
paddingVertical: 14,
|
|
327
|
+
paddingHorizontal: 32,
|
|
298
328
|
borderWidth: 1,
|
|
299
|
-
borderRadius:
|
|
329
|
+
borderRadius: 30, // Pill shaped
|
|
330
|
+
backgroundColor: "rgba(255,255,255,0.03)",
|
|
300
331
|
},
|
|
301
332
|
backgroundHint: {
|
|
302
333
|
textAlign: "center",
|
|
303
|
-
|
|
334
|
+
fontSize: 15,
|
|
335
|
+
fontWeight: "800",
|
|
336
|
+
letterSpacing: -0.2,
|
|
304
337
|
},
|
|
305
338
|
});
|
|
@@ -32,6 +32,7 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
|
|
|
32
32
|
onBack,
|
|
33
33
|
t,
|
|
34
34
|
alertMessages,
|
|
35
|
+
renderMascot,
|
|
35
36
|
} = props;
|
|
36
37
|
|
|
37
38
|
const tokens = useAppDesignTokens();
|
|
@@ -82,6 +83,7 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
|
|
|
82
83
|
onBack={onBack}
|
|
83
84
|
onTryAgain={onBack}
|
|
84
85
|
t={t}
|
|
86
|
+
renderMascot={renderMascot}
|
|
85
87
|
renderPreview={(onContinue) => <AutoSkipPreview onContinue={onContinue} />}
|
|
86
88
|
/>
|
|
87
89
|
</View>
|
|
@@ -4,16 +4,51 @@
|
|
|
4
4
|
* Optimized for Gemini 3 Pro Image (nano-banana-2) — natural language format
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export const IDENTITY_PRESERVATION_CORE = `IDENTITY PRESERVATION (HIGHEST PRIORITY):
|
|
8
|
-
Preserve the EXACT facial appearance from
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
export const IDENTITY_PRESERVATION_CORE = `IDENTITY PRESERVATION (CRITICAL - HIGHEST PRIORITY):
|
|
8
|
+
Preserve the EXACT facial appearance from the uploaded photo with 100% accuracy.
|
|
9
|
+
|
|
10
|
+
MANDATORY REQUIREMENTS:
|
|
11
|
+
- Keep EVERY facial detail IDENTICAL: bone structure, facial proportions, eye shape, eye color, iris pattern, nose shape/size, lip shape/fullness, cheekbones, jawline, chin shape
|
|
12
|
+
- Preserve ALL unique characteristics: skin texture, pores, fine lines, smile lines, freckles, moles, birthmarks, scars, dimples, skin undertones
|
|
13
|
+
- Maintain EXACT facial proportions and face shape - do NOT elongate, widen, or alter face geometry
|
|
14
|
+
- Keep hair texture, color, and styling consistent with the uploaded photo
|
|
15
|
+
- Preserve the person's natural expression and personality - do NOT add artificial or exaggerated expressions
|
|
16
|
+
|
|
17
|
+
STRICTLY PROHIBITED:
|
|
18
|
+
- Do NOT alter, idealize, beautify, or enhance any facial feature
|
|
19
|
+
- Do NOT make the face look younger, older, more attractive, or different in any way
|
|
20
|
+
- Do NOT add makeup, change skin tone, or smooth skin texture artificially
|
|
21
|
+
- Do NOT create a plastic, doll-like, or AI-generated appearance
|
|
22
|
+
- Do NOT change facial proportions to fit beauty standards
|
|
23
|
+
- The person MUST be instantly recognizable as themselves - if a friend wouldn't recognize them, the generation has failed
|
|
24
|
+
|
|
25
|
+
RESULT REQUIREMENT:
|
|
26
|
+
The final image must look like a REAL photograph of the ACTUAL person from the uploaded photo - not an idealized or beautified version.`;
|
|
27
|
+
|
|
28
|
+
export const IDENTITY_PRESERVATION_COUPLE = `IDENTITY PRESERVATION (CRITICAL - HIGHEST PRIORITY):
|
|
29
|
+
Preserve the EXACT facial appearance of BOTH people from the uploaded photos with 100% accuracy.
|
|
30
|
+
|
|
31
|
+
MANDATORY REQUIREMENTS FOR BOTH PERSONS:
|
|
32
|
+
- Keep EVERY facial detail IDENTICAL for both individuals: bone structure, facial proportions, eye shape, eye color, iris pattern, nose shape/size, lip shape/fullness, cheekbones, jawline, chin shape
|
|
33
|
+
- Preserve ALL unique characteristics for both: skin texture, pores, fine lines, smile lines, freckles, moles, birthmarks, scars, dimples, skin undertones
|
|
34
|
+
- Maintain EXACT facial proportions and face shapes for both people - do NOT alter face geometry
|
|
35
|
+
- Keep hair texture, color, and styling consistent with uploaded photos for both
|
|
36
|
+
- Preserve natural expressions and personalities of both individuals
|
|
37
|
+
|
|
38
|
+
COUPLE REQUIREMENTS:
|
|
39
|
+
- The resulting image MUST show BOTH individuals together as a couple
|
|
40
|
+
- Both people must be positioned naturally together with authentic interaction
|
|
41
|
+
- Maintain accurate relative heights and proportions between the two people
|
|
42
|
+
|
|
43
|
+
STRICTLY PROHIBITED:
|
|
44
|
+
- Do NOT alter, idealize, beautify, or enhance any facial feature of either person
|
|
45
|
+
- Do NOT make either person look younger, older, or more attractive
|
|
46
|
+
- Do NOT add makeup, change skin tones, or smooth skin artificially
|
|
47
|
+
- Do NOT create plastic, doll-like, or AI-generated appearances
|
|
48
|
+
- Both people MUST be instantly recognizable as themselves - if friends wouldn't recognize them, the generation has failed
|
|
49
|
+
|
|
50
|
+
RESULT REQUIREMENT:
|
|
51
|
+
The final image must look like a REAL photograph of the ACTUAL two people from the uploaded photos - not idealized or beautified versions.`;
|
|
17
52
|
|
|
18
53
|
export const PHOTOREALISTIC_RENDERING = `STYLE: Photorealistic photograph, high quality, professional photography, natural lighting with realistic shadows.
|
|
19
54
|
PROHIBITED: No anime, cartoons, illustrations, sketches, 3D renders, paintings, or non-photorealistic styles.`;
|
|
@@ -31,6 +31,7 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
|
|
|
31
31
|
onBack,
|
|
32
32
|
t,
|
|
33
33
|
alertMessages,
|
|
34
|
+
renderMascot,
|
|
34
35
|
} = props;
|
|
35
36
|
|
|
36
37
|
const tokens = useAppDesignTokens();
|
|
@@ -83,6 +84,7 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
|
|
|
83
84
|
onBack={onBack}
|
|
84
85
|
onTryAgain={onBack}
|
|
85
86
|
t={t}
|
|
87
|
+
renderMascot={renderMascot}
|
|
86
88
|
renderPreview={(onContinue) => <AutoSkipPreview onContinue={onContinue} />}
|
|
87
89
|
/>
|
|
88
90
|
</View>
|
|
@@ -32,6 +32,7 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
|
|
|
32
32
|
onBack,
|
|
33
33
|
t,
|
|
34
34
|
alertMessages,
|
|
35
|
+
renderMascot,
|
|
35
36
|
} = props;
|
|
36
37
|
|
|
37
38
|
const tokens = useAppDesignTokens();
|
|
@@ -84,6 +85,7 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
|
|
|
84
85
|
onBack={onBack}
|
|
85
86
|
onTryAgain={onBack}
|
|
86
87
|
t={t}
|
|
88
|
+
renderMascot={renderMascot}
|
|
87
89
|
renderPreview={(onContinue) => <AutoSkipPreview onContinue={onContinue} />}
|
|
88
90
|
/>
|
|
89
91
|
</View>
|
|
@@ -29,7 +29,7 @@ export const env = {
|
|
|
29
29
|
|
|
30
30
|
// Generation Timeouts
|
|
31
31
|
generationImageTimeoutMs: getEnvValue("GENERATION_IMAGE_TIMEOUT_MS", 120000) as number,
|
|
32
|
-
generationVideoTimeoutMs: getEnvValue("GENERATION_VIDEO_TIMEOUT_MS",
|
|
32
|
+
generationVideoTimeoutMs: getEnvValue("GENERATION_VIDEO_TIMEOUT_MS", 600000) as number, // 10 min for complex videos
|
|
33
33
|
generationMultiImageTimeoutMs: getEnvValue("GENERATION_MULTI_IMAGE_TIMEOUT_MS", 120000) as number,
|
|
34
34
|
|
|
35
35
|
// Polling Configuration
|