99 lines
4.1 KiB
JavaScript
99 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
// Cross-platform generation script for the llm-pricing package.
|
|
// Generates TypeScript modules from JSON data files:
|
|
// 1. defaultPrices.ts ← default-model-prices.json (synced from Langfuse)
|
|
// 2. modelCatalog.ts ← model-catalog.json (our maintained catalog metadata)
|
|
//
|
|
// Usage: node scripts/generate.mjs
|
|
//
|
|
// To update the source JSON files:
|
|
// - Pricing: pnpm run sync-prices (fetches from Langfuse, requires curl)
|
|
// - Catalog: pnpm run generate-catalog (uses Claude CLI to research models)
|
|
|
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
import { join, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const srcDir = join(__dirname, "..", "src");
|
|
|
|
// --- 1. Generate defaultPrices.ts from default-model-prices.json ---
|
|
|
|
const pricesJsonPath = join(srcDir, "default-model-prices.json");
|
|
|
|
if (existsSync(pricesJsonPath)) {
|
|
const raw = JSON.parse(readFileSync(pricesJsonPath, "utf-8"));
|
|
const stripped = raw.map((e) => ({
|
|
modelName: e.modelName.trim(),
|
|
matchPattern: e.matchPattern,
|
|
startDate: e.createdAt,
|
|
pricingTiers: e.pricingTiers.map((t) => ({
|
|
name: t.name,
|
|
isDefault: t.isDefault,
|
|
priority: t.priority,
|
|
conditions: t.conditions.map((c) => ({
|
|
usageDetailPattern: c.usageDetailPattern,
|
|
operator: c.operator,
|
|
value: c.value,
|
|
})),
|
|
prices: t.prices,
|
|
})),
|
|
}));
|
|
|
|
let out = 'import type { DefaultModelDefinition } from "./types.js";\n\n';
|
|
out += "// Auto-generated from default-model-prices.json — do not edit manually.\n";
|
|
out +=
|
|
"// Run `pnpm run sync-prices` to update the JSON, then `pnpm run generate` to regenerate.\n";
|
|
out += "// Source: https://github.com/langfuse/langfuse\n\n";
|
|
out += "export const defaultModelPrices: DefaultModelDefinition[] = ";
|
|
out += JSON.stringify(stripped, null, 2) + ";\n";
|
|
|
|
writeFileSync(join(srcDir, "defaultPrices.ts"), out);
|
|
console.log(`Generated defaultPrices.ts (${stripped.length} models)`);
|
|
} else {
|
|
console.log("Skipping defaultPrices.ts — default-model-prices.json not found");
|
|
}
|
|
|
|
// --- 2. Generate modelCatalog.ts from model-catalog.json ---
|
|
|
|
const catalogJsonPath = join(srcDir, "model-catalog.json");
|
|
|
|
if (existsSync(catalogJsonPath)) {
|
|
const data = JSON.parse(readFileSync(catalogJsonPath, "utf-8"));
|
|
|
|
// Backfill missing fields for old entries
|
|
for (const key of Object.keys(data)) {
|
|
if (data[key].releaseDate === undefined) data[key].releaseDate = null;
|
|
if (data[key].isHidden === undefined) data[key].isHidden = false;
|
|
if (data[key].supportsStructuredOutput === undefined)
|
|
data[key].supportsStructuredOutput = false;
|
|
if (data[key].supportsParallelToolCalls === undefined)
|
|
data[key].supportsParallelToolCalls = false;
|
|
if (data[key].supportsStreamingToolCalls === undefined)
|
|
data[key].supportsStreamingToolCalls = false;
|
|
if (data[key].deprecationDate === undefined) data[key].deprecationDate = null;
|
|
if (data[key].knowledgeCutoff === undefined) data[key].knowledgeCutoff = null;
|
|
if (data[key].resolvedAt === undefined) data[key].resolvedAt = new Date().toISOString();
|
|
{
|
|
// Always recompute base model name (don't trust existing values)
|
|
// Strip trailing date (-YYYYMMDD or -YYYY-MM-DD) and -latest suffix
|
|
// Keep original naming (dots, etc.) — don't normalize
|
|
let base = key.replace(/-\d{4}-?\d{2}-?\d{2}$/, "").replace(/-latest$/, "");
|
|
data[key].baseModelName = base !== key ? base : null;
|
|
}
|
|
}
|
|
|
|
let out = 'import type { ModelCatalogEntry } from "./types.js";\n\n';
|
|
out += "// Auto-generated from model-catalog.json — do not edit manually.\n";
|
|
out +=
|
|
"// Run `pnpm run generate-catalog` to update the JSON, then `pnpm run generate` to regenerate.\n\n";
|
|
out += "export const modelCatalog: Record<string, ModelCatalogEntry> = ";
|
|
out += JSON.stringify(data, null, 2) + ";\n";
|
|
|
|
writeFileSync(join(srcDir, "modelCatalog.ts"), out);
|
|
console.log(`Generated modelCatalog.ts (${Object.keys(data).length} entries)`);
|
|
} else {
|
|
console.log("Skipping modelCatalog.ts — model-catalog.json not found");
|
|
}
|