@umituz/react-native-ai-generation-content 1.34.2 → 1.35.1

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.34.2",
3
+ "version": "1.35.1",
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",
@@ -1,16 +1,28 @@
1
1
  /**
2
2
  * Generic Wizard Flow Component
3
3
  * Config-driven wizard for AI generation features
4
+ * Supports both scenario object and scenarioId (resolved from registry)
4
5
  */
5
6
 
6
7
  import React, { useMemo, useCallback, useEffect, useRef, useState } from "react";
7
8
  import { View, StyleSheet } from "react-native";
8
- import { useAppDesignTokens, useAlert, AlertType, AlertMode } from "@umituz/react-native-design-system";
9
+ import {
10
+ useAppDesignTokens,
11
+ useAlert,
12
+ AlertType,
13
+ AlertMode,
14
+ } from "@umituz/react-native-design-system";
9
15
  import { useFlow } from "../../../infrastructure/flow/useFlow";
10
- import { StepType, type StepDefinition } from "../../../../../domain/entities/flow-config.types";
16
+ import {
17
+ StepType,
18
+ type StepDefinition,
19
+ } from "../../../../../domain/entities/flow-config.types";
11
20
  import type { WizardFeatureConfig } from "../../domain/entities/wizard-config.types";
12
21
  import { buildFlowStepsFromWizard } from "../../infrastructure/builders/dynamic-step-builder";
13
- import { useWizardGeneration, type WizardScenarioData } from "../hooks/useWizardGeneration";
22
+ import {
23
+ useWizardGeneration,
24
+ type WizardScenarioData,
25
+ } from "../hooks/useWizardGeneration";
14
26
  import type { AlertMessages } from "../../../../../presentation/hooks/generation/types";
15
27
  import type { UploadedImage } from "../../../../../presentation/hooks/generation/useAIGenerateState";
16
28
  import type { Creation } from "../../../../creations/domain/entities/Creation";
@@ -19,17 +31,25 @@ import { useResultActions } from "../../../../result-preview/presentation/hooks/
19
31
  import { validateScenario } from "../utilities/validateScenario";
20
32
  import { WizardStepRenderer } from "./WizardStepRenderer";
21
33
  import { StarRatingPicker } from "../../../../result-preview/presentation/components/StarRatingPicker";
34
+ import {
35
+ getConfiguredScenario,
36
+ getDefaultOutputType,
37
+ } from "../../../../scenarios/infrastructure/scenario-registry";
22
38
 
23
39
  declare const __DEV__: boolean;
24
40
 
