@umituz/react-native-ai-generation-content 1.20.1 → 1.20.2

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.20.1",
3
+ "version": "1.20.2",
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",
@@ -6,24 +6,47 @@
6
6
  import { useState, useCallback, useMemo } from "react";
7
7
  import { useGenerationExecution } from "./useGenerationExecution";
8
8
  import { validateImageToVideoGeneration } from "./useImageToVideoValidation";
9
- import { INITIAL_IMAGE_TO_VIDEO_STATE } from "./useImageToVideoFeature.constants";
10
- import type {
11
- UseImageToVideoFeatureProps,
12
- UseImageToVideoFeatureReturn,
13
- } from "./useImageToVideoFeature.types";
14
9
  import type {
15
10
  ImageToVideoFeatureState,
16
- ImageToVideoGenerateParams,
11
+ ImageToVideoFeatureConfig,
17
12
  ImageToVideoResult,
13
+ ImageToVideoFeatureCallbacks,
14
+ ImageToVideoGenerateParams,
18
15
  } from "../../domain/types";
19
16
 
20
17
  declare const __DEV__: boolean;
21
18
 
22
- export function useImageToVideoFeature(
23
- props: UseImageToVideoFeatureProps,
24
- ): UseImageToVideoFeatureReturn {
19
+ // Initial state (inlined from constants file)
20
+ const INITIAL_STATE: ImageToVideoFeatureState = {
21
+ imageUri: null,
22
+ motionPrompt: "",
23
+ videoUrl: null,
24
+ thumbnailUrl: null,
25
+ isProcessing: false,
26
+ progress: 0,
27
+ error: null,
28
+ };
29
+
30
+ // Types (inlined from types file)
31
+ export interface UseImageToVideoFeatureProps {
32
+ config: ImageToVideoFeatureConfig;
33
+ callbacks?: ImageToVideoFeatureCallbacks;
34
+ userId: string;
35
+ }
36
+
37
+ export interface UseImageToVideoFeatureReturn {
38
+ state: ImageToVideoFeatureState;
39
+ setImageUri: (uri: string) => void;
40
+ setMotionPrompt: (prompt: string) => void;
41
+ generate: (params?: ImageToVideoGenerateParams) => Promise<ImageToVideoResult>;
42
+ reset: () => void;
43
+ isReady: boolean;
44
+ canGenerate: boolean;
45
+ }
46
+
47
+ export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseImageToVideoFeatureReturn {
25
48
  const { config, callbacks, userId } = props;
26
- const [state, setState] = useState<ImageToVideoFeatureState>(INITIAL_IMAGE_TO_VIDEO_STATE);
49
+ const [state, setState] = useState<ImageToVideoFeatureState>(INITIAL_STATE);
27
50
 
28
51
  const executeGeneration = useGenerationExecution({
29
52
  userId,
@@ -68,30 +91,17 @@ export function useImageToVideoFeature(
68
91
  return validation;
69
92
  }
70
93
 
71
- return executeGeneration(
72
- effectiveImageUri!,
73
- effectiveMotionPrompt,
74
- options
75
- );
94
+ return executeGeneration(effectiveImageUri!, effectiveMotionPrompt, options);
76
95
  },
77
96
  [state.imageUri, state.motionPrompt, callbacks, config.creditCost, executeGeneration],
78
97
  );
79
98
 
80
99
  const reset = useCallback(() => {
81
- setState(INITIAL_IMAGE_TO_VIDEO_STATE);
100
+ setState(INITIAL_STATE);
82
101
  }, []);
83
102
 
84
- const isReady = useMemo(
85
- () => state.imageUri !== null && !state.isProcessing,
86
- [state.imageUri, state.isProcessing],
87
- );
88
-
89
- const canGenerate = useMemo(
90
- () => isReady && !state.error,
91
- [isReady, state.error],
92
- );
103
+ const isReady = useMemo(() => state.imageUri !== null && !state.isProcessing, [state.imageUri, state.isProcessing]);
104
+ const canGenerate = useMemo(() => isReady && !state.error, [isReady, state.error]);
93
105
 
94
106
  return { state, setImageUri, setMotionPrompt, generate, reset, isReady, canGenerate };
95
107
  }
96
-
97
- export type { UseImageToVideoFeatureProps, UseImageToVideoFeatureReturn } from "./useImageToVideoFeature.types";
@@ -1,9 +1,15 @@
1
1
  /**
2
2
  * useTextToVideoFeature Hook
3
- * Single Responsibility: Orchestrate text-to-video generation with callbacks
3
+ * Uses centralized orchestrator for auth, credits, moderation, and error handling
4
4
  */
5
5
 
6
6
  import { useState, useCallback, useMemo } from "react";
7
+ import {
8
+ useGenerationOrchestrator,
9
+ type GenerationStrategy,
10
+ type AlertMessages,
11
+ } from "../../../../presentation/hooks/generation";
12
+ import { executeTextToVideo } from "../../infrastructure/services";
7
13
  import type {
8
14
  TextToVideoFeatureState,
9
15
  TextToVideoConfig,
@@ -13,7 +19,6 @@ import type {
13
19
  TextToVideoInputBuilder,
14
20
  TextToVideoResultExtractor,
15
21
  } from "../../domain/types";
16
- import { executeVideoGeneration } from "./textToVideoExecution";
17
22
 
18
23
  declare const __DEV__: boolean;
19
24
 
@@ -47,12 +52,126 @@ const INITIAL_STATE: TextToVideoFeatureState = {
47
52
  error: null,
48
53
  };
49
54
 
50
- export function useTextToVideoFeature(
51
- props: UseTextToVideoFeatureProps,
52
- ): UseTextToVideoFeatureReturn {
55
+ const DEFAULT_ALERT_MESSAGES: AlertMessages = {
56
+ networkError: "No internet connection. Please check your network.",
57
+ policyViolation: "Content not allowed. Please try again.",
58
+ saveFailed: "Failed to save. Please try again.",
59
+ creditFailed: "Credit operation failed. Please try again.",
60
+ unknown: "An error occurred. Please try again.",
61
+ };
62
+
63
+ interface VideoGenerationInput {
64
+ prompt: string;
65
+ options?: TextToVideoOptions;
66
+ creationId: string;
67
+ }
68
+
69
+ function generateCreationId(): string {
70
+ return `text-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
71
+ }
72
+
73
+ export function useTextToVideoFeature(props: UseTextToVideoFeatureProps): UseTextToVideoFeatureReturn {
53
74
  const { config, callbacks, userId, buildInput, extractResult } = props;
54
75
  const [state, setState] = useState<TextToVideoFeatureState>(INITIAL_STATE);
55
76
 
77
+ // Strategy for orchestrator
78
+ const strategy: GenerationStrategy<VideoGenerationInput, TextToVideoResult> = useMemo(
79
+ () => ({
80
+ execute: async (input, onProgress) => {
81
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
82
+ console.log("[TextToVideo] Executing generation:", input.prompt.slice(0, 100));
83
+ }
84
+
85
+ // Notify generation start
86
+ callbacks.onGenerationStart?.({
87
+ creationId: input.creationId,
88
+ type: "text-to-video",
89
+ prompt: input.prompt,
90
+ metadata: input.options as Record<string, unknown> | undefined,
91
+ }).catch(() => {});
92
+
93
+ const result = await executeTextToVideo(
94
+ { prompt: input.prompt, userId, options: input.options },
95
+ {
96
+ model: config.model,
97
+ buildInput,
98
+ extractResult,
99
+ onProgress: (progress) => {
100
+ setState((prev) => ({ ...prev, progress }));
101
+ onProgress?.(progress);
102
+ callbacks.onProgress?.(progress);
103
+ },
104
+ },
105
+ );
106
+
107
+ if (!result.success || !result.videoUrl) {
108
+ throw new Error(result.error || "Generation failed");
109
+ }
110
+
111
+ // Update state with result
112
+ setState((prev) => ({
113
+ ...prev,
114
+ videoUrl: result.videoUrl ?? null,
115
+ thumbnailUrl: result.thumbnailUrl ?? null,
116
+ }));
117
+
118
+ return result;
119
+ },
120
+ getCreditCost: () => config.creditCost,
121
+ save: async (result, uid) => {
122
+ if (result.success && result.videoUrl) {
123
+ await callbacks.onCreationSave?.({
124
+ creationId: generateCreationId(),
125
+ type: "text-to-video",
126
+ videoUrl: result.videoUrl,
127
+ thumbnailUrl: result.thumbnailUrl,
128
+ prompt: state.prompt,
129
+ });
130
+ }
131
+ },
132
+ }),
133
+ [config, callbacks, buildInput, extractResult, userId, state.prompt],
134
+ );
135
+
136
+ // Use orchestrator with optional callbacks for credits
137
+ const orchestrator = useGenerationOrchestrator(strategy, {
138
+ userId,
139
+ alertMessages: DEFAULT_ALERT_MESSAGES,
140
+ auth: callbacks.onAuthCheck
141
+ ? { isAuthenticated: callbacks.onAuthCheck, onAuthRequired: () => {} }
142
+ : undefined,
143
+ credits: callbacks.onCreditCheck
144
+ ? {
145
+ checkCredits: async (cost) => (await callbacks.onCreditCheck?.(cost)) ?? true,
146
+ deductCredits: async (cost) => { await callbacks.onCreditDeduct?.(cost); },
147
+ onCreditsExhausted: () => callbacks.onShowPaywall?.(config.creditCost),
148
+ }
149
+ : undefined,
150
+ moderation: callbacks.onModeration
151
+ ? {
152
+ checkContent: async (input) => {
153
+ const result = await callbacks.onModeration!((input as VideoGenerationInput).prompt);
154
+ return result;
155
+ },
156
+ onShowWarning: callbacks.onShowModerationWarning,
157
+ }
158
+ : undefined,
159
+ onSuccess: (result) => {
160
+ const videoResult = result as TextToVideoResult;
161
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
162
+ console.log("[TextToVideo] Success!", videoResult.videoUrl?.slice(0, 50));
163
+ }
164
+ callbacks.onGenerate?.(videoResult);
165
+ },
166
+ onError: (err) => {
167
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
168
+ console.log("[TextToVideo] Error:", err.message);
169
+ }
170
+ setState((prev) => ({ ...prev, error: err.message }));
171
+ callbacks.onError?.(err.message);
172
+ },
173
+ });
174
+
56
175
  const setPrompt = useCallback(
57
176
  (prompt: string) => {
58
177
  setState((prev) => ({ ...prev, prompt, error: null }));
@@ -70,9 +189,6 @@ export function useTextToVideoFeature(
70
189
  const error = "Prompt is required";
71
190
  setState((prev) => ({ ...prev, error }));
72
191
  callbacks.onError?.(error);
73
- if (__DEV__) {
74
- console.log("[TextToVideoFeature] Generate failed: Prompt is required");
75
- }
76
192
  return { success: false, error };
77
193
  }
78
194
 
@@ -80,74 +196,30 @@ export function useTextToVideoFeature(
80
196
  setState((prev) => ({ ...prev, prompt: effectivePrompt }));
81
197
  }
82
198
 
83
- if (callbacks.onAuthCheck && !callbacks.onAuthCheck()) {
84
- if (__DEV__) {
85
- console.log("[TextToVideoFeature] Generate failed: Authentication required");
86
- }
87
- return { success: false, error: "Authentication required" };
88
- }
199
+ setState((prev) => ({ ...prev, isProcessing: true, progress: 0, error: null }));
89
200
 
90
- if (
91
- callbacks.onCreditCheck &&
92
- !(await callbacks.onCreditCheck(config.creditCost))
93
- ) {
94
- callbacks.onShowPaywall?.(config.creditCost);
95
- if (__DEV__) {
96
- console.log("[TextToVideoFeature] Generate failed: Insufficient credits");
97
- }
98
- return { success: false, error: "Insufficient credits" };
99
- }
201
+ const creationId = generateCreationId();
202
+ await orchestrator.generate({ prompt: effectivePrompt, options, creationId });
100
203
 
101
- if (callbacks.onModeration) {
102
- const moderationResult = await callbacks.onModeration(effectivePrompt);
103
- if (!moderationResult.allowed && moderationResult.warnings.length > 0) {
104
- return new Promise((resolve) => {
105
- callbacks.onShowModerationWarning?.(
106
- moderationResult.warnings,
107
- () => {
108
- setState((prev) => ({ ...prev, isProcessing: false }));
109
- resolve({ success: false, error: "Content policy violation" });
110
- },
111
- async () => {
112
- const result = await executeVideoGeneration(
113
- effectivePrompt,
114
- options,
115
- { userId, config, callbacks, buildInput, extractResult },
116
- {
117
- onStateUpdate: (update) =>
118
- setState((prev) => ({ ...prev, ...update })),
119
- },
120
- );
121
- resolve(result);
122
- },
123
- );
124
- });
125
- }
204
+ setState((prev) => ({ ...prev, isProcessing: false }));
205
+
206
+ // Return result based on state
207
+ if (orchestrator.error) {
208
+ return { success: false, error: orchestrator.error.message };
126
209
  }
127
210
 
128
- return executeVideoGeneration(
129
- effectivePrompt,
130
- options,
131
- { userId, config, callbacks, buildInput, extractResult },
132
- { onStateUpdate: (update) => setState((prev) => ({ ...prev, ...update })) },
133
- );
211
+ return orchestrator.result || { success: false, error: "No result" };
134
212
  },
135
- [state.prompt, callbacks, config, userId, buildInput, extractResult],
213
+ [state.prompt, callbacks, orchestrator],
136
214
  );
137
215
 
138
216
  const reset = useCallback(() => {
139
217
  setState(INITIAL_STATE);
140
- }, []);
141
-
142
- const isReady = useMemo(
143
- () => state.prompt.trim().length > 0 && !state.isProcessing,
144
- [state.prompt, state.isProcessing],
145
- );
218
+ orchestrator.reset();
219
+ }, [orchestrator]);
146
220
 
147
- const canGenerate = useMemo(
148
- () => isReady && !state.error,
149
- [isReady, state.error],
150
- );
221
+ const isReady = useMemo(() => state.prompt.trim().length > 0 && !state.isProcessing, [state.prompt, state.isProcessing]);
222
+ const canGenerate = useMemo(() => isReady && !state.error, [isReady, state.error]);
151
223
 
152
224
  return { state, setPrompt, generate, reset, isReady, canGenerate };
153
225
  }
@@ -1,15 +0,0 @@
1
- /**
2
- * useImageToVideoFeature Constants
3
- */
4
-
5
- import type { ImageToVideoFeatureState } from "../../domain/types";
6
-
7
- export const INITIAL_IMAGE_TO_VIDEO_STATE: ImageToVideoFeatureState = {
8
- imageUri: null,
9
- motionPrompt: "",
10
- videoUrl: null,
11
- thumbnailUrl: null,
12
- isProcessing: false,
13
- progress: 0,
14
- error: null,
15
- };
@@ -1,27 +0,0 @@
1
- /**
2
- * useImageToVideoFeature Type Definitions
3
- */
4
-
5
- import type {
6
- ImageToVideoFeatureState,
7
- ImageToVideoFeatureConfig,
8
- ImageToVideoResult,
9
- ImageToVideoFeatureCallbacks,
10
- ImageToVideoGenerateParams,
11
- } from "../../domain/types";
12
-
13
- export interface UseImageToVideoFeatureProps {
14
- config: ImageToVideoFeatureConfig;
15
- callbacks?: ImageToVideoFeatureCallbacks;
16
- userId: string;
17
- }
18
-
19
- export interface UseImageToVideoFeatureReturn {
20
- state: ImageToVideoFeatureState;
21
- setImageUri: (uri: string) => void;
22
- setMotionPrompt: (prompt: string) => void;
23
- generate: (params?: ImageToVideoGenerateParams) => Promise<ImageToVideoResult>;
24
- reset: () => void;
25
- isReady: boolean;
26
- canGenerate: boolean;
27
- }
@@ -1,134 +0,0 @@
1
- /**
2
- * Text-to-Video Execution
3
- * Core execution logic for text-to-video generation
4
- */
5
-
6
- import { executeTextToVideo } from "../../infrastructure/services";
7
- import type {
8
- TextToVideoConfig,
9
- TextToVideoCallbacks,
10
- TextToVideoResult,
11
- TextToVideoOptions,
12
- TextToVideoInputBuilder,
13
- TextToVideoResultExtractor,
14
- } from "../../domain/types";
15
-
16
- declare const __DEV__: boolean;
17
-
18
- export interface ExecutionContext {
19
- userId: string;
20
- config: TextToVideoConfig;
21
- callbacks: TextToVideoCallbacks;
22
- buildInput: TextToVideoInputBuilder;
23
- extractResult?: TextToVideoResultExtractor;
24
- }
25
-
26
- export interface ExecutionCallbacks {
27
- onStateUpdate: (update: {
28
- isProcessing?: boolean;
29
- progress?: number;
30
- videoUrl?: string | null;
31
- thumbnailUrl?: string | null;
32
- error?: string | null;
33
- }) => void;
34
- }
35
-
36
- function generateCreationId(): string {
37
- return `text-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
38
- }
39
-
40
- export async function executeVideoGeneration(
41
- prompt: string,
42
- options: TextToVideoOptions | undefined,
43
- context: ExecutionContext,
44
- executionCallbacks: ExecutionCallbacks,
45
- ): Promise<TextToVideoResult> {
46
- const { userId, config, callbacks, buildInput, extractResult } = context;
47
- const { onStateUpdate } = executionCallbacks;
48
- const creationId = generateCreationId();
49
-
50
- onStateUpdate({ isProcessing: true, progress: 0, error: null });
51
-
52
- if (__DEV__) {
53
- console.log(
54
- "[TextToVideoFeature] Starting generation with prompt:",
55
- prompt,
56
- "creationId:",
57
- creationId,
58
- );
59
- }
60
-
61
- if (callbacks.onGenerationStart) {
62
- callbacks
63
- .onGenerationStart({
64
- creationId,
65
- type: "text-to-video",
66
- prompt,
67
- metadata: options as Record<string, unknown> | undefined,
68
- })
69
- .catch((err) => {
70
- if (__DEV__) {
71
- console.warn("[TextToVideoFeature] onGenerationStart failed:", err);
72
- }
73
- });
74
- }
75
-
76
- if (__DEV__) {
77
- console.log("[TextToVideoFeature] Starting executeTextToVideo...");
78
- }
79
-
80
- try {
81
- const result = await executeTextToVideo(
82
- { prompt, userId, options },
83
- {
84
- model: config.model,
85
- buildInput,
86
- extractResult,
87
- onProgress: (progress) => {
88
- onStateUpdate({ progress });
89
- callbacks.onProgress?.(progress);
90
- },
91
- },
92
- );
93
-
94
- if (result.success && result.videoUrl) {
95
- onStateUpdate({
96
- videoUrl: result.videoUrl,
97
- thumbnailUrl: result.thumbnailUrl ?? null,
98
- isProcessing: false,
99
- progress: 100,
100
- });
101
-
102
- if (callbacks.onCreditDeduct) {
103
- await callbacks.onCreditDeduct(config.creditCost);
104
- }
105
-
106
- if (callbacks.onCreationSave) {
107
- await callbacks.onCreationSave({
108
- creationId,
109
- type: "text-to-video",
110
- videoUrl: result.videoUrl,
111
- thumbnailUrl: result.thumbnailUrl,
112
- prompt,
113
- metadata: options as Record<string, unknown> | undefined,
114
- });
115
- }
116
-
117
- callbacks.onGenerate?.(result);
118
- } else {
119
- const error = result.error || "Generation failed";
120
- onStateUpdate({ isProcessing: false, error });
121
- callbacks.onError?.(error);
122
- }
123
-
124
- return result;
125
- } catch (err) {
126
- const errorMessage = err instanceof Error ? err.message : String(err);
127
- if (__DEV__) {
128
- console.error("[TextToVideoFeature] Generation error:", errorMessage);
129
- }
130
- onStateUpdate({ isProcessing: false, error: errorMessage });
131
- callbacks.onError?.(errorMessage);
132
- return { success: false, error: errorMessage };
133
- }
134
- }