@umituz/react-native-ai-generation-content 1.25.25 → 1.26.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.25.25",
3
+ "version": "1.26.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",
@@ -98,7 +98,25 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
98
98
 
99
99
  // Ensure scenario has required fields - use feature config as fallback
100
100
  const validatedScenario = useMemo(() => {
101
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
102
+ console.log("[GenericWizardFlow] Validating scenario", {
103
+ hasScenario: !!scenario,
104
+ scenarioId: scenario?.id,
105
+ hasAiPrompt: scenario?.aiPrompt !== undefined,
106
+ hasModel: !!scenario?.model,
107
+ scenarioModel: scenario?.model,
108
+ outputType: scenario?.outputType,
109
+ });
110
+ }
111
+
101
112
  if (scenario && scenario.id && scenario.aiPrompt !== undefined) {
113
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
114
+ console.log("[GenericWizardFlow] Scenario validation passed", {
115
+ scenarioId: scenario.id,
116
+ model: scenario.model,
117
+ outputType: scenario.outputType,
118
+ });
119
+ }
102
120
  return scenario;
103
121
  }
104
122
 
@@ -38,7 +38,6 @@ export interface CoupleFutureResult {
38
38
  }
39
39
 
40
40
  export const COUPLE_FUTURE_DEFAULTS = {
41
- model: "fal-ai/nano-banana/edit",
42
41
  aspectRatio: "4:3" as NanoBananaAspectRatio,
43
42
  outputFormat: "jpeg" as NanoBananaOutputFormat,
44
43
  timeoutMs: 300000,
@@ -9,21 +9,24 @@ export interface MemeGenerationParams {
9
9
  export class MemeGenerationService {
10
10
  /**
11
11
  * Enhance a simple user prompt into a rich image generation prompt
12
+ * @param prompt - The user's meme idea
13
+ * @param modelId - REQUIRED: Text-to-text model ID from app config
12
14
  */
13
- async enhancePrompt(prompt: string, modelId?: string): Promise<string> {
15
+ async enhancePrompt(prompt: string, modelId: string): Promise<string> {
14
16
  try {
15
17
  const provider = providerRegistry.getActiveProvider();
16
18
  if (!provider) {
17
19
  throw new Error("AI provider not available");
18
20
  }
19
21
 
20
- const systemPrompt = `You are an AI art director. Take the user's simple meme idea and transform it into a visually rich, detailed, and funny image generation prompt. Your response should be only the new prompt, no explanations. Idea: "${prompt}"`;
22
+ if (!modelId) {
23
+ throw new Error("modelId is required for enhancePrompt. Please provide model from app config.");
24
+ }
21
25
 
22
- // Use provided modelId or try to find a default text-to-text model
23
- const model = modelId || "fal-ai/llama-3-8b-instruct";
26
+ const systemPrompt = `You are an AI art director. Take the user's simple meme idea and transform it into a visually rich, detailed, and funny image generation prompt. Your response should be only the new prompt, no explanations. Idea: "${prompt}"`;
24
27
 
25
28
  const result = await provider.run<{ text?: string, data?: { text: string } }>(
26
- model,
29
+ modelId,
27
30
  { prompt: systemPrompt }
28
31
  );
29
32
 
@@ -41,23 +44,25 @@ export class MemeGenerationService {
41
44
 
42
45
  /**
43
46
  * Generate a meme image
44
- * @param prompt The final prompt to use (should already be enhanced if desired)
45
- * @param modelId Optional Fal model ID
47
+ * @param prompt - The final prompt to use (should already be enhanced if desired)
48
+ * @param modelId - REQUIRED: Image generation model ID from app config
46
49
  */
47
- async generateMeme(prompt: string, modelId?: string): Promise<string> {
50
+ async generateMeme(prompt: string, modelId: string): Promise<string> {
48
51
  try {
49
52
  const provider = providerRegistry.getActiveProvider();
50
53
  if (!provider) {
51
54
  throw new Error("AI provider not available");
52
55
  }
53
56
 
54
- const finalPrompt = `High-quality, funny meme: ${prompt}. Cinematic, vibrant, clean subject, NO TEXT in image.`;
57
+ if (!modelId) {
58
+ throw new Error("modelId is required for generateMeme. Please provide model from app config.");
59
+ }
55
60
 
56
- const model = modelId || "fal-ai/flux/schnell";
61
+ const finalPrompt = `High-quality, funny meme: ${prompt}. Cinematic, vibrant, clean subject, NO TEXT in image.`;
57
62
 
58
63
  const result = await provider.run<{ images: { url: string }[] }>(
59
- model,
60
- {
64
+ modelId,
65
+ {
61
66
  prompt: finalPrompt,
62
67
  image_size: "square",
63
68
  num_inference_steps: 4
@@ -62,11 +62,16 @@ export const MemeGeneratorFeature: React.FC<MemeGeneratorFeatureProps> = ({
62
62
  description: s.description
63
63
  })), [stylesList]);
64
64
 
65
+ // Validate model is provided from app
66
+ if (!config.model) {
67
+ throw new Error(
68
+ "MemeGeneratorFeature: model is required in config. " +
69
+ "Please provide model from app's generation config."
70
+ );
71
+ }
72
+
65
73
  const { state, setPrompt, generate, reset, isReady } = useTextToImageFeature({
66
- config: {
67
- ...config,
68
- model: config.model || "fal-ai/nano-banana-edit",
69
- },
74
+ config,
70
75
  userId,
71
76
  });
72
77
 
package/src/index.ts CHANGED
@@ -167,6 +167,15 @@ export * from "./features/partner-upload";
167
167
  export * from "./features/scenarios";
168
168
  export * from "./infrastructure/orchestration";
169
169
 
170
+ // Generation Config Provider (App Configuration)
171
+ export {
172
+ GenerationConfigProvider,
173
+ useGenerationConfig,
174
+ type GenerationModels,
175
+ type GenerationConfigContextValue,
176
+ type GenerationConfigProviderProps,
177
+ } from "./infrastructure/providers";
178
+
170
179
  // Result Preview Domain
171
180
  export * from "./domains/result-preview";
172
181
 
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Generation Config Provider
3
+ * Provides app-specific configuration to the package
4
+ * NO hard-coded models, everything comes from app!
5
+ */
6
+
7
+ import React, { createContext, useContext, type ReactNode } from "react";
8
+
9
+ declare const __DEV__: boolean;
10
+
11
+ // ============================================================================
12
+ // Types
13
+ // ============================================================================
14
+
15
+ export interface GenerationModels {
16
+ /** Image generation with face identity preservation (couple photos) */
17
+ readonly imageCoupleMultiRef: string;
18
+ /** Text-to-image generation */
19
+ readonly imageTextToImage: string;
20
+ /** Image-to-video generation */
21
+ readonly imageToVideo: string;
22
+ /** Text-to-video generation */
23
+ readonly textToVideo: string;
24
+ /** AI Kiss video */
25
+ readonly aiKiss?: string;
26
+ /** AI Hug video */
27
+ readonly aiHug?: string;
28
+ /** Face swap */
29
+ readonly faceSwap?: string;
30
+ /** Meme generation (caption) */
31
+ readonly memeCaption?: string;
32
+ /** Meme generation (image) */
33
+ readonly memeImage?: string;
34
+ /** Text to voice */
35
+ readonly textToVoice?: string;
36
+ }
37
+
38
+ export interface GenerationConfigContextValue {
39
+ /** AI models configuration from app */
40
+ readonly models: GenerationModels;
41
+ /** Get model for specific feature type */
42
+ readonly getModel: (featureType: keyof GenerationModels) => string;
43
+ }
44
+
45
+ // ============================================================================
46
+ // Context
47
+ // ============================================================================
48
+
49
+ const GenerationConfigContext = createContext<GenerationConfigContextValue | null>(null);
50
+
51
+ // ============================================================================
52
+ // Provider
53
+ // ============================================================================
54
+
55
+ export interface GenerationConfigProviderProps {
56
+ readonly children: ReactNode;
57
+ readonly models: GenerationModels;
58
+ }
59
+
60
+ export const GenerationConfigProvider: React.FC<GenerationConfigProviderProps> = ({
61
+ children,
62
+ models,
63
+ }) => {
64
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
65
+ console.log("[GenerationConfigProvider] Initialized with models:", {
66
+ imageCoupleMultiRef: models.imageCoupleMultiRef,
67
+ imageTextToImage: models.imageTextToImage,
68
+ imageToVideo: models.imageToVideo,
69
+ textToVideo: models.textToVideo,
70
+ });
71
+ }
72
+
73
+ const getModel = (featureType: keyof GenerationModels): string => {
74
+ const model = models[featureType];
75
+ if (!model) {
76
+ throw new Error(
77
+ `Model not configured for feature: ${featureType}. Please configure in app's GenerationConfigProvider.`
78
+ );
79
+ }
80
+ return model;
81
+ };
82
+
83
+ const value: GenerationConfigContextValue = {
84
+ models,
85
+ getModel,
86
+ };
87
+
88
+ return (
89
+ <GenerationConfigContext.Provider value={value}>
90
+ {children}
91
+ </GenerationConfigContext.Provider>
92
+ );
93
+ };
94
+
95
+ // ============================================================================
96
+ // Hook
97
+ // ============================================================================
98
+
99
+ export const useGenerationConfig = (): GenerationConfigContextValue => {
100
+ const context = useContext(GenerationConfigContext);
101
+
102
+ if (!context) {
103
+ throw new Error(
104
+ "useGenerationConfig must be used within GenerationConfigProvider. " +
105
+ "Wrap your app with <GenerationConfigProvider models={{...}}>"
106
+ );
107
+ }
108
+
109
+ return context;
110
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Providers
3
+ * App-level configuration providers
4
+ */
5
+
6
+ export {
7
+ GenerationConfigProvider,
8
+ useGenerationConfig,
9
+ type GenerationModels,
10
+ type GenerationConfigContextValue,
11
+ type GenerationConfigProviderProps,
12
+ } from "./generation-config.provider";
@@ -20,6 +20,8 @@ export interface SynchronousGenerationConfig<T = unknown> {
20
20
  checkCredits?: (userId: string, type: string) => Promise<boolean>;
21
21
  deductCredits?: (userId: string, type: string) => Promise<void>;
22
22
  execute: (prompt: string, metadata?: Record<string, unknown>) => Promise<T>;
23
+ /** Model ID for metadata tracking */
24
+ model?: string;
23
25
  }
24
26
 
25
27
  export async function generateSynchronously<T = string>(
@@ -67,20 +69,21 @@ export async function generateSynchronously<T = string>(
67
69
  await config.deductCredits(input.userId, input.type || "generation");
68
70
  }
69
71
 
70
- return createSuccessResult(result);
72
+ return createSuccessResult(result, config.model || "unknown");
71
73
  } catch (error) {
72
74
  return createErrorResult(
73
75
  error instanceof Error ? error.message : "generation_failed",
76
+ config.model || "unknown",
74
77
  );
75
78
  }
76
79
  }
77
80
 
78
- function createSuccessResult<T>(data: T): GenerationResult<T> {
81
+ function createSuccessResult<T>(data: T, model: string): GenerationResult<T> {
79
82
  return {
80
83
  success: true,
81
84
  data,
82
85
  metadata: {
83
- model: "default",
86
+ model,
84
87
  startTime: Date.now(),
85
88
  endTime: Date.now(),
86
89
  duration: 0,
@@ -88,12 +91,12 @@ function createSuccessResult<T>(data: T): GenerationResult<T> {
88
91
  };
89
92
  }
90
93
 
91
- function createErrorResult<T>(error: string): GenerationResult<T> {
94
+ function createErrorResult<T>(error: string, model: string): GenerationResult<T> {
92
95
  return {
93
96
  success: false,
94
97
  error,
95
98
  metadata: {
96
- model: "default",
99
+ model,
97
100
  startTime: Date.now(),
98
101
  endTime: Date.now(),
99
102
  duration: 0,
@@ -18,6 +18,8 @@ interface FeatureGenerationConfig {
18
18
  onError?: (error: GenerationError) => void;
19
19
  creditCost?: number;
20
20
  onCreditsExhausted?: () => void;
21
+ /** REQUIRED for video features: Video generation model ID from app config */
22
+ videoModel?: string;
21
23
  }
22
24
 
23
25
  export function useAIFeatureGeneration({
@@ -28,6 +30,7 @@ export function useAIFeatureGeneration({
28
30
  onError,
29
31
  creditCost = 1,
30
32
  onCreditsExhausted,
33
+ videoModel,
31
34
  }: FeatureGenerationConfig) {
32
35
 
33
36
  // Hook for standard image features
@@ -58,16 +61,23 @@ export function useAIFeatureGeneration({
58
61
  const { generate: generateImageToVideo } = useGenerationOrchestrator(
59
62
  {
60
63
  execute: async (input: { imageUri: string; prompt: string; duration: number }, onProgress) => {
64
+ if (!videoModel) {
65
+ throw new Error(
66
+ "videoModel is required for image-to-video feature. " +
67
+ "Please provide videoModel from app's generation config."
68
+ );
69
+ }
70
+
61
71
  const result = await executeImageToVideo(
62
72
  {
63
73
  imageUri: input.imageUri, // Pass URI directly
64
- imageBase64: await prepareImage(input.imageUri),
74
+ imageBase64: await prepareImage(input.imageUri),
65
75
  motionPrompt: input.prompt,
66
76
  options: { duration: input.duration },
67
77
  userId: userId || "anonymous",
68
78
  },
69
79
  {
70
- model: "kling-video", // Default or hardcoded for now, ideal to get from config
80
+ model: videoModel,
71
81
  buildInput: (image, prompt, opts) => ({
72
82
  image,
73
83
  prompt,
@@ -88,6 +98,13 @@ export function useAIFeatureGeneration({
88
98
  const { generate: generateTextToVideo } = useGenerationOrchestrator(
89
99
  {
90
100
  execute: async (input: { prompt: string; duration: number }, onProgress) => {
101
+ if (!videoModel) {
102
+ throw new Error(
103
+ "videoModel is required for text-to-video feature. " +
104
+ "Please provide videoModel from app's generation config."
105
+ );
106
+ }
107
+
91
108
  const result = await executeTextToVideo(
92
109
  {
93
110
  prompt: input.prompt,
@@ -95,7 +112,7 @@ export function useAIFeatureGeneration({
95
112
  userId: userId || "anonymous",
96
113
  },
97
114
  {
98
- model: "kling-video", // Default
115
+ model: videoModel,
99
116
  buildInput: (prompt, opts) => ({ prompt, ...opts }),
100
117
  onProgress,
101
118
  }