25
41
  export interface GenericWizardFlowProps {
26
42
  readonly featureConfig: WizardFeatureConfig;
27
43
  readonly scenario?: WizardScenarioData;
44
+ readonly scenarioId?: string;
28
45
  readonly userId?: string;
29
46
  readonly alertMessages?: AlertMessages;
30
47
  readonly skipResultStep?: boolean;
31
48
  readonly onStepChange?: (stepId: string, stepType: StepType | string) => void;
32
- readonly onGenerationStart?: (data: Record<string, unknown>, proceedToGenerating: () => void) => void;
49
+ readonly onGenerationStart?: (
50
+ data: Record<string, unknown>,
51
+ proceedToGenerating: () => void,
52
+ ) => void;
33
53
  readonly onGenerationComplete?: (result: unknown) => void;
34
54
  readonly onGenerationError?: (error: string) => void;
35
55
  readonly onCreditsExhausted?: () => void;
@@ -42,42 +62,137 @@ export interface GenericWizardFlowProps {
42
62
  readonly renderResult?: (result: unknown) => React.ReactElement | null;
43
63
  }
44
64
 
45
- export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
46
- featureConfig,
47
- scenario,
48
- userId,
49
- alertMessages,
50
- skipResultStep = false,
51
- onStepChange,
52
- onGenerationStart,
53
- onGenerationComplete,
54
- onGenerationError,
55
- onCreditsExhausted,
56
- onBack,
57
- onTryAgain,
58
- t,
59
- translations: _translations,
60
- renderPreview,
61
- renderGenerating,
62
- renderResult,
63
- }) => {
65
+ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
66
+ const {
67
+ featureConfig,
68
+ scenario: scenarioProp,
69
+ scenarioId,
70
+ userId,
71
+ alertMessages,
72
+ skipResultStep = false,
73
+ onStepChange,
74
+ onGenerationStart,
75
+ onGenerationComplete,
76
+ onGenerationError,
77
+ onCreditsExhausted,
78
+ onBack,
79
+ onTryAgain,
80
+ t,
81
+ renderPreview,
82
+ renderGenerating,
83
+ renderResult,
84
+ } = props;
85
+
64
86
  const tokens = useAppDesignTokens();
65
87
  const alert = useAlert();
88
+
89
+ // Resolve scenario from prop or registry
90
+ const scenario = useMemo<WizardScenarioData | undefined>(() => {
91
+ if (scenarioProp) {
92
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
93
+ console.log("[GenericWizardFlow] Using scenario from prop:", {
94
+ id: scenarioProp.id,
95
+ outputType: scenarioProp.outputType,
96
+ });
97
+ }
98
+ return scenarioProp;
99
+ }
100
+
101
+ if (scenarioId) {
102
+ const found = getConfiguredScenario(scenarioId);
103
+ if (found) {
104
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
105
+ console.log("[GenericWizardFlow] Resolved from registry:", {
106
+ id: found.id,
107
+ outputType: found.outputType,
108
+ });
109
+ }
110
+ return found;
111
+ }
112
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
113
+ console.warn("[GenericWizardFlow] Scenario not in registry:", scenarioId);
114
+ }
115
+ return { id: scenarioId, outputType: getDefaultOutputType() };
116
+ }
117
+
118
+ return undefined;
119
+ }, [scenarioProp, scenarioId]);
120
+
121
+ const validatedScenario = useMemo(
122
+ () => validateScenario(scenario),
123
+ [scenario],
124
+ );
125
+
126
+ return (
127
+ <WizardFlowContent
128
+ featureConfig={featureConfig}
129
+ scenario={scenario}
130
+ validatedScenario={validatedScenario}
131
+ userId={userId}
132
+ alertMessages={alertMessages}
133
+ skipResultStep={skipResultStep}
134
+ onStepChange={onStepChange}
135
+ onGenerationStart={onGenerationStart}
136
+ onGenerationComplete={onGenerationComplete}
137
+ onGenerationError={onGenerationError}
138
+ onCreditsExhausted={onCreditsExhausted}
139
+ onBack={onBack}
140
+ onTryAgain={onTryAgain}
141
+ t={t}
142
+ tokens={tokens}
143
+ alert={alert}
144
+ renderPreview={renderPreview}
145
+ renderGenerating={renderGenerating}
146
+ renderResult={renderResult}
147
+ />
148
+ );
149
+ };
150
+
151
+ interface WizardFlowContentProps
152
+ extends Omit<GenericWizardFlowProps, "scenarioId" | "translations"> {
153
+ readonly validatedScenario: WizardScenarioData;
154
+ readonly tokens: ReturnType<typeof useAppDesignTokens>;
155
+ readonly alert: ReturnType<typeof useAlert>;
156
+ }
157
+
158
+ const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
159
+ const {
160
+ featureConfig,
161
+ scenario,
162
+ validatedScenario,
163
+ userId,
164
+ alertMessages,
165
+ skipResultStep = false,
166
+ onStepChange,
167
+ onGenerationStart,
168
+ onGenerationComplete,
169
+ onGenerationError,
170
+ onCreditsExhausted,
171
+ onBack,
172
+ onTryAgain,
173
+ t,
174
+ tokens,
175
+ alert,
176
+ renderPreview,
177
+ renderGenerating,
178
+ renderResult,
179
+ } = props;
180
+
66
181
  const [currentCreation, setCurrentCreation] = useState<Creation | null>(null);
