@umituz/react-native-ai-generation-content 1.27.13 → 1.27.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.27.13",
3
+ "version": "1.27.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",
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * Image-to-Video Feature Hook
3
- * Provider-agnostic hook with callbacks integration
3
+ * Uses centralized useGenerationOrchestrator for consistent auth, credits, and error handling
4
4
  */
5
5
 
6
6
  import { useState, useCallback, useMemo } from "react";
7
- import { useGenerationExecution } from "./useGenerationExecution";
8
- import { validateImageToVideoGeneration } from "./useImageToVideoValidation";
7
+ import {
8
+ useGenerationOrchestrator,
9
+ type GenerationStrategy,
10
+ type AlertMessages,
11
+ } from "../../../../presentation/hooks/generation";
12
+ import { executeImageToVideo } from "../../infrastructure/services";
9
13
  import type {
10
14
  ImageToVideoFeatureState,
11
15
  ImageToVideoFeatureConfig,
@@ -16,7 +20,6 @@ import type {
16
20
 
17
21
  declare const __DEV__: boolean;
18
22
 
19
- // Initial state (inlined from constants file)
20
23
  const INITIAL_STATE: ImageToVideoFeatureState = {
21
24
  imageUri: null,
22
25
  motionPrompt: "",
@@ -27,7 +30,14 @@ const INITIAL_STATE: ImageToVideoFeatureState = {
27
30
  error: null,
28
31
  };
29
32
 
30
- // Types (inlined from types file)
33
+ const DEFAULT_ALERT_MESSAGES: AlertMessages = {
34
+ networkError: "No internet connection. Please check your network.",
35
+ policyViolation: "Content not allowed. Please try again.",
36
+ saveFailed: "Failed to save. Please try again.",
37
+ creditFailed: "Credit operation failed. Please try again.",
38
+ unknown: "An error occurred. Please try again.",
39
+ };
40
+
31
41
  export interface UseImageToVideoFeatureProps {
32
42
  config: ImageToVideoFeatureConfig;
33
43
  callbacks?: ImageToVideoFeatureCallbacks;
@@ -44,15 +54,99 @@ export interface UseImageToVideoFeatureReturn {
44
54
  canGenerate: boolean;
45
55
  }
46
56
 
57
+ interface VideoGenerationInput {
58
+ imageUri: string;
59
+ imageBase64: string;
60
+ motionPrompt: string;
61
+ options?: Omit<ImageToVideoGenerateParams, "imageUri" | "motionPrompt">;
62
+ creationId: string;
63
+ }
64
+
65
+ function generateCreationId(): string {
66
+ return `image-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
67
+ }
68
+
47
69
  export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseImageToVideoFeatureReturn {
48
70
  const { config, callbacks, userId } = props;
49
71
  const [state, setState] = useState<ImageToVideoFeatureState>(INITIAL_STATE);
50
72
 
51
- const executeGeneration = useGenerationExecution({
73
+ const strategy: GenerationStrategy<VideoGenerationInput, ImageToVideoResult> = useMemo(
74
+ () => ({
75
+ execute: async (input, onProgress) => {
76
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
77
+ console.log("[ImageToVideo] Executing generation, creationId:", input.creationId);
78
+ }
79
+
80
+ config.onProcessingStart?.();
81
+
82
+ callbacks?.onGenerationStart?.({
83
+ creationId: input.creationId,
84
+ type: "image-to-video",
85
+ imageUri: input.imageUri,
86
+ metadata: input.options as Record<string, unknown> | undefined,
87
+ }).catch(() => {});
88
+
89
+ const result = await executeImageToVideo(
90
+ {
91
+ imageUri: input.imageUri,
92
+ imageBase64: input.imageBase64,
93
+ userId,
94
+ motionPrompt: input.motionPrompt || undefined,
95
+ options: input.options,
96
+ },
97
+ {
98
+ model: config.model,
99
+ buildInput: config.buildInput,
100
+ extractResult: config.extractResult,
101
+ onProgress: (progress) => {
102
+ setState((prev) => ({ ...prev, progress }));
103
+ onProgress?.(progress);
104
+ callbacks?.onProgress?.(progress);
105
+ },
106
+ },
107
+ );
108
+
109
+ if (!result.success || !result.videoUrl) {
110
+ throw new Error(result.error || "Generation failed");
111
+ }
112
+
113
+ setState((prev) => ({
114
+ ...prev,
115
+ videoUrl: result.videoUrl ?? null,
116
+ thumbnailUrl: result.thumbnailUrl ?? null,
117
+ }));
118
+
119
+ return result;
120
+ },
121
+ getCreditCost: () => config.creditCost ?? 0,
122
+ save: async (result) => {
123
+ if (result.success && result.videoUrl && state.imageUri) {
124
+ await callbacks?.onCreationSave?.({
125
+ creationId: generateCreationId(),
126
+ type: "image-to-video",
127
+ videoUrl: result.videoUrl,
128
+ thumbnailUrl: result.thumbnailUrl,
129
+ imageUri: state.imageUri,
130
+ });
131
+ }
132
+ },
133
+ }),
134
+ [config, callbacks, userId, state.imageUri],
135
+ );
136
+
137
+ const orchestrator = useGenerationOrchestrator(strategy, {
52
138
  userId,
53
- config,
54
- callbacks,
55
- setState,
139
+ alertMessages: DEFAULT_ALERT_MESSAGES,
140
+ onCreditsExhausted: () => callbacks?.onShowPaywall?.(config.creditCost ?? 0),
141
+ onSuccess: (result) => {
142
+ const videoResult = result as ImageToVideoResult;
143
+ callbacks?.onGenerate?.(videoResult);
144
+ config.onProcessingComplete?.(videoResult);
145
+ },
146
+ onError: (err) => {
147
+ callbacks?.onError?.(err.message);
148
+ config.onError?.(err.message);
149
+ },
56
150
  });
57
151
 
58
152
  const setImageUri = useCallback(
@@ -77,23 +171,40 @@ export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseI
77
171
  console.log("[ImageToVideoFeature] generate called, hasImage:", !!effectiveImageUri);
78
172
  }
79
173
 
174
+ if (!effectiveImageUri) {
175
+ const error = "Image is required";
176
+ setState((prev) => ({ ...prev, error }));
177
+ callbacks?.onError?.(error);
178
+ return { success: false, error };
179
+ }
180
+
80
181
  if (paramImageUri) {
81
182
  setState((prev) => ({ ...prev, imageUri: paramImageUri }));
82
183
  }
83
184
 
84
- const validation = await validateImageToVideoGeneration(
85
- effectiveImageUri,
86
- callbacks,
87
- config.creditCost,
88
- );
89
-
90
- if (!validation.shouldProceed) {
91
- return validation;
185
+ setState((prev) => ({ ...prev, isProcessing: true, error: null, progress: 0 }));
186
+
187
+ try {
188
+ const imageBase64 = await config.prepareImage(effectiveImageUri);
189
+
190
+ const input: VideoGenerationInput = {
191
+ imageUri: effectiveImageUri,
192
+ imageBase64,
193
+ motionPrompt: effectiveMotionPrompt,
194
+ options,
195
+ creationId: generateCreationId(),
196
+ };
197
+
198
+ await orchestrator.generate(input);
199
+ setState((prev) => ({ ...prev, isProcessing: false }));
200
+ return { success: true, videoUrl: state.videoUrl || undefined };
201
+ } catch (error) {
202
+ const message = error instanceof Error ? error.message : "Generation failed";
203
+ setState((prev) => ({ ...prev, isProcessing: false, error: message }));
204
+ return { success: false, error: message };
92
205
  }
93
-
94
- return executeGeneration(effectiveImageUri!, effectiveMotionPrompt, options);
95
206
  },
96
- [state.imageUri, state.motionPrompt, callbacks, config.creditCost, executeGeneration],
207
+ [state.imageUri, state.motionPrompt, state.videoUrl, config, callbacks, orchestrator],
97
208
  );
98
209
 
99
210
  const reset = useCallback(() => {
@@ -83,13 +83,6 @@ export type {
83
83
  UseTextToImageFormReturn,
84
84
  } from "./presentation";
85
85
 
86
- // Provider-based Feature Hook
87
- export { useTextToImageFeature } from "./presentation";
88
- export type {
89
- UseTextToImageFeatureProps,
90
- UseTextToImageFeatureReturn,
91
- } from "./presentation";
92
-
93
86
  // =============================================================================
94
87
  // PRESENTATION LAYER - Components
95
88
  // =============================================================================
@@ -21,10 +21,3 @@ export type {
21
21
  UseTextToImageFormOptions,
22
22
  UseTextToImageFormReturn,
23
23
  } from "./useTextToImageForm";
24
-
25
- // Provider-based Feature Hook
26
- export { useTextToImageFeature } from "./useTextToImageFeature";
27
- export type {
28
- UseTextToImageFeatureProps,
29
- UseTextToImageFeatureReturn,
30
- } from "./useTextToImageFeature";
@@ -3,14 +3,9 @@
3
3
  * Uses ONLY configured app services - no alternatives
4
4
  */
5
5
 
6
- import * as FileSystem from "expo-file-system";
6
+ import { readFileAsBase64 } from "@umituz/react-native-design-system";
7
7
  import { getAuthService, getCreditService, getPaywallService, isAppServicesConfigured } from "../config/app-services.config";
8
8
 
9
- async function readFileAsBase64(uri: string): Promise<string> {
10
- const base64 = await FileSystem.readAsStringAsync(uri, { encoding: "base64" });
11
- return `data:image/jpeg;base64,${base64}`;
12
- }
13
-
14
9
  declare const __DEV__: boolean;
15
10
 
16
11
  export type ImageSelector = () => Promise<string | null>;
@@ -1,143 +0,0 @@
1
- /**
2
- * useGenerationExecution Hook
3
- * Handles the core generation execution logic for image-to-video
4
- */
5
-
6
- import { useCallback } from "react";
7
- import { executeImageToVideo } from "../../infrastructure/services";
8
- import type {
9
- ImageToVideoFeatureConfig,
10
- ImageToVideoFeatureCallbacks,
11
- ImageToVideoResult,
12
- ImageToVideoGenerateParams,
13
- ImageToVideoFeatureState,
14
- } from "../../domain/types";
15
-
16
- declare const __DEV__: boolean;
17
-
18
- interface UseGenerationExecutionParams {
19
- userId: string;
20
- config: ImageToVideoFeatureConfig;
21
- callbacks?: ImageToVideoFeatureCallbacks;
22
- setState: React.Dispatch<React.SetStateAction<ImageToVideoFeatureState>>;
23
- }
24
-
25
- export function useGenerationExecution({
26
- userId,
27
- config,
28
- callbacks,
29
- setState,
30
- }: UseGenerationExecutionParams) {
31
- return useCallback(
32
- async (
33
- imageUri: string,
34
- motionPrompt: string,
35
- options?: Omit<ImageToVideoGenerateParams, "imageUri" | "motionPrompt">,
36
- ): Promise<ImageToVideoResult> => {
37
- const creationId = `image-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
38
-
39
- setState((prev) => ({
40
- ...prev,
41
- imageUri,
42
- isProcessing: true,
43
- progress: 0,
44
- error: null,
45
- }));
46
-
47
- if (typeof __DEV__ !== "undefined" && __DEV__) {
48
- console.log("[ImageToVideoFeature] Starting generation, creationId:", creationId);
49
- }
50
-
51
- config.onProcessingStart?.();
52
-
53
- if (callbacks?.onGenerationStart) {
54
- callbacks.onGenerationStart({
55
- creationId,
56
- type: "image-to-video",
57
- imageUri,
58
- metadata: options as Record<string, unknown> | undefined,
59
- }).catch((err) => {
60
- if (typeof __DEV__ !== "undefined" && __DEV__) {
61
- console.warn("[ImageToVideoFeature] onGenerationStart failed:", err);
62
- }
63
- });
64
- }
65
-
66
- try {
67
- const imageBase64 = await config.prepareImage(imageUri);
68
-
69
- if (typeof __DEV__ !== "undefined" && __DEV__) {
70
- console.log("[ImageToVideoFeature] Image prepared, calling executeImageToVideo");
71
- }
72
-
73
- const result = await executeImageToVideo(
74
- {
75
- imageUri,
76
- imageBase64,
77
- userId,
78
- motionPrompt: motionPrompt || undefined,
79
- options,
80
- },
81
- {
82
- model: config.model,
83
- buildInput: config.buildInput,
84
- extractResult: config.extractResult,
85
- onProgress: (progress) => {
86
- setState((prev) => ({ ...prev, progress }));
87
- callbacks?.onProgress?.(progress);
88
- },
89
- },
90
- );
91
-
92
- if (result.success && result.videoUrl) {
93
- setState((prev) => ({
94
- ...prev,
95
- videoUrl: result.videoUrl ?? null,
96
- thumbnailUrl: result.thumbnailUrl ?? null,
97
- isProcessing: false,
98
- progress: 100,
99
- }));
100
-
101
- if (callbacks?.onCreditDeduct && config.creditCost) {
102
- await callbacks.onCreditDeduct(config.creditCost);
103
- }
104
-
105
- if (callbacks?.onCreationSave) {
106
- await callbacks.onCreationSave({
107
- creationId,
108
- type: "image-to-video",
109
- videoUrl: result.videoUrl,
110
- thumbnailUrl: result.thumbnailUrl,
111
- imageUri,
112
- metadata: options as Record<string, unknown> | undefined,
113
- });
114
- }
115
-
116
- callbacks?.onGenerate?.(result);
117
- } else {
118
- const error = result.error || "Generation failed";
119
- setState((prev) => ({ ...prev, isProcessing: false, error }));
120
- config.onError?.(error);
121
- callbacks?.onError?.(error);
122
- }
123
-
124
- config.onProcessingComplete?.(result);
125
- return result;
126
- } catch (err) {
127
- const errorMessage = err instanceof Error ? err.message : String(err);
128
- if (typeof __DEV__ !== "undefined" && __DEV__) {
129
- console.error("[ImageToVideoFeature] Generation error:", errorMessage);
130
- }
131
- setState((prev) => ({
132
- ...prev,
133
- isProcessing: false,
134
- error: errorMessage,
135
- }));
136
- config.onError?.(errorMessage);
137
- callbacks?.onError?.(errorMessage);
138
- return { success: false, error: errorMessage };
139
- }
140
- },
141
- [userId, config, callbacks],
142
- );
143
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * Image-to-Video Validation Utilities
3
- */
4
-
5
- import type { ImageToVideoFeatureCallbacks, ImageToVideoResult } from "../../domain/types";
6
-
7
- declare const __DEV__: boolean;
8
-
9
- export interface ValidationResult extends ImageToVideoResult {
10
- shouldProceed: boolean;
11
- }
12
-
13
- export async function validateImageToVideoGeneration(
14
- effectiveImageUri: string | null,
15
- callbacks?: ImageToVideoFeatureCallbacks,
16
- creditCost?: number,
17
- ): Promise<ValidationResult> {
18
- if (!effectiveImageUri) {
19
- const error = "Image is required";
20
- if (typeof __DEV__ !== "undefined" && __DEV__) {
21
- console.log("[ImageToVideoFeature] Generate failed: Image is required");
22
- }
23
- callbacks?.onError?.(error);
24
- return { success: false, error, shouldProceed: false };
25
- }
26
-
27
- if (callbacks?.onAuthCheck && !callbacks.onAuthCheck()) {
28
- if (typeof __DEV__ !== "undefined" && __DEV__) {
29
- console.log("[ImageToVideoFeature] Generate failed: Authentication required");
30
- }
31
- return { success: false, error: "Authentication required", shouldProceed: false };
32
- }
33
-
34
- if (callbacks?.onCreditCheck && creditCost) {
35
- const hasCredits = await callbacks.onCreditCheck(creditCost);
36
- if (!hasCredits) {
37
- callbacks?.onShowPaywall?.(creditCost);
38
- if (typeof __DEV__ !== "undefined" && __DEV__) {
39
- console.log("[ImageToVideoFeature] Generate failed: Insufficient credits");
40
- }
41
- return { success: false, error: "Insufficient credits", shouldProceed: false };
42
- }
43
- }
44
-
45
- return { success: true, shouldProceed: true };
46
- }
@@ -1,111 +0,0 @@
1
- /**
2
- * Text-to-Image Feature Hook
3
- * Provider-agnostic hook for text-to-image generation
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
- import { executeTextToImage } from "../../infrastructure/services";
8
- import type {
9
- TextToImageFeatureState,
10
- TextToImageFeatureConfig,
11
- TextToImageResult,
12
- TextToImageOptions,
13
- } from "../../domain/types";
14
-
15
- export interface UseTextToImageFeatureProps {
16
- config: TextToImageFeatureConfig;
17
- userId: string;
18
- }
19
-
20
- export interface UseTextToImageFeatureReturn {
21
- state: TextToImageFeatureState;
22
- setPrompt: (prompt: string) => void;
23
- generate: (options?: TextToImageOptions) => Promise<TextToImageResult>;
24
- reset: () => void;
25
- isReady: boolean;
26
- }
27
-
28
- const initialState: TextToImageFeatureState = {
29
- prompt: "",
30
- imageUrl: null,
31
- imageUrls: [],
32
- isProcessing: false,
33
- progress: 0,
34
- error: null,
35
- };
36
-
37
- export function useTextToImageFeature(
38
- props: UseTextToImageFeatureProps,
39
- ): UseTextToImageFeatureReturn {
40
- const { config, userId } = props;
41
- const [state, setState] = useState<TextToImageFeatureState>(initialState);
42
-
43
- const setPrompt = useCallback(
44
- (prompt: string) => {
45
- setState((prev) => ({ ...prev, prompt, error: null }));
46
- config.onPromptChange?.(prompt);
47
- },
48
- [config],
49
- );
50
-
51
- const generate = useCallback(
52
- async (options?: TextToImageOptions): Promise<TextToImageResult> => {
53
- if (!state.prompt) {
54
- const error = "Prompt is required";
55
- setState((prev) => ({ ...prev, error }));
56
- return { success: false, error };
57
- }
58
-
59
- setState((prev) => ({
60
- ...prev,
61
- isProcessing: true,
62
- progress: 0,
63
- error: null,
64
- }));
65
-
66
- config.onProcessingStart?.();
67
-
68
- const result = await executeTextToImage(
69
- { prompt: state.prompt, userId, options },
70
- {
71
- model: config.model,
72
- buildInput: config.buildInput,
73
- extractResult: config.extractResult,
74
- onProgress: (progress) => {
75
- setState((prev) => ({ ...prev, progress }));
76
- },
77
- },
78
- );
79
-
80
- if (result.success && result.imageUrl) {
81
- setState((prev) => ({
82
- ...prev,
83
- imageUrl: result.imageUrl ?? null,
84
- imageUrls: result.imageUrls ?? [],
85
- isProcessing: false,
86
- progress: 100,
87
- }));
88
- } else {
89
- const error = result.error || "Generation failed";
90
- setState((prev) => ({
91
- ...prev,
92
- isProcessing: false,
93
- error,
94
- }));
95
- config.onError?.(error);
96
- }
97
-
98
- config.onProcessingComplete?.(result);
99
- return result;
100
- },
101
- [state.prompt, userId, config],
102
- );
103
-
104
- const reset = useCallback(() => {
105
- setState(initialState);
106
- }, []);
107
-
108
- const isReady = state.prompt.length > 0 && !state.isProcessing;
109
-
110
- return { state, setPrompt, generate, reset, isReady };
111
- }