This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import type { PublicModelPrice } from "../api/publicPricingClient";
|
||||
import type { TextTokenCreditRate } from "./taskLifecycle";
|
||||
|
||||
const TOKENS_PER_MILLION = 1_000_000;
|
||||
const BACKEND_TOKEN_PRICE_UNIT = 1_000;
|
||||
const CREDITS_PER_CNY = 100;
|
||||
const MILLS_PER_CNY = 1_000;
|
||||
const CREDITS_PER_MILL = CREDITS_PER_CNY / MILLS_PER_CNY;
|
||||
|
||||
function isUsablePrice(value: number | null | undefined): value is number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
||||
}
|
||||
|
||||
function normalizeModelKey(value: string): string {
|
||||
return value.trim().toLowerCase();
|
||||
}
|
||||
|
||||
function compactModelKey(value: string): string {
|
||||
return normalizeModelKey(value).replace(/[^a-z0-9]+/g, "");
|
||||
}
|
||||
|
||||
function addCandidate(
|
||||
candidates: PublicModelPrice[],
|
||||
seen: Set<string>,
|
||||
price: PublicModelPrice,
|
||||
): void {
|
||||
const key = normalizeModelKey(price.modelKey);
|
||||
if (seen.has(key)) return;
|
||||
seen.add(key);
|
||||
candidates.push(price);
|
||||
}
|
||||
|
||||
export function millsPerThousandTokensToCreditsPerMillion(
|
||||
priceMills: number,
|
||||
): number {
|
||||
if (!isUsablePrice(priceMills)) return 0;
|
||||
return (
|
||||
priceMills *
|
||||
(TOKENS_PER_MILLION / BACKEND_TOKEN_PRICE_UNIT) *
|
||||
CREDITS_PER_MILL
|
||||
);
|
||||
}
|
||||
|
||||
export function modelPriceToTextTokenCreditRate(
|
||||
price: PublicModelPrice,
|
||||
): TextTokenCreditRate | null {
|
||||
if (
|
||||
!isUsablePrice(price.inputPriceMills) ||
|
||||
!isUsablePrice(price.outputPriceMills)
|
||||
)
|
||||
return null;
|
||||
|
||||
return {
|
||||
inputCreditsPerMillion: millsPerThousandTokensToCreditsPerMillion(
|
||||
price.inputPriceMills,
|
||||
),
|
||||
outputCreditsPerMillion: millsPerThousandTokensToCreditsPerMillion(
|
||||
price.outputPriceMills,
|
||||
),
|
||||
source: "server",
|
||||
modelKey: price.modelKey,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveTextTokenCreditRate(
|
||||
prices: PublicModelPrice[],
|
||||
modelKey: string | null | undefined,
|
||||
): TextTokenCreditRate | null {
|
||||
const normalizedTarget = normalizeModelKey(modelKey || "");
|
||||
if (!normalizedTarget) return null;
|
||||
|
||||
const compactTarget = compactModelKey(normalizedTarget);
|
||||
const candidates: PublicModelPrice[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
for (const price of prices) {
|
||||
if (normalizeModelKey(price.modelKey) === normalizedTarget) {
|
||||
addCandidate(candidates, seen, price);
|
||||
}
|
||||
}
|
||||
|
||||
for (const price of prices) {
|
||||
if (compactModelKey(price.modelKey) === compactTarget) {
|
||||
addCandidate(candidates, seen, price);
|
||||
}
|
||||
}
|
||||
|
||||
for (const price of prices) {
|
||||
const compactPriceKey = compactModelKey(price.modelKey);
|
||||
if (
|
||||
compactPriceKey.includes(compactTarget) ||
|
||||
compactTarget.includes(compactPriceKey)
|
||||
) {
|
||||
addCandidate(candidates, seen, price);
|
||||
}
|
||||
}
|
||||
|
||||
for (const price of candidates) {
|
||||
const rate = modelPriceToTextTokenCreditRate(price);
|
||||
if (rate) return rate;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user