67
182
  const [showRatingPicker, setShowRatingPicker] = useState(false);
68
183
  const [hasRated, setHasRated] = useState(false);
69
- const [, setIsGeneratingDismissed] = useState(false);
70
184
  const prevStepIdRef = useRef<string | undefined>(undefined);
71
-
72
185
  const repository = useMemo(() => createCreationsRepository("creations"), []);
73
186
 
74
- const flowSteps = useMemo<StepDefinition[]>(() => {
75
- return buildFlowStepsFromWizard(featureConfig, {
76
- includePreview: true,
77
- includeGenerating: true,
78
- includeResult: !skipResultStep,
79
- });
80
- }, [featureConfig, skipResultStep]);
187
+ const flowSteps = useMemo<StepDefinition[]>(
188
+ () =>
189
+ buildFlowStepsFromWizard(featureConfig, {
190
+ includePreview: true,
191
+ includeGenerating: true,
192
+ includeResult: !skipResultStep,
193
+ }),
194
+ [featureConfig, skipResultStep],
195
+ );
81
196
 
82
197
  const flow = useFlow({ steps: flowSteps, initialStepIndex: 0 });
83
198
  const {
@@ -92,30 +207,25 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
92
207
  setResult,
93
208
  } = flow;
94
209
 
95
- const resultImageUrl = currentCreation?.output?.imageUrl || currentCreation?.uri || "";
210
+ const resultImageUrl =
211
+ currentCreation?.output?.imageUrl || currentCreation?.uri || "";
96
212
  const resultVideoUrl = currentCreation?.output?.videoUrl || "";
97
- const { isSaving, isSharing, handleDownload, handleShare } = useResultActions({
98
- imageUrl: resultImageUrl,
99
- videoUrl: resultVideoUrl,
100
- });
101
-
102
- const validatedScenario = useMemo(() => validateScenario(scenario), [scenario]);
103
-
104
- const handleGenerationComplete = useCallback((result: unknown) => {
105
- if (typeof __DEV__ !== "undefined" && __DEV__) {
106
- console.log("[GenericWizardFlow] Generation completed", { skipResultStep });
107
- }
108
- setResult(result);
109
- setCurrentCreation(result as Creation);
110
-
111
- // Call onGenerationComplete first so parent can navigate if needed
112
- onGenerationComplete?.(result);
213
+ const { isSaving, isSharing, handleDownload, handleShare } = useResultActions(
214
+ { imageUrl: resultImageUrl, videoUrl: resultVideoUrl },
215
+ );
113
216
 
114
- // Only go to result step if not skipping
115
- if (!skipResultStep) {
116
- nextStep();
117
- }
118
- }, [setResult, nextStep, onGenerationComplete, skipResultStep]);
217
+ const handleGenerationComplete = useCallback(
218
+ (result: unknown) => {
219
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
220
+ console.log("[WizardFlowContent] Generation completed");
221
+ }
222
+ setResult(result);
223
+ setCurrentCreation(result as Creation);
224
+ onGenerationComplete?.(result);
225
+ if (!skipResultStep) nextStep();
226
+ },
227
+ [setResult, nextStep, onGenerationComplete, skipResultStep],
228
+ );
119
229
 
120
230
  useWizardGeneration({
121
231
  scenario: validatedScenario,
@@ -129,92 +239,74 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
129
239
  });
130
240
 
