@umituz/react-native-ai-generation-content 1.17.221 → 1.17.222

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.17.221",
3
+ "version": "1.17.222",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -10,6 +10,7 @@ import type {
10
10
  ImageToVideoFeatureCallbacks,
11
11
  ImageToVideoResult,
12
12
  ImageToVideoGenerateParams,
13
+ ImageToVideoFeatureState,
13
14
  } from "../../domain/types";
14
15
 
15
16
  declare const __DEV__: boolean;
@@ -18,7 +19,7 @@ interface UseGenerationExecutionParams {
18
19
  userId: string;
19
20
  config: ImageToVideoFeatureConfig;
20
21
  callbacks?: ImageToVideoFeatureCallbacks;
21
- setState: React.Dispatch<React.SetStateAction<any>>;
22
+ setState: React.Dispatch<React.SetStateAction<ImageToVideoFeatureState>>;
22
23
  }
23
24
 
24
25
  export function useGenerationExecution({
@@ -35,7 +36,7 @@ export function useGenerationExecution({
35
36
  ): Promise<ImageToVideoResult> => {
36
37
  const creationId = `image-to-video_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
37
38
 
38
- setState((prev: any) => ({
39
+ setState((prev) => ({
39
40
  ...prev,
40
41
  imageUri,
41
42
  isProcessing: true,
@@ -82,14 +83,14 @@ export function useGenerationExecution({
82
83
  buildInput: config.buildInput,
83
84
  extractResult: config.extractResult,
84
85
  onProgress: (progress) => {
85
- setState((prev: any) => ({ ...prev, progress }));
86
+ setState((prev) => ({ ...prev, progress }));
86
87
  callbacks?.onProgress?.(progress);
87
88
  },
88
89
  },
89
90
  );
90
91
 
91
92
  if (result.success && result.videoUrl) {
92
- setState((prev: any) => ({
93
+ setState((prev) => ({
93
94
  ...prev,
94
95
  videoUrl: result.videoUrl ?? null,
95
96
  thumbnailUrl: result.thumbnailUrl ?? null,
@@ -115,7 +116,7 @@ export function useGenerationExecution({
115
116
  callbacks?.onGenerate?.(result);
116
117
  } else {
117
118
  const error = result.error || "Generation failed";
118
- setState((prev: any) => ({ ...prev, isProcessing: false, error }));
119
+ setState((prev) => ({ ...prev, isProcessing: false, error }));
119
120
  config.onError?.(error);
120
121
  callbacks?.onError?.(error);
121
122
  }
@@ -127,7 +128,7 @@ export function useGenerationExecution({
127
128
  if (typeof __DEV__ !== "undefined" && __DEV__) {
128
129
  console.error("[ImageToVideoFeature] Generation error:", errorMessage);
129
130
  }
130
- setState((prev: any) => ({
131
+ setState((prev) => ({
131
132
  ...prev,
132
133
  isProcessing: false,
133
134
  error: errorMessage,
@@ -68,7 +68,11 @@ export function useImageToVideoFeature(
68
68
  return validation;
69
69
  }
70
70
 
71
- return executeGeneration(effectiveImageUri, effectiveMotionPrompt, options);
71
+ return executeGeneration(
72
+ effectiveImageUri!,
73
+ effectiveMotionPrompt,
74
+ options
75
+ );
72
76
  },
73
77
  [state.imageUri, state.motionPrompt, callbacks, config.creditCost, executeGeneration],
74
78
  );
@@ -2,7 +2,7 @@
2
2
  * Image-to-Video Validation Utilities
3
3
  */
4
4
 
5
- import type { ImageToVideoFeatureCallbacks, ImageToVideoGenerateParams, ImageToVideoResult } from "../../domain/types";
5
+ import type { ImageToVideoFeatureCallbacks, ImageToVideoResult } from "../../domain/types";
6
6
 
7
7
  declare const __DEV__: boolean;
8
8
 
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Job Poller Factory
3
+ * Creates pre-configured job poller instances
4
+ */
5
+
6
+ import type { PollingConfig } from "../../domain/entities";
7
+ import type { PollJobOptions } from "./job-poller.types";
8
+ import { pollJob } from "./job-poller.service";
9
+
10
+ export function createJobPoller(defaultConfig?: Partial<PollingConfig>) {
11
+ return {
12
+ poll<T = unknown>(options: Omit<PollJobOptions, "config">) {
13
+ return pollJob<T>({ ...options, config: defaultConfig });
14
+ },
15
+ };
16
+ }
@@ -3,33 +3,21 @@
3
3
  * Provider-agnostic job polling with exponential backoff
4
4
  */
5
5
 
6
- import type { IAIProvider, JobStatus } from "../../domain/interfaces";
7
- import type { PollingConfig } from "../../domain/entities";
6
+ import type { IAIProvider } from "../../domain/interfaces"; // eslint-disable-line @typescript-eslint/no-unused-vars
7
+ import type { PollingConfig } from "../../domain/entities"; // eslint-disable-line @typescript-eslint/no-unused-vars
8
8
  import { DEFAULT_POLLING_CONFIG } from "../../domain/entities";
9
9
  import { calculatePollingInterval } from "../utils/polling-interval.util";
10
10
  import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
11
11
  import { validateResult } from "../utils/result-validator.util";
12
12
  import { isTransientError } from "../utils/error-classifier.util";
13
+ import { calculateProgressFromJobStatus } from "../utils/progress-calculator.util";
14
+ import type { PollJobOptions, PollJobResult } from "./job-poller.types";
15
+ import { createJobPoller } from "./job-poller-factory"; // eslint-disable-line @typescript-eslint/no-unused-vars
13
16
 
14
- declare const __DEV__: boolean;
15
-
16
- export interface PollJobOptions {
17
- provider: IAIProvider;
18
- model: string;
19
- requestId: string;
20
- config?: Partial<PollingConfig>;
21
- onProgress?: (progress: number) => void;
22
- onStatusChange?: (status: JobStatus) => void;
23
- signal?: AbortSignal;
24
- }
17
+ // IAIProvider and PollingConfig are used indirectly through provider methods
18
+ // createJobPoller is re-exported
25
19
 
26
- export interface PollJobResult<T = unknown> {
27
- success: boolean;
28
- data?: T;
29
- error?: Error;
30
- attempts: number;
31
- elapsedMs: number;
32
- }
20
+ declare const __DEV__: boolean;
33
21
 
34
22
  const MAX_CONSECUTIVE_TRANSIENT_ERRORS = 5;
35
23
 
@@ -57,7 +45,6 @@ export async function pollJob<T = unknown>(
57
45
  let lastProgress = 0;
58
46
 
59
47
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
60
- // Check for abort
61
48
  if (signal?.aborted) {
62
49
  return {
63
50
  success: false,
@@ -67,18 +54,15 @@ export async function pollJob<T = unknown>(
67
54
  };
68
55
  }
69
56
 
70
- // Wait for polling interval (skip first attempt)
71
57
  if (attempt > 0) {
72
58
  const interval = calculatePollingInterval({ attempt, config: pollingConfig });
73
59
  await new Promise<void>((resolve) => setTimeout(() => resolve(), interval));
74
60
  }
75
61
 
76
62
  try {
77
- // Get job status
78
63
  const status = await provider.getJobStatus(model, requestId);
79
64
  onStatusChange?.(status);
80
65
 
81
- // Check for errors in status
82
66
  const statusCheck = checkStatusForErrors(status);
83
67
 
84
68
  if (statusCheck.shouldStop && statusCheck.hasError) {
@@ -90,24 +74,19 @@ export async function pollJob<T = unknown>(
90
74
  };
91
75
  }
92
76
 
93
- // Reset transient error counter on success
94
77
  consecutiveTransientErrors = 0;
95
78
 
96
- // Update progress
97
- const progress = calculateProgressFromStatus(status, attempt, maxAttempts);
79
+ const progress = calculateProgressFromJobStatus(status, attempt, maxAttempts);
98
80
  if (progress > lastProgress) {
99
81
  lastProgress = progress;
100
82
  onProgress?.(progress);
101
83
  }
102
84
 
103
- // Check if complete
104
85
  if (isJobComplete(status)) {
105
86
  onProgress?.(90);
106
87
 
107
- // Fetch result
108
88
  const result = await provider.getJobResult<T>(model, requestId);
109
89
 
110
- // Validate result
111
90
  const validation = validateResult(result);
112
91
  if (!validation.isValid) {
113
92
  return {
@@ -131,7 +110,6 @@ export async function pollJob<T = unknown>(
131
110
  if (isTransientError(error)) {
132
111
  consecutiveTransientErrors++;
133
112
 
134
- // Too many consecutive transient errors
135
113
  if (consecutiveTransientErrors >= MAX_CONSECUTIVE_TRANSIENT_ERRORS) {
136
114
  return {
137
115
  success: false,
@@ -141,10 +119,8 @@ export async function pollJob<T = unknown>(
141
119
  };
142
120
  }
143
121
 
144
- // Continue retrying
145
122
  if (attempt < maxAttempts - 1) {
146
123
  if (typeof __DEV__ !== "undefined" && __DEV__) {
147
-
148
124
  console.log(
149
125
  `[JobPoller] Transient error, retrying (${attempt + 1}/${maxAttempts})`,
150
126
  );
@@ -153,7 +129,6 @@ export async function pollJob<T = unknown>(
153
129
  }
154
130
  }
155
131
 
156
- // Permanent error or max retries reached
157
132
  return {
158
133
  success: false,
159
134
  error: error instanceof Error ? error : new Error(String(error)),
@@ -163,7 +138,6 @@ export async function pollJob<T = unknown>(
163
138
  }
164
139
  }
165
140
 
166
- // Max attempts reached
167
141
  return {
168
142
  success: false,
169
143
  error: new Error(`Polling timeout after ${maxAttempts} attempts`),
@@ -172,37 +146,5 @@ export async function pollJob<T = unknown>(
172
146
  };
173
147
  }
174
148
 
175
- /**
176
- * Calculate progress percentage from job status
177
- */
178
- function calculateProgressFromStatus(
179
- status: JobStatus,
180
- attempt: number,
181
- maxAttempts: number,
182
- ): number {
183
- const statusString = String(status.status).toUpperCase();
184
-
185
- switch (statusString) {
186
- case "IN_QUEUE":
187
- return 30 + Math.min(attempt * 2, 10);
188
- case "IN_PROGRESS":
189
- return 50 + Math.min(attempt * 3, 30);
190
- case "COMPLETED":
191
- return 90;
192
- case "FAILED":
193
- return 0;
194
- default:
195
- return 20 + Math.min((attempt / maxAttempts) * 30, 30);
196
- }
197
- }
198
-
199
- /**
200
- * Create a job poller with preset configuration
201
- */
202
- export function createJobPoller(defaultConfig?: Partial<PollingConfig>) {
203
- return {
204
- poll<T = unknown>(options: Omit<PollJobOptions, "config">) {
205
- return pollJob<T>({ ...options, config: defaultConfig });
206
- },
207
- };
208
- }
149
+ export { createJobPoller } from "./job-poller-factory";
150
+ export type { PollJobOptions, PollJobResult } from "./job-poller.types";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Job Poller Type Definitions
3
+ */
4
+
5
+ import type { IAIProvider, JobStatus } from "../../domain/interfaces";
6
+ import type { PollingConfig } from "../../domain/entities";
7
+
8
+ export interface PollJobOptions {
9
+ provider: IAIProvider;
10
+ model: string;
11
+ requestId: string;
12
+ config?: Partial<PollingConfig>;
13
+ onProgress?: (progress: number) => void;
14
+ onStatusChange?: (status: JobStatus) => void;
15
+ signal?: AbortSignal;
16
+ }
17
+
18
+ export interface PollJobResult<T = unknown> {
19
+ success: boolean;
20
+ data?: T;
21
+ error?: Error;
22
+ attempts: number;
23
+ elapsedMs: number;
24
+ }
@@ -6,94 +6,16 @@
6
6
 
7
7
  import { providerRegistry } from "./provider-registry.service";
8
8
  import { cleanBase64 } from "../utils";
9
+ import { defaultExtractVideoResult } from "../utils/video-result-extractor.util";
9
10
  import type { VideoFeatureType, VideoFeatureInputData } from "../../domain/interfaces";
11
+ import type {
12
+ ExecuteVideoFeatureOptions,
13
+ VideoFeatureResult,
14
+ VideoFeatureRequest,
15
+ } from "./video-feature-executor.types";
10
16
 
11
17
  declare const __DEV__: boolean;
12
18
 
13
- /**
14
- * Result extractor function type
15
- */
16
- export type VideoResultExtractor = (result: unknown) => string | undefined;
17
-
18
- /**
19
- * Execution options
20
- */
21
- export interface ExecuteVideoFeatureOptions {
22
- extractResult?: VideoResultExtractor;
23
- onProgress?: (progress: number) => void;
24
- }
25
-
26
- /**
27
- * Execution result
28
- */
29
- export interface VideoFeatureResult {
30
- success: boolean;
31
- videoUrl?: string;
32
- error?: string;
33
- requestId?: string;
34
- }
35
-
36
- /**
37
- * Request data for video features
38
- */
39
- export interface VideoFeatureRequest {
40
- sourceImageBase64: string;
41
- targetImageBase64: string;
42
- prompt?: string;
43
- options?: Record<string, unknown>;
44
- }
45
-
46
- /**
47
- * Default result extractor - handles common response formats
48
- * Supports FAL data wrapper and nested object formats
49
- */
50
- function defaultExtractVideoResult(result: unknown): string | undefined {
51
- if (typeof result !== "object" || result === null) return undefined;
52
-
53
- const r = result as Record<string, unknown>;
54
-
55
- if (typeof __DEV__ !== "undefined" && __DEV__) {
56
- console.log("[VideoExtractor] Result keys:", Object.keys(r));
57
- }
58
-
59
- // Handle fal.ai data wrapper
60
- const data = (r.data as Record<string, unknown>) ?? r;
61
-
62
- if (typeof __DEV__ !== "undefined" && __DEV__) {
63
- console.log("[VideoExtractor] Data keys:", Object.keys(data));
64
- }
65
-
66
- // Direct string values
67
- if (typeof data.video === "string") return data.video;
68
- if (typeof data.videoUrl === "string") return data.videoUrl;
69
- if (typeof data.video_url === "string") return data.video_url;
70
- if (typeof data.output === "string") return data.output;
71
- if (typeof data.url === "string") return data.url;
72
-
73
- // Object with url property (e.g., { video: { url: "..." } })
74
- const videoObj = data.video as Record<string, unknown> | undefined;
75
- if (videoObj && typeof videoObj === "object" && typeof videoObj.url === "string") {
76
- if (typeof __DEV__ !== "undefined" && __DEV__) {
77
- console.log("[VideoExtractor] Found data.video.url:", videoObj.url);
78
- }
79
- return videoObj.url;
80
- }
81
-
82
- // Array format (e.g., { videos: [{ url: "..." }] })
83
- if (Array.isArray(data.videos) && typeof data.videos[0]?.url === "string") {
84
- if (typeof __DEV__ !== "undefined" && __DEV__) {
85
- console.log("[VideoExtractor] Found videos[0].url:", data.videos[0].url);
86
- }
87
- return data.videos[0].url;
88
- }
89
-
90
- if (typeof __DEV__ !== "undefined" && __DEV__) {
91
- console.log("[VideoExtractor] No video URL found in result");
92
- }
93
-
94
- return undefined;
95
- }
96
-
97
19
  /**
98
20
  * Execute any video feature using the active provider
99
21
  * Uses subscribe for video features to handle long-running generation with progress updates
@@ -173,24 +95,33 @@ export async function executeVideoFeature(
173
95
  requestId: (result as { requestId?: string })?.requestId,
174
96
  };
175
97
  } catch (error) {
176
- // Extract detailed error message from FAL API errors
177
- let message = "Processing failed";
178
- if (error instanceof Error) {
179
- message = error.message;
180
- } else if (typeof error === "object" && error !== null) {
181
- const errObj = error as Record<string, unknown>;
182
- if (errObj.detail) {
183
- message = JSON.stringify(errObj.detail);
184
- } else if (errObj.message) {
185
- message = String(errObj.message);
186
- }
187
- }
98
+ const message = extractErrorMessage(error, featureType);
99
+ return { success: false, error: message };
100
+ }
101
+ }
188
102
 
189
- if (__DEV__) {
190
- console.error(`[Video:${featureType}] Error:`, message, error);
103
+ /**
104
+ * Extract error message from various error formats
105
+ */
106
+ function extractErrorMessage(error: unknown, featureType: VideoFeatureType): string {
107
+ let message = "Processing failed";
108
+
109
+ if (error instanceof Error) {
110
+ message = error.message;
111
+ } else if (typeof error === "object" && error !== null) {
112
+ const errObj = error as Record<string, unknown>;
113
+ if (errObj.detail) {
114
+ message = JSON.stringify(errObj.detail);
115
+ } else if (errObj.message) {
116
+ message = String(errObj.message);
191
117
  }
192
- return { success: false, error: message };
193
118
  }
119
+
120
+ if (__DEV__) {
121
+ console.error(`[Video:${featureType}] Error:`, message, error);
122
+ }
123
+
124
+ return message;
194
125
  }
195
126
 
196
127
  /**
@@ -200,3 +131,9 @@ export function hasVideoFeatureSupport(): boolean {
200
131
  const provider = providerRegistry.getActiveProvider();
201
132
  return provider !== null && provider.isInitialized();
202
133
  }
134
+
135
+ export type {
136
+ ExecuteVideoFeatureOptions,
137
+ VideoFeatureResult,
138
+ VideoFeatureRequest,
139
+ } from "./video-feature-executor.types";
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Video Feature Executor Type Definitions
3
+ */
4
+
5
+ /**
6
+ * Result extractor function type
7
+ */
8
+ export type VideoResultExtractor = (result: unknown) => string | undefined;
9
+
10
+ /**
11
+ * Execution options
12
+ */
13
+ export interface ExecuteVideoFeatureOptions {
14
+ extractResult?: VideoResultExtractor;
15
+ onProgress?: (progress: number) => void;
16
+ }
17
+
18
+ /**
19
+ * Execution result
20
+ */
21
+ export interface VideoFeatureResult {
22
+ success: boolean;
23
+ videoUrl?: string;
24
+ error?: string;
25
+ requestId?: string;
26
+ }
27
+
28
+ /**
29
+ * Request data for video features
30
+ */
31
+ export interface VideoFeatureRequest {
32
+ sourceImageBase64: string;
33
+ targetImageBase64: string;
34
+ prompt?: string;
35
+ options?: Record<string, unknown>;
36
+ }
@@ -10,6 +10,7 @@ import {
10
10
  type ProgressStageConfig,
11
11
  } from "../../domain/entities";
12
12
  import type { AIJobStatusType } from "../../domain/interfaces/ai-provider.interface";
13
+ import type { JobStatus } from "../../domain/interfaces";
13
14
 
14
15
  export interface ProgressOptions {
15
16
  status: GenerationStatus;
@@ -126,3 +127,28 @@ export function getProgressFromJobStatus(
126
127
  const generationStatus = mapJobStatusToGenerationStatus(jobStatus);
127
128
  return getProgressForStatus({ status: generationStatus, stages });
128
129
  }
130
+
131
+ /**
132
+ * Calculate progress percentage from job status and attempt number
133
+ * Used by job poller for granular progress reporting during polling
134
+ */
135
+ export function calculateProgressFromJobStatus(
136
+ status: JobStatus,
137
+ attempt: number,
138
+ maxAttempts: number,
139
+ ): number {
140
+ const statusString = String(status.status).toUpperCase();
141
+
142
+ switch (statusString) {
143
+ case "IN_QUEUE":
144
+ return 30 + Math.min(attempt * 2, 10);
145
+ case "IN_PROGRESS":
146
+ return 50 + Math.min(attempt * 3, 30);
147
+ case "COMPLETED":
148
+ return 90;
149
+ case "FAILED":
150
+ return 0;
151
+ default:
152
+ return 20 + Math.min((attempt / maxAttempts) * 30, 30);
153
+ }
154
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Video Result Extractor Utility
3
+ * Extracts video URL from various provider response formats
4
+ */
5
+
6
+ import type { VideoResultExtractor } from "../services/video-feature-executor.types";
7
+
8
+ declare const __DEV__: boolean;
9
+
10
+ /**
11
+ * Default result extractor - handles common response formats
12
+ * Supports FAL data wrapper and nested object formats
13
+ */
14
+ export const defaultExtractVideoResult: VideoResultExtractor = (result) => {
15
+ if (typeof result !== "object" || result === null) return undefined;
16
+
17
+ const r = result as Record<string, unknown>;
18
+
19
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
20
+ console.log("[VideoExtractor] Result keys:", Object.keys(r));
21
+ }
22
+
23
+ // Handle fal.ai data wrapper
24
+ const data = (r.data as Record<string, unknown>) ?? r;
25
+
26
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
27
+ console.log("[VideoExtractor] Data keys:", Object.keys(data));
28
+ }
29
+
30
+ // Direct string values
31
+ if (typeof data.video === "string") return data.video;
32
+ if (typeof data.videoUrl === "string") return data.videoUrl;
33
+ if (typeof data.video_url === "string") return data.video_url;
34
+ if (typeof data.output === "string") return data.output;
35
+ if (typeof data.url === "string") return data.url;
36
+
37
+ // Object with url property (e.g., { video: { url: "..." } })
38
+ const videoObj = data.video as Record<string, unknown> | undefined;
39
+ if (videoObj && typeof videoObj === "object" && typeof videoObj.url === "string") {
40
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
41
+ console.log("[VideoExtractor] Found data.video.url:", videoObj.url);
42
+ }
43
+ return videoObj.url;
44
+ }
45
+
46
+ // Array format (e.g., { videos: [{ url: "..." }] })
47
+ if (Array.isArray(data.videos) && typeof data.videos[0]?.url === "string") {
48
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
49
+ console.log("[VideoExtractor] Found videos[0].url:", data.videos[0].url);
50
+ }
51
+ return data.videos[0].url;
52
+ }
53
+
54
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
55
+ console.log("[VideoExtractor] No video URL found in result");
56
+ }
57
+
58
+ return undefined;
59
+ };