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

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.14",
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,
@@ -80,11 +80,14 @@ function applyStyleEnhancements(prompt: string, wizardData: Record<string, unkno
80
80
  // Strategy Factory
81
81
  // ============================================================================
82
82
 
83
+ declare const __DEV__: boolean;
84
+
83
85
  export function createImageStrategy(options: CreateImageStrategyOptions): WizardStrategy {
84
86
  const { scenario, collectionName = "creations" } = options;
85
87
  const repository = createCreationsRepository(collectionName);
86
88
 
87
89
  let lastInputRef: WizardImageInput | null = null;
90
+ let processingCreationId: string | null = null;
88
91
 
89
92
  return {
90
93
  execute: async (input: unknown) => {
@@ -106,28 +109,63 @@ export function createImageStrategy(options: CreateImageStrategyOptions): Wizard
106
109
 
107
110
  getCreditCost: () => 1,
108
111
 
109
- save: async (result: unknown, uid) => {
110
- const input = lastInputRef;
111
- const imageResult = result as { imageUrl?: string };
112
- if (!input || !scenario?.id || !imageResult.imageUrl) return;
112
+ saveAsProcessing: async (uid: string, input: unknown) => {
113
+ const imageInput = input as WizardImageInput;
114
+ const creationId = `${scenario.id}_${Date.now()}`;
115
+ processingCreationId = creationId;
113
116
 
114
- const creation = {
115
- id: `${scenario.id}_${Date.now()}`,
116
- uri: imageResult.imageUrl,
117
+ await repository.create(uid, {
118
+ id: creationId,
119
+ uri: "",
117
120
  type: scenario.id,
118
- prompt: input.prompt,
119
- status: "completed" as const,
121
+ prompt: imageInput.prompt,
122
+ status: "processing" as const,
120
123
  createdAt: new Date(),
121
124
  isShared: false,
122
125
  isFavorite: false,
123
- metadata: {
124
- scenarioId: scenario.id,
125
- scenarioTitle: scenario.title,
126
- },
127
- output: { imageUrl: imageResult.imageUrl },
128
- };
129
-
130
- await repository.create(uid, creation);
126
+ metadata: { scenarioId: scenario.id, scenarioTitle: scenario.title },
127
+ });
128
+
129
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
130
+ console.log("[ImageStrategy] Saved as processing", { creationId });
131
+ }
132
+
133
+ return creationId;
134
+ },
135
+
136
+ save: async (result: unknown, uid: string, creationId?: string) => {
137
+ const input = lastInputRef;
138
+ const imageResult = result as { imageUrl?: string };
139
+ if (!input || !scenario?.id || !imageResult.imageUrl) return;
140
+
141
+ const idToUpdate = creationId || processingCreationId;
142
+
143
+ if (idToUpdate) {
144
+ // Update existing processing creation to completed
145
+ await repository.update(uid, idToUpdate, {
146
+ uri: imageResult.imageUrl,
147
+ status: "completed" as const,
148
+ output: { imageUrl: imageResult.imageUrl },
149
+ });
150
+
151
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
152
+ console.log("[ImageStrategy] Updated to completed", { creationId: idToUpdate });
153
+ }
154
+ } else {
155
+ // Fallback: create new (shouldn't happen normally)
156
+ await repository.create(uid, {
157
+ id: `${scenario.id}_${Date.now()}`,
158
+ uri: imageResult.imageUrl,
159
+ type: scenario.id,
160
+ prompt: input.prompt,
161
+ status: "completed" as const,
162
+ createdAt: new Date(),
163
+ isShared: false,
164
+ isFavorite: false,
165
+ metadata: { scenarioId: scenario.id, scenarioTitle: scenario.title },
166
+ output: { imageUrl: imageResult.imageUrl },
167
+ });
168
+ }
131
169
  },
132
170
  };
133
171
  }
@@ -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,62 +31,52 @@ 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;
79
+ let processingCreationId: string | null = null;
124
80
 
125
81
  return {
126
82
  execute: async (input: unknown) => {
@@ -147,28 +103,63 @@ export function createVideoStrategy(options: CreateVideoStrategyOptions): Wizard
147
103
 
148
104
  getCreditCost: () => 1,
149
105
 
150
- save: async (result: unknown, uid) => {
151
- const input = lastInputRef;
152
- const videoResult = result as { videoUrl?: string };
153
- if (!input || !scenario?.id || !videoResult.videoUrl) return;
106
+ saveAsProcessing: async (uid: string, input: unknown) => {
107
+ const videoInput = input as WizardVideoInput;
108
+ const creationId = `${scenario.id}_${Date.now()}`;
109
+ processingCreationId = creationId;
154
110
 
155
- const creation = {
156
- id: `${scenario.id}_${Date.now()}`,
157
- uri: videoResult.videoUrl,
111
+ await repository.create(uid, {
112
+ id: creationId,
113
+ uri: "",
158
114
  type: scenario.id,
159
- prompt: input.prompt,
160
- status: "completed" as const,
115
+ prompt: videoInput.prompt,
116
+ status: "processing" as const,
161
117
  createdAt: new Date(),
162
118
  isShared: false,
163
119
  isFavorite: false,
164
- metadata: {
165
- scenarioId: scenario.id,
166
- scenarioTitle: scenario.title,
167
- },
168
- output: { videoUrl: videoResult.videoUrl },
169
- };
120
+ metadata: { scenarioId: scenario.id, scenarioTitle: scenario.title },
121
+ });
122
+
123
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
124
+ console.log("[VideoStrategy] Saved as processing", { creationId });
125
+ }
126
+
127
+ return creationId;
128
+ },
170
129
 
171
- await repository.create(uid, creation);
130
+ save: async (result: unknown, uid: string, creationId?: string) => {
131
+ const input = lastInputRef;
132
+ const videoResult = result as { videoUrl?: string };
133
+ if (!input || !scenario?.id || !videoResult.videoUrl) return;
134
+
135
+ const idToUpdate = creationId || processingCreationId;
136
+
137
+ if (idToUpdate) {
138
+ // Update existing processing creation to completed
139
+ await repository.update(uid, idToUpdate, {
140
+ uri: videoResult.videoUrl,
141
+ status: "completed" as const,
142
+ output: { videoUrl: videoResult.videoUrl },
143
+ });
144
+
145
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
146
+ console.log("[VideoStrategy] Updated to completed", { creationId: idToUpdate });
147
+ }
148
+ } else {
149
+ // Fallback: create new (shouldn't happen normally)
150
+ await repository.create(uid, {
151
+ id: `${scenario.id}_${Date.now()}`,
152
+ uri: videoResult.videoUrl,
153
+ type: scenario.id,
154
+ prompt: input.prompt,
155
+ status: "completed" as const,
156
+ createdAt: new Date(),
157
+ isShared: false,
158
+ isFavorite: false,
159
+ metadata: { scenarioId: scenario.id, scenarioTitle: scenario.title },
160
+ output: { videoUrl: videoResult.videoUrl },
161
+ });
162
+ }
172
163
  },
173
164
  };
174
165
  }