131
241
  useEffect(() => {
132
- if (currentStep && onStepChange) {
133
- const currentStepId = currentStep.id;
134
- if (prevStepIdRef.current !== currentStepId) {
135
- prevStepIdRef.current = currentStepId;
136
- onStepChange(currentStep.id, currentStep.type);
137
- // Reset dismissed state when entering generating step
138
- if (currentStep.type === StepType.GENERATING) {
139
- setIsGeneratingDismissed(false);
140
- }
141
- }
242
+ if (currentStep && onStepChange && prevStepIdRef.current !== currentStep.id) {
243
+ prevStepIdRef.current = currentStep.id;
244
+ onStepChange(currentStep.id, currentStep.type);
142
245
  }
143
- }, [currentStep, currentStepIndex, onStepChange]);
246
+ }, [currentStep, onStepChange]);
144
247
 
145
- // Handle dismiss generating - go back but generation continues in background
146
248
  const handleDismissGenerating = useCallback(() => {
147
249
  if (typeof __DEV__ !== "undefined" && __DEV__) {
148
- console.log("[GenericWizardFlow] Dismissing generating screen - generation continues in background");
250
+ console.log("[WizardFlowContent] Dismissing - generation continues");
149
251
  }
150
- setIsGeneratingDismissed(true);
151
- // Show alert that generation continues
152
252
  alert.show(
153
253
  AlertType.INFO,
154
254
  AlertMode.TOAST,
155
255
  t("generator.backgroundTitle"),
156
- t("generator.backgroundMessage")
256
+ t("generator.backgroundMessage"),
157
257
  );
158
- // Go back to previous step (or close)
159
258
  onBack?.();
160
259
  }, [alert, t, onBack]);
161
260
 
162
261
  const handleBack = useCallback(() => {
163
- if (currentStepIndex === 0) {
164
- onBack?.();
165
- } else {
166
- previousStep();
167
- }
262
+ if (currentStepIndex === 0) onBack?.();
263
+ else previousStep();
168
264
  }, [currentStepIndex, previousStep, onBack]);
169
265
 
