@umituz/react-native-ai-generation-content 1.27.25 → 1.27.26
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/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +13 -11
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts +5 -6
- package/src/domains/generation/wizard/infrastructure/utils/index.ts +8 -0
- package/src/domains/generation/wizard/infrastructure/utils/wizard-data-extractors.ts +198 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.26",
|
|
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",
|
package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./wizard-strategy.constants";
|
|
17
17
|
import { buildFacePreservationPrompt } from "../../../../prompts/infrastructure/builders/face-preservation-builder";
|
|
18
18
|
import { buildInteractionStylePrompt, type InteractionStyle } from "../../../../prompts/infrastructure/builders/interaction-style-builder";
|
|
19
|
+
import { extractPrompt, extractSelection } from "../utils";
|
|
19
20
|
|
|
20
21
|
declare const __DEV__: boolean;
|
|
21
22
|
|
|
@@ -165,9 +166,8 @@ export async function buildImageInput(
|
|
|
165
166
|
): Promise<ImageGenerationInput | null> {
|
|
166
167
|
const photos = await extractPhotosFromWizardData(wizardData);
|
|
167
168
|
|
|
168
|
-
//
|
|
169
|
-
const
|
|
170
|
-
const prompt = userPrompt?.trim() || scenario.aiPrompt?.trim();
|
|
169
|
+
// Extract prompt using type-safe extractor with fallback
|
|
170
|
+
const prompt = extractPrompt(wizardData, scenario.aiPrompt);
|
|
171
171
|
|
|
172
172
|
if (!prompt) {
|
|
173
173
|
throw new Error("Prompt is required for image generation");
|
|
@@ -178,18 +178,19 @@ export async function buildImageInput(
|
|
|
178
178
|
if (photos.length > 0) {
|
|
179
179
|
const styleEnhancements: string[] = [];
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
// Extract selections using type-safe extractor
|
|
182
|
+
const romanticMoods = extractSelection(wizardData.selection_romantic_mood);
|
|
183
|
+
if (Array.isArray(romanticMoods) && romanticMoods.length > 0) {
|
|
183
184
|
styleEnhancements.push(`Mood: ${romanticMoods.join(", ")}`);
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
const artStyle = wizardData.selection_art_style
|
|
187
|
-
if (artStyle && artStyle !== DEFAULT_STYLE_VALUE) {
|
|
187
|
+
const artStyle = extractSelection(wizardData.selection_art_style);
|
|
188
|
+
if (typeof artStyle === "string" && artStyle !== DEFAULT_STYLE_VALUE) {
|
|
188
189
|
styleEnhancements.push(`Art style: ${artStyle}`);
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
const artist = wizardData.selection_artist_style
|
|
192
|
-
if (artist && artist !== DEFAULT_STYLE_VALUE) {
|
|
192
|
+
const artist = extractSelection(wizardData.selection_artist_style);
|
|
193
|
+
if (typeof artist === "string" && artist !== DEFAULT_STYLE_VALUE) {
|
|
193
194
|
styleEnhancements.push(`Artist style: ${artist}`);
|
|
194
195
|
}
|
|
195
196
|
|
|
@@ -198,8 +199,9 @@ export async function buildImageInput(
|
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
//
|
|
202
|
-
const
|
|
202
|
+
// Extract style using type-safe extractor (for text-to-image)
|
|
203
|
+
const styleValue = extractSelection(wizardData.style);
|
|
204
|
+
const style = typeof styleValue === "string" ? styleValue : undefined;
|
|
203
205
|
|
|
204
206
|
// Get interaction style from scenario (default: romantic for couple apps)
|
|
205
207
|
const interactionStyle = (scenario.interactionStyle as InteractionStyle) ?? "romantic";
|
package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { createCreationsRepository } from "../../../../creations/infrastructure/
|
|
|
10
10
|
import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
|
|
11
11
|
import type { WizardStrategy } from "./wizard-strategy.types";
|
|
12
12
|
import { PHOTO_KEY_PREFIX, VIDEO_FEATURE_PATTERNS } from "./wizard-strategy.constants";
|
|
13
|
+
import { extractPrompt, extractDuration } from "../utils";
|
|
13
14
|
|
|
14
15
|
// ============================================================================
|
|
15
16
|
// Types
|
|
@@ -86,17 +87,15 @@ export async function buildVideoInput(
|
|
|
86
87
|
): Promise<VideoGenerationInput | null> {
|
|
87
88
|
const photos = await extractPhotosFromWizardData(wizardData);
|
|
88
89
|
|
|
89
|
-
//
|
|
90
|
-
const
|
|
91
|
-
const motionPrompt = wizardData.motion_prompt as string | undefined;
|
|
92
|
-
const prompt = userPrompt?.trim() || motionPrompt?.trim() || scenario.aiPrompt?.trim();
|
|
90
|
+
// Extract prompt using type-safe extractor with fallback
|
|
91
|
+
const prompt = extractPrompt(wizardData, scenario.aiPrompt);
|
|
93
92
|
|
|
94
93
|
if (!prompt) {
|
|
95
94
|
throw new Error("Prompt is required for video generation");
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
//
|
|
99
|
-
const duration = wizardData
|
|
97
|
+
// Extract duration using type-safe extractor (default: 5 seconds)
|
|
98
|
+
const duration = extractDuration(wizardData, 5);
|
|
100
99
|
|
|
101
100
|
return {
|
|
102
101
|
sourceImageBase64: photos[0],
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Data Extractors
|
|
3
|
+
* Type-safe utilities for extracting values from wizard data
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Type Guards + Normalizers
|
|
6
|
+
* @see https://www.typescriptlang.org/docs/handbook/2/narrowing.html
|
|
7
|
+
* @see https://betterstack.com/community/guides/scaling-nodejs/typescript-type-guards/
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Type Guards
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check if value is a non-null object
|
|
16
|
+
*/
|
|
17
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
18
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if object has a specific property
|
|
23
|
+
* Uses 'in' operator for safe property checking
|
|
24
|
+
*/
|
|
25
|
+
function hasProperty<K extends string>(
|
|
26
|
+
obj: Record<string, unknown>,
|
|
27
|
+
key: K,
|
|
28
|
+
): obj is Record<K, unknown> {
|
|
29
|
+
return key in obj;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// String Extractors
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extracts string from various input formats:
|
|
38
|
+
* - Direct string: "my text"
|
|
39
|
+
* - Object with text field: { text: "my text" }
|
|
40
|
+
* - Object with uri field (fallback): { uri: "my text" }
|
|
41
|
+
*
|
|
42
|
+
* @param value - The value to extract string from
|
|
43
|
+
* @returns The extracted string or undefined
|
|
44
|
+
*/
|
|
45
|
+
export function extractString(value: unknown): string | undefined {
|
|
46
|
+
// Direct string
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Object with text or uri field
|
|
52
|
+
if (isObject(value)) {
|
|
53
|
+
if (hasProperty(value, "text") && typeof value.text === "string") {
|
|
54
|
+
return value.text;
|
|
55
|
+
}
|
|
56
|
+
if (hasProperty(value, "uri") && typeof value.uri === "string") {
|
|
57
|
+
return value.uri;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Extracts and trims string, returning undefined if empty
|
|
66
|
+
*/
|
|
67
|
+
export function extractTrimmedString(value: unknown): string | undefined {
|
|
68
|
+
const str = extractString(value);
|
|
69
|
+
const trimmed = str?.trim();
|
|
70
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Number Extractors
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extracts number from various input formats:
|
|
79
|
+
* - Direct number: 5
|
|
80
|
+
* - Object with value field: { value: 5 }
|
|
81
|
+
* - Object with selection field: { selection: 5 }
|
|
82
|
+
*
|
|
83
|
+
* @param value - The value to extract number from
|
|
84
|
+
* @returns The extracted number or undefined
|
|
85
|
+
*/
|
|
86
|
+
export function extractNumber(value: unknown): number | undefined {
|
|
87
|
+
// Direct number
|
|
88
|
+
if (typeof value === "number" && !Number.isNaN(value)) {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Object with value or selection field
|
|
93
|
+
if (isObject(value)) {
|
|
94
|
+
if (hasProperty(value, "value") && typeof value.value === "number") {
|
|
95
|
+
return value.value;
|
|
96
|
+
}
|
|
97
|
+
if (hasProperty(value, "selection") && typeof value.selection === "number") {
|
|
98
|
+
return value.selection;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Selection Extractors
|
|
107
|
+
// ============================================================================
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Extracts selection value (string or string array) from wizard data
|
|
111
|
+
*
|
|
112
|
+
* @param value - The value to extract selection from
|
|
113
|
+
* @returns The extracted selection or undefined
|
|
114
|
+
*/
|
|
115
|
+
export function extractSelection(value: unknown): string | string[] | undefined {
|
|
116
|
+
// Direct string
|
|
117
|
+
if (typeof value === "string") {
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Direct string array
|
|
122
|
+
if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
123
|
+
return value as string[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Object with selection field
|
|
127
|
+
if (isObject(value)) {
|
|
128
|
+
if (hasProperty(value, "selection")) {
|
|
129
|
+
const selection = value.selection;
|
|
130
|
+
if (typeof selection === "string") {
|
|
131
|
+
return selection;
|
|
132
|
+
}
|
|
133
|
+
if (Array.isArray(selection) && selection.every((v) => typeof v === "string")) {
|
|
134
|
+
return selection as string[];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// Prompt Extractor (Specialized)
|
|
144
|
+
// ============================================================================
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Extracts prompt from wizard data with fallback chain
|
|
148
|
+
* Checks multiple keys in order: prompt, motion_prompt, text
|
|
149
|
+
*
|
|
150
|
+
* @param wizardData - The wizard data object
|
|
151
|
+
* @param fallback - Optional fallback value (e.g., scenario.aiPrompt)
|
|
152
|
+
* @returns The extracted and trimmed prompt or undefined
|
|
153
|
+
*/
|
|
154
|
+
export function extractPrompt(
|
|
155
|
+
wizardData: Record<string, unknown>,
|
|
156
|
+
fallback?: string,
|
|
157
|
+
): string | undefined {
|
|
158
|
+
// Priority chain for prompt keys
|
|
159
|
+
const promptKeys = ["prompt", "motion_prompt", "text", "userPrompt"];
|
|
160
|
+
|
|
161
|
+
for (const key of promptKeys) {
|
|
162
|
+
if (key in wizardData) {
|
|
163
|
+
const extracted = extractTrimmedString(wizardData[key]);
|
|
164
|
+
if (extracted) {
|
|
165
|
+
return extracted;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Use fallback if provided
|
|
171
|
+
return fallback?.trim() || undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ============================================================================
|
|
175
|
+
// Duration Extractor (Specialized)
|
|
176
|
+
// ============================================================================
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Extracts duration from wizard data
|
|
180
|
+
* Handles both direct number and object with value field
|
|
181
|
+
*
|
|
182
|
+
* @param wizardData - The wizard data object
|
|
183
|
+
* @param defaultValue - Default duration if not found
|
|
184
|
+
* @returns The extracted duration in seconds
|
|
185
|
+
*/
|
|
186
|
+
export function extractDuration(
|
|
187
|
+
wizardData: Record<string, unknown>,
|
|
188
|
+
defaultValue = 5,
|
|
189
|
+
): number {
|
|
190
|
+
const durationData = wizardData.duration;
|
|
191
|
+
|
|
192
|
+
const extracted = extractNumber(durationData);
|
|
193
|
+
if (extracted !== undefined && extracted > 0) {
|
|
194
|
+
return extracted;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return defaultValue;
|
|
198
|
+
}
|