@@ -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
+ }
@@ -6,5 +6,8 @@
6
6
  export interface WizardStrategy {
7
7
  execute: (input: unknown) => Promise<{ imageUrl?: string; videoUrl?: string }>;
8
8
  getCreditCost: () => number;
9
- save?: (result: unknown, userId: string) => Promise<void>;
9
+ /** Save as processing when generation starts - returns creation ID */
10
+ saveAsProcessing?: (userId: string, input: unknown) => Promise<string>;
11
+ /** Update to completed when generation finishes */
12
+ save?: (result: unknown, userId: string, creationId?: string) => Promise<void>;
10
13
  }
@@ -1,12 +1,11 @@
1
1
  /**
2
2
  * useWizardGeneration Hook
3
3
  * Wizard generation using orchestrator + strategy factory pattern
4
- * Includes background job tracking for CreationsGallery display
4
+ * Saves to Firestore with status="processing" at start for gallery display
5
5
  */
6
6
 
7
7
  import { useEffect, useRef, useMemo, useCallback } from "react";
8
8
  import { useGenerationOrchestrator } from "../../../../../presentation/hooks/generation";
9
- import { usePendingJobs } from "../../../../../presentation/hooks/use-pending-jobs";
10
9
  import { createWizardStrategy, buildWizardInput } from "../../infrastructure/strategies";