170
- // Wrapper for nextStep that checks onGenerationStart before transitioning to GENERATING
171
266
  const handleNextStep = useCallback(() => {
172
- const nextIndex = currentStepIndex + 1;
173
- const nextStepDef = flowSteps[nextIndex];
174
-
175
- // If next step is GENERATING, we must call onGenerationStart for feature gating
176
- if (nextStepDef?.type === StepType.GENERATING) {
177
- if (typeof __DEV__ !== "undefined" && __DEV__) {
178
- console.log("[GenericWizardFlow] About to enter GENERATING step, calling onGenerationStart");
179
- }
180
- if (onGenerationStart) {
181
- onGenerationStart(customData, () => {
182
- if (typeof __DEV__ !== "undefined" && __DEV__) {
183
- console.log("[GenericWizardFlow] onGenerationStart callback invoked, proceeding to generation");
184
- }
185
- nextStep();
186
- });
187
- return;
188
- }
267
+ const nextStepDef = flowSteps[currentStepIndex + 1];
268
+ if (nextStepDef?.type === StepType.GENERATING && onGenerationStart) {
269
+ onGenerationStart(customData, nextStep);
270
+ return;
189
271
  }
190
-
191
272
  nextStep();
192
273
  }, [currentStepIndex, flowSteps, customData, onGenerationStart, nextStep]);
193
274
 
194
- const handlePhotoContinue = useCallback((stepId: string, image: UploadedImage) => {
195
- setCustomData(stepId, image);
196
- // Use handleNextStep which handles onGenerationStart check
197
- handleNextStep();
198
- }, [setCustomData, handleNextStep]);
199
-
200
- const handleOpenRatingPicker = useCallback(() => {
201
- setShowRatingPicker(true);
202
- }, []);
203
-
204
- const handleSubmitRating = useCallback(async (rating: number, description: string) => {
205
- if (!currentCreation?.id || !userId) return;
206
- const success = await repository.rate(userId, currentCreation.id, rating, description);
207
- if (success) {
208
- setHasRated(true);
209
- alert.show(AlertType.SUCCESS, AlertMode.TOAST, t("result.rateSuccessTitle"), t("result.rateSuccessMessage"));
210
- }
211
- setShowRatingPicker(false);
212
- }, [currentCreation, userId, repository, alert, t]);
275
+ const handlePhotoContinue = useCallback(
276
+ (stepId: string, image: UploadedImage) => {
277
+ setCustomData(stepId, image);
278
+ handleNextStep();
279
+ },
280
+ [setCustomData, handleNextStep],
281
+ );
213
282
 
214
- const showRatingButton = Boolean(userId) && !hasRated;
283
+ const handleSubmitRating = useCallback(
284
+ async (rating: number, description: string) => {
285
+ if (!currentCreation?.id || !userId) return;
286
+ const success = await repository.rate(
287
+ userId,
288
+ currentCreation.id,
289
+ rating,
290
+ description,
291
+ );
292
+ if (success) {
293
+ setHasRated(true);
294
+ alert.show(
295
+ AlertType.SUCCESS,
296
+ AlertMode.TOAST,
297
+ t("result.rateSuccessTitle"),
298
+ t("result.rateSuccessMessage"),
299
+ );
300
+ }
301
+ setShowRatingPicker(false);
302
+ },
303
+ [currentCreation, userId, repository, alert, t],
304
+ );
215
305
 
216
306
  return (
217
- <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
307
+ <View
308
+ style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
309
+ >
218
310
  <WizardStepRenderer
219
311
  step={currentStep}
220
312
  scenario={scenario}
@@ -223,13 +315,13 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
223
315
  generationResult={generationResult}
224
316
  isSaving={isSaving}
225
317
  isSharing={isSharing}
226
- showRating={showRatingButton}
318
+ showRating={Boolean(userId) && !hasRated}
227
319
  onNext={handleNextStep}
228
320
  onBack={handleBack}
229
321
  onPhotoContinue={handlePhotoContinue}
230
322
  onDownload={handleDownload}
231
323
  onShare={handleShare}
232
- onRate={handleOpenRatingPicker}
324
+ onRate={() => setShowRatingPicker(true)}
233
325
  onTryAgain={onTryAgain}
234
326
  onDismissGenerating={handleDismissGenerating}
235
327
  t={t}
@@ -251,7 +343,5 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
251
343
  };
252
344
 
253
345
  const styles = StyleSheet.create({
254
- container: {
255
- flex: 1,
256
- },
346
+ container: { flex: 1 },
257
347
  });
@@ -21,6 +21,16 @@ export {
21
21
  } from "./infrastructure/scenario-helpers";
22
22
  export type { AppScenarioConfig } from "./infrastructure/scenario-helpers";
23
23
 
24
+ // Scenario Registry - Singleton for app configuration
25
+ export {
26
+ configureScenarios,
27
+ getConfiguredScenario,
28
+ getDefaultOutputType,
29
+ isScenariosConfigured,
30
+ getAllConfiguredScenarios,
31
+ } from "./infrastructure/scenario-registry";
32
+ export type { ConfiguredScenario } from "./infrastructure/scenario-registry";
33
+
24
34
  // Utils
25
35
  export { createStoryTemplate } from "./infrastructure/utils/scenario-utils";
26
36
 
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Scenario Registry
3
+ * Singleton registry for app-configured scenarios
4
+ * Apps configure once at startup, package uses internally
5
+ */
6
+
7
+ import type { Scenario, ScenarioOutputType } from "../domain/Scenario";
8
+
9
+ declare const __DEV__: boolean;
10
+
11
+ /** Configured scenario with required outputType */
12
+ export interface ConfiguredScenario extends Scenario {
13
+ readonly outputType: ScenarioOutputType;
14
+ readonly [key: string]: unknown;
15
+ }
16
+
17
+ interface ScenarioRegistryState {
18
+ scenarios: Map<string, ConfiguredScenario>;
19
+ defaultOutputType: ScenarioOutputType;
20
+ isConfigured: boolean;
21
+ }
22
+
23
+ const state: ScenarioRegistryState = {
24
+ scenarios: new Map(),
25
+ defaultOutputType: "video",
26
+ isConfigured: false,
27
+ };
28
+
29
+ /**
30
+ * Configure scenarios for this app
31
+ * Call once at app startup
32
+ */
33
+ export const configureScenarios = (
34
+ scenarios: readonly ConfiguredScenario[],
35
+ defaultOutputType: ScenarioOutputType = "video",
36
+ ): void => {
37
+ state.scenarios.clear();
38
+
39
+ for (const scenario of scenarios) {
40
+ state.scenarios.set(scenario.id, scenario);
41
+ }
42
+
43
+ state.defaultOutputType = defaultOutputType;
44
+ state.isConfigured = true;
45
+
46
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
47
+ console.log("[ScenarioRegistry] Configured:", {
48
+ count: scenarios.length,
49
+ defaultOutputType,
50
+ });
51
+ }
52
+ };
53
+
54
+ /**
55
+ * Get scenario by ID from configured scenarios
56
+ */
57
+ export const getConfiguredScenario = (
58
+ id: string,
59
+ ): ConfiguredScenario | undefined => {
60
+ const found = state.scenarios.get(id);
61
+
62
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
63
+ console.log("[ScenarioRegistry] getConfiguredScenario:", {
64
+ id,
65
+ found: !!found,
66
+ outputType: found?.outputType,
67
+ });
68
+ }
69
+
70
+ return found;
71
+ };
72
+
73
+ /**
74
+ * Get default output type for this app
75
+ */
76
+ export const getDefaultOutputType = (): ScenarioOutputType => {
77
+ return state.defaultOutputType;
78
+ };
79
+
80
+ /**
81
+ * Check if scenarios are configured
82
+ */
83
+ export const isScenariosConfigured = (): boolean => {
84
+ return state.isConfigured;
85
+ };
86
+
87
+ /**
88
+ * Get all configured scenarios
89
+ */
90
+ export const getAllConfiguredScenarios = (): readonly ConfiguredScenario[] => {
91
+ return Array.from(state.scenarios.values());
92
+ };
93
+
94
+ /**
95
+ * Reset registry (for testing)
96
+ */
97
+ export const resetScenarioRegistry = (): void => {
98
+ state.scenarios.clear();
99
+ state.defaultOutputType = "video";
100
+ state.isConfigured = false;
101
+ };
@@ -1,100 +1,64 @@
1
1
  /**
2
2
  * Generation Config Provider
3
- * Provides app-specific configuration to the package
4
- * NO hard-coded models, everything comes from app!
3
+ * Provides app-specific AI models configuration
4
+ * For scenarios, use configureScenarios() from scenario-registry
5
5
  */
