@umituz/react-native-ai-generation-content 1.89.40 → 1.89.48
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/GalleryScreenHeader.tsx +0 -2
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +0 -2
- package/src/domains/generation/infrastructure/appearance-analysis.ts +47 -1
- package/src/domains/generation/infrastructure/couple-generation-builder.ts +184 -6
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +36 -6
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +113 -14
- package/src/domains/generation/wizard/presentation/components/WizardFlowContent.tsx +7 -0
- package/src/domains/generation/wizard/presentation/screens/SelectionScreen.tsx +14 -1
- package/src/domains/generation/wizard/presentation/screens/TextInputScreen.tsx +6 -1
- package/src/infrastructure/utils/couple-input.util.ts +72 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.89.
|
|
3
|
+
"version": "1.89.48",
|
|
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",
|
|
@@ -7,7 +7,6 @@ import React, { useMemo } from "react";
|
|
|
7
7
|
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens, type DesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
|
-
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
11
10
|
|
|
12
11
|
interface GalleryScreenHeaderProps {
|
|
13
12
|
readonly title: string;
|
|
@@ -16,7 +15,6 @@ interface GalleryScreenHeaderProps {
|
|
|
16
15
|
|
|
17
16
|
export const GalleryScreenHeader: React.FC<GalleryScreenHeaderProps> = ({ title, onBack }) => {
|
|
18
17
|
const tokens = useAppDesignTokens();
|
|
19
|
-
const insets = useSafeAreaInsets();
|
|
20
18
|
const styles = useMemo(() => createStyles(tokens), [tokens]);
|
|
21
19
|
|
|
22
20
|
return (
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, { useMemo, useCallback, useState } from "react";
|
|
2
2
|
import { View, FlatList } from "react-native";
|
|
3
|
-
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
3
|
import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
|
|
5
4
|
import { FilterSheet, useAppFocusEffect } from "@umituz/react-native-design-system/molecules";
|
|
6
5
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
@@ -38,7 +37,6 @@ export function CreationsGalleryScreen({
|
|
|
38
37
|
onShareToFeed,
|
|
39
38
|
}: CreationsGalleryScreenProps) {
|
|
40
39
|
const tokens = useAppDesignTokens();
|
|
41
|
-
const insets = useSafeAreaInsets();
|
|
42
40
|
const [viewMode, setViewMode] = useState<"list" | "grid">("list");
|
|
43
41
|
|
|
44
42
|
const { data: creations, isLoading, refetch } = useCreations({ userId, repository });
|
|
@@ -19,6 +19,17 @@ export async function getAppearanceContext(
|
|
|
19
19
|
photoUris: string[],
|
|
20
20
|
isCoupleMode: boolean,
|
|
21
21
|
): Promise<string> {
|
|
22
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
23
|
+
|
|
24
|
+
if (DEV) {
|
|
25
|
+
console.log("[AppearanceAnalysis] ===== ANALYSIS START =====");
|
|
26
|
+
console.log("[AppearanceAnalysis] Photo URIs:", photoUris.length);
|
|
27
|
+
console.log("[AppearanceAnalysis] Is couple mode:", isCoupleMode);
|
|
28
|
+
console.log("[AppearanceAnalysis] URIs:", photoUris.map((uri, i) => ` ${i + 1}. ${uri.substring(0, 60)}...`));
|
|
29
|
+
console.log("[AppearanceAnalysis] Vision analysis: DISABLED (returning empty context)");
|
|
30
|
+
console.log("[AppearanceAnalysis] ===== ANALYSIS END =====");
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
// Vision analysis temporarily disabled due to API limitations
|
|
23
34
|
// Future: Implement vision analysis to extract appearance features
|
|
24
35
|
return "";
|
|
@@ -39,15 +50,50 @@ export async function enhancePromptWithAnalysis(
|
|
|
39
50
|
photoUris: string[],
|
|
40
51
|
isCoupleMode: boolean,
|
|
41
52
|
): Promise<string> {
|
|
53
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
54
|
+
|
|
55
|
+
if (DEV) {
|
|
56
|
+
console.log("[AppearanceAnalysis] ===== ENHANCE START =====");
|
|
57
|
+
console.log("[AppearanceAnalysis] Original prompt length:", originalPrompt.length);
|
|
58
|
+
console.log("[AppearanceAnalysis] Photo URIs:", photoUris.length);
|
|
59
|
+
console.log("[AppearanceAnalysis] Is couple mode:", isCoupleMode);
|
|
60
|
+
console.log("[AppearanceAnalysis] Original preview:", originalPrompt.substring(0, 200) + "...");
|
|
61
|
+
}
|
|
62
|
+
|
|
42
63
|
// Always apply basic couple refinement first
|
|
43
64
|
let finalPrompt = refinePromptForCouple(originalPrompt, isCoupleMode);
|
|
44
65
|
|
|
45
|
-
if (
|
|
66
|
+
if (DEV) {
|
|
67
|
+
console.log("[AppearanceAnalysis] After refinePromptForCouple length:", finalPrompt.length);
|
|
68
|
+
console.log("[AppearanceAnalysis] After refine preview:", finalPrompt.substring(0, 250) + "...");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (photoUris.length === 0) {
|
|
72
|
+
if (DEV) {
|
|
73
|
+
console.log("[AppearanceAnalysis] No photos - returning refined prompt");
|
|
74
|
+
console.log("[AppearanceAnalysis] ===== ENHANCE END =====");
|
|
75
|
+
}
|
|
76
|
+
return finalPrompt;
|
|
77
|
+
}
|
|
46
78
|
|
|
47
79
|
const appearanceContext = await getAppearanceContext(photoUris, isCoupleMode);
|
|
48
80
|
|
|
49
81
|
if (appearanceContext) {
|
|
50
82
|
finalPrompt = `${appearanceContext}\n\n${finalPrompt}`;
|
|
83
|
+
if (DEV) {
|
|
84
|
+
console.log("[AppearanceAnalysis] ✅ Appearance context prepended");
|
|
85
|
+
console.log("[AppearanceAnalysis] Context length:", appearanceContext.length);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
if (DEV) {
|
|
89
|
+
console.log("[AppearanceAnalysis] ℹ️ No appearance context (vision disabled)");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (DEV) {
|
|
94
|
+
console.log("[AppearanceAnalysis] Final prompt length:", finalPrompt.length);
|
|
95
|
+
console.log("[AppearanceAnalysis] Final preview:", finalPrompt.substring(0, 300) + "...");
|
|
96
|
+
console.log("[AppearanceAnalysis] ===== ENHANCE END =====");
|
|
51
97
|
}
|
|
52
98
|
|
|
53
99
|
return finalPrompt;
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
* - Mood filter generation
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type { GenerationTarget } from "../../../exports/presentation";
|
|
16
15
|
import {
|
|
17
16
|
resolveCoupleInput,
|
|
18
17
|
prependContext,
|
|
@@ -74,6 +73,8 @@ export interface ScenarioGenerationInputParams {
|
|
|
74
73
|
export async function buildCoupleGenerationInput(
|
|
75
74
|
params: CoupleGenerationInputParams,
|
|
76
75
|
): Promise<CoupleGenerationInput> {
|
|
76
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
77
|
+
|
|
77
78
|
const {
|
|
78
79
|
partner1PhotoUri,
|
|
79
80
|
partner2PhotoUri,
|
|
@@ -84,33 +85,122 @@ export async function buildCoupleGenerationInput(
|
|
|
84
85
|
strength,
|
|
85
86
|
} = params;
|
|
86
87
|
|
|
88
|
+
if (DEV) {
|
|
89
|
+
console.log("[CoupleBuilder] ========================================");
|
|
90
|
+
console.log("[CoupleBuilder] ===== BUILD COUPLE GENERATION START =====");
|
|
91
|
+
console.log("[CoupleBuilder] ========================================");
|
|
92
|
+
console.log("[CoupleBuilder] ===== INPUT PARAMS =====");
|
|
93
|
+
console.log("[CoupleBuilder] Is couple mode:", isCoupleMode);
|
|
94
|
+
console.log("[CoupleBuilder] Base prompt length:", basePrompt.length);
|
|
95
|
+
console.log("[CoupleBuilder] Base prompt preview:", basePrompt.substring(0, 200) + "...");
|
|
96
|
+
console.log("[CoupleBuilder] Aspect ratio:", aspectRatio);
|
|
97
|
+
console.log("[CoupleBuilder] Has partner 2:", !!partner2PhotoUri);
|
|
98
|
+
console.log("[CoupleBuilder] Has custom instructions:", !!customInstructions);
|
|
99
|
+
console.log("[CoupleBuilder] Has strength:", strength !== undefined);
|
|
100
|
+
if (strength !== undefined) {
|
|
101
|
+
console.log("[CoupleBuilder] Strength value:", strength);
|
|
102
|
+
}
|
|
103
|
+
console.log("[CoupleBuilder] Partner 1 URI:", partner1PhotoUri.substring(0, 80) + "...");
|
|
104
|
+
if (partner2PhotoUri) {
|
|
105
|
+
console.log("[CoupleBuilder] Partner 2 URI:", partner2PhotoUri.substring(0, 80) + "...");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
87
109
|
// 1. GET PHOTO URIs - Couple mode kontrolü
|
|
88
110
|
const photoUris =
|
|
89
111
|
isCoupleMode && partner2PhotoUri
|
|
90
112
|
? [partner1PhotoUri, partner2PhotoUri]
|
|
91
113
|
: [partner1PhotoUri];
|
|
92
114
|
|
|
115
|
+
if (DEV) {
|
|
116
|
+
console.log("[CoupleBuilder] ===== STEP 1: PHOTO URIs =====");
|
|
117
|
+
console.log("[CoupleBuilder] Photo URIs count:", photoUris.length);
|
|
118
|
+
console.log("[CoupleBuilder] Photo 1:", photoUris[0].substring(0, 60) + "...");
|
|
119
|
+
if (photoUris.length > 1) {
|
|
120
|
+
console.log("[CoupleBuilder] Photo 2:", photoUris[1].substring(0, 60) + "...");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
93
124
|
// 2. ANALYZE APPEARANCE - Wardrobe'daki gibi
|
|
94
125
|
// Fotoğrafları analiz et ve context çıkar
|
|
126
|
+
if (DEV) {
|
|
127
|
+
console.log("[CoupleBuilder] ===== STEP 2: APPEARANCE ANALYSIS =====");
|
|
128
|
+
console.log("[CoupleBuilder] Calling getAppearanceContext with:", {
|
|
129
|
+
photoCount: photoUris.length,
|
|
130
|
+
isCoupleMode
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
95
134
|
const appearanceContext = await getAppearanceContext(
|
|
96
135
|
photoUris,
|
|
97
136
|
isCoupleMode,
|
|
98
137
|
);
|
|
99
138
|
|
|
139
|
+
if (DEV) {
|
|
140
|
+
console.log("[CoupleBuilder] Appearance context length:", appearanceContext.length);
|
|
141
|
+
if (appearanceContext.length > 0) {
|
|
142
|
+
console.log("[CoupleBuilder] Appearance context preview:", appearanceContext.substring(0, 150) + "...");
|
|
143
|
+
} else {
|
|
144
|
+
console.log("[CoupleBuilder] ℹ️ No appearance context returned (vision disabled)");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
100
148
|
// 3. REFINE FOR COUPLE + PREPEND CONTEXT - Wardrobe mantığı
|
|
101
149
|
// Coupler modu için prompt'u iyileştir ve context'i ekle
|
|
150
|
+
if (DEV) {
|
|
151
|
+
console.log("[CoupleBuilder] ===== STEP 3: REFINE & PREPEND CONTEXT =====");
|
|
152
|
+
console.log("[CoupleBuilder] Calling refinePromptForCouple with:", {
|
|
153
|
+
basePromptLength: basePrompt.length,
|
|
154
|
+
isCoupleMode
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
102
158
|
const refinedPrompt = prependContext(
|
|
103
159
|
refinePromptForCouple(basePrompt, isCoupleMode),
|
|
104
160
|
appearanceContext,
|
|
105
161
|
);
|
|
106
162
|
|
|
163
|
+
if (DEV) {
|
|
164
|
+
console.log("[CoupleBuilder] After refinePromptForCouple + prependContext:");
|
|
165
|
+
console.log("[CoupleBuilder] Refined prompt length:", refinedPrompt.length);
|
|
166
|
+
console.log("[CoupleBuilder] Refined prompt preview:", refinedPrompt.substring(0, 300) + "...");
|
|
167
|
+
}
|
|
168
|
+
|
|
107
169
|
// 4. CREATE FINAL PROMPT - Photorealistic
|
|
170
|
+
if (DEV) {
|
|
171
|
+
console.log("[CoupleBuilder] ===== STEP 4: CREATE PHOTOREALISTIC PROMPT =====");
|
|
172
|
+
console.log("[CoupleBuilder] Calling createPhotorealisticPrompt with:", {
|
|
173
|
+
isCouple: isCoupleMode,
|
|
174
|
+
hasCustomInstructions: !!customInstructions
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
108
178
|
const prompt = createPhotorealisticPrompt(refinedPrompt, {
|
|
109
179
|
isCouple: isCoupleMode,
|
|
110
180
|
customInstructions,
|
|
111
181
|
});
|
|
112
182
|
|
|
183
|
+
if (DEV) {
|
|
184
|
+
console.log("[CoupleBuilder] Final prompt length:", prompt.length);
|
|
185
|
+
console.log("[CoupleBuilder] Final prompt preview:", prompt.substring(0, 500) + "...");
|
|
186
|
+
console.log("[CoupleBuilder] Has custom instructions:", !!customInstructions);
|
|
187
|
+
if (customInstructions) {
|
|
188
|
+
console.log("[CoupleBuilder] Custom instructions:", customInstructions);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
113
192
|
// 5. RESOLVE COUPLE INPUT - Doğru target ve image'lar
|
|
193
|
+
if (DEV) {
|
|
194
|
+
console.log("[CoupleBuilder] ===== STEP 5: RESOLVE COUPLE INPUT =====");
|
|
195
|
+
console.log("[CoupleBuilder] Calling resolveCoupleInput with:", {
|
|
196
|
+
partner1PhotoUri: partner1PhotoUri.substring(0, 50) + "...",
|
|
197
|
+
partner2PhotoUri: partner2PhotoUri ? partner2PhotoUri.substring(0, 50) + "..." : null,
|
|
198
|
+
isCoupleMode,
|
|
199
|
+
singleTarget: "p-image-edit/pruna",
|
|
200
|
+
coupleTarget: "p-image-edit/pruna"
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
114
204
|
const { target, imageUrls } = resolveCoupleInput(
|
|
115
205
|
partner1PhotoUri,
|
|
116
206
|
partner2PhotoUri,
|
|
@@ -119,7 +209,22 @@ export async function buildCoupleGenerationInput(
|
|
|
119
209
|
{ model: "p-image-edit", providerId: "pruna" }, // Couple target
|
|
120
210
|
);
|
|
121
211
|
|
|
212
|
+
if (DEV) {
|
|
213
|
+
console.log("[CoupleBuilder] Target resolution result:");
|
|
214
|
+
console.log("[CoupleBuilder] Target model:", target.model);
|
|
215
|
+
console.log("[CoupleBuilder] Target provider:", target.providerId);
|
|
216
|
+
console.log("[CoupleBuilder] Image URLs count:", imageUrls.length);
|
|
217
|
+
console.log("[CoupleBuilder] Image 1:", imageUrls[0]?.substring(0, 80) + "...");
|
|
218
|
+
if (imageUrls.length > 1) {
|
|
219
|
+
console.log("[CoupleBuilder] Image 2:", imageUrls[1]?.substring(0, 80) + "...");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
122
223
|
// 6. BUILD PARAMS - Wardrobe formatında
|
|
224
|
+
if (DEV) {
|
|
225
|
+
console.log("[CoupleBuilder] ===== STEP 6: BUILD PARAMS =====");
|
|
226
|
+
}
|
|
227
|
+
|
|
123
228
|
const genParams: Record<string, unknown> = {
|
|
124
229
|
prompt,
|
|
125
230
|
image_urls: imageUrls,
|
|
@@ -131,6 +236,19 @@ export async function buildCoupleGenerationInput(
|
|
|
131
236
|
genParams.strength = strength;
|
|
132
237
|
}
|
|
133
238
|
|
|
239
|
+
if (DEV) {
|
|
240
|
+
console.log("[CoupleBuilder] Final params structure:");
|
|
241
|
+
console.log("[CoupleBuilder] Keys:", Object.keys(genParams).join(", "));
|
|
242
|
+
console.log("[CoupleBuilder] 'image_urls' count:", Array.isArray(genParams.image_urls) ? genParams.image_urls.length : "N/A");
|
|
243
|
+
console.log("[CoupleBuilder] 'aspect_ratio':", genParams.aspect_ratio);
|
|
244
|
+
console.log("[CoupleBuilder] 'strength':", genParams.strength ?? "not set");
|
|
245
|
+
console.log("[CoupleBuilder] ========================================");
|
|
246
|
+
console.log("[CoupleBuilder] ===== BUILD COUPLE GENERATION END =====");
|
|
247
|
+
console.log("[CoupleBuilder] ========================================");
|
|
248
|
+
console.log("[CoupleBuilder] Returning: { target, prompt, params }");
|
|
249
|
+
console.log("");
|
|
250
|
+
}
|
|
251
|
+
|
|
134
252
|
return {
|
|
135
253
|
target,
|
|
136
254
|
prompt,
|
|
@@ -147,34 +265,80 @@ export async function buildCoupleGenerationInput(
|
|
|
147
265
|
export async function buildScenarioGenerationInput(
|
|
148
266
|
params: ScenarioGenerationInputParams,
|
|
149
267
|
): Promise<CoupleGenerationInput> {
|
|
268
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
269
|
+
|
|
150
270
|
const {
|
|
151
271
|
partner1PhotoUri,
|
|
152
272
|
partner2PhotoUri,
|
|
153
273
|
isCoupleMode,
|
|
154
274
|
scenarioPrompt,
|
|
155
|
-
customInstructions,
|
|
156
275
|
} = params;
|
|
157
276
|
|
|
277
|
+
if (DEV) {
|
|
278
|
+
console.log("[ScenarioBuilder] ========================================");
|
|
279
|
+
console.log("[ScenarioBuilder] ===== BUILD SCENARIO GENERATION START =====");
|
|
280
|
+
console.log("[ScenarioBuilder] ========================================");
|
|
281
|
+
console.log("[ScenarioBuilder] ===== INPUT PARAMS =====");
|
|
282
|
+
console.log("[ScenarioBuilder] Is couple mode:", isCoupleMode);
|
|
283
|
+
console.log("[ScenarioBuilder] Scenario prompt length:", scenarioPrompt.length);
|
|
284
|
+
console.log("[ScenarioBuilder] Scenario prompt preview:", scenarioPrompt.substring(0, 200) + "...");
|
|
285
|
+
console.log("[ScenarioBuilder] Partner 1 URI:", partner1PhotoUri.substring(0, 80) + "...");
|
|
286
|
+
if (partner2PhotoUri) {
|
|
287
|
+
console.log("[ScenarioBuilder] Partner 2 URI:", partner2PhotoUri.substring(0, 80) + "...");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
158
291
|
// 1. GET PHOTO URIs
|
|
159
292
|
const photoUris =
|
|
160
293
|
isCoupleMode && partner2PhotoUri
|
|
161
294
|
? [partner1PhotoUri, partner2PhotoUri]
|
|
162
295
|
: [partner1PhotoUri];
|
|
163
296
|
|
|
297
|
+
if (DEV) {
|
|
298
|
+
console.log("[ScenarioBuilder] ===== STEP 1: PHOTO URIs =====");
|
|
299
|
+
console.log("[ScenarioBuilder] Photo URIs count:", photoUris.length);
|
|
300
|
+
}
|
|
301
|
+
|
|
164
302
|
// 2. ANALYZE APPEARANCE
|
|
303
|
+
if (DEV) {
|
|
304
|
+
console.log("[ScenarioBuilder] ===== STEP 2: APPEARANCE ANALYSIS =====");
|
|
305
|
+
}
|
|
306
|
+
|
|
165
307
|
const appearanceContext = await getAppearanceContext(
|
|
166
308
|
photoUris,
|
|
167
309
|
isCoupleMode,
|
|
168
310
|
);
|
|
169
311
|
|
|
312
|
+
if (DEV) {
|
|
313
|
+
console.log("[ScenarioBuilder] Appearance context length:", appearanceContext.length);
|
|
314
|
+
if (appearanceContext.length > 0) {
|
|
315
|
+
console.log("[ScenarioBuilder] Appearance context preview:", appearanceContext.substring(0, 150) + "...");
|
|
316
|
+
} else {
|
|
317
|
+
console.log("[ScenarioBuilder] ℹ️ No appearance context (vision disabled)");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
170
321
|
// 3. REFINE FOR COUPLE + PREPEND CONTEXT
|
|
171
322
|
// Senaryo prompt'unu (zaten photorealistic) dynamic context ile birleştir
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
323
|
+
if (DEV) {
|
|
324
|
+
console.log("[ScenarioBuilder] ===== STEP 3: REFINE & PREPEND CONTEXT =====");
|
|
325
|
+
console.log("[ScenarioBuilder] Calling refinePromptForCouple...");
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const refinedPrompt = refinePromptForCouple(scenarioPrompt, isCoupleMode);
|
|
329
|
+
const finalPrompt = prependContext(refinedPrompt, appearanceContext);
|
|
330
|
+
|
|
331
|
+
if (DEV) {
|
|
332
|
+
console.log("[ScenarioBuilder] After refinePromptForCouple length:", refinedPrompt.length);
|
|
333
|
+
console.log("[ScenarioBuilder] After prependContext length:", finalPrompt.length);
|
|
334
|
+
console.log("[ScenarioBuilder] Final prompt preview:", finalPrompt.substring(0, 300) + "...");
|
|
335
|
+
}
|
|
176
336
|
|
|
177
337
|
// 4. RESOLVE COUPLE INPUT
|
|
338
|
+
if (DEV) {
|
|
339
|
+
console.log("[ScenarioBuilder] ===== STEP 4: RESOLVE COUPLE INPUT =====");
|
|
340
|
+
}
|
|
341
|
+
|
|
178
342
|
const { target, imageUrls } = resolveCoupleInput(
|
|
179
343
|
partner1PhotoUri,
|
|
180
344
|
partner2PhotoUri,
|
|
@@ -183,7 +347,21 @@ export async function buildScenarioGenerationInput(
|
|
|
183
347
|
{ model: "p-image-edit", providerId: "pruna" }, // Couple target
|
|
184
348
|
);
|
|
185
349
|
|
|
350
|
+
if (DEV) {
|
|
351
|
+
console.log("[ScenarioBuilder] Target:", target.model, "/", target.providerId);
|
|
352
|
+
console.log("[ScenarioBuilder] Image URLs count:", imageUrls.length);
|
|
353
|
+
}
|
|
354
|
+
|
|
186
355
|
// 5. BUILD PARAMS - Scenario formatında
|
|
356
|
+
if (DEV) {
|
|
357
|
+
console.log("[ScenarioBuilder] ===== STEP 5: BUILD PARAMS =====");
|
|
358
|
+
console.log("[ScenarioBuilder] Aspect ratio: 3:4");
|
|
359
|
+
console.log("[ScenarioBuilder] ========================================");
|
|
360
|
+
console.log("[ScenarioBuilder] ===== BUILD SCENARIO GENERATION END =====");
|
|
361
|
+
console.log("[ScenarioBuilder] ========================================");
|
|
362
|
+
console.log("");
|
|
363
|
+
}
|
|
364
|
+
|
|
187
365
|
return {
|
|
188
366
|
target,
|
|
189
367
|
prompt: finalPrompt,
|
package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts
CHANGED
|
@@ -58,6 +58,28 @@ export async function executeImageGeneration(
|
|
|
58
58
|
const mode = imageUrls.length > 0 ? "Photo-based" : "Text-to-image";
|
|
59
59
|
const totalImageSize = imageUrls.reduce((sum, url) => sum + url.length, 0);
|
|
60
60
|
|
|
61
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
62
|
+
console.log("[ImageExecutor] ===== EXECUTION START =====");
|
|
63
|
+
console.log("[ImageExecutor] Mode:", mode);
|
|
64
|
+
console.log("[ImageExecutor] Model:", model);
|
|
65
|
+
console.log("[ImageExecutor] Provider ID:", providerId);
|
|
66
|
+
console.log("[ImageExecutor] ===== INPUT DATA =====");
|
|
67
|
+
console.log("[ImageExecutor] Photo count:", imageUrls.length);
|
|
68
|
+
console.log("[ImageExecutor] Total image size:", Math.round(totalImageSize / 1024), "KB");
|
|
69
|
+
console.log("[ImageExecutor] Image sizes:", imageUrls.map((url, i) => ` Photo ${i + 1}: ${(url.length / 1024).toFixed(2)}KB`));
|
|
70
|
+
console.log("[ImageExecutor] Aspect ratio:", input.aspectRatio || MODEL_INPUT_DEFAULTS.aspectRatio);
|
|
71
|
+
console.log("[ImageExecutor] ===== PROMPT =====");
|
|
72
|
+
console.log("[ImageExecutor] Prompt length:", finalPrompt.length);
|
|
73
|
+
console.log("[ImageExecutor] Prompt preview:");
|
|
74
|
+
console.log(finalPrompt.substring(0, 400) + "...");
|
|
75
|
+
console.log("[ImageExecutor] ===== MODEL INPUT =====");
|
|
76
|
+
console.log("[ImageExecutor] Model:", model);
|
|
77
|
+
console.log("[ImageExecutor] Input keys:", Object.keys(MODEL_INPUT_DEFAULTS));
|
|
78
|
+
console.log("[ImageExecutor] Output format:", MODEL_INPUT_DEFAULTS.outputFormat);
|
|
79
|
+
console.log("[ImageExecutor] Num images:", MODEL_INPUT_DEFAULTS.numImages);
|
|
80
|
+
console.log("[ImageExecutor] Safety checker:", MODEL_INPUT_DEFAULTS.enableSafetyChecker);
|
|
81
|
+
}
|
|
82
|
+
|
|
61
83
|
addGenerationLog(sid, TAG, `${mode} generation starting`, 'info', {
|
|
62
84
|
model,
|
|
63
85
|
photoCount: imageUrls.length,
|
|
@@ -70,16 +92,24 @@ export async function executeImageGeneration(
|
|
|
70
92
|
const modelInput: Record<string, unknown> = {
|
|
71
93
|
prompt: finalPrompt,
|
|
72
94
|
aspect_ratio: input.aspectRatio || MODEL_INPUT_DEFAULTS.aspectRatio,
|
|
73
|
-
output_format: MODEL_INPUT_DEFAULTS.outputFormat,
|
|
74
|
-
num_images: MODEL_INPUT_DEFAULTS.numImages,
|
|
75
|
-
enable_safety_checker: MODEL_INPUT_DEFAULTS.enableSafetyChecker,
|
|
76
95
|
};
|
|
77
96
|
|
|
78
|
-
// p-image-edit (and typical multi-ref models) usually expect 'images' key
|
|
79
|
-
// supporting both 'images' and 'image_urls' for maximum compatibility
|
|
80
97
|
if (imageUrls.length > 0) {
|
|
81
|
-
modelInput.images = imageUrls;
|
|
82
98
|
modelInput.image_urls = imageUrls;
|
|
99
|
+
modelInput.images = imageUrls;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
103
|
+
console.log("[ImageExecutor] ===== MODEL INPUT CONSTRUCTED =====");
|
|
104
|
+
console.log("[ImageExecutor] Input keys:", Object.keys(modelInput));
|
|
105
|
+
console.log("[ImageExecutor] Has 'images':", "images" in modelInput, "(count:", Array.isArray(modelInput.images) ? modelInput.images.length : "N/A", ")");
|
|
106
|
+
console.log("[ImageExecutor] Has 'image_urls':", "image_urls" in modelInput, "(count:", Array.isArray(modelInput.image_urls) ? modelInput.image_urls.length : "N/A", ")");
|
|
107
|
+
console.log("[ImageExecutor] Images array length:", imageUrls.length);
|
|
108
|
+
if (imageUrls.length > 0) {
|
|
109
|
+
console.log("[ImageExecutor] First image preview:", imageUrls[0].substring(0, 80) + "...");
|
|
110
|
+
console.log("[ImageExecutor] Last image preview:", imageUrls[imageUrls.length - 1].substring(0, 80) + "...");
|
|
111
|
+
}
|
|
112
|
+
console.log("[ImageExecutor] ===== CALLING PROVIDER =====");
|
|
83
113
|
}
|
|
84
114
|
|
|
85
115
|
addGenerationLog(sid, TAG, 'Calling provider.subscribe()...');
|
package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { extractPhotosAsBase64, extractPhotoUris } from "./shared/photo-extracti
|
|
|
11
11
|
import { executeImageGeneration } from "./image-generation.executor";
|
|
12
12
|
import type { WizardImageInput, CreateImageStrategyOptions } from "./image-generation.types";
|
|
13
13
|
import { enhancePromptWithAnalysis } from "../../../infrastructure/appearance-analysis";
|
|
14
|
+
import { createPhotorealisticPrompt } from "../../../../prompts/domain/base/creators";
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
// ============================================================================
|
|
@@ -21,17 +22,65 @@ export async function buildImageInput(
|
|
|
21
22
|
wizardData: Record<string, unknown>,
|
|
22
23
|
scenario: WizardScenarioData,
|
|
23
24
|
): Promise<WizardImageInput | null> {
|
|
25
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
26
|
+
|
|
27
|
+
if (DEV) {
|
|
28
|
+
console.log("[ImageStrategy] ===== BUILD IMAGE INPUT START =====");
|
|
29
|
+
console.log("[ImageStrategy] Scenario ID:", scenario.id);
|
|
30
|
+
console.log("[ImageStrategy] Scenario model:", scenario.model);
|
|
31
|
+
console.log("[ImageStrategy] Scenario provider:", scenario.providerId);
|
|
32
|
+
console.log("[ImageStrategy] ===== WIZARD DATA KEYS =====");
|
|
33
|
+
const wizardKeys = Object.keys(wizardData);
|
|
34
|
+
console.log("[ImageStrategy] Total keys:", wizardKeys.length);
|
|
35
|
+
console.log("[ImageStrategy] Keys:", wizardKeys.slice(0, 20).join(", ") + (wizardKeys.length > 20 ? "..." : ""));
|
|
36
|
+
|
|
37
|
+
// Log photo-related keys
|
|
38
|
+
const photoKeys = wizardKeys.filter(k => k.includes("photo"));
|
|
39
|
+
if (photoKeys.length > 0) {
|
|
40
|
+
console.log("[ImageStrategy] Photo-related keys:", photoKeys.join(", "));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Log selection/style keys
|
|
44
|
+
const selectionKeys = wizardKeys.filter(k => k.includes("selection") || k.includes("style"));
|
|
45
|
+
if (selectionKeys.length > 0) {
|
|
46
|
+
console.log("[ImageStrategy] Selection/style keys:", selectionKeys.join(", "));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
24
50
|
// Extract photo URIs first (for couple refinement)
|
|
25
51
|
const photoUris = extractPhotoUris(wizardData);
|
|
26
|
-
const photos = await extractPhotosAsBase64(wizardData);
|
|
52
|
+
const photos = await extractPhotosAsBase64(wizardData, DEV);
|
|
53
|
+
|
|
54
|
+
if (DEV) {
|
|
55
|
+
console.log("[ImageStrategy] ===== EXTRACTION COMPLETE =====");
|
|
56
|
+
console.log("[ImageStrategy] Photo URIs count:", photoUris.length);
|
|
57
|
+
console.log("[ImageStrategy] Base64 photos count:", photos.length);
|
|
58
|
+
}
|
|
27
59
|
|
|
28
60
|
// Extract prompt with fallback to default
|
|
29
61
|
let prompt = extractPrompt(wizardData, scenario.aiPrompt);
|
|
30
62
|
|
|
63
|
+
if (DEV) {
|
|
64
|
+
console.log("[ImageStrategy] ===== PROMPT EXTRACTION =====");
|
|
65
|
+
console.log("[ImageStrategy] Scenario aiPrompt type:", typeof scenario.aiPrompt);
|
|
66
|
+
console.log("[ImageStrategy] Scenario aiPrompt length:", typeof scenario.aiPrompt === "string" ? scenario.aiPrompt.length : "N/A");
|
|
67
|
+
if (typeof scenario.aiPrompt === "string") {
|
|
68
|
+
console.log("[ImageStrategy] Scenario aiPrompt preview:", scenario.aiPrompt.substring(0, 200) + "...");
|
|
69
|
+
}
|
|
70
|
+
console.log("[ImageStrategy] Extracted prompt type:", typeof prompt);
|
|
71
|
+
console.log("[ImageStrategy] Extracted prompt length:", prompt?.length ?? 0);
|
|
72
|
+
if (prompt) {
|
|
73
|
+
console.log("[ImageStrategy] Extracted prompt preview:", prompt.substring(0, 200) + "...");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
31
77
|
if (!prompt) {
|
|
32
78
|
const defaultPrompt = IMAGE_PROCESSING_PROMPTS[scenario.id];
|
|
33
79
|
if (defaultPrompt) {
|
|
34
80
|
prompt = defaultPrompt;
|
|
81
|
+
if (DEV) {
|
|
82
|
+
console.log("[ImageStrategy] Using default prompt for scenario:", scenario.id);
|
|
83
|
+
}
|
|
35
84
|
} else {
|
|
36
85
|
throw new Error("Prompt is required for image generation");
|
|
37
86
|
}
|
|
@@ -40,20 +89,49 @@ export async function buildImageInput(
|
|
|
40
89
|
// Apply style enhancements for photo-based generation
|
|
41
90
|
let finalPrompt = prompt;
|
|
42
91
|
if (photos.length > 0) {
|
|
43
|
-
finalPrompt = applyStyleEnhancements(prompt, wizardData);
|
|
44
|
-
|
|
45
|
-
// ✅ Apply couple refinement (same logic as Wardrobe)
|
|
46
|
-
// This ensures consistency across all couple generation scenarios
|
|
47
92
|
const isCoupleMode = photos.length >= 2;
|
|
48
|
-
|
|
93
|
+
const styleEnhanced = applyStyleEnhancements(prompt, wizardData);
|
|
94
|
+
|
|
95
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
96
|
+
console.log("[ImageStrategy] ===== STRATEGY START =====");
|
|
97
|
+
console.log("[ImageStrategy] Scenario:", scenario.id);
|
|
98
|
+
console.log("[ImageStrategy] Model:", scenario.model);
|
|
99
|
+
console.log("[ImageStrategy] Provider:", scenario.providerId);
|
|
100
|
+
console.log("[ImageStrategy] ===== PROMPT FLOW =====");
|
|
101
|
+
console.log("[ImageStrategy] [1/5] Original scenario prompt:");
|
|
102
|
+
console.log("[ImageStrategy] Length:", prompt.length);
|
|
103
|
+
console.log("[ImageStrategy] Preview:", prompt.substring(0, 150) + "...");
|
|
104
|
+
console.log("[ImageStrategy] [2/5] Style enhancements applied:", styleEnhanced !== prompt);
|
|
105
|
+
if (styleEnhanced !== prompt) {
|
|
106
|
+
console.log("[ImageStrategy] Enhanced preview:", styleEnhanced.substring(0, 150) + "...");
|
|
107
|
+
}
|
|
108
|
+
console.log("[ImageStrategy] [3/5] Couple mode:", isCoupleMode);
|
|
109
|
+
console.log("[ImageStrategy] Photo count:", photos.length);
|
|
110
|
+
console.log("[ImageStrategy] [4/5] Calling enhancePromptWithAnalysis...");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const refinedPrompt = await enhancePromptWithAnalysis(styleEnhanced, photoUris, isCoupleMode);
|
|
114
|
+
|
|
115
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
116
|
+
console.log("[ImageStrategy] After enhancePromptWithAnalysis:");
|
|
117
|
+
console.log("[ImageStrategy] Length:", refinedPrompt.length);
|
|
118
|
+
console.log("[ImageStrategy] Preview:", refinedPrompt.substring(0, 200) + "...");
|
|
119
|
+
console.log("[ImageStrategy] [5/5] Calling createPhotorealisticPrompt (Wardrobe style)...");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
finalPrompt = createPhotorealisticPrompt(refinedPrompt, {
|
|
123
|
+
isCouple: isCoupleMode,
|
|
124
|
+
customInstructions: undefined,
|
|
125
|
+
});
|
|
49
126
|
|
|
50
127
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
51
|
-
console.log("[ImageStrategy]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
128
|
+
console.log("[ImageStrategy] ===== STRATEGY END =====");
|
|
129
|
+
console.log("[ImageStrategy] Final prompt length:", finalPrompt.length);
|
|
130
|
+
console.log("[ImageStrategy] Final prompt preview:");
|
|
131
|
+
console.log(finalPrompt.substring(0, 600) + "...");
|
|
132
|
+
console.log("[ImageStrategy] ===== OUTPUT =====");
|
|
133
|
+
console.log("[ImageStrategy] Photo count:", photos.length);
|
|
134
|
+
console.log("[ImageStrategy] Photo sizes:", photos.map((p, i) => `Photo ${i + 1}: ${(p.length / 1024).toFixed(2)}KB`));
|
|
57
135
|
}
|
|
58
136
|
}
|
|
59
137
|
|
|
@@ -61,8 +139,29 @@ export async function buildImageInput(
|
|
|
61
139
|
const styleValue = extractSelection(wizardData.style);
|
|
62
140
|
const style = typeof styleValue === "string" ? styleValue : undefined;
|
|
63
141
|
|
|
64
|
-
|
|
65
|
-
|
|
142
|
+
let aspectRatio = typeof wizardData.aspect_ratio === "string" ? wizardData.aspect_ratio : undefined;
|
|
143
|
+
|
|
144
|
+
if (!aspectRatio && photos.length > 0) {
|
|
145
|
+
aspectRatio = "3:4"; // Wardrobe default
|
|
146
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
147
|
+
console.log("[ImageStrategy] No aspect_ratio in wizardData, using Wardrobe default: 3:4");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
152
|
+
console.log("[ImageStrategy] ===== STYLE & ASPECT RATIO =====");
|
|
153
|
+
console.log("[ImageStrategy] wizardData.style:", wizardData.style);
|
|
154
|
+
console.log("[ImageStrategy] Extracted styleValue:", styleValue);
|
|
155
|
+
console.log("[ImageStrategy] Final style:", style || "none");
|
|
156
|
+
console.log("[ImageStrategy] wizardData.aspect_ratio:", wizardData.aspect_ratio);
|
|
157
|
+
console.log("[ImageStrategy] Final aspectRatio:", aspectRatio || "default");
|
|
158
|
+
console.log("[ImageStrategy] ===== FINAL OUTPUT =====");
|
|
159
|
+
console.log("[ImageStrategy] Photos count:", photos.length);
|
|
160
|
+
console.log("[ImageStrategy] Prompt length:", finalPrompt.length);
|
|
161
|
+
console.log("[ImageStrategy] Aspect ratio:", aspectRatio || "default");
|
|
162
|
+
console.log("[ImageStrategy] Returning WizardImageInput");
|
|
163
|
+
console.log("[ImageStrategy] ===== STRATEGY COMPLETE =====");
|
|
164
|
+
}
|
|
66
165
|
|
|
67
166
|
return { photos, prompt: finalPrompt, style, aspectRatio };
|
|
68
167
|
}
|
|
@@ -227,6 +227,13 @@ export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
|
|
|
227
227
|
[customData, featureConfig.steps, calculateCredits, creditCost, validatedScenario.outputType, validatedScenario.inputType],
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
+
// Reset local state when scenario changes
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
setCurrentCreation(null);
|
|
233
|
+
setShowRatingPicker(false);
|
|
234
|
+
setHasRated(false);
|
|
235
|
+
}, [scenario?.id]);
|
|
236
|
+
|
|
230
237
|
useEffect(() => {
|
|
231
238
|
if (currentStep && onStepChange && prevStepIdRef.current !== currentStep.id) {
|
|
232
239
|
prevStepIdRef.current = currentStep.id;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Generic selection step for wizard flows (duration, style, etc.)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React, { useState, useCallback, useMemo } from "react";
|
|
6
|
+
import React, { useState, useCallback, useMemo, useEffect } from "react";
|
|
7
7
|
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { NavigationHeader } from "@umituz/react-native-design-system/molecules";
|
|
@@ -42,6 +42,19 @@ export const SelectionScreen: React.FC<SelectionScreenProps> = ({
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
const isMultiSelect = config?.multiSelect ?? false;
|
|
45
|
+
|
|
46
|
+
// Reset selection when initialValue, options, or config changes (e.g., when scenario changes)
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const optionIds = options.map((opt) => opt.id);
|
|
49
|
+
|
|
50
|
+
if (isMultiSelect) {
|
|
51
|
+
const initialArr = initialValue && Array.isArray(initialValue) ? initialValue : [];
|
|
52
|
+
setSelected(initialArr.filter((id) => optionIds.includes(id)));
|
|
53
|
+
} else {
|
|
54
|
+
const initialStr = typeof initialValue === "string" ? initialValue : "";
|
|
55
|
+
setSelected(optionIds.includes(initialStr) ? initialStr : "");
|
|
56
|
+
}
|
|
57
|
+
}, [initialValue, options, isMultiSelect]);
|
|
45
58
|
const isRequired = config?.required ?? true;
|
|
46
59
|
const canContinue = isRequired
|
|
47
60
|
? isMultiSelect ? (selected as string[]).length > 0 : selected !== ""
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses design system: NavigationHeader + ScreenLayout
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { useState, useCallback, useMemo } from "react";
|
|
7
|
+
import React, { useState, useCallback, useMemo, useEffect } from "react";
|
|
8
8
|
import { View, TextInput, StyleSheet } from "react-native";
|
|
9
9
|
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system/atoms";
|
|
10
10
|
import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
|
|
@@ -36,6 +36,11 @@ export const TextInputScreen: React.FC<TextInputScreenProps> = ({
|
|
|
36
36
|
const alert = useAlert();
|
|
37
37
|
const [text, setText] = useState(initialValue);
|
|
38
38
|
|
|
39
|
+
// Reset text when initialValue changes (e.g., when scenario changes)
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
setText(initialValue);
|
|
42
|
+
}, [initialValue]);
|
|
43
|
+
|
|
39
44
|
// Validate config - REQUIRED, NO DEFAULTS
|
|
40
45
|
if (!config) {
|
|
41
46
|
throw new Error("[TextInputScreen] Config is required but was not provided.");
|
|
@@ -20,16 +20,54 @@ export function resolveCoupleInput(
|
|
|
20
20
|
singleTarget: GenerationTargetLike,
|
|
21
21
|
coupleTarget: GenerationTargetLike,
|
|
22
22
|
): CoupleInputResult {
|
|
23
|
+
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
24
|
+
|
|
25
|
+
if (DEV) {
|
|
26
|
+
console.log("[CoupleUtil] ===== RESOLVE COUPLE INPUT =====");
|
|
27
|
+
console.log("[CoupleUtil] Is couple mode:", isCoupleMode);
|
|
28
|
+
console.log("[CoupleUtil] Has partner 2:", !!partner2PhotoUri);
|
|
29
|
+
console.log("[CoupleUtil] Partner 1 URI:", partner1PhotoUri.substring(0, 60) + "...");
|
|
30
|
+
if (partner2PhotoUri) {
|
|
31
|
+
console.log("[CoupleUtil] Partner 2 URI:", partner2PhotoUri.substring(0, 60) + "...");
|
|
32
|
+
}
|
|
33
|
+
console.log("[CoupleUtil] Single target:", `${singleTarget.model}/${singleTarget.providerId}`);
|
|
34
|
+
console.log("[CoupleUtil] Couple target:", `${coupleTarget.model}/${coupleTarget.providerId}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
23
37
|
if (isCoupleMode && partner2PhotoUri) {
|
|
24
|
-
|
|
38
|
+
const result = {
|
|
25
39
|
target: coupleTarget,
|
|
26
40
|
imageUrls: [partner1PhotoUri, partner2PhotoUri],
|
|
27
41
|
};
|
|
42
|
+
|
|
43
|
+
if (DEV) {
|
|
44
|
+
console.log("[CoupleUtil] ===== COUPLE MODE SELECTED =====");
|
|
45
|
+
console.log("[CoupleUtil] Target model:", result.target.model);
|
|
46
|
+
console.log("[CoupleUtil] Target provider:", result.target.providerId);
|
|
47
|
+
console.log("[CoupleUtil] Image URLs:", result.imageUrls.length);
|
|
48
|
+
console.log("[CoupleUtil] Image 1:", result.imageUrls[0].substring(0, 60) + "...");
|
|
49
|
+
console.log("[CoupleUtil] Image 2:", result.imageUrls[1].substring(0, 60) + "...");
|
|
50
|
+
console.log("[CoupleUtil] ===== RESOLVE COMPLETE =====");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
28
54
|
}
|
|
29
|
-
|
|
55
|
+
|
|
56
|
+
const result = {
|
|
30
57
|
target: singleTarget,
|
|
31
58
|
imageUrls: [partner1PhotoUri],
|
|
32
59
|
};
|
|
60
|
+
|
|
61
|
+
if (DEV) {
|
|
62
|
+
console.log("[CoupleUtil] ===== SINGLE MODE SELECTED =====");
|
|
63
|
+
console.log("[CoupleUtil] Target model:", result.target.model);
|
|
64
|
+
console.log("[CoupleUtil] Target provider:", result.target.providerId);
|
|
65
|
+
console.log("[CoupleUtil] Image URLs:", result.imageUrls.length);
|
|
66
|
+
console.log("[CoupleUtil] Image 1:", result.imageUrls[0].substring(0, 60) + "...");
|
|
67
|
+
console.log("[CoupleUtil] ===== RESOLVE COMPLETE =====");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
33
71
|
}
|
|
34
72
|
|
|
35
73
|
/**
|
|
@@ -47,6 +85,13 @@ export function prependContext(
|
|
|
47
85
|
* Primarily used to fix "baked" prompts that were generated with a specific mode in mind.
|
|
48
86
|
*/
|
|
49
87
|
export function refinePromptForCouple(prompt: string, isCouple: boolean): string {
|
|
88
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
89
|
+
console.log("[CoupleUtil] ===== REFINE PROMPT START =====");
|
|
90
|
+
console.log("[CoupleUtil] Is couple mode:", isCouple);
|
|
91
|
+
console.log("[CoupleUtil] Original prompt length:", prompt.length);
|
|
92
|
+
console.log("[CoupleUtil] Original prompt preview:", prompt.substring(0, 200) + "...");
|
|
93
|
+
}
|
|
94
|
+
|
|
50
95
|
if (isCouple) {
|
|
51
96
|
// Ensure couple context is present
|
|
52
97
|
let refined = prompt
|
|
@@ -64,22 +109,36 @@ export function refinePromptForCouple(prompt: string, isCouple: boolean): string
|
|
|
64
109
|
refined = refined
|
|
65
110
|
.replace(/\b(dress|gown)\b/gi, "$1 (worn by Person 1)")
|
|
66
111
|
.replace(/\b(suit|tuxedo|linen trousers)\b/gi, "$1 (worn by Person 2)");
|
|
67
|
-
|
|
112
|
+
|
|
68
113
|
// Also add explicit mapping to the top if not already there
|
|
69
114
|
if (!refined.includes("DIRECTIVE: MAP PHOTO 1 TO PERSON 1")) {
|
|
70
115
|
refined = `DIRECTIVE: MAP PHOTO 1 TO PERSON 1, MAP PHOTO 2 TO PERSON 2\n\n${refined}`;
|
|
71
116
|
}
|
|
117
|
+
|
|
118
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
119
|
+
console.log("[CoupleUtil] ✅ Clothing mapping applied!");
|
|
120
|
+
console.log("[CoupleUtil] ✅ Directive added for photo mapping");
|
|
121
|
+
}
|
|
72
122
|
}
|
|
73
123
|
|
|
74
124
|
// If it doesn't already have couple-hints, add them at the start
|
|
75
125
|
if (!/\b(couple|both|matching|dual|two people)\b/i.test(refined) && !refined.includes("DIRECTIVE:")) {
|
|
76
126
|
refined = `A photo of a couple, ${refined}`;
|
|
127
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
128
|
+
console.log("[CoupleUtil] ✅ Added 'A photo of a couple' prefix");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
133
|
+
console.log("[CoupleUtil] Refined prompt length:", refined.length);
|
|
134
|
+
console.log("[CoupleUtil] Refined prompt preview:", refined.substring(0, 300) + "...");
|
|
135
|
+
console.log("[CoupleUtil] ===== REFINE PROMPT END =====");
|
|
77
136
|
}
|
|
78
137
|
return refined;
|
|
79
138
|
} else {
|
|
80
139
|
// Solo mode: AGGRESSIVELY remove plural references to prevent "ghost" people
|
|
81
|
-
|
|
82
|
-
// Instead of removing the clothing descriptions, just remove the gender labels
|
|
140
|
+
const soloRefined = prompt
|
|
141
|
+
// Instead of removing the clothing descriptions, just remove the gender labels
|
|
83
142
|
// so the AI can apply the relevant clothing to the single person it sees.
|
|
84
143
|
.replace(/\sfor women\b/gi, "")
|
|
85
144
|
.replace(/\sfor men\b/gi, "")
|
|
@@ -90,7 +149,7 @@ export function refinePromptForCouple(prompt: string, isCouple: boolean): string
|
|
|
90
149
|
.replace(/\bcoordinating\b/gi, "")
|
|
91
150
|
.replace(/\bcouple\b/gi, "person")
|
|
92
151
|
.replace(/\bduo\b/gi, "person")
|
|
93
|
-
.replace(/\bpair\b/gi, "person")
|
|
152
|
+
.replace(/\bpair\b/gi, "person")
|
|
94
153
|
.replace(/\bdoubles\b/gi, "")
|
|
95
154
|
.replace(/\bboth\b/gi, "the person")
|
|
96
155
|
.replace(/\bthey are\b/gi, "the person is")
|
|
@@ -109,6 +168,13 @@ export function refinePromptForCouple(prompt: string, isCouple: boolean): string
|
|
|
109
168
|
.replace(/\bhats\b/gi, "hat")
|
|
110
169
|
.replace(/\baccessories\b/gi, "accessory")
|
|
111
170
|
.replace(/\s+/g, ' ').trim();
|
|
171
|
+
|
|
172
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
173
|
+
console.log("[CoupleUtil] ✅ Solo mode - removed all plural references");
|
|
174
|
+
console.log("[CoupleUtil] Solo refined prompt length:", soloRefined.length);
|
|
175
|
+
console.log("[CoupleUtil] ===== REFINE PROMPT END =====");
|
|
176
|
+
}
|
|
177
|
+
return soloRefined;
|
|
112
178
|
}
|
|
113
179
|
}
|
|
114
180
|
|