@umituz/react-native-ai-fal-provider 2.2.0 → 2.2.1

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": "2.2.0",
3
+ "version": "2.2.1",
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",
@@ -0,0 +1,19 @@
1
+ /**
2
+ * FAL Model Configuration Type
3
+ */
4
+
5
+ import type { FalModelType } from "../entities/fal.types";
6
+
7
+ export interface FalModelConfig {
8
+ readonly id: string;
9
+ readonly name: string;
10
+ readonly type: FalModelType;
11
+ readonly isDefault?: boolean;
12
+ readonly isActive?: boolean;
13
+ readonly pricing?: {
14
+ readonly freeUserCost: number;
15
+ readonly premiumUserCost: number;
16
+ };
17
+ readonly description?: string;
18
+ readonly order?: number;
19
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Model Selection Types
3
- * Types for useModels hook and model selection functionality
3
+ * Generic types for model selection - applications provide their own model lists
4
4
  */
5
5
 
6
6
  import type { FalModelConfig } from "../constants/default-models.constants";
@@ -8,54 +8,8 @@ import type { FalModelType } from "../entities/fal.types";
8
8
 
9
9
  /**
10
10
  * Public API model types (subset of FalModelType)
11
- * UI components support these core model types
12
11
  */
13
12
  export type ModelType = Extract<
14
13
  FalModelType,
15
14
  "text-to-image" | "text-to-video" | "image-to-video" | "text-to-voice"
16
15
  >;
17
-
18
- /**
19
- * Configuration for model selection behavior
20
- */
21
- export interface ModelSelectionConfig {
22
- /** Initial model ID to select */
23
- readonly initialModelId?: string;
24
- /** Default credit cost when model has no pricing */
25
- readonly defaultCreditCost?: number;
26
- /** Default model ID when no models loaded */
27
- readonly defaultModelId?: string;
28
- }
29
-
30
- /**
31
- * Model selection state
32
- */
33
- export interface ModelSelectionState {
34
- /** All available models for the type */
35
- readonly models: FalModelConfig[];
36
- /** Currently selected model */
37
- readonly selectedModel: FalModelConfig | null;
38
- /** Credit cost based on selected model */
39
- readonly creditCost: number;
40
- /** Selected model's FAL ID for API calls */
41
- readonly modelId: string;
42
- /** Loading state */
43
- readonly isLoading: boolean;
44
- /** Error message if fetch failed */
45
- readonly error: string | null;
46
- }
47
-
48
- /**
49
- * Model selection actions
50
- */
51
- export interface ModelSelectionActions {
52
- /** Select a model by ID */
53
- readonly selectModel: (modelId: string) => void;
54
- /** Refresh models from source */
55
- readonly refreshModels: () => void;
56
- }
57
-
58
- /**
59
- * Complete return type for useModels hook
60
- */
61
- export type UseModelsReturn = ModelSelectionState & ModelSelectionActions;
@@ -14,13 +14,6 @@ export type {
14
14
  FalSubscribeOptions,
15
15
  } from "../domain/entities/fal.types";
16
16
 
17
- export type {
18
- GenerationCost,
19
- CostTrackerConfig,
20
- CostSummary,
21
- ModelCostInfo,
22
- } from "../domain/entities/cost-tracking.types";
23
-
24
17
  export { FalErrorType } from "../domain/entities/error.types";
25
18
  export type {
26
19
  FalErrorCategory,
@@ -28,22 +21,7 @@ export type {
28
21
  FalErrorMessages,
29
22
  } from "../domain/entities/error.types";
30
23
 
31
- export {
32
- DEFAULT_TEXT_TO_IMAGE_MODELS,
33
- DEFAULT_TEXT_TO_VOICE_MODELS,
34
- DEFAULT_TEXT_TO_VIDEO_MODELS,
35
- DEFAULT_IMAGE_TO_VIDEO_MODELS,
36
- DEFAULT_TEXT_TO_TEXT_MODELS,
37
- DEFAULT_CREDIT_COSTS,
38
- DEFAULT_MODEL_IDS,
39
- getAllDefaultModels,
40
- getDefaultModelsByType,
41
- getDefaultModel,
42
- findModelById,
43
- } from "../domain/constants/default-models.constants";
44
- export type { FalModelConfig } from "../domain/constants/default-models.constants";
45
-
46
- export { FAL_IMAGE_FEATURE_MODELS } from "../domain/constants/feature-models.constants";
24
+ export type { FalModelConfig } from "../domain/types/fal-model-config.types";
47
25
 
48
26
  export type {
49
27
  UpscaleOptions,
@@ -55,11 +33,6 @@ export type {
55
33
  ReplaceBackgroundOptions,
56
34
  VideoFromImageOptions,
57
35
  TextToVideoOptions,
58
- ModelType,
59
- ModelSelectionConfig,
60
- ModelSelectionState,
61
- ModelSelectionActions,
62
- UseModelsReturn,
63
36
  ImageFeatureType,
64
37
  VideoFeatureType,
65
38
  AIProviderConfig,
@@ -50,8 +50,6 @@ export {
50
50
  isString,
51
51
  } from "../infrastructure/utils/validators/string-validator.util";
52
52
 
53
- export { CostTracker } from "../infrastructure/utils/cost-tracker";
54
-
55
53
  export {
56
54
  isFalModelType,
57
55
  isModelType,
@@ -1,30 +1,15 @@
1
1
  /**
2
- * FAL Models Service - Model retrieval and selection logic
2
+ * FAL Models Service - Model utilities
3
3
  */
4
4
 
5
- import type { FalModelType } from "../../domain/entities/fal.types";
6
- import type { ModelType, ModelSelectionConfig } from "../../domain/types/model-selection.types";
7
- import { DEFAULT_CREDIT_COSTS, DEFAULT_MODEL_IDS } from "../../domain/constants/default-models.constants";
8
- import {
9
- type FalModelConfig,
10
- getDefaultModelsByType,
11
- getDefaultModel as getDefaultModelFromConstants,
12
- findModelById as findModelByIdFromConstants,
13
- } from "../../domain/constants/default-models.constants";
5
+ import type { FalModelConfig } from "../../domain/types/fal-model-config.types";
14
6
 
15
7
  export type { FalModelConfig };
16
8
 
17
9
  /**
18
- * Model selection result
10
+ * Sort models by order and name
19
11
  */
20
- export interface ModelSelectionResult {
21
- models: FalModelConfig[];
22
- selectedModel: FalModelConfig | null;
23
- defaultCreditCost: number;
24
- defaultModelId: string;
25
- }
26
-
27
- function sortModels(models: FalModelConfig[]): FalModelConfig[] {
12
+ export function sortModels(models: FalModelConfig[]): FalModelConfig[] {
28
13
  return [...models].sort((a, b) => {
29
14
  if (a.order !== b.order) {
30
15
  return (a.order ?? 0) - (b.order ?? 0);
@@ -33,110 +18,23 @@ function sortModels(models: FalModelConfig[]): FalModelConfig[] {
33
18
  });
34
19
  }
35
20
 
36
- export function getModels(type: FalModelType): FalModelConfig[] {
37
- return sortModels(getDefaultModelsByType(type));
38
- }
39
-
40
- export function getDefaultModel(type: FalModelType): FalModelConfig | undefined {
41
- return getDefaultModelFromConstants(type);
42
- }
43
-
44
- export function findModelById(id: string): FalModelConfig | undefined {
45
- return findModelByIdFromConstants(id);
46
- }
47
-
48
- export function getModelPricing(modelId: string): { freeUserCost: number; premiumUserCost: number } | null {
49
- const model = findModelById(modelId);
50
- return model?.pricing ?? null;
51
- }
52
-
53
- /**
54
- * Get credit cost for a model
55
- * Returns the model's free user cost if available, otherwise returns the default cost for the type
56
- * NOTE: Use ?? instead of || to handle 0 values correctly (free models)
57
- */
58
- export function getModelCreditCost(modelId: string, modelType: FalModelType): number {
59
- const pricing = getModelPricing(modelId);
60
- // CRITICAL: Use !== undefined instead of truthy check
61
- // because freeUserCost can be 0 for free models!
62
- if (pricing && pricing.freeUserCost !== undefined) {
63
- return pricing.freeUserCost;
64
- }
65
- return DEFAULT_CREDIT_COSTS[modelType] ?? 0;
66
- }
67
-
68
21
  /**
69
- * Get default credit cost for a model type
22
+ * Find model by ID
70
23
  */
71
- export function getDefaultCreditCost(modelType: FalModelType): number {
72
- return DEFAULT_CREDIT_COSTS[modelType] ?? 0;
24
+ export function findModelById(id: string, models: FalModelConfig[]): FalModelConfig | undefined {
25
+ return models.find((m) => m.id === id);
73
26
  }
74
27
 
75
28
  /**
76
- * Get default model ID for a model type
29
+ * Get default model from a list
77
30
  */
78
- export function getDefaultModelId(modelType: FalModelType): string {
79
- return DEFAULT_MODEL_IDS[modelType] ?? "";
31
+ export function getDefaultModel(models: FalModelConfig[]): FalModelConfig | undefined {
32
+ if (models.length === 0) return undefined;
33
+ return models.find((m) => m.isDefault) ?? models[0];
80
34
  }
81
35
 
82
- /**
83
- * Select initial model based on configuration
84
- * Returns the model matching initialModelId, or the default model, or the first model
85
- */
86
- export function selectInitialModel(
87
- models: FalModelConfig[],
88
- config: ModelSelectionConfig | undefined,
89
- modelType: ModelType
90
- ): FalModelConfig | null {
91
- if (models.length === 0) {
92
- return null;
93
- }
94
-
95
- const defaultModelId = getDefaultModelId(modelType);
96
- const targetId = config?.initialModelId ?? defaultModelId;
97
-
98
- return (
99
- models.find((m) => m.id === targetId) ??
100
- models.find((m) => m.isDefault) ??
101
- models[0]
102
- );
103
- }
104
-
105
- /**
106
- * Get model selection data for a model type
107
- * Returns models, selected model, and default configuration
108
- */
109
- export function getModelSelectionData(
110
- modelType: ModelType,
111
- config?: ModelSelectionConfig
112
- ): ModelSelectionResult {
113
- // ModelType is now a subset of FalModelType, so this cast is safe
114
- const models = getModels(modelType);
115
- const defaultCreditCost = config?.defaultCreditCost ?? getDefaultCreditCost(modelType);
116
- const defaultModelId = config?.defaultModelId ?? getDefaultModelId(modelType);
117
- const selectedModel = selectInitialModel(models, config, modelType);
118
-
119
- return {
120
- models,
121
- selectedModel,
122
- defaultCreditCost,
123
- defaultModelId,
124
- };
125
- }
126
-
127
- // Singleton service export
128
36
  export const falModelsService = {
129
- getModels,
130
- getDefaultModel,
37
+ sortModels,
131
38
  findById: findModelById,
132
- getModelPricing,
133
- getModelCreditCost,
134
- getDefaultCreditCost,
135
- getDefaultModelId,
136
- selectInitialModel,
137
- getModelSelectionData,
138
- getTextToImageModels: () => getModels("text-to-image"),
139
- getTextToVoiceModels: () => getModels("text-to-voice"),
140
- getTextToVideoModels: () => getModels("text-to-video"),
141
- getImageToVideoModels: () => getModels("image-to-video"),
39
+ getDefaultModel,
142
40
  };
@@ -103,9 +103,5 @@ export {
103
103
  getJobsByStatus,
104
104
  } from "./job-storage";
105
105
 
106
- export { executeWithCostTracking } from "./cost-tracking-executor.util";
107
- export { CostTracker } from "./cost-tracker";
108
- export type { CostSummary, GenerationCost } from "./cost-tracker";
109
-
110
106
  export { FalGenerationStateManager } from "./fal-generation-state-manager.util";
111
107
  export type { GenerationState } from "./fal-generation-state-manager.util";
@@ -1,101 +1,56 @@
1
1
  /**
2
- * useModels Hook
3
- * Manages FAL AI model selection with dynamic credit costs
4
- *
5
- * @example
6
- * const { models, selectedModel, selectModel, creditCost, modelId } = useModels({
7
- * type: "text-to-video",
8
- * config: { defaultCreditCost: 20, defaultModelId: "fal-ai/minimax-video" }
9
- * });
2
+ * useModels Hook - Model selection management
10
3
  */
11
4
 
12
- import { useState, useEffect, useCallback, useMemo } from "react";
13
- import { falModelsService } from "../../infrastructure/services/fal-models.service";
14
- import type { FalModelConfig } from "../../domain/constants/default-models.constants";
15
- import type {
16
- ModelType,
17
- ModelSelectionConfig,
18
- UseModelsReturn,
19
- } from "../../domain/types/model-selection.types";
20
-
21
- export type { UseModelsReturn } from "../../domain/types/model-selection.types";
5
+ import { useState, useCallback, useMemo, useEffect } from "react";
6
+ import { falModelsService, type FalModelConfig } from "../../infrastructure/services/fal-models.service";
22
7
 
23
8
  export interface UseModelsProps {
24
- /** Model type to fetch */
25
- readonly type: ModelType;
26
- /** Optional configuration */
27
- readonly config?: ModelSelectionConfig;
9
+ readonly models: FalModelConfig[];
10
+ readonly initialModelId?: string;
28
11
  }
29
12
 
30
- export function useModels(props: UseModelsProps): UseModelsReturn {
31
- const { type, config } = props;
32
-
33
- const [models, setModels] = useState<FalModelConfig[]>([]);
34
- const [selectedModel, setSelectedModel] = useState<FalModelConfig | null>(null);
35
- const [isLoading, setIsLoading] = useState(true);
36
- const [error, setError] = useState<string | null>(null);
13
+ export interface UseModelsReturn {
14
+ readonly models: FalModelConfig[];
15
+ readonly selectedModel: FalModelConfig | null;
16
+ readonly selectModel: (modelId: string) => void;
17
+ readonly modelId: string;
18
+ }
37
19
 
38
- // Memoize config to prevent unnecessary re-renders when parent re-renders
39
- // Only recreate when actual config values change
40
- const memoizedConfig = useMemo(() => config, [
41
- config?.initialModelId,
42
- config?.defaultCreditCost,
43
- config?.defaultModelId,
44
- ]);
20
+ export function useModels(props: UseModelsProps): UseModelsReturn {
21
+ const { models, initialModelId } = props;
45
22
 
46
- // Unified load function - eliminates duplication between effect and manual reload
47
- const performLoad = useCallback(() => {
48
- setIsLoading(true);
49
- setError(null);
23
+ const sortedModels = useMemo(() => falModelsService.sortModels(models), [models]);
50
24
 
51
- try {
52
- const selectionData = falModelsService.getModelSelectionData(type, memoizedConfig);
53
- setModels(selectionData.models);
54
- setSelectedModel(selectionData.selectedModel);
55
- } catch (err) {
56
- setError(err instanceof Error ? err.message : 'Failed to load models');
57
- } finally {
58
- setIsLoading(false);
25
+ const [selectedModel, setSelectedModel] = useState<FalModelConfig | null>(() => {
26
+ if (initialModelId) {
27
+ const initial = falModelsService.findById(initialModelId, sortedModels);
28
+ if (initial) return initial;
59
29
  }
60
- }, [type, memoizedConfig]);
30
+ return falModelsService.getDefaultModel(sortedModels) ?? null;
31
+ });
61
32
 
62
- // Auto-load on mount and when dependencies change
63
33
  useEffect(() => {
64
- performLoad();
65
- }, [performLoad]);
66
-
67
- // Alias for manual reloads (same function, clearer name for external API)
68
- const loadModels = performLoad;
34
+ if (initialModelId) {
35
+ const model = falModelsService.findById(initialModelId, sortedModels);
36
+ if (model) setSelectedModel(model);
37
+ }
38
+ }, [initialModelId, sortedModels]);
69
39
 
70
40
  const selectModel = useCallback(
71
41
  (modelId: string) => {
72
- const model = models.find((m) => m.id === modelId);
73
- if (model) {
74
- setSelectedModel(model);
75
- }
42
+ const model = falModelsService.findById(modelId, sortedModels);
43
+ if (model) setSelectedModel(model);
76
44
  },
77
- [models],
45
+ [sortedModels]
78
46
  );
79
47
 
80
- const creditCost = useMemo(() => {
81
- return falModelsService.getModelCreditCost(
82
- selectedModel?.id ?? falModelsService.getDefaultModelId(type),
83
- type
84
- );
85
- }, [selectedModel, type]);
86
-
87
- const modelId = useMemo(() => {
88
- return selectedModel?.id ?? falModelsService.getDefaultModelId(type);
89
- }, [selectedModel, type]);
48
+ const modelId = useMemo(() => selectedModel?.id ?? "", [selectedModel]);
90
49
 
91
50
  return {
92
- models,
51
+ models: sortedModels,
93
52
  selectedModel,
94
53
  selectModel,
95
- creditCost,
96
54
  modelId,
97
- isLoading,
98
- error,
99
- refreshModels: loadModels,
100
55
  };
101
56
  }
@@ -1,113 +0,0 @@
1
- /**
2
- * Default FAL AI Models Catalog
3
- * Provides default model configurations for all FAL AI capabilities
4
- */
5
-
6
- import type { FalModelType } from "../entities/fal.types";
7
- import { DEFAULT_TEXT_TO_IMAGE_MODELS } from "./models/text-to-image.models";
8
- import { DEFAULT_TEXT_TO_VOICE_MODELS } from "./models/text-to-voice.models";
9
- import { DEFAULT_TEXT_TO_VIDEO_MODELS } from "./models/text-to-video.models";
10
- import { DEFAULT_IMAGE_TO_VIDEO_MODELS } from "./models/image-to-video.models";
11
- import { DEFAULT_TEXT_TO_TEXT_MODELS } from "./models/text-to-text.models";
12
-
13
- // Export model lists
14
- export { DEFAULT_TEXT_TO_IMAGE_MODELS };
15
- export { DEFAULT_TEXT_TO_VOICE_MODELS };
16
- export { DEFAULT_TEXT_TO_VIDEO_MODELS };
17
- export { DEFAULT_IMAGE_TO_VIDEO_MODELS };
18
- export { DEFAULT_TEXT_TO_TEXT_MODELS };
19
-
20
- export interface FalModelConfig {
21
- readonly id: string;
22
- readonly name: string;
23
- readonly type: FalModelType;
24
- readonly isDefault?: boolean;
25
- readonly isActive?: boolean;
26
- readonly pricing?: {
27
- readonly freeUserCost: number;
28
- readonly premiumUserCost: number;
29
- };
30
- readonly description?: string;
31
- readonly order?: number;
32
- }
33
-
34
- /**
35
- * Default credit costs for each model type
36
- * Supports all FalModelType values
37
- */
38
- export const DEFAULT_CREDIT_COSTS: Record<FalModelType, number> = {
39
- "text-to-image": 2,
40
- "text-to-video": 20,
41
- "image-to-video": 20,
42
- "text-to-voice": 3,
43
- "image-to-image": 2,
44
- "text-to-text": 1,
45
- } as const;
46
-
47
- /**
48
- * Default model IDs for each model type
49
- * Supports all FalModelType values
50
- */
51
- export const DEFAULT_MODEL_IDS: Record<FalModelType, string> = {
52
- "text-to-image": "fal-ai/flux/schnell",
53
- "text-to-video": "fal-ai/minimax-video",
54
- "image-to-video": "fal-ai/kling-video/v1.5/pro/image-to-video",
55
- "text-to-voice": "fal-ai/playai/tts/v3",
56
- "image-to-image": "fal-ai/flux/schnell",
57
- "text-to-text": "fal-ai/flux/schnell",
58
- } as const;
59
-
60
- /**
61
- * Get all default models
62
- */
63
- export function getAllDefaultModels(): FalModelConfig[] {
64
- return [
65
- ...DEFAULT_TEXT_TO_IMAGE_MODELS,
66
- ...DEFAULT_TEXT_TO_VOICE_MODELS,
67
- ...DEFAULT_TEXT_TO_VIDEO_MODELS,
68
- ...DEFAULT_IMAGE_TO_VIDEO_MODELS,
69
- ...DEFAULT_TEXT_TO_TEXT_MODELS,
70
- ];
71
- }
72
-
73
- /**
74
- * Get default models by type
75
- */
76
- export function getDefaultModelsByType(type: FalModelType): FalModelConfig[] {
77
- switch (type) {
78
- case "text-to-image":
79
- return DEFAULT_TEXT_TO_IMAGE_MODELS;
80
- case "text-to-voice":
81
- return DEFAULT_TEXT_TO_VOICE_MODELS;
82
- case "text-to-video":
83
- return DEFAULT_TEXT_TO_VIDEO_MODELS;
84
- case "image-to-video":
85
- return DEFAULT_IMAGE_TO_VIDEO_MODELS;
86
- case "text-to-text":
87
- return DEFAULT_TEXT_TO_TEXT_MODELS;
88
- case "image-to-image":
89
- return [];
90
- default: {
91
- return [];
92
- }
93
- }
94
- }
95
-
96
- /**
97
- * Get default model for a type
98
- * Returns the model marked as default, or the first model, or undefined if no models exist
99
- */
100
- export function getDefaultModel(type: FalModelType): FalModelConfig | undefined {
101
- const models = getDefaultModelsByType(type);
102
- if (models.length === 0) {
103
- return undefined;
104
- }
105
- return models.find((m) => m.isDefault) ?? models[0];
106
- }
107
-
108
- /**
109
- * Find model by ID across all types
110
- */
111
- export function findModelById(id: string): FalModelConfig | undefined {
112
- return getAllDefaultModels().find((m) => m.id === id);
113
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * FAL Feature Models Catalog
3
- * Default model IDs for image processing features
4
- * Video models are provided by the app via config
5
- */
6
-
7
- import type { ImageFeatureType } from "../types";
8
-
9
- /**
10
- * FAL model IDs for IMAGE processing features
11
- */
12
- export const FAL_IMAGE_FEATURE_MODELS: Record<ImageFeatureType, string> = {
13
- "upscale": "fal-ai/clarity-upscaler",
14
- "photo-restore": "fal-ai/aura-sr",
15
- "face-swap": "fal-ai/face-swap",
16
- "anime-selfie": "fal-ai/flux-pro/kontext",
17
- "remove-background": "fal-ai/birefnet",
18
- "remove-object": "fal-ai/fooocus/inpaint",
19
- "hd-touch-up": "fal-ai/clarity-upscaler",
20
- "replace-background": "fal-ai/bria/background/replace",
21
- } as const;
@@ -1,18 +0,0 @@
1
- /**
2
- * Image-to-Video Models
3
- */
4
-
5
- import type { FalModelConfig } from "../default-models.constants";
6
-
7
- export const DEFAULT_IMAGE_TO_VIDEO_MODELS: FalModelConfig[] = [
8
- {
9
- id: "fal-ai/kling-video/v1.5/pro/image-to-video",
10
- name: "Kling I2V",
11
- type: "image-to-video",
12
- isDefault: true,
13
- isActive: true,
14
- pricing: { freeUserCost: 15, premiumUserCost: 8 },
15
- description: "High-quality image to video generation",
16
- order: 1,
17
- },
18
- ];
@@ -1,10 +0,0 @@
1
- /**
2
- * Model Catalog Index
3
- * Exports all model lists
4
- */
5
-
6
- export { DEFAULT_TEXT_TO_IMAGE_MODELS } from "./text-to-image.models";
7
- export { DEFAULT_TEXT_TO_VOICE_MODELS } from "./text-to-voice.models";
8
- export { DEFAULT_TEXT_TO_VIDEO_MODELS } from "./text-to-video.models";
9
- export { DEFAULT_IMAGE_TO_VIDEO_MODELS } from "./image-to-video.models";
10
- export { DEFAULT_TEXT_TO_TEXT_MODELS } from "./text-to-text.models";
@@ -1,18 +0,0 @@
1
- /**
2
- * Text-to-Image Models
3
- */
4
-
5
- import type { FalModelConfig } from "../default-models.constants";
6
-
7
- export const DEFAULT_TEXT_TO_IMAGE_MODELS: FalModelConfig[] = [
8
- {
9
- id: "xai/grok-imagine-image",
10
- name: "Grok Imagine",
11
- type: "text-to-image",
12
- isDefault: true,
13
- isActive: true,
14
- pricing: { freeUserCost: 0.5, premiumUserCost: 0.25 },
15
- description: "X.AI's cost-effective text-to-image generation ($0.02/image)",
16
- order: 1,
17
- },
18
- ];
@@ -1,18 +0,0 @@
1
- /**
2
- * Text-to-Text Models
3
- */
4
-
5
- import type { FalModelConfig } from "../default-models.constants";
6
-
7
- export const DEFAULT_TEXT_TO_TEXT_MODELS: FalModelConfig[] = [
8
- {
9
- id: "fal-ai/llama-3-8b-instruct",
10
- name: "Llama 3 8B Instruct",
11
- type: "text-to-text",
12
- isDefault: true,
13
- isActive: true,
14
- pricing: { freeUserCost: 0.1, premiumUserCost: 0.05 },
15
- description: "Fast and reliable text generation",
16
- order: 1,
17
- },
18
- ];
@@ -1,48 +0,0 @@
1
- /**
2
- * Text-to-Video Models
3
- */
4
-
5
- import type { FalModelConfig } from "../default-models.constants";
6
-
7
- export const DEFAULT_TEXT_TO_VIDEO_MODELS: FalModelConfig[] = [
8
- {
9
- id: "fal-ai/hunyuan-video/1",
10
- name: "Hunyuan",
11
- type: "text-to-video",
12
- isDefault: true,
13
- isActive: true,
14
- pricing: { freeUserCost: 10, premiumUserCost: 5 },
15
- description: "High-quality video generation",
16
- order: 1,
17
- },
18
- {
19
- id: "fal-ai/minimax-video",
20
- name: "MiniMax",
21
- type: "text-to-video",
22
- isDefault: false,
23
- isActive: true,
24
- pricing: { freeUserCost: 15, premiumUserCost: 8 },
25
- description: "Advanced video generation with better dynamics",
26
- order: 2,
27
- },
28
- {
29
- id: "fal-ai/kling-video/v1.5/pro/text-to-video",
30
- name: "Kling 1.5",
31
- type: "text-to-video",
32
- isDefault: false,
33
- isActive: true,
34
- pricing: { freeUserCost: 20, premiumUserCost: 10 },
35
- description: "Professional video generation",
36
- order: 3,
37
- },
38
- {
39
- id: "fal-ai/mochi-v1",
40
- name: "Mochi",
41
- type: "text-to-video",
42
- isDefault: false,
43
- isActive: true,
44
- pricing: { freeUserCost: 8, premiumUserCost: 4 },
45
- description: "Fast video generation",
46
- order: 4,
47
- },
48
- ];
@@ -1,28 +0,0 @@
1
- /**
2
- * Text-to-Voice Models
3
- */
4
-
5
- import type { FalModelConfig } from "../default-models.constants";
6
-
7
- export const DEFAULT_TEXT_TO_VOICE_MODELS: FalModelConfig[] = [
8
- {
9
- id: "fal-ai/playai/tts/v3",
10
- name: "PlayAI TTS v3",
11
- type: "text-to-voice",
12
- isDefault: true,
13
- isActive: true,
14
- pricing: { freeUserCost: 1, premiumUserCost: 0.5 },
15
- description: "High-quality text-to-speech synthesis",
16
- order: 1,
17
- },
18
- {
19
- id: "fal-ai/eleven-labs/tts",
20
- name: "ElevenLabs TTS",
21
- type: "text-to-voice",
22
- isDefault: false,
23
- isActive: true,
24
- pricing: { freeUserCost: 2, premiumUserCost: 1 },
25
- description: "Premium voice synthesis with multiple voice options",
26
- order: 2,
27
- },
28
- ];
@@ -1,39 +0,0 @@
1
- /**
2
- * Cost Tracking Types
3
- * Real-time cost tracking for AI generation operations
4
- */
5
-
6
- export interface GenerationCost {
7
- readonly model: string;
8
- readonly operation: string;
9
- readonly estimatedCost: number;
10
- readonly actualCost: number;
11
- readonly currency: string;
12
- readonly timestamp: number;
13
- readonly requestId?: string;
14
- readonly metadata?: Record<string, unknown>;
15
- }
16
-
17
- export interface CostTrackerConfig {
18
- readonly currency?: string;
19
- readonly trackEstimatedCost?: boolean;
20
- readonly trackActualCost?: boolean;
21
- readonly onCostUpdate?: (cost: GenerationCost) => void;
22
- }
23
-
24
- export interface ModelCostInfo {
25
- readonly model: string;
26
- readonly costPerRequest: number;
27
- readonly costPerToken?: number;
28
- readonly costPerSecond?: number;
29
- readonly currency: string;
30
- }
31
-
32
- export interface CostSummary {
33
- readonly totalCost: number;
34
- readonly totalGenerations: number;
35
- readonly averageCost: number;
36
- readonly currency: string;
37
- readonly modelBreakdown: Record<string, number>;
38
- readonly operationBreakdown: Record<string, number>;
39
- }
@@ -1,179 +0,0 @@
1
- /**
2
- * Cost Tracker
3
- * Tracks and manages real-time cost information for AI generations
4
- */
5
-
6
- import type {
7
- GenerationCost,
8
- CostTrackerConfig,
9
- ModelCostInfo,
10
- } from "../../domain/entities/cost-tracking.types";
11
- import { findModelById } from "../../domain/constants/default-models.constants";
12
- import { filterByProperty, filterByTimeRange } from "./collections";
13
- import { getErrorMessage } from './helpers/error-helpers.util';
14
-
15
- export type { GenerationCost } from "../../domain/entities/cost-tracking.types";
16
-
17
- export interface CostSummary {
18
- totalEstimatedCost: number;
19
- totalActualCost: number;
20
- currency: string;
21
- operationCount: number;
22
- }
23
-
24
- function calculateCostSummary(costs: GenerationCost[], currency: string): CostSummary {
25
- return costs.reduce(
26
- (summary, cost) => ({
27
- totalEstimatedCost: summary.totalEstimatedCost + cost.estimatedCost,
28
- totalActualCost: summary.totalActualCost + cost.actualCost,
29
- currency,
30
- operationCount: summary.operationCount + 1,
31
- }),
32
- { totalEstimatedCost: 0, totalActualCost: 0, currency, operationCount: 0 }
33
- );
34
- }
35
-
36
- export class CostTracker {
37
- private config: Required<CostTrackerConfig>;
38
- private costHistory: GenerationCost[] = [];
39
- private currentOperationCosts: Map<string, number> = new Map();
40
-
41
- constructor(config?: CostTrackerConfig) {
42
- this.config = {
43
- currency: config?.currency ?? "USD",
44
- trackEstimatedCost: config?.trackEstimatedCost ?? true,
45
- trackActualCost: config?.trackActualCost ?? true,
46
- onCostUpdate: config?.onCostUpdate ?? (() => {}),
47
- };
48
- }
49
-
50
- getModelCostInfo(modelId: string): ModelCostInfo {
51
- try {
52
- const model = findModelById(modelId);
53
-
54
- if (model?.pricing) {
55
- return {
56
- model: modelId,
57
- costPerRequest: model.pricing.freeUserCost,
58
- currency: this.config.currency,
59
- };
60
- }
61
- } catch (error) {
62
- // Log error but continue with default cost info
63
- console.warn(
64
- `[cost-tracker] Failed to get model cost info for ${modelId}:`,
65
- getErrorMessage(error)
66
- );
67
- }
68
-
69
- // Return default cost info (0 cost) if model not found or error occurred
70
- return {
71
- model: modelId,
72
- costPerRequest: 0,
73
- currency: this.config.currency,
74
- };
75
- }
76
-
77
- calculateEstimatedCost(modelId: string): number {
78
- const costInfo = this.getModelCostInfo(modelId);
79
- return costInfo.costPerRequest;
80
- }
81
-
82
- startOperation(modelId: string, operation: string): string {
83
- // Generate unique operation ID
84
- let uniqueId: string;
85
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
86
- uniqueId = crypto.randomUUID();
87
- } else {
88
- // Fallback: Use timestamp with random component and counter
89
- // Format: timestamp-randomCounter-operationHash
90
- const timestamp = Date.now().toString(36);
91
- const random = Math.random().toString(36).substring(2, 11);
92
- const operationHash = operation.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0).toString(36);
93
- uniqueId = `${timestamp}-${random}-${operationHash}`;
94
- }
95
-
96
- const estimatedCost = this.calculateEstimatedCost(modelId);
97
-
98
- this.currentOperationCosts.set(uniqueId, estimatedCost);
99
-
100
- if (this.config.trackEstimatedCost) {
101
- const cost: GenerationCost = {
102
- model: modelId,
103
- operation,
104
- estimatedCost,
105
- actualCost: 0,
106
- currency: this.config.currency,
107
- timestamp: Date.now(),
108
- };
109
-
110
- this.costHistory.push(cost);
111
- this.config.onCostUpdate(cost);
112
- }
113
-
114
- return uniqueId;
115
- }
116
-
117
- completeOperation(
118
- operationId: string,
119
- modelId: string,
120
- operation: string,
121
- requestId?: string,
122
- actualCost?: number,
123
- ): GenerationCost | null {
124
- const estimatedCost = this.currentOperationCosts.get(operationId) ?? 0;
125
- const finalActualCost = actualCost ?? estimatedCost;
126
-
127
- this.currentOperationCosts.delete(operationId);
128
-
129
- const cost: GenerationCost = {
130
- model: modelId,
131
- operation,
132
- estimatedCost,
133
- actualCost: finalActualCost,
134
- currency: this.config.currency,
135
- timestamp: Date.now(),
136
- requestId,
137
- };
138
-
139
- this.costHistory.push(cost);
140
-
141
- if (this.config.trackActualCost) {
142
- this.config.onCostUpdate(cost);
143
- }
144
-
145
- return cost;
146
- }
147
-
148
- /**
149
- * Mark an operation as failed - removes from pending without adding to history
150
- */
151
- failOperation(operationId: string): void {
152
- this.currentOperationCosts.delete(operationId);
153
- }
154
-
155
- getCostSummary(): CostSummary {
156
- return calculateCostSummary(this.costHistory, this.config.currency);
157
- }
158
-
159
- getCostHistory(): readonly GenerationCost[] {
160
- return this.costHistory;
161
- }
162
-
163
- clearHistory(): void {
164
- this.costHistory = [];
165
- this.currentOperationCosts.clear();
166
- }
167
-
168
- getCostsByModel(modelId: string): GenerationCost[] {
169
- return filterByProperty(this.costHistory, "model", modelId);
170
- }
171
-
172
- getCostsByOperation(operation: string): GenerationCost[] {
173
- return filterByProperty(this.costHistory, "operation", operation);
174
- }
175
-
176
- getCostsByTimeRange(startTime: number, endTime: number): GenerationCost[] {
177
- return filterByTimeRange(this.costHistory, "timestamp", startTime, endTime);
178
- }
179
- }
@@ -1,63 +0,0 @@
1
- /**
2
- * Cost Tracking Executor
3
- * Wraps operations with cost tracking logic
4
- */
5
-
6
- import type { CostTracker } from "./cost-tracker";
7
- import { getErrorMessage } from './helpers/error-helpers.util';
8
-
9
- interface ExecuteWithCostTrackingOptions<T> {
10
- tracker: CostTracker | null;
11
- model: string;
12
- operation: string;
13
- execute: () => Promise<T>;
14
- getRequestId?: (result: T) => string | undefined;
15
- }
16
-
17
- /**
18
- * Execute an operation with cost tracking
19
- * Handles start, complete, and fail operations automatically
20
- */
21
- export async function executeWithCostTracking<T>(
22
- options: ExecuteWithCostTrackingOptions<T>
23
- ): Promise<T> {
24
- const { tracker, model, operation, execute, getRequestId } = options;
25
-
26
- if (!tracker) {
27
- return execute();
28
- }
29
-
30
- const operationId = tracker.startOperation(model, operation);
31
-
32
- try {
33
- const result = await execute();
34
-
35
- try {
36
- const requestId = getRequestId?.(result);
37
- tracker.completeOperation(operationId, model, operation, requestId);
38
- } catch (costError) {
39
- // Cost tracking failure shouldn't break the operation
40
- // Log for debugging and audit trail
41
- console.error(
42
- `[cost-tracking] Failed to complete cost tracking for ${operation} on ${model}:`,
43
- getErrorMessage(costError),
44
- { operationId, model, operation }
45
- );
46
- }
47
-
48
- return result;
49
- } catch (error) {
50
- try {
51
- tracker.failOperation(operationId);
52
- } catch (failError) {
53
- // Cost tracking cleanup failure on error path
54
- // Log for debugging and audit trail
55
- console.error(
56
- `[cost-tracking] Failed to mark operation as failed for ${operation} on ${model}:`,
57
- getErrorMessage(failError),
58
- { operationId, model, operation }
59
- );
60
- }
61
- throw error;
62
- }
63
- }