53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { prisma } from "@/lib/db";
|
|
import type { TokenUsage } from "./types";
|
|
|
|
// Rough 2026 unit prices (USD). Tune in one place; admin cost dashboards read AiCostLog.
|
|
const PRICE = {
|
|
gptInputPer1k: 0.0025,
|
|
gptOutputPer1k: 0.01,
|
|
elevenPer1kChars: 0.3,
|
|
dallePerImage: 0.04,
|
|
};
|
|
|
|
export function scriptCostUsd(usage: TokenUsage): number {
|
|
return round4(
|
|
(usage.inputTokens / 1000) * PRICE.gptInputPer1k +
|
|
(usage.outputTokens / 1000) * PRICE.gptOutputPer1k
|
|
);
|
|
}
|
|
|
|
export function audioCostUsd(characters: number): number {
|
|
return round4((characters / 1000) * PRICE.elevenPer1kChars);
|
|
}
|
|
|
|
export function artCostUsd(images: number): number {
|
|
return round4(images * PRICE.dallePerImage);
|
|
}
|
|
|
|
export interface CostEntry {
|
|
provider: "openai" | "elevenlabs";
|
|
operation: "script" | "audio" | "art" | "repurpose";
|
|
units: number;
|
|
costUsd: number;
|
|
episodeId?: string;
|
|
userId?: string;
|
|
}
|
|
|
|
/** Record an AI usage/cost line for the admin monitoring dashboard. */
|
|
export async function recordCost(entry: CostEntry): Promise<void> {
|
|
await prisma.aiCostLog.create({
|
|
data: {
|
|
provider: entry.provider,
|
|
operation: entry.operation,
|
|
units: entry.units,
|
|
costUsd: entry.costUsd.toFixed(4),
|
|
episodeId: entry.episodeId,
|
|
userId: entry.userId,
|
|
},
|
|
});
|
|
}
|
|
|
|
function round4(n: number): number {
|
|
return Math.round(n * 10000) / 10000;
|
|
}
|