@umituz/react-native-ai-fal-provider 1.0.83 → 1.0.85
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.
|
|
3
|
+
"version": "1.0.85",
|
|
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,39 @@
|
|
|
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
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,72 +4,163 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export type {
|
|
7
|
-
FalConfig,
|
|
8
|
-
|
|
7
|
+
FalConfig,
|
|
8
|
+
FalModel,
|
|
9
|
+
FalModelType,
|
|
10
|
+
FalModelPricing,
|
|
11
|
+
FalJobInput,
|
|
12
|
+
FalJobResult,
|
|
13
|
+
FalLogEntry,
|
|
14
|
+
FalQueueStatus,
|
|
15
|
+
FalSubscribeOptions,
|
|
9
16
|
} from "./domain/entities/fal.types";
|
|
10
17
|
|
|
18
|
+
export type {
|
|
19
|
+
GenerationCost,
|
|
20
|
+
CostTrackerConfig,
|
|
21
|
+
CostSummary,
|
|
22
|
+
ModelCostInfo,
|
|
23
|
+
} from "./domain/entities/cost-tracking.types";
|
|
24
|
+
|
|
11
25
|
export { FalErrorType } from "./domain/entities/error.types";
|
|
12
|
-
export type {
|
|
26
|
+
export type {
|
|
27
|
+
FalErrorCategory,
|
|
28
|
+
FalErrorInfo,
|
|
29
|
+
FalErrorMessages,
|
|
30
|
+
} from "./domain/entities/error.types";
|
|
13
31
|
|
|
14
32
|
export {
|
|
15
|
-
DEFAULT_TEXT_TO_IMAGE_MODELS,
|
|
16
|
-
|
|
17
|
-
|
|
33
|
+
DEFAULT_TEXT_TO_IMAGE_MODELS,
|
|
34
|
+
DEFAULT_TEXT_TO_VOICE_MODELS,
|
|
35
|
+
DEFAULT_TEXT_TO_VIDEO_MODELS,
|
|
36
|
+
DEFAULT_IMAGE_TO_VIDEO_MODELS,
|
|
37
|
+
getAllDefaultModels,
|
|
38
|
+
getDefaultModelsByType,
|
|
39
|
+
getDefaultModel,
|
|
40
|
+
findModelById,
|
|
18
41
|
} from "./domain/constants/default-models.constants";
|
|
19
42
|
export type { FalModelConfig } from "./domain/constants/default-models.constants";
|
|
20
43
|
|
|
21
44
|
export {
|
|
22
|
-
FAL_IMAGE_FEATURE_MODELS,
|
|
45
|
+
FAL_IMAGE_FEATURE_MODELS,
|
|
46
|
+
FAL_VIDEO_FEATURE_MODELS,
|
|
47
|
+
getAllFeatureModels,
|
|
23
48
|
} from "./domain/constants/feature-models.constants";
|
|
24
49
|
export type { FeatureModelConfig } from "./domain/constants/feature-models.constants";
|
|
25
50
|
|
|
26
51
|
export {
|
|
27
|
-
FalProvider,
|
|
28
|
-
|
|
29
|
-
|
|
52
|
+
FalProvider,
|
|
53
|
+
falProvider,
|
|
54
|
+
falModelsService,
|
|
55
|
+
getImageFeatureModel,
|
|
56
|
+
getVideoFeatureModel,
|
|
57
|
+
NSFWContentError,
|
|
58
|
+
cancelCurrentFalRequest,
|
|
59
|
+
hasRunningFalRequest,
|
|
30
60
|
} from "./infrastructure/services";
|
|
31
61
|
export type { FalProviderType } from "./infrastructure/services";
|
|
32
62
|
|
|
33
63
|
export {
|
|
34
|
-
categorizeFalError,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
64
|
+
categorizeFalError,
|
|
65
|
+
falErrorMapper,
|
|
66
|
+
mapFalError,
|
|
67
|
+
isFalErrorRetryable,
|
|
68
|
+
buildSingleImageInput,
|
|
69
|
+
buildDualImageInput,
|
|
70
|
+
buildUpscaleInput,
|
|
71
|
+
buildPhotoRestoreInput,
|
|
72
|
+
buildVideoFromImageInput,
|
|
73
|
+
buildFaceSwapInput,
|
|
74
|
+
buildImageToImageInput,
|
|
75
|
+
buildRemoveBackgroundInput,
|
|
76
|
+
buildRemoveObjectInput,
|
|
77
|
+
buildReplaceBackgroundInput,
|
|
78
|
+
buildHDTouchUpInput,
|
|
39
79
|
} from "./infrastructure/utils";
|
|
40
80
|
|
|
81
|
+
export { CostTracker } from "./infrastructure/utils/cost-tracker";
|
|
82
|
+
|
|
41
83
|
export {
|
|
42
|
-
isFalModelType,
|
|
43
|
-
|
|
44
|
-
|
|
84
|
+
isFalModelType,
|
|
85
|
+
isModelType,
|
|
86
|
+
isFalErrorType,
|
|
87
|
+
isValidBase64Image,
|
|
88
|
+
isValidApiKey,
|
|
89
|
+
isValidModelId,
|
|
90
|
+
isValidPrompt,
|
|
91
|
+
isValidTimeout,
|
|
92
|
+
isValidRetryCount,
|
|
45
93
|
} from "./infrastructure/utils";
|
|
46
94
|
|
|
47
95
|
export {
|
|
48
|
-
formatImageDataUri,
|
|
49
|
-
|
|
50
|
-
|
|
96
|
+
formatImageDataUri,
|
|
97
|
+
extractBase64,
|
|
98
|
+
getDataUriExtension,
|
|
99
|
+
isImageDataUri,
|
|
100
|
+
calculateTimeoutWithJitter,
|
|
101
|
+
formatCreditCost,
|
|
102
|
+
truncatePrompt,
|
|
103
|
+
sanitizePrompt,
|
|
104
|
+
buildErrorMessage,
|
|
105
|
+
isDefined,
|
|
106
|
+
removeNullish,
|
|
107
|
+
debounce,
|
|
108
|
+
throttle,
|
|
51
109
|
} from "./infrastructure/utils";
|
|
52
110
|
|
|
53
111
|
export {
|
|
54
|
-
createJobMetadata,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
112
|
+
createJobMetadata,
|
|
113
|
+
updateJobMetadata,
|
|
114
|
+
isJobCompleted,
|
|
115
|
+
isJobRunning,
|
|
116
|
+
isJobStale,
|
|
117
|
+
getJobDuration,
|
|
118
|
+
formatJobDuration,
|
|
119
|
+
calculateJobProgress,
|
|
120
|
+
serializeJobMetadata,
|
|
121
|
+
deserializeJobMetadata,
|
|
122
|
+
filterValidJobs,
|
|
123
|
+
sortJobsByCreation,
|
|
124
|
+
getActiveJobs,
|
|
125
|
+
getCompletedJobs,
|
|
58
126
|
} from "./infrastructure/utils";
|
|
59
127
|
|
|
60
128
|
export {
|
|
61
|
-
saveJobMetadata,
|
|
62
|
-
|
|
129
|
+
saveJobMetadata,
|
|
130
|
+
loadJobMetadata,
|
|
131
|
+
deleteJobMetadata,
|
|
132
|
+
loadAllJobs,
|
|
133
|
+
cleanupOldJobs,
|
|
134
|
+
getJobsByModel,
|
|
135
|
+
getJobsByStatus,
|
|
136
|
+
updateJobStatus,
|
|
63
137
|
} from "./infrastructure/utils";
|
|
64
138
|
|
|
65
|
-
export type {
|
|
139
|
+
export type {
|
|
140
|
+
FalJobMetadata,
|
|
141
|
+
IJobStorage,
|
|
142
|
+
InMemoryJobStorage,
|
|
143
|
+
} from "./infrastructure/utils";
|
|
66
144
|
|
|
67
145
|
export type {
|
|
68
|
-
UpscaleOptions,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
146
|
+
UpscaleOptions,
|
|
147
|
+
PhotoRestoreOptions,
|
|
148
|
+
FaceSwapOptions,
|
|
149
|
+
ImageToImagePromptConfig,
|
|
150
|
+
RemoveBackgroundOptions,
|
|
151
|
+
RemoveObjectOptions,
|
|
152
|
+
ReplaceBackgroundOptions,
|
|
153
|
+
VideoFromImageOptions,
|
|
154
|
+
ModelType,
|
|
155
|
+
ModelSelectionConfig,
|
|
156
|
+
ModelSelectionState,
|
|
157
|
+
ModelSelectionActions,
|
|
158
|
+
UseModelsReturn,
|
|
72
159
|
} from "./domain/types";
|
|
73
160
|
|
|
74
161
|
export { useFalGeneration, useModels } from "./presentation/hooks";
|
|
75
|
-
export type {
|
|
162
|
+
export type {
|
|
163
|
+
UseFalGenerationOptions,
|
|
164
|
+
UseFalGenerationResult,
|
|
165
|
+
UseModelsProps,
|
|
166
|
+
} from "./presentation/hooks";
|
|
@@ -18,11 +18,22 @@ import type {
|
|
|
18
18
|
ProviderCapabilities,
|
|
19
19
|
} from "@umituz/react-native-ai-generation-content";
|
|
20
20
|
import type { FalQueueStatus } from "../../domain/entities/fal.types";
|
|
21
|
+
import type { CostTrackerConfig } from "../../domain/entities/cost-tracking.types";
|
|
21
22
|
import { DEFAULT_FAL_CONFIG, FAL_CAPABILITIES } from "./fal-provider.constants";
|
|
22
23
|
import { mapFalStatusToJobStatus } from "./fal-status-mapper";
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
import {
|
|
25
|
+
FAL_IMAGE_FEATURE_MODELS,
|
|
26
|
+
FAL_VIDEO_FEATURE_MODELS,
|
|
27
|
+
} from "../../domain/constants/feature-models.constants";
|
|
28
|
+
import {
|
|
29
|
+
buildImageFeatureInput as buildImageFeatureInputImpl,
|
|
30
|
+
buildVideoFeatureInput as buildVideoFeatureInputImpl,
|
|
31
|
+
} from "../builders";
|
|
32
|
+
import {
|
|
33
|
+
handleFalSubscription,
|
|
34
|
+
handleFalRun,
|
|
35
|
+
} from "./fal-provider-subscription";
|
|
36
|
+
import { CostTracker } from "../utils/cost-tracker";
|
|
26
37
|
|
|
27
38
|
declare const __DEV__: boolean | undefined;
|
|
28
39
|
|
|
@@ -33,6 +44,7 @@ export class FalProvider implements IAIProvider {
|
|
|
33
44
|
private apiKey: string | null = null;
|
|
34
45
|
private initialized = false;
|
|
35
46
|
private currentAbortController: AbortController | null = null;
|
|
47
|
+
private costTracker: CostTracker | null = null;
|
|
36
48
|
|
|
37
49
|
initialize(configData: AIProviderConfig): void {
|
|
38
50
|
this.apiKey = configData.apiKey;
|
|
@@ -53,6 +65,40 @@ export class FalProvider implements IAIProvider {
|
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Enable cost tracking
|
|
70
|
+
*/
|
|
71
|
+
enableCostTracking(config?: CostTrackerConfig): void {
|
|
72
|
+
this.costTracker = new CostTracker(config);
|
|
73
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
74
|
+
console.log("[FalProvider] Cost tracking enabled");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Disable cost tracking
|
|
80
|
+
*/
|
|
81
|
+
disableCostTracking(): void {
|
|
82
|
+
this.costTracker = null;
|
|
83
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
84
|
+
console.log("[FalProvider] Cost tracking disabled");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if cost tracking is enabled
|
|
90
|
+
*/
|
|
91
|
+
isCostTrackingEnabled(): boolean {
|
|
92
|
+
return this.costTracker !== null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get cost tracker instance
|
|
97
|
+
*/
|
|
98
|
+
getCostTracker(): CostTracker | null {
|
|
99
|
+
return this.costTracker;
|
|
100
|
+
}
|
|
101
|
+
|
|
56
102
|
isInitialized(): boolean {
|
|
57
103
|
return this.initialized;
|
|
58
104
|
}
|
|
@@ -75,7 +121,10 @@ export class FalProvider implements IAIProvider {
|
|
|
75
121
|
}
|
|
76
122
|
}
|
|
77
123
|
|
|
78
|
-
async submitJob(
|
|
124
|
+
async submitJob(
|
|
125
|
+
model: string,
|
|
126
|
+
input: Record<string, unknown>,
|
|
127
|
+
): Promise<JobSubmission> {
|
|
79
128
|
this.validateInitialization();
|
|
80
129
|
const result = await fal.queue.submit(model, { input });
|
|
81
130
|
return {
|
|
@@ -91,7 +140,10 @@ export class FalProvider implements IAIProvider {
|
|
|
91
140
|
return mapFalStatusToJobStatus(status as unknown as FalQueueStatus);
|
|
92
141
|
}
|
|
93
142
|
|
|
94
|
-
async getJobResult<T = unknown>(
|
|
143
|
+
async getJobResult<T = unknown>(
|
|
144
|
+
model: string,
|
|
145
|
+
requestId: string,
|
|
146
|
+
): Promise<T> {
|
|
95
147
|
this.validateInitialization();
|
|
96
148
|
const result = await fal.queue.result(model, { requestId });
|
|
97
149
|
return result.data as T;
|
|
@@ -106,13 +158,43 @@ export class FalProvider implements IAIProvider {
|
|
|
106
158
|
this.cancelCurrentRequest();
|
|
107
159
|
this.currentAbortController = new AbortController();
|
|
108
160
|
|
|
109
|
-
const
|
|
161
|
+
const operationId = this.costTracker?.startOperation(model, "subscribe");
|
|
162
|
+
|
|
163
|
+
const { result, requestId } = await handleFalSubscription<T>(
|
|
164
|
+
model,
|
|
165
|
+
input,
|
|
166
|
+
options,
|
|
167
|
+
this.currentAbortController.signal,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (operationId && this.costTracker) {
|
|
171
|
+
this.costTracker.completeOperation(
|
|
172
|
+
operationId,
|
|
173
|
+
model,
|
|
174
|
+
"subscribe",
|
|
175
|
+
requestId ?? undefined,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
110
179
|
return result;
|
|
111
180
|
}
|
|
112
181
|
|
|
113
|
-
async run<T = unknown>(
|
|
182
|
+
async run<T = unknown>(
|
|
183
|
+
model: string,
|
|
184
|
+
input: Record<string, unknown>,
|
|
185
|
+
options?: RunOptions,
|
|
186
|
+
): Promise<T> {
|
|
114
187
|
this.validateInitialization();
|
|
115
|
-
|
|
188
|
+
|
|
189
|
+
const operationId = this.costTracker?.startOperation(model, "run");
|
|
190
|
+
|
|
191
|
+
const result = await handleFalRun<T>(model, input, options);
|
|
192
|
+
|
|
193
|
+
if (operationId && this.costTracker) {
|
|
194
|
+
this.costTracker.completeOperation(operationId, model, "run");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result;
|
|
116
198
|
}
|
|
117
199
|
|
|
118
200
|
reset(): void {
|
|
@@ -139,7 +221,10 @@ export class FalProvider implements IAIProvider {
|
|
|
139
221
|
return FAL_IMAGE_FEATURE_MODELS[feature];
|
|
140
222
|
}
|
|
141
223
|
|
|
142
|
-
buildImageFeatureInput(
|
|
224
|
+
buildImageFeatureInput(
|
|
225
|
+
feature: ImageFeatureType,
|
|
226
|
+
data: ImageFeatureInputData,
|
|
227
|
+
): Record<string, unknown> {
|
|
143
228
|
return buildImageFeatureInputImpl(feature, data);
|
|
144
229
|
}
|
|
145
230
|
|
|
@@ -147,7 +232,10 @@ export class FalProvider implements IAIProvider {
|
|
|
147
232
|
return FAL_VIDEO_FEATURE_MODELS[feature];
|
|
148
233
|
}
|
|
149
234
|
|
|
150
|
-
buildVideoFeatureInput(
|
|
235
|
+
buildVideoFeatureInput(
|
|
236
|
+
feature: VideoFeatureType,
|
|
237
|
+
data: VideoFeatureInputData,
|
|
238
|
+
): Record<string, unknown> {
|
|
151
239
|
return buildVideoFeatureInputImpl(feature, data);
|
|
152
240
|
}
|
|
153
241
|
}
|
|
@@ -0,0 +1,189 @@
|
|
|
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
|
+
CostSummary,
|
|
10
|
+
ModelCostInfo,
|
|
11
|
+
} from "../../domain/entities/cost-tracking.types";
|
|
12
|
+
import { findModelById } from "../../domain/constants/default-models.constants";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean | undefined;
|
|
15
|
+
|
|
16
|
+
export class CostTracker {
|
|
17
|
+
private config: Required<CostTrackerConfig>;
|
|
18
|
+
private costHistory: GenerationCost[] = [];
|
|
19
|
+
private currentOperationCosts: Map<string, number> = new Map();
|
|
20
|
+
|
|
21
|
+
constructor(config?: CostTrackerConfig) {
|
|
22
|
+
this.config = {
|
|
23
|
+
currency: config?.currency ?? "USD",
|
|
24
|
+
trackEstimatedCost: config?.trackEstimatedCost ?? true,
|
|
25
|
+
trackActualCost: config?.trackActualCost ?? true,
|
|
26
|
+
onCostUpdate: config?.onCostUpdate ?? (() => {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get cost information for a model
|
|
32
|
+
*/
|
|
33
|
+
getModelCostInfo(modelId: string): ModelCostInfo {
|
|
34
|
+
const model = findModelById(modelId);
|
|
35
|
+
|
|
36
|
+
if (model?.pricing) {
|
|
37
|
+
return {
|
|
38
|
+
model: modelId,
|
|
39
|
+
costPerRequest: model.pricing.freeUserCost,
|
|
40
|
+
currency: this.config.currency,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
45
|
+
console.warn("[CostTracker] No pricing found for model:", modelId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
model: modelId,
|
|
50
|
+
costPerRequest: 0,
|
|
51
|
+
currency: this.config.currency,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Calculate estimated cost for a generation
|
|
57
|
+
*/
|
|
58
|
+
calculateEstimatedCost(modelId: string): number {
|
|
59
|
+
const costInfo = this.getModelCostInfo(modelId);
|
|
60
|
+
return costInfo.costPerRequest;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Start tracking a generation operation
|
|
65
|
+
*/
|
|
66
|
+
startOperation(modelId: string, operation: string): string {
|
|
67
|
+
const operationId = `${Date.now()}-${operation}`;
|
|
68
|
+
const estimatedCost = this.calculateEstimatedCost(modelId);
|
|
69
|
+
|
|
70
|
+
this.currentOperationCosts.set(operationId, estimatedCost);
|
|
71
|
+
|
|
72
|
+
if (this.config.trackEstimatedCost) {
|
|
73
|
+
const cost: GenerationCost = {
|
|
74
|
+
model: modelId,
|
|
75
|
+
operation,
|
|
76
|
+
estimatedCost,
|
|
77
|
+
actualCost: 0,
|
|
78
|
+
currency: this.config.currency,
|
|
79
|
+
timestamp: Date.now(),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
this.costHistory.push(cost);
|
|
83
|
+
this.config.onCostUpdate(cost);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return operationId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Complete tracking for a generation operation
|
|
91
|
+
*/
|
|
92
|
+
completeOperation(
|
|
93
|
+
operationId: string,
|
|
94
|
+
modelId: string,
|
|
95
|
+
operation: string,
|
|
96
|
+
requestId?: string,
|
|
97
|
+
actualCost?: number,
|
|
98
|
+
): GenerationCost | null {
|
|
99
|
+
const estimatedCost = this.currentOperationCosts.get(operationId) ?? 0;
|
|
100
|
+
const finalActualCost = actualCost ?? estimatedCost;
|
|
101
|
+
|
|
102
|
+
this.currentOperationCosts.delete(operationId);
|
|
103
|
+
|
|
104
|
+
const cost: GenerationCost = {
|
|
105
|
+
model: modelId,
|
|
106
|
+
operation,
|
|
107
|
+
estimatedCost,
|
|
108
|
+
actualCost: finalActualCost,
|
|
109
|
+
currency: this.config.currency,
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
requestId,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
this.costHistory.push(cost);
|
|
115
|
+
|
|
116
|
+
if (this.config.trackActualCost) {
|
|
117
|
+
this.config.onCostUpdate(cost);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return cost;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get cost summary for all tracked operations
|
|
125
|
+
*/
|
|
126
|
+
getCostSummary(): CostSummary {
|
|
127
|
+
const completedCosts = this.costHistory.filter((c) => c.actualCost > 0);
|
|
128
|
+
const totalCost = completedCosts.reduce((sum, c) => sum + c.actualCost, 0);
|
|
129
|
+
const totalGenerations = completedCosts.length;
|
|
130
|
+
const averageCost = totalGenerations > 0 ? totalCost / totalGenerations : 0;
|
|
131
|
+
|
|
132
|
+
const modelBreakdown: Record<string, number> = {};
|
|
133
|
+
const operationBreakdown: Record<string, number> = {};
|
|
134
|
+
|
|
135
|
+
for (const cost of completedCosts) {
|
|
136
|
+
modelBreakdown[cost.model] =
|
|
137
|
+
(modelBreakdown[cost.model] ?? 0) + cost.actualCost;
|
|
138
|
+
operationBreakdown[cost.operation] =
|
|
139
|
+
(operationBreakdown[cost.operation] ?? 0) + cost.actualCost;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
totalCost,
|
|
144
|
+
totalGenerations,
|
|
145
|
+
averageCost,
|
|
146
|
+
currency: this.config.currency,
|
|
147
|
+
modelBreakdown,
|
|
148
|
+
operationBreakdown,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get cost history
|
|
154
|
+
*/
|
|
155
|
+
getCostHistory(): readonly GenerationCost[] {
|
|
156
|
+
return this.costHistory;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Clear cost history
|
|
161
|
+
*/
|
|
162
|
+
clearHistory(): void {
|
|
163
|
+
this.costHistory = [];
|
|
164
|
+
this.currentOperationCosts.clear();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get costs for a specific model
|
|
169
|
+
*/
|
|
170
|
+
getCostsByModel(modelId: string): GenerationCost[] {
|
|
171
|
+
return this.costHistory.filter((c) => c.model === modelId);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get costs for a specific operation type
|
|
176
|
+
*/
|
|
177
|
+
getCostsByOperation(operation: string): GenerationCost[] {
|
|
178
|
+
return this.costHistory.filter((c) => c.operation === operation);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get costs for a specific time range
|
|
183
|
+
*/
|
|
184
|
+
getCostsByTimeRange(startTime: number, endTime: number): GenerationCost[] {
|
|
185
|
+
return this.costHistory.filter(
|
|
186
|
+
(c) => c.timestamp >= startTime && c.timestamp <= endTime,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export { categorizeFalError } from "./error-categorizer";
|
|
6
|
-
export {
|
|
6
|
+
export {
|
|
7
|
+
falErrorMapper,
|
|
8
|
+
mapFalError,
|
|
9
|
+
isFalErrorRetryable,
|
|
10
|
+
} from "./error-mapper";
|
|
7
11
|
|
|
8
12
|
export {
|
|
9
13
|
buildSingleImageInput,
|
|
@@ -78,3 +82,5 @@ export {
|
|
|
78
82
|
} from "./job-storage";
|
|
79
83
|
|
|
80
84
|
export type { IJobStorage, InMemoryJobStorage } from "./job-storage";
|
|
85
|
+
|
|
86
|
+
export { CostTracker } from "./cost-tracker";
|