@umituz/react-native-ai-generation-content 1.78.0 → 1.80.0

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.78.0",
3
+ "version": "1.80.0",
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",
@@ -13,3 +13,6 @@ export type { IAIProviderJobManager } from "../../domains/background/domain/inte
13
13
  export type { IAIProviderExecutor } from "./provider-executor.interface";
14
14
  export type { IAIProviderImageFeatures } from "./provider-image-features.interface";
15
15
  export type { IAIProviderVideoFeatures } from "./provider-video-features.interface";
16
+
17
+ // Video Model Configuration
18
+ export type { VideoModelConfig, ModelCapabilityOption } from "./video-model-config.types";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * VideoModelConfig - Model-Agnostic Configuration Interface
3
+ * Encapsulates ALL model-specific behavior in a single config object.
4
+ * Adding a new model = creating one config file. No other changes needed.
5
+ */
6
+
7
+ export interface ModelCapabilityOption {
8
+ readonly id: string;
9
+ readonly label: string;
10
+ readonly value: string | number;
11
+ }
12
+
13
+ export interface VideoModelConfig {
14
+ /** Fal.ai model endpoint (e.g., "fal-ai/minimax/hailuo-02/standard/image-to-video") */
15
+ readonly modelId: string;
16
+
17
+ /** Human-readable display name */
18
+ readonly displayName: string;
19
+
20
+ /** What this model supports (drives wizard UI) */
21
+ readonly capabilities: {
22
+ readonly resolutions: ReadonlyArray<ModelCapabilityOption>;
23
+ readonly durations: ReadonlyArray<ModelCapabilityOption>;
24
+ readonly aspectRatios?: ReadonlyArray<ModelCapabilityOption>;
25
+ readonly defaults: {
26
+ readonly resolution: string;
27
+ readonly duration: number;
28
+ readonly aspectRatio?: string;
29
+ };
30
+ };
31
+
32
+ /**
33
+ * Maps generic WizardVideoInput to model-specific API parameters.
34
+ * This is the core adapter function - eliminates all model-specific if/else checks.
35
+ */
36
+ readonly buildInput: (input: {
37
+ readonly prompt: string;
38
+ readonly sourceImageBase64?: string;
39
+ readonly targetImageBase64?: string;
40
+ readonly duration?: number;
41
+ readonly aspectRatio?: string;
42
+ readonly resolution?: string;
43
+ }) => Record<string, unknown>;
44
+
45
+ /**
46
+ * Pricing data for credit calculation.
47
+ * Keys are resolution IDs matching capabilities.resolutions[].id
48
+ */
49
+ readonly pricing: {
50
+ readonly costPerSecond: Record<string, number>;
51
+ };
52
+ }
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Video Generation Executor
3
- * Handles the actual video generation execution
4
- * Uses direct provider calls for text-to-video and image-to-video generation models
3
+ * Handles the actual video generation execution.
4
+ * Model-agnostic: uses VideoModelConfig.buildInput() for model-specific parameters.
5
+ * Fallback: generic input builder when no modelConfig is provided.
5
6
  */
6
7
 
7
8
  import type { WizardVideoInput } from "./video-generation.types";
9
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
8
10
  import { GENERATION_TIMEOUT_MS, BASE64_IMAGE_PREFIX } from "./wizard-strategy.constants";
9
11
  import { createGenerationError, GenerationErrorType } from "../../../../../infrastructure/utils/error-factory";
10
12
 
@@ -29,14 +31,38 @@ function formatBase64(base64: string | undefined): string | undefined {
29
31
  return base64.startsWith("data:") ? base64 : `${BASE64_IMAGE_PREFIX}${base64}`;
30
32
  }
31
33
 
34
+ /**
35
+ * Generic input builder - used when no modelConfig is provided.
36
+ * Sends standard parameters without model-specific logic.
37
+ */
38
+ function buildGenericInput(input: WizardVideoInput): Record<string, unknown> {
39
+ const modelInput: Record<string, unknown> = { prompt: input.prompt };
40
+ const sourceImage = formatBase64(input.sourceImageBase64);
41
+
42
+ if (sourceImage && sourceImage.length > 0) {
43
+ modelInput.image_url = sourceImage;
44
+ }
45
+ if (input.duration) {
46
+ modelInput.duration = input.duration;
47
+ }
48
+ if (input.aspectRatio) {
49
+ modelInput.aspect_ratio = input.aspectRatio;
50
+ }
51
+ if (input.resolution) {
52
+ modelInput.resolution = input.resolution;
53
+ }
54
+
55
+ return modelInput;
56
+ }
57
+
32
58
  /**
33
59
  * Execute video generation using direct provider call
34
- * For text-to-video and image-to-video generation models (NOT features)
35
60
  */