6
6
 
7
7
  import React, { createContext, useContext, type ReactNode } from "react";
8
8
 
9
9
  declare const __DEV__: boolean;
10
10
 
11
- // ============================================================================
12
- // Types
13
- // ============================================================================
14
-
15
11
  export interface GenerationModels {
16
- /** Image generation with face identity preservation (couple photos) */
17
12
  readonly imageCoupleMultiRef?: string;
18
- /** Text-to-image generation */
19
13
  readonly imageTextToImage?: string;
20
- /** Image-to-video generation */
21
14
  readonly imageToVideo?: string;
22
- /** Text-to-video generation */
23
15
  readonly textToVideo?: string;
24
- /** AI Kiss video */
25
16
  readonly aiKiss?: string;
26
- /** AI Hug video */
27
17
  readonly aiHug?: string;
28
- /** Face swap */
29
18
  readonly faceSwap?: string;
30
- /** Meme generation (caption) */
31
19
  readonly memeCaption?: string;
32
- /** Meme generation (image) */
33
20
  readonly memeImage?: string;
34
- /** Text to voice */
35
21
  readonly textToVoice?: string;
36
22
  }
37
23
 
38
24
  export interface GenerationConfigValue {
39
- /** AI models configuration from app */
40
25
  readonly models: GenerationModels;
41
- /** Get model for specific feature type */
42
26
  readonly getModel: (featureType: keyof GenerationModels) => string;
43
27
  }
