@umituz/react-native-ai-generation-content 1.37.12 → 1.37.13

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.37.12",
3
+ "version": "1.37.13",
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",
@@ -3,8 +3,7 @@
3
3
  * Handles the actual image generation execution
4
4
  */
5
5
 
6
- import { buildFacePreservationPrompt } from "../../../../prompts/infrastructure/builders/face-preservation-builder";
7
- import { buildInteractionStylePrompt } from "../../../../prompts/infrastructure/builders/interaction-style-builder";
6
+ import { buildUnifiedPrompt } from "./shared/unified-prompt-builder";
8
7
  import type { WizardImageInput } from "./image-generation.types";
9
8
  import {
10
9
  GENERATION_TIMEOUT_MS,
@@ -21,31 +20,19 @@ interface ExecutionResult {
21
20
  error?: string;
22
21
  }
23
22
 
24
- /**
25
- * Formats base64 string with proper data URI prefix
26
- */
27
23
  function formatBase64(base64: string): string {
28
24
  return base64.startsWith("data:") ? base64 : `${BASE64_IMAGE_PREFIX}${base64}`;
29
25
  }
30
26
 
31
- /**
32
- * Builds the final prompt based on input type (photo-based or text-to-image)
33
- */
34
27
  function buildFinalPrompt(input: WizardImageInput, imageUrls: string[]): string {
35
28
  const hasPhotos = imageUrls.length > 0;
36
29
 
37
30
  if (hasPhotos) {
38
- const facePrompt = buildFacePreservationPrompt({
39
- scenarioPrompt: input.prompt,
40
- personCount: imageUrls.length,
31
+ return buildUnifiedPrompt({
32
+ basePrompt: input.prompt,
33
+ photoCount: imageUrls.length,
34
+ interactionStyle: input.interactionStyle,
41
35
  });
42
-
43
- const interactionPrompt = buildInteractionStylePrompt({
44
- style: input.interactionStyle ?? "romantic",
45
- personCount: imageUrls.length,
46
- });
47
-
48
- return interactionPrompt ? `${facePrompt}\n\n${interactionPrompt}` : facePrompt;
49
36
  }
50
37
 
51
38
  // Text-to-image with optional style
@@ -56,9 +43,6 @@ function buildFinalPrompt(input: WizardImageInput, imageUrls: string[]): string
56
43
  return input.prompt;
57
44
  }
58
45
 
59
- /**
60
- * Executes image generation using the AI provider
61
- */
62
46
  export async function executeImageGeneration(
63
47
  input: WizardImageInput,
64
48
  model: string,
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Unified Prompt Builder
3
+ * Single prompt building logic for ALL generation types (image & video)
4
+ * Uses MultiPersonPromptStructure for photo-based scenarios
5
+ * Uses createEnhancedPrompt for text-only scenarios
6
+ */
7
+
8
+ import { createMultiPersonPrompt } from "../../../../../prompts/domain/entities/MultiPersonPromptStructure";
9
+ import { createEnhancedPrompt } from "../../../../../prompts/domain/entities/BasePromptStructure";
10
+
11
+ export interface BuildPromptOptions {
12
+ /** Base scenario prompt (aiPrompt from scenario config) */
13
+ readonly basePrompt: string;
14
+ /** Number of photos/people in generation */
15
+ readonly photoCount: number;
16
+ /** Interaction style from scenario (optional - only if scenario specifies it) */
17
+ readonly interactionStyle?: string;
18
+ }
19
+
20
+ /**
21
+ * Build unified prompt for any generation type
22
+ * - Photo-based: Uses createMultiPersonPrompt with @image1, @image2 references
23
+ * - Text-only: Uses createEnhancedPrompt with identity preservation
24
+ */
25
+ export function buildUnifiedPrompt(options: BuildPromptOptions): string {
26
+ const { basePrompt, photoCount, interactionStyle } = options;
27
+
28
+ // Text-only generation (no photos)
29
+ if (photoCount === 0) {
30
+ return createEnhancedPrompt(basePrompt, {
31
+ includeIdentityPreservation: false,
32
+ includePhotoRealism: true,
33
+ includePoseGuidelines: true,
34
+ });
35
+ }
36
+
37
+ // Photo-based generation - use multi-person prompt with @imageN references
38
+ let finalPrompt = createMultiPersonPrompt(basePrompt, photoCount);
39
+
40
+ // Add interaction style if specified by scenario (no defaults)
41
+ if (interactionStyle) {
42
+ finalPrompt = `${finalPrompt}\n\nINTERACTION STYLE: ${interactionStyle}`;
43
+ }
44
+
45
+ return finalPrompt;
46
+ }
@@ -5,54 +5,20 @@
5
5
 
6
6
  import { executeVideoFeature } from "../../../../../infrastructure/services/video-feature-executor.service";
7
7
  import { createCreationsRepository } from "../../../../creations/infrastructure/adapters";
8
+ import { buildUnifiedPrompt } from "./shared/unified-prompt-builder";
8
9
  import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
9
- import type { ScenarioInputType } from "../../../../scenarios/domain/Scenario";
10
10
  import type { WizardStrategy } from "./wizard-strategy.types";
11
11
  import { VIDEO_PROCESSING_PROMPTS } from "./wizard-strategy.constants";
12
12
  import { extractPrompt, extractDuration, extractAspectRatio, extractResolution } from "../utils";
13
13
  import { extractPhotosAsBase64 } from "./shared/photo-extraction.utils";
14
14
  import { getVideoFeatureType } from "./video-generation.utils";
15
15
  import type { WizardVideoInput, CreateVideoStrategyOptions } from "./video-generation.types";
16
+ import { validatePhotoCount } from "./video-generation.types";
16
17
 
17
18
  declare const __DEV__: boolean;
18
19
 
19
20
  export type { WizardVideoInput, WizardVideoResult, CreateVideoStrategyOptions } from "./video-generation.types";
20
21
 
21
- interface PhotoValidationResult {
22
- isValid: boolean;
23
- errorKey?: string;
24
- }
25
-
26
- function validatePhotoCount(
27
- photoCount: number,
28
- inputType: ScenarioInputType | undefined,
29
- ): PhotoValidationResult {
30
- const effectiveInputType = inputType ?? "single";
31
-
32
- switch (effectiveInputType) {
33
- case "dual":
34
- if (photoCount < 2) {
35
- return {
36
- isValid: false,
37
- errorKey: "error.generation.dualPhotosRequired",
38
- };
39
- }
40
- break;
41
- case "single":
42
- if (photoCount < 1) {
43
- return {
44
- isValid: false,
45
- errorKey: "error.generation.photoRequired",
46
- };
47
- }
48
- break;
49
- case "text":
50
- break;
51
- }
52
-
53
- return { isValid: true };
54
- }
55
-
56
22
  export async function buildVideoInput(
57
23
  wizardData: Record<string, unknown>,
58
24
  scenario: WizardScenarioData,
@@ -65,61 +31,50 @@ export async function buildVideoInput(
65
31
 
66
32
  const validation = validatePhotoCount(photos.length, scenario.inputType);
67
33
  if (!validation.isValid) {
68
- if (typeof __DEV__ !== "undefined" && __DEV__) {
69
- console.log("[VideoStrategy] Validation failed", {
70
- scenarioId: scenario.id,
71
- inputType: scenario.inputType,
72
- photoCount: photos.length,
73
- errorKey: validation.errorKey,
74
- });
75
- }
76
34
  throw new Error(validation.errorKey ?? "error.generation.invalidInput");
77
35
  }
78
36
 
79
- let prompt = extractPrompt(wizardData, scenario.aiPrompt);
37
+ let basePrompt = extractPrompt(wizardData, scenario.aiPrompt);
80
38
 
81
- if (!prompt) {
39
+ if (!basePrompt) {
82
40
  const defaultPrompt = VIDEO_PROCESSING_PROMPTS[scenario.id];
83
41
  if (defaultPrompt) {
84
- prompt = defaultPrompt;
42
+ basePrompt = defaultPrompt;
85
43
  } else {
86
44
  throw new Error("error.generation.promptRequired");
87
45
  }
88
46
  }
89
47
 
90
- const input: WizardVideoInput = {
48
+ // Build unified prompt with face preservation
49
+ const finalPrompt = buildUnifiedPrompt({
50
+ basePrompt,
51
+ photoCount: photos.length,
52
+ interactionStyle: scenario.interactionStyle as string | undefined,
53
+ });
54
+
55
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
56
+ console.log("[VideoStrategy] Prompt built", {
57
+ baseLength: basePrompt.length,
58
+ finalLength: finalPrompt.length,
59
+ photoCount: photos.length,
60
+ });
61
+ }
62
+
63
+ return {
91
64
  sourceImageBase64: photos[0],
92
65
  targetImageBase64: photos[1] || photos[0],
93
- prompt,
66
+ prompt: finalPrompt,
94
67
  duration: extractDuration(wizardData),
95
68
  aspectRatio: extractAspectRatio(wizardData),
96
69
  resolution: extractResolution(wizardData),
97
70
  };
98
-
99
- if (typeof __DEV__ !== "undefined" && __DEV__) {
100
- console.log("[VideoStrategy] Input built", {
101
- hasSource: !!input.sourceImageBase64,
102
- hasTarget: !!input.targetImageBase64,
103
- duration: input.duration,
104
- });
105
- }
106
-
107
- return input;
108
71
  }
109
72
 
110
- // ============================================================================
111
- // Strategy Factory
112
- // ============================================================================
113
-
114
73
  export function createVideoStrategy(options: CreateVideoStrategyOptions): WizardStrategy {
115
74
  const { scenario, collectionName = "creations" } = options;
116
75
  const repository = createCreationsRepository(collectionName);
117
76
  const videoFeatureType = getVideoFeatureType(scenario.id);
118
77
 
119
- if (typeof __DEV__ !== "undefined" && __DEV__) {
120
- console.log("[VideoStrategy] Created", { scenarioId: scenario.id, videoFeatureType });
121
- }
122
-
123
78
  let lastInputRef: WizardVideoInput | null = null;
124
79
 
125
80
  return {
@@ -152,7 +107,7 @@ export function createVideoStrategy(options: CreateVideoStrategyOptions): Wizard
152
107
  const videoResult = result as { videoUrl?: string };
153
108
  if (!input || !scenario?.id || !videoResult.videoUrl) return;
154
109
 
155
- const creation = {
110
+ await repository.create(uid, {
156
111
  id: `${scenario.id}_${Date.now()}`,
157
112
  uri: videoResult.videoUrl,
158
113
  type: scenario.id,
@@ -161,14 +116,9 @@ export function createVideoStrategy(options: CreateVideoStrategyOptions): Wizard
161
116
  createdAt: new Date(),
162
117
  isShared: false,
163
118
  isFavorite: false,
164
- metadata: {
165
- scenarioId: scenario.id,
166
- scenarioTitle: scenario.title,
167
- },
119
+ metadata: { scenarioId: scenario.id, scenarioTitle: scenario.title },
168
120
  output: { videoUrl: videoResult.videoUrl },
169
- };
170
-
171
- await repository.create(uid, creation);
121
+ });
172
122
  },
173
123
  };
174
124
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
7
+ import type { ScenarioInputType } from "../../../../scenarios/domain/Scenario";
7
8
 
8
9
  export interface WizardVideoInput {
9
10
  /** Source image (optional for text-to-video) */
@@ -27,3 +28,32 @@ export interface CreateVideoStrategyOptions {
27
28
  readonly scenario: WizardScenarioData;
28
29
  readonly collectionName?: string;
29
30
  }
31
+
32
+ export interface PhotoValidationResult {
33
+ isValid: boolean;
34
+ errorKey?: string;
35
+ }
36
+
37
+ export function validatePhotoCount(
38
+ photoCount: number,
39
+ inputType: ScenarioInputType | undefined,
40
+ ): PhotoValidationResult {
41
+ const effectiveInputType = inputType ?? "single";
42
+
43
+ switch (effectiveInputType) {
44
+ case "dual":
45
+ if (photoCount < 2) {
46
+ return { isValid: false, errorKey: "error.generation.dualPhotosRequired" };
47
+ }
48
+ break;
49
+ case "single":
50
+ if (photoCount < 1) {
51
+ return { isValid: false, errorKey: "error.generation.photoRequired" };
52
+ }
53
+ break;
54
+ case "text":
55
+ break;
56
+ }
57
+
58
+ return { isValid: true };
59
+ }