36
61
  export async function executeVideoGeneration(
37
62
  input: WizardVideoInput,
38
63
  model: string,
39
64
  onProgress?: (status: string) => void,
65
+ modelConfig?: VideoModelConfig,
40
66
  ): Promise<ExecutionResult> {
41
67
  const { providerRegistry } = await import("../../../../../infrastructure/services/provider-registry.service");
42
68
 
@@ -50,47 +76,19 @@ export async function executeVideoGeneration(
50
76
  }
51
77
 
52
78
  try {
53
- const sourceImage = formatBase64(input.sourceImageBase64);
54
-
55
79
  if (typeof __DEV__ !== "undefined" && __DEV__) {
56
80
  console.log("[VideoExecutor] Generation starting", {
57
81
  model,
82
+ hasModelConfig: !!modelConfig,
58
83
  duration: input.duration,
59
- aspectRatio: input.aspectRatio,
60
84
  resolution: input.resolution,
61
85
  });
62
86
  }
63
87
 
64
- // Detect Minimax subject reference model
65
- const isSubjectReference = model.includes("minimax") || model.includes("hailuo");
66
-
67
- const modelInput: Record<string, unknown> = {
68
- prompt: input.prompt,
69
- };
70
-
71
- if (sourceImage && sourceImage.length > 0) {
72
- modelInput.image_url = sourceImage;
73
- }
74
-
75
- if (isSubjectReference) {
76
- modelInput.prompt_optimizer = true;
77
- if (input.duration) {
78
- modelInput.duration = String(input.duration);
79
- }
80
- if (input.resolution) {
81
- modelInput.resolution = input.resolution;
82
- }
83
- } else {
84
- if (input.duration) {
85
- modelInput.duration = input.duration;
86
- }
87
- if (input.aspectRatio) {
88
- modelInput.aspect_ratio = input.aspectRatio;
89
- }
90
- if (input.resolution) {
91
- modelInput.resolution = input.resolution;
92
- }
93
- }
88
+ // Use modelConfig.buildInput() if available, otherwise generic fallback
89
+ const modelInput = modelConfig
90
+ ? modelConfig.buildInput(input)
91
+ : buildGenericInput(input);
94
92
 
95
93
  let lastStatus = "";
96
94
  const result = await provider.subscribe(model, modelInput, {
@@ -126,6 +124,7 @@ export async function executeVideoGeneration(
126
124
  export async function submitVideoGenerationToQueue(
127
125
  input: WizardVideoInput,
128
126
  model: string,
127
+ modelConfig?: VideoModelConfig,
129
128
  ): Promise<SubmissionResult> {
130
129
  const { providerRegistry } = await import("../../../../../infrastructure/services/provider-registry.service");
131
130
 
@@ -139,37 +138,10 @@ export async function submitVideoGenerationToQueue(
139
138
  }
140
139
 
141
140
  try {
142
- const sourceImage = formatBase64(input.sourceImageBase64);
143
-
144
- const isSubjectReference = model.includes("minimax") || model.includes("hailuo");
145
-
146
- const modelInput: Record<string, unknown> = {
147
- prompt: input.prompt,
148
- };
149
-
150
- if (sourceImage && sourceImage.length > 0) {
151
- modelInput.image_url = sourceImage;
152
- }
153
-
154
- if (isSubjectReference) {
155
- modelInput.prompt_optimizer = true;
156
- if (input.duration) {
157
- modelInput.duration = String(input.duration);
158
- }
159
- if (input.resolution) {
160
- modelInput.resolution = input.resolution;
161
- }
162
- } else {
163
- if (input.duration) {
164
- modelInput.duration = input.duration;
165
- }
166
- if (input.aspectRatio) {
167
- modelInput.aspect_ratio = input.aspectRatio;
168
- }
169
- if (input.resolution) {
170
- modelInput.resolution = input.resolution;
171
- }
172
- }
141
+ // Use modelConfig.buildInput() if available, otherwise generic fallback
142
+ const modelInput = modelConfig
143
+ ? modelConfig.buildInput(input)
144
+ : buildGenericInput(input);
173
145
 
174
146
  const submission = await provider.submitJob(model, modelInput);
175
147
 
@@ -67,7 +67,7 @@ export async function buildVideoInput(
67
67
  }
68
68
 
69
69
  export function createVideoStrategy(options: CreateVideoStrategyOptions): WizardStrategy {
70
- const { scenario, creditCost } = options;
70
+ const { scenario, modelConfig, creditCost } = options;
71
71
 
72
72
  // Validate model early - fail fast
73
73
  if (!scenario.model) {
@@ -78,10 +78,9 @@ export function createVideoStrategy(options: CreateVideoStrategyOptions): Wizard
78
78
 
79
79
  return {
80
80
  execute: async (input: unknown) => {
81
- // Runtime validation with descriptive errors
82
81
  const videoInput = validateWizardVideoInput(input);
83
82
 
84
- const result = await executeVideoGeneration(videoInput, model);
83
+ const result = await executeVideoGeneration(videoInput, model, undefined, modelConfig);
85
84
 
86
85
  if (!result.success || !result.videoUrl) {
87
86
  throw new Error(result.error || "Video generation failed");
@@ -91,10 +90,9 @@ export function createVideoStrategy(options: CreateVideoStrategyOptions): Wizard
91
90
  },
92
91
 
93
92
  submitToQueue: async (input: unknown) => {
94
- // Runtime validation with descriptive errors
95
93
  const videoInput = validateWizardVideoInput(input);
96
94
 
97
- const result = await submitVideoGenerationToQueue(videoInput, model);
95
+ const result = await submitVideoGenerationToQueue(videoInput, model, modelConfig);
98
96
 
99
97
  return {
100
98
  success: result.success,
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
7
7
  import type { ScenarioInputType } from "../../../../scenarios/domain/Scenario";
8
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
8
9
 
9
10
  export interface WizardVideoInput {
10
11
  /** Source image (optional for text-to-video) */
@@ -26,6 +27,8 @@ export interface WizardVideoResult {
26
27
 
27
28
  export interface CreateVideoStrategyOptions {
28
29
  readonly scenario: WizardScenarioData;
30
+ /** Model configuration - encapsulates all model-specific behavior */
31
+ readonly modelConfig?: VideoModelConfig;
29
32
  readonly collectionName?: string;
30
33
  /** Credit cost for this generation - REQUIRED, determined by the app */
31
34
  readonly creditCost: number;
@@ -6,6 +6,7 @@
6
6
 
7
7
  import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
8
8
  import type { WizardStrategy } from "./wizard-strategy.types";
9
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
9
10
  import { createImageStrategy, buildImageInput } from "./image-generation.strategy";
10
11
  import { createVideoStrategy, buildVideoInput } from "./video-generation.strategy";
11
12
 
@@ -17,6 +18,8 @@ export type { WizardStrategy } from "./wizard-strategy.types";
17
18
 
18
19
  export interface CreateWizardStrategyOptions {
19
20
  readonly scenario: WizardScenarioData;
21
+ /** Model configuration - encapsulates all model-specific behavior */
22
+ readonly modelConfig?: VideoModelConfig;
20
23
  readonly collectionName?: string;
21
24
  /** Credit cost for this generation - REQUIRED, determined by the app */
22
25
  readonly creditCost: number;
@@ -27,14 +30,14 @@ export interface CreateWizardStrategyOptions {
27
30
  // ============================================================================
28
31
 
29
32
  export function createWizardStrategy(options: CreateWizardStrategyOptions): WizardStrategy {
30
- const { scenario, collectionName, creditCost } = options;
33
+ const { scenario, modelConfig, collectionName, creditCost } = options;
31
34
 
32
35
  if (scenario.outputType === "image") {
33
36
  return createImageStrategy({ scenario, collectionName, creditCost });
34
37
  }
35
38
 
36
39
  // Default to video strategy for video outputType or undefined
37
- return createVideoStrategy({ scenario, collectionName, creditCost });
40
+ return createVideoStrategy({ scenario, modelConfig, collectionName, creditCost });
38
41
  }
39
42
 
40
43
  // ============================================================================
@@ -11,6 +11,7 @@ import type { WizardScenarioData } from "../hooks/useWizardGeneration";
11
11
  import type { AlertMessages } from "../../../../../presentation/hooks/generation/types";
12
12
  import type { GenerationErrorInfo } from "./WizardFlow.types";
13
13
  import type { CreditCalculatorFn } from "../../domain/types/credit-calculation.types";
14
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
14
15
  import { validateScenario } from "../utilities/validateScenario";
15
16
  import { WizardFlowContent } from "./WizardFlowContent";
16
17
  import {
@@ -24,6 +25,8 @@ export interface GenericWizardFlowProps {
24
25
  readonly featureConfig: WizardFeatureConfig;
25
26
  readonly scenario?: WizardScenarioData;
26
27
  readonly scenarioId?: string;
28
+ /** Model configuration - encapsulates all model-specific behavior */
29
+ readonly modelConfig?: VideoModelConfig;
27
30
  readonly userId?: string;
28
31
  readonly alertMessages: AlertMessages;
29
32
  /** Credit cost for this generation - REQUIRED, determined by the app */
@@ -54,6 +57,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
54
57
  featureConfig,
55
58
  scenario: scenarioProp,
56
59
  scenarioId,
60
+ modelConfig,
57
61
  userId,
58
62
  alertMessages,
59
63
  creditCost,
@@ -111,6 +115,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = (props) => {
111
115
  featureConfig={featureConfig}
112
116
  scenario={scenario}
113
117
  validatedScenario={validatedScenario}
118
+ modelConfig={modelConfig}
114
119
  userId={userId}
115
120
  alertMessages={alertMessages}
116
121
  creditCost={creditCost}
@@ -20,11 +20,14 @@ import { extractDuration, extractResolution } from "../../infrastructure/utils/c
20
20
  import { WizardStepRenderer } from "./WizardStepRenderer";
21
21
  import { StarRatingPicker } from "../../../../result-preview/presentation/components/StarRatingPicker";
22
22
  import type { CreditCalculatorFn } from "../../domain/types/credit-calculation.types";
23
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
23
24
 
24
25
  export interface WizardFlowContentProps {
25
26
  readonly featureConfig: WizardFeatureConfig;
26
27
  readonly scenario?: WizardScenarioData;
27
28
  readonly validatedScenario: WizardScenarioData;
29
+ /** Model configuration - encapsulates all model-specific behavior */
30
+ readonly modelConfig?: VideoModelConfig;
28
31
  readonly userId?: string;
29
32
  readonly alertMessages: AlertMessages;
30
33
  /** Credit cost for this generation - REQUIRED, determined by the app */
@@ -54,6 +57,7 @@ export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
54
57
  featureConfig,
55
58
  scenario,
56
59
  validatedScenario,
60
+ modelConfig,
57
61
  userId,
58
62
  alertMessages,
59
63
  creditCost, // Still needed for initial feature gate in parent
@@ -174,6 +178,7 @@ export const WizardFlowContent: React.FC<WizardFlowContentProps> = (props) => {
174
178
 
175
179
  useWizardGeneration({
176
180
  scenario: validatedScenario,
181
+ modelConfig,
177
182
  wizardData: customData,
178
183
  userId,
179
184
  isGeneratingStep: currentStep?.type === StepType.GENERATING,
@@ -22,6 +22,7 @@ export type {
22
22
  export const useWizardGeneration = (props: UseWizardGenerationProps): UseWizardGenerationReturn => {
23
23
  const {
24
24
  scenario,
25
+ modelConfig,
25
26
  wizardData,
26
27
  userId,
27
28
  isGeneratingStep,
@@ -43,7 +44,7 @@ export const useWizardGeneration = (props: UseWizardGenerationProps): UseWizardG
43
44
  }, []);
44
45
 
45
46
  const persistence = useMemo(() => createCreationPersistence(), []);
46
- const strategy = useMemo(() => createWizardStrategy({ scenario, creditCost }), [scenario, creditCost]);
47
+ const strategy = useMemo(() => createWizardStrategy({ scenario, modelConfig, creditCost }), [scenario, modelConfig, creditCost]);
47
48
  const isVideoMode = scenario.outputType === "video" && !!strategy.submitToQueue;
48
49
 
49
50
  const videoGeneration = useVideoQueueGeneration({
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { AlertMessages } from "../../../../../presentation/hooks/generation/types";
7
7
  import type { ScenarioInputType, ScenarioPromptType } from "../../../../scenarios/domain/Scenario";
8
+ import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
8
9
 
9
10
  export type WizardOutputType = "image" | "video";
10
11
 
@@ -26,6 +27,8 @@ export interface WizardScenarioData {
26
27
 
27
28
  export interface UseWizardGenerationProps {
28
29
  readonly scenario: WizardScenarioData;
30
+ /** Model configuration - encapsulates all model-specific behavior */
31
+ readonly modelConfig?: VideoModelConfig;
29
32
  readonly wizardData: Record<string, unknown>;
30
33
  readonly userId?: string;
31
34
  readonly isGeneratingStep: boolean;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Build Wizard Config from VideoModelConfig
3
+ * Generates wizard step configuration from model capabilities.
4
+ * No hardcoded model-specific values - everything comes from config.
5
+ */
6
+
7
+ import type { VideoModelConfig } from "../../../../domain/interfaces/video-model-config.types";
8
+ import type { WizardFeatureConfig } from "../domain/entities/wizard-feature-config.types";
9
+ import type { WizardStepConfig } from "../domain/entities/wizard-step.types";
10
+
11
+ /**
12
+ * Builds a WizardFeatureConfig from a VideoModelConfig + input steps.
13
+ * Input steps (photo upload, text input) come from the caller.
14
+ * Resolution/duration/aspectRatio steps are auto-generated from model capabilities.
15
+ */
16
+ export function buildWizardConfigFromModelConfig(
17
+ modelConfig: VideoModelConfig,
18
+ inputSteps: readonly WizardStepConfig[],
19
+ ): WizardFeatureConfig {
20
+ const steps: WizardStepConfig[] = [...inputSteps];
21
+
22
+ if (modelConfig.capabilities.resolutions.length > 0) {
23
+ steps.push({
24
+ id: "resolution",
25
+ type: "selection" as const,
26
+ titleKey: "generation.resolution.title",
27
+ selectionType: "resolution" as const,
28
+ options: modelConfig.capabilities.resolutions.map((r) => ({
29
+ id: r.id,
30
+ label: r.label,
31
+ value: r.value,
32
+ })),
33
+ required: true,
34
+ defaultValue: modelConfig.capabilities.defaults.resolution,
35
+ });
36
+ }
37
+
38
+ if (modelConfig.capabilities.aspectRatios && modelConfig.capabilities.aspectRatios.length > 0) {
39
+ steps.push({
40
+ id: "aspect_ratio",
41
+ type: "selection" as const,
42
+ titleKey: "generation.aspectRatio.title",
43
+ selectionType: "aspect_ratio" as const,
44
+ options: modelConfig.capabilities.aspectRatios.map((a) => ({
45
+ id: a.id,
46
+ label: a.label,
47
+ value: a.value,
48
+ })),
49
+ required: true,
50
+ defaultValue: modelConfig.capabilities.defaults.aspectRatio,
51
+ });
52
+ }
53
+
54
+ if (modelConfig.capabilities.durations.length > 0) {
55
+ steps.push({
56
+ id: "duration",
57
+ type: "selection" as const,
58
+ titleKey: "generation.duration.title",
59
+ selectionType: "duration" as const,
60
+ layout: "list" as const,
61
+ options: modelConfig.capabilities.durations.map((d) => ({
62
+ id: d.id,
63
+ label: d.label,
64
+ value: d.value,
65
+ })),
66
+ required: true,
67
+ defaultValue: modelConfig.capabilities.defaults.duration,
68
+ });
69
+ }
70
+
71
+ return {
72
+ id: modelConfig.modelId,
73
+ name: modelConfig.displayName,
74
+ steps,
75
+ };
76
+ }
package/src/index.ts CHANGED
@@ -40,3 +40,9 @@ export {
40
40
  getCreditConfig,
41
41
  } from "./domains/generation/wizard";
42
42
  export type { ValidationResult, CreditCalculatorFn } from "./domains/generation/wizard";
43
+
44
+ // Video Model Config (for app-side model definitions)
45
+ export type { VideoModelConfig, ModelCapabilityOption } from "./domain/interfaces";
46
+
47
+ // Wizard Config Builder (generates wizard steps from VideoModelConfig)
48
+ export { buildWizardConfigFromModelConfig } from "./domains/generation/wizard/utilities/build-wizard-config";