44
28
 
45
- // ============================================================================
46
- // Context
47
- // ============================================================================
48
-
49
- const GenerationConfigContext = createContext<GenerationConfigValue | null>(null);
50
-
51
- // ============================================================================
52
- // Provider
53
- // ============================================================================
29
+ const GenerationConfigContext = createContext<GenerationConfigValue | null>(
30
+ null,
31
+ );
54
32
 
55
33
  export interface GenerationConfigProviderProps {
56
34
  readonly children: ReactNode;
57
35
  readonly models: GenerationModels;
58
36
  }
59
37
 
60
- export const GenerationConfigProvider: React.FC<GenerationConfigProviderProps> = ({
61
- children,
62
- models,
63
- }) => {
38
+ export const GenerationConfigProvider: React.FC<
39
+ GenerationConfigProviderProps
40
+ > = ({ children, models }) => {
64
41
  if (typeof __DEV__ !== "undefined" && __DEV__) {
65
42
  const configuredModels = Object.entries(models)
66
43
  .filter(([, value]) => !!value)
67
44
  .map(([key]) => key);
68
-
69
- console.log("[GenerationConfigProvider] Initialized with models:", {
70
- configured: configuredModels,
71
- imageCoupleMultiRef: models.imageCoupleMultiRef || "not configured",
72
- imageTextToImage: models.imageTextToImage || "not configured",
73
- imageToVideo: models.imageToVideo || "not configured",
74
- textToVideo: models.textToVideo || "not configured",
75
- });
45
+ console.log("[GenerationConfigProvider] Models:", configuredModels);
76
46
  }
77
47
 
78
48
  const getModel = (featureType: keyof GenerationModels): string => {
79
49
  const model = models[featureType];
80
50
  if (!model) {
81
- const availableModels = Object.keys(models).filter(
82
- (key) => models[key as keyof GenerationModels]
51
+ const available = Object.keys(models).filter(
52
+ (key) => models[key as keyof GenerationModels],
83
53
  );
84
-
85
54
  throw new Error(
86
- `Model not configured for feature: ${featureType}.\n\n` +
87
- `This app only supports: ${availableModels.join(", ") || "none"}.\n` +
88
- `Please configure '${featureType}' in your GenerationConfigProvider if you need it.`
55
+ `Model not configured: ${featureType}. Available: ${available.join(", ") || "none"}`,
89
56
  );
90
57
  }
91
58
  return model;
92
59
  };
93
60
 
94
- const value: GenerationConfigValue = {
95
- models,
96
- getModel,
97
- };
61
+ const value: GenerationConfigValue = { models, getModel };
98
62
 
99
63
  return (
100
64
  <GenerationConfigContext.Provider value={value}>
@@ -103,19 +67,12 @@ export const GenerationConfigProvider: React.FC<GenerationConfigProviderProps> =
103
67
  );
104
68
  };
105
69
 
106
- // ============================================================================
107
- // Hook
108
- // ============================================================================
109
-
110
70
  export const useGenerationConfig = (): GenerationConfigValue => {
111
71
  const context = useContext(GenerationConfigContext);
112
-
113
72
  if (!context) {
114
73
  throw new Error(
115
- "useGenerationConfig must be used within GenerationConfigProvider. " +
116
- "Wrap your app with <GenerationConfigProvider models={{...}}>"
74
+ "useGenerationConfig must be used within GenerationConfigProvider",
117
75
  );
118
76
  }
119
-
120
77
  return context;
121
78
  };