11
10
  import type {
12
11
  UseWizardGenerationProps,
@@ -34,23 +33,19 @@ export const useWizardGeneration = (
34
33
  onSuccess,
35
34
  onError,
36
35
  onCreditsExhausted,
37
- trackAsBackgroundJob = true,
38
36
  } = props;
39
37
 
40
38
  const hasStarted = useRef(false);
41
- const currentJobIdRef = useRef<string | null>(null);
42
-
43
- const { addJob, updateJob, removeJob } = usePendingJobs();
39
+ const currentCreationIdRef = useRef<string | null>(null);
44
40
 
45
41
  useEffect(() => {
46
42
  if (typeof __DEV__ !== "undefined" && __DEV__) {
47
43
  console.log("[useWizardGeneration] Initialized", {
48
44
  scenarioId: scenario.id,
49
45
  outputType: scenario.outputType,
50
- trackAsBackgroundJob,
51
46
  });
52
47
  }
53
- }, [scenario.id, scenario.outputType, trackAsBackgroundJob]);
48
+ }, [scenario.id, scenario.outputType]);
54
49
 
55
50
  const strategy = useMemo(() => {
56
51
  return createWizardStrategy({
@@ -62,17 +57,14 @@ export const useWizardGeneration = (
62
57
  const handleSuccess = useCallback(
63
58
  (result: unknown) => {
64
59
  if (typeof __DEV__ !== "undefined" && __DEV__) {
65
- console.log("[useWizardGeneration] Success");
66
- }
67
-
68
- if (trackAsBackgroundJob && currentJobIdRef.current) {
69
- removeJob(currentJobIdRef.current);
70
- currentJobIdRef.current = null;
60
+ console.log("[useWizardGeneration] Success", {
61
+ creationId: currentCreationIdRef.current,
62
+ });
71
63
  }
72
-
64
+ currentCreationIdRef.current = null;
73
65
  onSuccess?.(result);
74
66
  },
75
- [trackAsBackgroundJob, removeJob, onSuccess],
67
+ [onSuccess],
76
68
  );
77
69
 
78
70
  const handleError = useCallback(
@@ -80,17 +72,11 @@ export const useWizardGeneration = (
80
72
  if (typeof __DEV__ !== "undefined" && __DEV__) {
81
73
  console.log("[useWizardGeneration] Error:", err.message);
82
74
  }
83
-
84
- if (trackAsBackgroundJob && currentJobIdRef.current) {
85
- updateJob({
86
- id: currentJobIdRef.current,
87
- updates: { status: "failed", error: err.message, progress: 0 },
88
- });
89
- }
90
-
75
+ // Note: Failed status update is handled by orchestrator via strategy
76
+ currentCreationIdRef.current = null;
91
77
  onError?.(err.message);
92
78
  },
93
- [trackAsBackgroundJob, updateJob, onError],
79
+ [onError],
94
80
  );
95
81
 
96
82
  const { generate, isGenerating } = useGenerationOrchestrator(strategy, {
@@ -113,31 +99,27 @@ export const useWizardGeneration = (
113
99
  hasStarted.current = true;
114
100
 
115
101
  buildWizardInput(wizardData, scenario)
116
- .then((input) => {
102
+ .then(async (input) => {
117
103
  if (!input) {
118
104
  hasStarted.current = false;
119
105
  onError?.("Failed to build generation input");
120
106
  return;
121
107
  }
122
108
 
123
- if (trackAsBackgroundJob && scenario.outputType) {
124
- const jobId = `wizard-${scenario.id}-${Date.now()}`;
125
- currentJobIdRef.current = jobId;
126
-
127
- addJob({
128
- id: jobId,
129
- input: {
130
- scenarioId: scenario.id,
131
- scenarioTitle: scenario.title,
132
- outputType: scenario.outputType,
133
- },
134
- type: scenario.outputType,
135
- status: "processing",
136
- progress: 10,
137
- });
138
-
139
- if (typeof __DEV__ !== "undefined" && __DEV__) {
140
- console.log("[useWizardGeneration] Created background job:", jobId);
109
+ // Save to Firestore with status="processing" BEFORE starting generation
110
+ if (strategy.saveAsProcessing && userId) {
111
+ try {
112
+ const creationId = await strategy.saveAsProcessing(userId, input);
113
+ currentCreationIdRef.current = creationId;
114
+
115
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
116
+ console.log("[useWizardGeneration] Saved as processing:", creationId);
117
+ }
118
+ } catch (err) {
119
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
120
+ console.error("[useWizardGeneration] saveAsProcessing error:", err);
121
+ }
122
+ // Continue with generation even if save fails
141
123
  }
142
124
  }
143
125
 
@@ -162,8 +144,8 @@ export const useWizardGeneration = (
162
144
  isGenerating,
163
145
  generate,
164
146
  onError,
165
- trackAsBackgroundJob,
166
- addJob,
147
+ strategy,
148
+ userId,
167
149
  ]);
168
150
 
169
151
  return { isGenerating };