Browse Source

feat(24-02): track incurred cost for video and external providers

- Add SelectedModelPricing interface to providers.ts
- Update SelectedModel type with optional pricing field
- Track fal.ai costs in nanoBanana execution and regeneration
- Track fal.ai costs in generateVideo execution and regeneration
- Skip cost tracking for Replicate (no pricing API available)
- Gemini continues to use hardcoded pricing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
0aba3b6f84
  1. 46
      src/store/workflowStore.ts
  2. 7
      src/types/providers.ts

46
src/store/workflowStore.ts

@ -1021,8 +1021,16 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
});
// Track cost
const generationCost = calculateGenerationCost(nodeData.model, nodeData.resolution);
get().addIncurredCost(generationCost);
// Cost tracking: Gemini (hardcoded), fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
// External fal.ai provider - use pricing from selectedModel
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
} else if (!nodeData.selectedModel || nodeData.selectedModel.provider === "gemini") {
// Legacy Gemini or Gemini via selectedModel - use hardcoded pricing
const generationCost = calculateGenerationCost(nodeData.model, nodeData.resolution);
get().addIncurredCost(generationCost);
}
// Note: Replicate has no pricing API, so costs are not tracked
// Auto-save to generations folder if configured
const genPath = get().generationsPath;
@ -1226,6 +1234,13 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
selectedVideoHistoryIndex: 0,
});
// Track cost for video generation
// Cost tracking: fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
}
// Note: Replicate has no pricing API, so video costs are not tracked
// Auto-save video to generations folder if configured
const genPath = get().generationsPath;
if (genPath) {
@ -1264,6 +1279,12 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
selectedVideoHistoryIndex: 0,
});
// Track cost for video generation (image fallback case)
// Cost tracking: fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
}
// Auto-save image preview to generations folder if configured
const genPath = get().generationsPath;
if (genPath) {
@ -1750,8 +1771,13 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
});
// Track cost
const generationCost = calculateGenerationCost(nodeData.model, nodeData.resolution);
get().addIncurredCost(generationCost);
// Cost tracking: Gemini (hardcoded), fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
} else if (!nodeData.selectedModel || nodeData.selectedModel.provider === "gemini") {
const generationCost = calculateGenerationCost(nodeData.model, nodeData.resolution);
get().addIncurredCost(generationCost);
}
// Auto-save to generations folder if configured
const genPath = get().generationsPath;
@ -2009,6 +2035,12 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
selectedVideoHistoryIndex: 0,
});
// Track cost for video regeneration
// Cost tracking: fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
}
// Auto-save video to generations folder if configured
const genPath = get().generationsPath;
if (genPath) {
@ -2046,6 +2078,12 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
selectedVideoHistoryIndex: 0,
});
// Track cost for video regeneration (image fallback case)
// Cost tracking: fal.ai (from API). Replicate excluded (no pricing API).
if (nodeData.selectedModel?.provider === "fal" && nodeData.selectedModel?.pricing) {
get().addIncurredCost(nodeData.selectedModel.pricing.amount);
}
// Auto-save image preview to generations folder if configured
const genPath = get().generationsPath;
if (genPath) {

7
src/types/providers.ts

@ -8,11 +8,18 @@
// Provider Types for multi-provider support (image/video generation)
export type ProviderType = "gemini" | "openai" | "replicate" | "fal";
// Model pricing info (stored when model is selected)
export interface SelectedModelPricing {
type: 'per-run' | 'per-second';
amount: number;
}
// Selected model for image/video generation nodes
export interface SelectedModel {
provider: ProviderType;
modelId: string;
displayName: string;
pricing?: SelectedModelPricing; // Optional pricing info from provider API
}
export interface ProviderConfig {

Loading…
Cancel
Save