@umituz/react-native-ai-generation-content 1.88.7 → 1.88.8
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/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 +78 -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.8",
|
|
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
|
};
|
|
@@ -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,19 @@ 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
|
+
/>
|
|
199
|
+
</View>
|
|
200
|
+
<AtomicText type="bodySmall" style={[styles.hint, { color: tokens.colors.textSecondary, opacity: 0.7 }]}>
|
|
201
|
+
{messages.hint}
|
|
202
|
+
</AtomicText>
|
|
189
203
|
</View>
|
|
190
204
|
|
|
191
|
-
<AtomicText type="bodySmall" style={[styles.hint, { color: tokens.colors.textSecondary }]}>
|
|
192
|
-
{messages.hint}
|
|
193
|
-
</AtomicText>
|
|
194
|
-
|
|
195
205
|
{onDismiss && (
|
|
196
206
|
<TouchableOpacity
|
|
197
207
|
style={[styles.backgroundHintButton, { borderColor: tokens.colors.primary }]}
|
|
@@ -218,17 +228,16 @@ const styles = StyleSheet.create({
|
|
|
218
228
|
width: "85%",
|
|
219
229
|
maxWidth: 400,
|
|
220
230
|
alignItems: "center",
|
|
221
|
-
gap: 16,
|
|
222
231
|
},
|
|
223
232
|
scanFrame: {
|
|
224
|
-
width:
|
|
225
|
-
height:
|
|
226
|
-
borderRadius:
|
|
227
|
-
borderWidth:
|
|
233
|
+
width: 160,
|
|
234
|
+
height: 160,
|
|
235
|
+
borderRadius: 80, // Circular for better look
|
|
236
|
+
borderWidth: 1,
|
|
228
237
|
overflow: "hidden",
|
|
229
238
|
justifyContent: "center",
|
|
230
239
|
alignItems: "center",
|
|
231
|
-
marginBottom:
|
|
240
|
+
marginBottom: 24,
|
|
232
241
|
},
|
|
233
242
|
scanOverlay: {
|
|
234
243
|
...StyleSheet.absoluteFillObject,
|
|
@@ -236,70 +245,93 @@ const styles = StyleSheet.create({
|
|
|
236
245
|
alignItems: "center",
|
|
237
246
|
},
|
|
238
247
|
scanLine: {
|
|
239
|
-
width: "
|
|
240
|
-
height:
|
|
248
|
+
width: "140%",
|
|
249
|
+
height: 2,
|
|
241
250
|
position: "absolute",
|
|
242
|
-
left: "-
|
|
243
|
-
|
|
251
|
+
left: "-20%",
|
|
252
|
+
},
|
|
253
|
+
mascotContainer: {
|
|
254
|
+
zIndex: 5,
|
|
255
|
+
justifyContent: "center",
|
|
256
|
+
alignItems: "center",
|
|
244
257
|
},
|
|
245
258
|
spinnerOverlay: {
|
|
246
259
|
zIndex: 10,
|
|
247
260
|
},
|
|
248
261
|
title: {
|
|
249
262
|
textAlign: "center",
|
|
263
|
+
fontWeight: "900",
|
|
264
|
+
letterSpacing: -0.5,
|
|
265
|
+
marginBottom: 20,
|
|
250
266
|
},
|
|
251
267
|
stepsRow: {
|
|
252
268
|
flexDirection: "row",
|
|
253
269
|
alignItems: "center",
|
|
254
270
|
justifyContent: "center",
|
|
255
|
-
marginVertical:
|
|
271
|
+
marginVertical: 12,
|
|
272
|
+
width: "100%",
|
|
256
273
|
},
|
|
257
274
|
stepItem: {
|
|
258
275
|
alignItems: "center",
|
|
259
|
-
|
|
276
|
+
width: 70,
|
|
260
277
|
},
|
|
261
278
|
stepBubble: {
|
|
262
|
-
width:
|
|
263
|
-
height:
|
|
264
|
-
borderRadius:
|
|
279
|
+
width: 36,
|
|
280
|
+
height: 36,
|
|
281
|
+
borderRadius: 18,
|
|
265
282
|
justifyContent: "center",
|
|
266
283
|
alignItems: "center",
|
|
267
|
-
borderWidth:
|
|
284
|
+
borderWidth: 1,
|
|
285
|
+
marginBottom: 8,
|
|
268
286
|
},
|
|
269
287
|
stepNumber: {
|
|
270
|
-
fontSize:
|
|
271
|
-
fontWeight: "
|
|
288
|
+
fontSize: 14,
|
|
289
|
+
fontWeight: "800",
|
|
272
290
|
},
|
|
273
291
|
stepLabel: {
|
|
274
|
-
fontSize:
|
|
292
|
+
fontSize: 10,
|
|
293
|
+
textTransform: "uppercase",
|
|
294
|
+
letterSpacing: 0.5,
|
|
275
295
|
},
|
|
276
296
|
stepConnector: {
|
|
277
|
-
|
|
278
|
-
height:
|
|
297
|
+
flex: 1,
|
|
298
|
+
height: 1,
|
|
299
|
+
maxWidth: 30,
|
|
279
300
|
borderRadius: 1,
|
|
280
|
-
|
|
301
|
+
marginTop: -18, // Align with bubble center
|
|
281
302
|
marginHorizontal: 4,
|
|
282
303
|
},
|
|
283
304
|
message: {
|
|
284
305
|
textAlign: "center",
|
|
306
|
+
marginTop: 20,
|
|
307
|
+
fontSize: 16,
|
|
308
|
+
fontWeight: "600",
|
|
309
|
+
},
|
|
310
|
+
progressSection: {
|
|
311
|
+
width: "100%",
|
|
312
|
+
alignItems: "center",
|
|
313
|
+
marginTop: 24,
|
|
314
|
+
gap: 12,
|
|
285
315
|
},
|
|
286
|
-
|
|
316
|
+
progressWrapper: {
|
|
287
317
|
width: "100%",
|
|
288
|
-
|
|
318
|
+
height: 4, // Slimmer progress bar
|
|
289
319
|
},
|
|
290
320
|
hint: {
|
|
291
321
|
textAlign: "center",
|
|
292
|
-
marginTop: 4,
|
|
293
322
|
},
|
|
294
323
|
backgroundHintButton: {
|
|
295
|
-
marginTop:
|
|
296
|
-
paddingVertical:
|
|
297
|
-
paddingHorizontal:
|
|
324
|
+
marginTop: 40,
|
|
325
|
+
paddingVertical: 14,
|
|
326
|
+
paddingHorizontal: 32,
|
|
298
327
|
borderWidth: 1,
|
|
299
|
-
borderRadius:
|
|
328
|
+
borderRadius: 30, // Pill shaped
|
|
329
|
+
backgroundColor: "rgba(255,255,255,0.03)",
|
|
300
330
|
},
|
|
301
331
|
backgroundHint: {
|
|
302
332
|
textAlign: "center",
|
|
303
|
-
|
|
333
|
+
fontSize: 15,
|
|
334
|
+
fontWeight: "800",
|
|
335
|
+
letterSpacing: -0.2,
|
|
304
336
|
},
|
|
305
337
|
});
|
|
@@ -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
|