@umituz/react-native-ai-fal-provider 1.0.13 → 1.0.15

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-fal-provider",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "FAL AI provider for React Native - implements IAIProvider interface for unified AI generation",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -93,7 +93,9 @@ class FalClientService {
93
93
  const result = await Promise.race([
94
94
  fal.subscribe(modelEndpoint, {
95
95
  input,
96
- onQueueUpdate: (update) => {
96
+ logs: true,
97
+ pollInterval: 1000,
98
+ onQueueUpdate: (update: { status: string; logs?: unknown[] }) => {
97
99
  if (typeof __DEV__ !== "undefined" && __DEV__) {
98
100
  // eslint-disable-next-line no-console
99
101
  console.log("[FAL] Queue update:", { status: update.status });
@@ -0,0 +1,87 @@
1
+ /**
2
+ * FAL Feature Builder Service
3
+ * Handles building input data for different AI features
4
+ */
5
+
6
+ import type {
7
+ ImageFeatureType,
8
+ VideoFeatureType,
9
+ ImageFeatureInputData,
10
+ VideoFeatureInputData,
11
+ } from "@umituz/react-native-ai-generation-content";
12
+ import {
13
+ FAL_IMAGE_FEATURE_MODELS,
14
+ FAL_VIDEO_FEATURE_MODELS,
15
+ } from "../../domain/constants/feature-models.constants";
16
+ import {
17
+ buildUpscaleInput,
18
+ buildPhotoRestoreInput,
19
+ buildVideoFromImageInput,
20
+ buildFaceSwapInput,
21
+ buildAnimeSelfieInput,
22
+ buildRemoveBackgroundInput,
23
+ buildRemoveObjectInput,
24
+ buildReplaceBackgroundInput,
25
+ buildHDTouchUpInput,
26
+ } from "../utils/input-builders.util";
27
+
28
+ export function getImageFeatureModel(feature: ImageFeatureType): string {
29
+ return FAL_IMAGE_FEATURE_MODELS[feature];
30
+ }
31
+
32
+ export function getVideoFeatureModel(feature: VideoFeatureType): string {
33
+ return FAL_VIDEO_FEATURE_MODELS[feature];
34
+ }
35
+
36
+ export function buildImageFeatureInput(
37
+ feature: ImageFeatureType,
38
+ data: ImageFeatureInputData,
39
+ ): Record<string, unknown> {
40
+ const { imageBase64, targetImageBase64, prompt, options } = data;
41
+
42
+ switch (feature) {
43
+ case "upscale":
44
+ return buildUpscaleInput(imageBase64, options);
45
+ case "photo-restore":
46
+ return buildPhotoRestoreInput(imageBase64, options);
47
+ case "face-swap":
48
+ if (!targetImageBase64) {
49
+ throw new Error("Face swap requires target image");
50
+ }
51
+ return buildFaceSwapInput(imageBase64, targetImageBase64, options);
52
+ case "anime-selfie":
53
+ return buildAnimeSelfieInput(imageBase64, options);
54
+ case "remove-background":
55
+ return buildRemoveBackgroundInput(imageBase64, options);
56
+ case "remove-object":
57
+ return buildRemoveObjectInput(imageBase64, { prompt, ...options });
58
+ case "hd-touch-up":
59
+ return buildHDTouchUpInput(imageBase64, options);
60
+ case "replace-background":
61
+ if (!prompt) {
62
+ throw new Error("Replace background requires prompt");
63
+ }
64
+ return buildReplaceBackgroundInput(imageBase64, { prompt });
65
+ default:
66
+ throw new Error(`Unknown image feature: ${String(feature)}`);
67
+ }
68
+ }
69
+
70
+ export function buildVideoFeatureInput(
71
+ feature: VideoFeatureType,
72
+ data: VideoFeatureInputData,
73
+ ): Record<string, unknown> {
74
+ const { sourceImageBase64, targetImageBase64, prompt, options } = data;
75
+
76
+ switch (feature) {
77
+ case "ai-hug":
78
+ case "ai-kiss":
79
+ return buildVideoFromImageInput(sourceImageBase64, {
80
+ target_image: targetImageBase64,
81
+ motion_prompt: prompt,
82
+ ...options,
83
+ });
84
+ default:
85
+ throw new Error(`Unknown video feature: ${String(feature)}`);
86
+ }
87
+ }
@@ -18,25 +18,13 @@ import type {
18
18
  VideoFeatureInputData,
19
19
  ProviderCapabilities,
20
20
  } from "@umituz/react-native-ai-generation-content";
21
- import type {
22
- FalQueueStatus,
23
- FalLogEntry,
24
- } from "../../domain/entities/fal.types";
25
- import {
26
- FAL_IMAGE_FEATURE_MODELS,
27
- FAL_VIDEO_FEATURE_MODELS,
28
- } from "../../domain/constants/feature-models.constants";
21
+ import type { FalQueueStatus, FalLogEntry } from "../../domain/entities/fal.types";
29
22
  import {
30
- buildUpscaleInput,
31
- buildPhotoRestoreInput,
32
- buildVideoFromImageInput,
33
- buildFaceSwapInput,
34
- buildAnimeSelfieInput,
35
- buildRemoveBackgroundInput,
36
- buildRemoveObjectInput,
37
- buildReplaceBackgroundInput,
38
- buildHDTouchUpInput,
39
- } from "../utils/input-builders.util";
23
+ getImageFeatureModel,
24
+ getVideoFeatureModel,
25
+ buildImageFeatureInput,
26
+ buildVideoFeatureInput,
27
+ } from "./fal-feature-builder.service";
40
28
 
41
29
  declare const __DEV__: boolean;
42
30
 
@@ -45,11 +33,9 @@ const DEFAULT_CONFIG = {
45
33
  baseDelay: 1000,
46
34
  maxDelay: 10000,
47
35
  defaultTimeoutMs: 300000,
36
+ pollInterval: 1000,
48
37
  };
49
38
 
50
- /**
51
- * FAL provider capabilities
52
- */
53
39
  const FAL_CAPABILITIES: ProviderCapabilities = {
54
40
  imageFeatures: [
55
41
  "upscale",
@@ -112,7 +98,6 @@ export class FalProvider implements IAIProvider {
112
98
  this.initialized = true;
113
99
 
114
100
  if (typeof __DEV__ !== "undefined" && __DEV__) {
115
- // eslint-disable-next-line no-console
116
101
  console.log("[FalProvider] Initialized");
117
102
  }
118
103
  }
@@ -139,14 +124,9 @@ export class FalProvider implements IAIProvider {
139
124
  }
140
125
  }
141
126
 
142
- async submitJob(
143
- model: string,
144
- input: Record<string, unknown>,
145
- ): Promise<JobSubmission> {
127
+ async submitJob(model: string, input: Record<string, unknown>): Promise<JobSubmission> {
146
128
  this.validateInitialization();
147
-
148
129
  const result = await fal.queue.submit(model, { input });
149
-
150
130
  return {
151
131
  requestId: result.request_id,
152
132
  statusUrl: result.status_url,
@@ -156,20 +136,13 @@ export class FalProvider implements IAIProvider {
156
136
 
157
137
  async getJobStatus(model: string, requestId: string): Promise<JobStatus> {
158
138
  this.validateInitialization();
159
-
160
139
  const status = await fal.queue.status(model, { requestId, logs: true });
161
-
162
140
  return mapFalStatusToJobStatus(status as unknown as FalQueueStatus);
163
141
  }
164
142
 
165
- async getJobResult<T = unknown>(
166
- model: string,
167
- requestId: string,
168
- ): Promise<T> {
143
+ async getJobResult<T = unknown>(model: string, requestId: string): Promise<T> {
169
144
  this.validateInitialization();
170
-
171
145
  const result = await fal.queue.result(model, { requestId });
172
-
173
146
  return result.data as T;
174
147
  }
175
148
 
@@ -180,14 +153,10 @@ export class FalProvider implements IAIProvider {
180
153
  ): Promise<T> {
181
154
  this.validateInitialization();
182
155
 
183
- const timeoutMs =
184
- options?.timeoutMs ??
185
- this.config?.defaultTimeoutMs ??
186
- DEFAULT_CONFIG.defaultTimeoutMs;
156
+ const timeoutMs = options?.timeoutMs ?? this.config?.defaultTimeoutMs ?? DEFAULT_CONFIG.defaultTimeoutMs;
187
157
  let timeoutId: ReturnType<typeof setTimeout> | null = null;
188
158
 
189
159
  if (typeof __DEV__ !== "undefined" && __DEV__) {
190
- // eslint-disable-next-line no-console
191
160
  console.log("[FalProvider] Subscribe started:", { model, timeoutMs });
192
161
  }
193
162
 
@@ -195,59 +164,47 @@ export class FalProvider implements IAIProvider {
195
164
  const result = await Promise.race([
196
165
  fal.subscribe(model, {
197
166
  input,
198
- onQueueUpdate: (update) => {
199
- const jobStatus = mapFalStatusToJobStatus(
200
- update as unknown as FalQueueStatus,
201
- );
167
+ logs: true,
168
+ pollInterval: DEFAULT_CONFIG.pollInterval,
169
+ onQueueUpdate: (update: { status: string; logs?: unknown[] }) => {
170
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
171
+ console.log("[FalProvider] Queue update:", JSON.stringify(update));
172
+ }
173
+ const jobStatus = mapFalStatusToJobStatus(update as unknown as FalQueueStatus);
202
174
  options?.onQueueUpdate?.(jobStatus);
203
175
  },
204
176
  }),
205
177
  new Promise<never>((_, reject) => {
206
- timeoutId = setTimeout(
207
- () => reject(new Error("FAL subscription timeout")),
208
- timeoutMs,
209
- );
178
+ timeoutId = setTimeout(() => reject(new Error("FAL subscription timeout")), timeoutMs);
210
179
  }),
211
180
  ]);
212
181
 
213
182
  if (typeof __DEV__ !== "undefined" && __DEV__) {
214
- // eslint-disable-next-line no-console
215
183
  console.log("[FalProvider] Subscribe completed:", { model });
216
184
  }
217
185
 
218
186
  options?.onResult?.(result as T);
219
-
220
187
  return result as T;
221
188
  } finally {
222
- if (timeoutId) {
223
- clearTimeout(timeoutId);
224
- }
189
+ if (timeoutId) clearTimeout(timeoutId);
225
190
  }
226
191
  }
227
192
 
228
- async run<T = unknown>(
229
- model: string,
230
- input: Record<string, unknown>,
231
- options?: RunOptions,
232
- ): Promise<T> {
193
+ async run<T = unknown>(model: string, input: Record<string, unknown>, options?: RunOptions): Promise<T> {
233
194
  this.validateInitialization();
234
-
235
195
  options?.onProgress?.({ progress: 10, status: "IN_PROGRESS" });
236
196
 
237
197
  if (typeof __DEV__ !== "undefined" && __DEV__) {
238
- // eslint-disable-next-line no-console
239
198
  console.log("[FalProvider] run() model:", model, "inputKeys:", Object.keys(input));
240
199
  }
241
200
 
242
201
  const result = await fal.run(model, { input });
243
202
 
244
203
  if (typeof __DEV__ !== "undefined" && __DEV__) {
245
- // eslint-disable-next-line no-console
246
204
  console.log("[FalProvider] run() completed, hasResult:", !!result);
247
205
  }
248
206
 
249
207
  options?.onProgress?.({ progress: 100, status: "COMPLETED" });
250
-
251
208
  return result as T;
252
209
  }
253
210
 
@@ -257,77 +214,20 @@ export class FalProvider implements IAIProvider {
257
214
  this.initialized = false;
258
215
  }
259
216
 
260
- /**
261
- * Get model ID for an IMAGE feature
262
- */
263
217
  getImageFeatureModel(feature: ImageFeatureType): string {
264
- return FAL_IMAGE_FEATURE_MODELS[feature];
218
+ return getImageFeatureModel(feature);
265
219
  }
266
220
 
267
- /**
268
- * Build input for an IMAGE feature
269
- */
270
- buildImageFeatureInput(
271
- feature: ImageFeatureType,
272
- data: ImageFeatureInputData,
273
- ): Record<string, unknown> {
274
- const { imageBase64, targetImageBase64, prompt, options } = data;
275
-
276
- switch (feature) {
277
- case "upscale":
278
- return buildUpscaleInput(imageBase64, options);
279
- case "photo-restore":
280
- return buildPhotoRestoreInput(imageBase64, options);
281
- case "face-swap":
282
- if (!targetImageBase64) {
283
- throw new Error("Face swap requires target image");
284
- }
285
- return buildFaceSwapInput(imageBase64, targetImageBase64, options);
286
- case "anime-selfie":
287
- return buildAnimeSelfieInput(imageBase64, options);
288
- case "remove-background":
289
- return buildRemoveBackgroundInput(imageBase64, options);
290
- case "remove-object":
291
- return buildRemoveObjectInput(imageBase64, { prompt, ...options });
292
- case "hd-touch-up":
293
- return buildHDTouchUpInput(imageBase64, options);
294
- case "replace-background":
295
- if (!prompt) {
296
- throw new Error("Replace background requires prompt");
297
- }
298
- return buildReplaceBackgroundInput(imageBase64, { prompt });
299
- default:
300
- throw new Error(`Unknown image feature: ${String(feature)}`);
301
- }
221
+ buildImageFeatureInput(feature: ImageFeatureType, data: ImageFeatureInputData): Record<string, unknown> {
222
+ return buildImageFeatureInput(feature, data);
302
223
  }
303
224
 
304
- /**
305
- * Get model ID for a VIDEO feature
306
- */
307
225
  getVideoFeatureModel(feature: VideoFeatureType): string {
308
- return FAL_VIDEO_FEATURE_MODELS[feature];
226
+ return getVideoFeatureModel(feature);
309
227
  }
310
228
 
311
- /**
312
- * Build input for a VIDEO feature
313
- */
314
- buildVideoFeatureInput(
315
- feature: VideoFeatureType,
316
- data: VideoFeatureInputData,
317
- ): Record<string, unknown> {
318
- const { sourceImageBase64, targetImageBase64, prompt, options } = data;
319
-
320
- switch (feature) {
321
- case "ai-hug":
322
- case "ai-kiss":
323
- return buildVideoFromImageInput(sourceImageBase64, {
324
- target_image: targetImageBase64,
325
- motion_prompt: prompt,
326
- ...options,
327
- });
328
- default:
329
- throw new Error(`Unknown video feature: ${String(feature)}`);
330
- }
229
+ buildVideoFeatureInput(feature: VideoFeatureType, data: VideoFeatureInputData): Record<string, unknown> {
230
+ return buildVideoFeatureInput(feature, data);
331
231
  }
332
232
  }
333
233
 
@@ -6,3 +6,9 @@
6
6
  export { falClientService } from "./fal-client.service";
7
7
  export { FalProvider, falProvider } from "./fal-provider";
8
8
  export { falModelsService, type FalModelConfig, type ModelFetcher } from "./fal-models.service";
9
+ export {
10
+ getImageFeatureModel,
11
+ getVideoFeatureModel,
12
+ buildImageFeatureInput,
13
+ buildVideoFeatureInput,
14
+ } from "./fal-feature-builder.service";