Buckets:
| import { Client } from "@planetscale/database" | |
| import { readdir } from "node:fs/promises" | |
| import path from "node:path" | |
| import { drizzle } from "drizzle-orm/planetscale-serverless" | |
| import { geoStat, modelStat, providerStat } from "./database/schema" | |
| import { statModel, statProvider } from "./domain/model-normalization" | |
| import { | |
| chunks, | |
| collapseRows, | |
| inserted, | |
| isoWeekId, | |
| normalizeCountry, | |
| normalizeTier, | |
| periodKeyFor, | |
| rankBy, | |
| rankRowsWithMarketShare, | |
| startOfIsoWeek, | |
| startOfUtcDay, | |
| statPeriodKey, | |
| synthesizeAllTierRows, | |
| toStatBaseRow, | |
| type StatBaseAggregate, | |
| } from "./domain/stat" | |
| const DAY_MS = 86_400_000 | |
| const DEFAULT_UPSERT_CHUNK_SIZE = 100 | |
| const DEFAULT_TIERS = ["Go", "Free", "Paid"] | |
| const FREE_MODELS = new Set(["gpt-5-nano", "grok-code", "big-pickle"]) | |
| type Grain = "day" | "week" | |
| type MetricDimension = "model" | "provider" | "geo" | "geo-model" | |
| type LookupDimension = "model-provider-model" | "geo-continent" | |
| type ImportKey = `${MetricDimension | LookupDimension}-${Grain}` | |
| type QuerySpec = { | |
| name: string | |
| importKey: ImportKey | |
| importFlag: `--${ImportKey}` | |
| query: ReturnType<typeof metricQuery> | |
| } | |
| type RawRow = Record<string, string> | |
| type ImportOptions = { | |
| dataset: string | |
| databaseUrl: string | undefined | |
| directories: string[] | |
| dryRun: boolean | |
| periodStart: Date | undefined | |
| upsertChunkSize: number | |
| files: Partial<Record<ImportKey, string[]>> | |
| } | |
| type ModelAggregate = StatBaseAggregate & { provider: string; model: string; provider_model: string } | |
| type ProviderAggregate = StatBaseAggregate & { provider: string } | |
| type GeoAggregate = StatBaseAggregate & { provider: string; model: string; country: string; continent: string } | |
| type ModelStatRow = typeof modelStat.$inferInsert | |
| type ProviderStatRow = typeof providerStat.$inferInsert | |
| type GeoStatRow = typeof geoStat.$inferInsert | |
| const inputKeys = [ | |
| "model-day", | |
| "model-week", | |
| "model-provider-model-day", | |
| "model-provider-model-week", | |
| "provider-day", | |
| "provider-week", | |
| "geo-day", | |
| "geo-week", | |
| "geo-model-day", | |
| "geo-model-week", | |
| "geo-continent-day", | |
| "geo-continent-week", | |
| ] as const satisfies ImportKey[] | |
| if (import.meta.main) await main() | |
| async function main() { | |
| const command = process.argv[2] | |
| if (command === "queries") return printQueries(process.argv.slice(3)) | |
| if (command === "import") return importFiles(process.argv.slice(3)) | |
| usage() | |
| } | |
| function printQueries(args: string[]) { | |
| const flags = parseFlags(args) | |
| const limit = parseIntegerFlag(flags, "limit") ?? 1000 | |
| const tiers = parseListFlag(flags, "tiers") ?? DEFAULT_TIERS | |
| const queries = buildQueries(limit, tiers) | |
| const only = flags.get("only")?.[0] | |
| if (only) { | |
| const item = queries.find((query) => query.name === only) | |
| if (!item) fail(`Unknown --only ${only}. Expected one of: ${queries.map((query) => query.name).join(", ")}`) | |
| console.log(JSON.stringify(item.query, null, 2)) | |
| return | |
| } | |
| console.log( | |
| JSON.stringify( | |
| { | |
| tiers, | |
| import_hint: "bun src/honeycomb-backfill.ts import --dir downloads", | |
| queries, | |
| }, | |
| null, | |
| 2, | |
| ), | |
| ) | |
| } | |
| async function importFiles(args: string[]) { | |
| const parsed = parseImportOptions(args) | |
| const opts = { ...parsed, files: mergeFiles(parsed.files, await discoverFiles(parsed.directories)) } | |
| if (!inputKeys.some((key) => opts.files[key]?.length)) fail("No CSV or JSON import files were provided or discovered") | |
| const providerModelLookup = new Map([ | |
| ...(await lookupRows(opts.files["model-provider-model-day"], "day", opts, modelProviderModelLookup)), | |
| ...(await lookupRows(opts.files["model-provider-model-week"], "week", opts, modelProviderModelLookup)), | |
| ]) | |
| const continentLookup = new Map([ | |
| ...(await lookupRows(opts.files["geo-continent-day"], "day", opts, geoContinentLookup)), | |
| ...(await lookupRows(opts.files["geo-continent-week"], "week", opts, geoContinentLookup)), | |
| ]) | |
| const modelAggregates = [ | |
| ...(await metricRows(opts.files["model-day"], "day", opts, (row, base) => | |
| modelAggregate(row, base, providerModelLookup), | |
| )), | |
| ...(await metricRows(opts.files["model-week"], "week", opts, (row, base) => | |
| modelAggregate(row, base, providerModelLookup), | |
| )), | |
| ] | |
| const modelRows = modelRowsFromAggregates(modelAggregates) | |
| const providerRows = providerRowsFromAggregates([ | |
| ...(await metricRows(opts.files["provider-day"], "day", opts, (row, base) => ({ | |
| ...base, | |
| provider: provider(row) ?? "unknown", | |
| }))), | |
| ...(await metricRows(opts.files["provider-week"], "week", opts, (row, base) => ({ | |
| ...base, | |
| provider: provider(row) ?? "unknown", | |
| }))), | |
| ]) | |
| const geoRows = geoRowsFromAggregates([ | |
| ...(await metricRows(opts.files["geo-day"], "day", opts, (row, base) => ({ | |
| ...base, | |
| provider: "all", | |
| model: "all", | |
| country: country(row), | |
| continent: continentLookup.get(lookupKey(base, country(row))) ?? continent(row), | |
| }))), | |
| ...(await metricRows(opts.files["geo-week"], "week", opts, (row, base) => ({ | |
| ...base, | |
| provider: "all", | |
| model: "all", | |
| country: country(row), | |
| continent: continentLookup.get(lookupKey(base, country(row))) ?? continent(row), | |
| }))), | |
| ...(await metricRows(opts.files["geo-model-day"], "day", opts, (row, base) => | |
| geoModelAggregate(row, base, continentLookup), | |
| )), | |
| ...(await metricRows(opts.files["geo-model-week"], "week", opts, (row, base) => | |
| geoModelAggregate(row, base, continentLookup), | |
| )), | |
| ]) | |
| console.log( | |
| JSON.stringify( | |
| { | |
| inputs: Object.fromEntries( | |
| inputKeys.flatMap((key) => (opts.files[key]?.length ? [[key, opts.files[key].length]] : [])), | |
| ), | |
| modelRows: modelRows.length, | |
| providerRows: providerRows.length, | |
| geoRows: geoRows.length, | |
| dryRun: opts.dryRun, | |
| upsertChunkSize: opts.upsertChunkSize, | |
| }, | |
| null, | |
| 2, | |
| ), | |
| ) | |
| if (opts.dryRun) return | |
| if (!opts.databaseUrl) fail("DATABASE_URL is required unless --dry-run is set") | |
| const db = drizzle({ client: new Client({ url: opts.databaseUrl }) }) | |
| await upsertModelRows(db, modelRows, opts.upsertChunkSize) | |
| await upsertProviderRows(db, providerRows, opts.upsertChunkSize) | |
| await upsertGeoRows(db, geoRows, opts.upsertChunkSize) | |
| } | |
| function buildQueries(limit: number, tiers: string[]): QuerySpec[] { | |
| const daily = tiers.flatMap((tier) => [ | |
| querySpec( | |
| "model-day", | |
| tier, | |
| metricQuery(["date", "tier", "stat_provider_2", "stat_model_2"], limit, tierFilters(tier)), | |
| ), | |
| querySpec("provider-day", tier, metricQuery(["date", "tier", "stat_provider_2"], limit, tierFilters(tier))), | |
| querySpec("geo-day", tier, metricQuery(["date", "tier", "country", "continent"], limit, tierFilters(tier))), | |
| querySpec( | |
| "geo-model-day", | |
| tier, | |
| metricQuery( | |
| ["date", "tier", "stat_provider_2", "stat_model_2", "country", "continent"], | |
| limit, | |
| tierFilters(tier), | |
| ), | |
| ), | |
| ]) | |
| const weekly = tiers.flatMap((tier) => [ | |
| querySpec( | |
| "model-week", | |
| tier, | |
| metricQuery(["week", "tier", "stat_provider_2", "stat_model_2"], limit, tierFilters(tier)), | |
| ), | |
| querySpec("provider-week", tier, metricQuery(["week", "tier", "stat_provider_2"], limit, tierFilters(tier))), | |
| querySpec("geo-week", tier, metricQuery(["week", "tier", "country", "continent"], limit, tierFilters(tier))), | |
| querySpec( | |
| "geo-model-week", | |
| tier, | |
| metricQuery( | |
| ["week", "tier", "stat_provider_2", "stat_model_2", "country", "continent"], | |
| limit, | |
| tierFilters(tier), | |
| ), | |
| ), | |
| ]) | |
| return [...daily, ...weekly] | |
| } | |
| function querySpec(importKey: ImportKey, tier: string, query: ReturnType<typeof metricQuery>) { | |
| return { | |
| name: `${importKey}-${queryNameSegment(tier)}`, | |
| importKey, | |
| importFlag: `--${importKey}` as const, | |
| query, | |
| } | |
| } | |
| function metricQuery(breakdowns: string[], limit: number, filters: ReturnType<typeof commonFilters> = []) { | |
| return { | |
| granularity: 0, | |
| breakdowns, | |
| calculations: [ | |
| { op: "COUNT_DISTINCT", column: "session" }, | |
| { op: "COUNT" }, | |
| { op: "SUM", column: "tokens.input" }, | |
| { op: "SUM", column: "tokens.output" }, | |
| { op: "SUM", column: "tokens.reasoning" }, | |
| { op: "SUM", column: "tokens.cache_read" }, | |
| { op: "SUM", column: "tokens" }, | |
| { op: "SUM", column: "cost.input.microcents" }, | |
| { op: "SUM", column: "cost.output.microcents" }, | |
| { op: "SUM", column: "cost.total.microcents" }, | |
| { op: "AVG", column: "duration" }, | |
| { op: "P50", column: "duration" }, | |
| { op: "P95", column: "duration" }, | |
| { op: "AVG", column: "time_to_first_byte" }, | |
| { op: "P50", column: "time_to_first_byte" }, | |
| { op: "P95", column: "time_to_first_byte" }, | |
| { op: "AVG", column: "tps.output" }, | |
| ], | |
| filters: [...commonFilters(), ...filters], | |
| filter_combination: "AND", | |
| orders: [{ column: "tokens", op: "SUM", order: "descending" }], | |
| havings: [], | |
| limit, | |
| formulas: [], | |
| } | |
| } | |
| function tierFilters(tier: string) { | |
| if (tier === "all") return [] | |
| return [{ column: "tier", op: "=", value: tier }] | |
| } | |
| function queryNameSegment(value: string) { | |
| return ( | |
| value | |
| .toLowerCase() | |
| .replace(/[^a-z0-9]+/g, "-") | |
| .replace(/^-|-$/g, "") || "all" | |
| ) | |
| } | |
| function commonFilters() { | |
| return [ | |
| { column: "event_type", op: "=", value: "completions" }, | |
| { column: "model", op: "exists" }, | |
| { column: "model", op: "!=", value: "" }, | |
| { column: "model", op: "!=", value: "alpha-gpt-next" }, | |
| ] | |
| } | |
| function metricRows<T extends StatBaseAggregate>( | |
| files: string[] | undefined, | |
| grain: Grain, | |
| opts: ImportOptions, | |
| map: (row: RawRow, base: StatBaseAggregate) => T | T[], | |
| ) { | |
| if (!files) return Promise.resolve([]) | |
| return readFiles(files).then((rows) => rows.flatMap((row) => map(row, baseAggregate(row, grain, opts)))) | |
| } | |
| function lookupRows( | |
| files: string[] | undefined, | |
| grain: Grain, | |
| opts: ImportOptions, | |
| map: (row: RawRow, grain: Grain, opts: ImportOptions) => readonly (readonly [string, string])[], | |
| ) { | |
| if (!files) return Promise.resolve([]) | |
| return readFiles(files).then((rows) => | |
| Array.from( | |
| rows | |
| .flatMap((row) => map(row, grain, opts)) | |
| .reduce((result, [key, value]) => { | |
| if (value && value > (result.get(key) ?? "")) result.set(key, value) | |
| return result | |
| }, new Map<string, string>()), | |
| ), | |
| ) | |
| } | |
| async function readFiles(files: string[]) { | |
| return (await Promise.all(files.map(readRows))).flat() | |
| } | |
| async function discoverFiles(directories: string[]) { | |
| const classified = await Promise.all( | |
| (await Promise.all(directories.map(filesInDirectory))).flat().map(async (file) => ({ | |
| file, | |
| key: classifyRows(file, await readRows(file)), | |
| })), | |
| ) | |
| return classified.reduce<Partial<Record<ImportKey, string[]>>>((result, item) => { | |
| return { ...result, [item.key]: [...(result[item.key] ?? []), item.file] } | |
| }, {}) | |
| } | |
| async function filesInDirectory(directory: string): Promise<string[]> { | |
| return ( | |
| await Promise.all( | |
| (await readdir(directory, { withFileTypes: true })).map((entry) => { | |
| const file = path.join(directory, entry.name) | |
| if (entry.isDirectory()) return filesInDirectory(file) | |
| if (entry.isFile() && /\.(csv|json)$/i.test(entry.name)) return Promise.resolve([file]) | |
| return Promise.resolve([]) | |
| }), | |
| ) | |
| ).flat() | |
| } | |
| function classifyRows(file: string, rows: RawRow[]): ImportKey { | |
| if (rows.length === 0) fail(`Cannot classify empty export: ${file}`) | |
| const headers = new Set(rows.flatMap((row) => Object.keys(row).map(normalizeHeader))) | |
| const grain: Grain = headers.has("date") ? "day" : "week" | |
| if (hasHeader(headers, ["country", "cf.country"])) { | |
| if (hasHeader(headers, ["model", "stat_model", "stat_model_2"]) && hasMetricHeaders(headers)) | |
| return `geo-model-${grain}` | |
| return hasMetricHeaders(headers) ? `geo-${grain}` : `geo-continent-${grain}` | |
| } | |
| if (hasHeader(headers, ["model", "stat_model", "stat_model_2"])) | |
| return hasMetricHeaders(headers) ? `model-${grain}` : `model-provider-model-${grain}` | |
| if ( | |
| hasHeader(headers, [ | |
| "provider", | |
| "provider.normalized", | |
| "stat_provider", | |
| "stat_provider_2", | |
| "provider.model", | |
| "provider_model", | |
| ]) | |
| ) | |
| return `provider-${grain}` | |
| fail(`Cannot classify export from columns in ${file}`) | |
| } | |
| function hasMetricHeaders(headers: Set<string>) { | |
| return ["sumtokens", "sumtokensinput", "inputtokens", "totaltokens", "avgduration", "countdistinctsession"].some( | |
| (header) => headers.has(header), | |
| ) | |
| } | |
| function hasHeader(headers: Set<string>, names: string[]) { | |
| return names.some((name) => headers.has(normalizeHeader(name))) | |
| } | |
| function mergeFiles(left: Partial<Record<ImportKey, string[]>>, right: Partial<Record<ImportKey, string[]>>) { | |
| return inputKeys.reduce<Partial<Record<ImportKey, string[]>>>((result, key) => { | |
| const files = [...(left[key] ?? []), ...(right[key] ?? [])] | |
| if (files.length === 0) return result | |
| return { ...result, [key]: files } | |
| }, {}) | |
| } | |
| function modelProviderModelLookup(row: RawRow, grain: Grain, opts: ImportOptions): [string, string][] { | |
| const base = basePeriod(row, grain, opts) | |
| const value = providerModel(row) | |
| const author = provider(row) | |
| if (!value || !author) return [] | |
| return [[lookupKey({ ...base, dataset: opts.dataset, tier: tier(row), grain }, author, model(row)), value]] | |
| } | |
| function modelAggregate( | |
| row: RawRow, | |
| base: StatBaseAggregate, | |
| providerModelLookup: Map<string, string>, | |
| ): ModelAggregate[] { | |
| const author = provider(row) | |
| if (!author) return [] | |
| return [ | |
| { | |
| ...base, | |
| provider: author, | |
| model: model(row), | |
| provider_model: providerModelLookup.get(lookupKey(base, author, model(row))) ?? providerModel(row), | |
| }, | |
| ] | |
| } | |
| function geoContinentLookup(row: RawRow, grain: Grain, opts: ImportOptions): [string, string][] { | |
| const base = basePeriod(row, grain, opts) | |
| const value = continent(row) | |
| if (!value) return [] | |
| return [[lookupKey({ ...base, dataset: opts.dataset, tier: tier(row), grain }, country(row)), value]] | |
| } | |
| function geoModelAggregate(row: RawRow, base: StatBaseAggregate, continentLookup: Map<string, string>): GeoAggregate[] { | |
| const author = provider(row) | |
| if (!author) return [] | |
| return [ | |
| { | |
| ...base, | |
| provider: author, | |
| model: model(row), | |
| country: country(row), | |
| continent: continentLookup.get(lookupKey(base, country(row))) ?? continent(row), | |
| }, | |
| ] | |
| } | |
| function baseAggregate(row: RawRow, grain: Grain, opts: ImportOptions): StatBaseAggregate { | |
| return { | |
| ...basePeriod(row, grain, opts), | |
| grain, | |
| dataset: opts.dataset, | |
| tier: tier(row), | |
| sessions: integer(row, "sessions", ["COUNT_DISTINCT(session)"]), | |
| requests: integer(row, "requests", ["COUNT", "COUNT()"]), | |
| input_tokens: integer(row, "input_tokens", ["SUM(tokens.input)", "SUM(tokens_input)"]), | |
| output_tokens: integer(row, "output_tokens", ["SUM(tokens.output)", "SUM(tokens_output)"]), | |
| reasoning_tokens: integer(row, "reasoning_tokens", ["SUM(tokens.reasoning)", "SUM(tokens_reasoning)"]), | |
| cache_read_tokens: integer(row, "cache_read_tokens", ["SUM(tokens.cache_read)", "SUM(tokens_cache_read)"]), | |
| total_tokens: integer(row, "total_tokens", ["SUM(stat_tokens_total)", "SUM(tokens)", "SUM(tokens_total)"]), | |
| input_cost_microcents: integer(row, "input_cost_microcents", [ | |
| "SUM(cost.input.microcents)", | |
| "SUM(stat_cost_input_microcents)", | |
| ]), | |
| output_cost_microcents: integer(row, "output_cost_microcents", [ | |
| "SUM(cost.output.microcents)", | |
| "SUM(stat_cost_output_microcents)", | |
| ]), | |
| total_cost_microcents: integer(row, "total_cost_microcents", [ | |
| "SUM(cost.total.microcents)", | |
| "SUM(stat_cost_total_microcents)", | |
| ]), | |
| avg_duration_ms: nullableNumber(row, "avg_duration_ms", ["AVG(duration)", "AVG(duration_ms)"]), | |
| p50_duration_ms: nullableInteger(row, "p50_duration_ms", ["P50(duration)", "P50(duration_ms)"]), | |
| p95_duration_ms: nullableInteger(row, "p95_duration_ms", ["P95(duration)", "P95(duration_ms)"]), | |
| avg_ttfb_ms: nullableNumber(row, "avg_ttfb_ms", ["AVG(time_to_first_byte)", "AVG(ttfb_ms)"]), | |
| p50_ttfb_ms: nullableInteger(row, "p50_ttfb_ms", ["P50(time_to_first_byte)", "P50(ttfb_ms)"]), | |
| p95_ttfb_ms: nullableInteger(row, "p95_ttfb_ms", ["P95(time_to_first_byte)", "P95(ttfb_ms)"]), | |
| avg_output_tps: nullableNumber(row, "avg_output_tps", ["AVG(tps.output)", "AVG(stat_output_tps)"]), | |
| success_count: integer(row, "success_count", ["SUM(success)", "SUM(is_success)", "SUM(stat_success)"]), | |
| error_count: integer(row, "error_count", ["SUM(error)", "SUM(is_error)", "SUM(stat_error)"]), | |
| sample_count: integer(row, "sample_count", ["COUNT", "COUNT()"]), | |
| } | |
| } | |
| function basePeriod(row: RawRow, grain: Grain, opts: ImportOptions) { | |
| return { period_key: periodKey(row, grain, opts) } | |
| } | |
| function periodKey(row: RawRow, grain: Grain, opts: ImportOptions) { | |
| if (grain === "week") { | |
| const week = parseWeek(row) | |
| if (week) return week | |
| fail("weekly imports require a week or period_key column") | |
| } | |
| const time = parseTime(row) | |
| const start = time ? startOfUtcDay(time) : opts.periodStart | |
| if (!start) fail("daily imports require a time column or --period-start") | |
| return periodKeyFor("day", start) | |
| } | |
| function modelRowsFromAggregates(aggregates: ModelAggregate[]) { | |
| return rankModelRows([ | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "week").map(toModelRow), modelDimensionKey), | |
| modelDimensionKey, | |
| ), | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "day").map(toModelRow), modelDimensionKey), | |
| modelDimensionKey, | |
| ), | |
| ]) | |
| } | |
| function providerRowsFromAggregates(aggregates: ProviderAggregate[]) { | |
| return rankRowsWithMarketShare([ | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "week").map(toProviderRow), providerDimensionKey), | |
| providerDimensionKey, | |
| ), | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "day").map(toProviderRow), providerDimensionKey), | |
| providerDimensionKey, | |
| ), | |
| ]) | |
| } | |
| function geoRowsFromAggregates(aggregates: GeoAggregate[]) { | |
| return rankRowsWithMarketShare( | |
| [ | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "week").map(toGeoRow), geoDimensionKey), | |
| geoDimensionKey, | |
| ), | |
| ...synthesizeAllTierRows( | |
| collapseRows(aggregates.filter((item) => item.grain === "day").map(toGeoRow), geoDimensionKey), | |
| geoDimensionKey, | |
| ), | |
| ], | |
| geoMarketShareKey, | |
| ) | |
| } | |
| function toModelRow(data: ModelAggregate): ModelStatRow { | |
| return { ...toStatBaseRow(data), provider: data.provider, model: data.model, provider_model: data.provider_model } | |
| } | |
| function toProviderRow(data: ProviderAggregate): ProviderStatRow { | |
| return { ...toStatBaseRow(data), provider: data.provider } | |
| } | |
| function toGeoRow(data: GeoAggregate): GeoStatRow { | |
| return { | |
| ...toStatBaseRow(data), | |
| provider: data.provider, | |
| model: data.model, | |
| country: data.country, | |
| continent: data.continent, | |
| } | |
| } | |
| function rankModelRows(rows: ModelStatRow[]) { | |
| return Object.values( | |
| rows.reduce<Record<string, ModelStatRow[]>>((result, row) => { | |
| const key = statPeriodKey(row) | |
| result[key] = [...(result[key] ?? []), row] | |
| return result | |
| }, {}), | |
| ).flatMap((group) => { | |
| const tokenRanks = rankBy(group, (row) => row.total_tokens ?? 0) | |
| const requestRanks = rankBy(group, (row) => row.requests ?? 0) | |
| const costRanks = rankBy(group, (row) => row.total_cost_microcents ?? 0) | |
| return group.map((row) => ({ | |
| ...row, | |
| rank_by_tokens: tokenRanks.get(row) ?? null, | |
| rank_by_requests: requestRanks.get(row) ?? null, | |
| rank_by_cost: costRanks.get(row) ?? null, | |
| })) | |
| }) | |
| } | |
| function modelDimensionKey(row: ModelStatRow) { | |
| return [row.provider, row.model].join("\u0000") | |
| } | |
| function providerDimensionKey(row: ProviderStatRow) { | |
| return row.provider | |
| } | |
| function geoDimensionKey(row: GeoStatRow) { | |
| return [row.provider, row.model, row.country].join("\u0000") | |
| } | |
| function geoMarketShareKey(row: GeoStatRow) { | |
| return [statPeriodKey(row), row.provider, row.model].join("\u0000") | |
| } | |
| function lookupKey(base: { grain: string; period_key: string; dataset: string; tier: string }, ...dimension: string[]) { | |
| return [base.grain, base.period_key, base.dataset, base.tier, ...dimension].join("\u0000") | |
| } | |
| function tier(row: RawRow) { | |
| return normalizeTier(cell(row, ["stat_tier", "tier"]) || deriveTier(row)) | |
| } | |
| function deriveTier(row: RawRow) { | |
| const source = cell(row, ["source"]) | |
| const value = model(row) | |
| if (source === "lite") return "Go" | |
| if (FREE_MODELS.has(value) || /-free(:global)?$/.test(rawModel(row))) return "Free" | |
| return "Zen" | |
| } | |
| function provider(row: RawRow) { | |
| return statProvider(model(row), providerModel(row), cell(row, ["stat_provider_2", "stat_provider"])) | |
| } | |
| function model(row: RawRow) { | |
| return statModel(cell(row, ["stat_model_2", "stat_model"]) || rawModel(row), providerModel(row)) | |
| } | |
| function rawModel(row: RawRow) { | |
| return cell(row, ["model"]) || "unknown" | |
| } | |
| function providerModel(row: RawRow) { | |
| return cell(row, ["provider.model", "provider_model"]) || "" | |
| } | |
| function country(row: RawRow) { | |
| return normalizeCountry(cell(row, ["stat_country", "cf.country", "cf_country", "country"])) | |
| } | |
| function continent(row: RawRow) { | |
| return cell(row, ["cf.continent", "cf_continent", "continent"]) || "" | |
| } | |
| function integer(row: RawRow, name: string, aliases: string[] = []) { | |
| return Math.round(number(row, name, aliases)) | |
| } | |
| function nullableInteger(row: RawRow, name: string, aliases: string[] = []) { | |
| if (!hasCell(row, [name, ...aliases])) return null | |
| return Math.round(number(row, name, aliases)) | |
| } | |
| function nullableNumber(row: RawRow, name: string, aliases: string[] = []) { | |
| if (!hasCell(row, [name, ...aliases])) return null | |
| return Number(number(row, name, aliases).toFixed(2)) | |
| } | |
| function number(row: RawRow, name: string, aliases: string[] = []) { | |
| const value = Number(cell(row, [name, ...aliases]).replace(/,/g, "")) | |
| return Number.isFinite(value) ? value : 0 | |
| } | |
| function hasCell(row: RawRow, names: string[]) { | |
| return names.some((name) => row[name] !== undefined && row[name] !== "") | |
| } | |
| function cell(row: RawRow, names: string[]) { | |
| const normalized = normalizedCells(row) | |
| return ( | |
| names.flatMap((name) => [row[name], normalized.get(normalizeHeader(name))]).find((value) => value !== undefined) ?? | |
| "" | |
| ) | |
| } | |
| function normalizedCells(row: RawRow) { | |
| return new Map(Object.entries(row).map(([key, value]) => [normalizeHeader(key), value])) | |
| } | |
| function normalizeHeader(value: string) { | |
| return value.toLowerCase().replace(/[^a-z0-9]+/g, "") | |
| } | |
| function parseTime(row: RawRow) { | |
| const value = cell(row, ["date", "time", "timestamp", "datetime", "bucket"]) | |
| if (!value) return undefined | |
| const numeric = Number(value) | |
| const date = Number.isFinite(numeric) | |
| ? new Date(numeric > 10_000_000_000 ? numeric : numeric * 1000) | |
| : new Date(value) | |
| if (Number.isNaN(date.getTime())) fail(`Invalid time value: ${value}`) | |
| return date | |
| } | |
| function parseWeek(row: RawRow) { | |
| const value = cell(row, ["period_key", "week", "stat_week"]) | |
| if (!value) return undefined | |
| const match = /^(\d{4})-W(\d{1,2})$/.exec(value) | |
| if (!match) fail(`Invalid week value: ${value}`) | |
| const year = Number(match[1]) | |
| const week = Number(match[2]) | |
| if (week < 1 || week > 53) fail(`Invalid week value: ${value}`) | |
| const start = new Date(startOfIsoWeek(new Date(Date.UTC(year, 0, 4))).getTime() + (week - 1) * 7 * DAY_MS) | |
| const id = `${year}-W${String(week).padStart(2, "0")}` | |
| if (isoWeekId(start) !== id) fail(`Invalid week value: ${value}`) | |
| return id | |
| } | |
| async function readRows(file: string) { | |
| const text = await Bun.file(file).text() | |
| if (file.toLowerCase().endsWith(".json")) { | |
| const parsed: unknown = JSON.parse(text) | |
| return rowsFromJson(parsed) | |
| } | |
| return rowsFromCsv(text) | |
| } | |
| function rowsFromJson(value: unknown): RawRow[] { | |
| if (Array.isArray(value)) return value.flatMap(rowFromUnknown) | |
| if (!isRecord(value)) fail("JSON imports must be an array of rows or an object with results/data/rows") | |
| const rows = [value.results, value.data, value.rows].flatMap((candidate) => | |
| Array.isArray(candidate) ? candidate.flatMap(rowFromUnknown) : [], | |
| ) | |
| if (rows.length === 0) fail("JSON import did not contain rows") | |
| return rows | |
| } | |
| function rowFromUnknown(value: unknown): RawRow[] { | |
| if (!isRecord(value)) return [] | |
| const nested = isRecord(value.data) ? value.data : {} | |
| return [ | |
| Object.fromEntries( | |
| Object.entries({ ...value, ...nested }).flatMap(([key, item]) => { | |
| if (key === "data") return [] | |
| return [[key, cellValue(item)]] | |
| }), | |
| ), | |
| ] | |
| } | |
| function rowsFromCsv(text: string): RawRow[] { | |
| const [headers, ...rows] = csvRecords(text).filter((row) => row.some((value) => value.trim() !== "")) | |
| if (!headers) return [] | |
| return rows.map((row) => | |
| Object.fromEntries(headers.map((header, index) => [header.trim(), row[index]?.trim() ?? ""])), | |
| ) | |
| } | |
| function csvRecords(text: string) { | |
| const rows: string[][] = [] | |
| let row: string[] = [] | |
| let field = "" | |
| let quoted = false | |
| for (let index = 0; index < text.length; index++) { | |
| const char = text[index] | |
| const next = text[index + 1] | |
| if (quoted) { | |
| if (char === '"' && next === '"') { | |
| field += '"' | |
| index++ | |
| continue | |
| } | |
| if (char === '"') { | |
| quoted = false | |
| continue | |
| } | |
| field += char | |
| continue | |
| } | |
| if (char === '"') { | |
| quoted = true | |
| continue | |
| } | |
| if (char === ",") { | |
| row.push(field) | |
| field = "" | |
| continue | |
| } | |
| if (char === "\n") { | |
| row.push(field) | |
| rows.push(row) | |
| row = [] | |
| field = "" | |
| continue | |
| } | |
| if (char === "\r") continue | |
| field += char | |
| } | |
| row.push(field) | |
| rows.push(row) | |
| return rows | |
| } | |
| function cellValue(value: unknown) { | |
| if (value === null || value === undefined) return "" | |
| if (typeof value === "string") return value | |
| if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value) | |
| return JSON.stringify(value) ?? "" | |
| } | |
| function isRecord(value: unknown): value is Record<string, unknown> { | |
| return typeof value === "object" && value !== null && !Array.isArray(value) | |
| } | |
| async function upsertModelRows(db: ReturnType<typeof drizzle>, rows: ModelStatRow[], chunkSize: number) { | |
| const batches = chunks(rows, chunkSize) | |
| console.log(JSON.stringify({ table: "model_stat", batches: batches.length, chunkSize })) | |
| for (const chunk of batches) { | |
| await db | |
| .insert(modelStat) | |
| .values(chunk) | |
| .onDuplicateKeyUpdate({ | |
| set: { | |
| provider_model: inserted("provider_model"), | |
| sessions: inserted("sessions"), | |
| requests: inserted("requests"), | |
| input_tokens: inserted("input_tokens"), | |
| output_tokens: inserted("output_tokens"), | |
| reasoning_tokens: inserted("reasoning_tokens"), | |
| cache_read_tokens: inserted("cache_read_tokens"), | |
| total_tokens: inserted("total_tokens"), | |
| input_cost_microcents: inserted("input_cost_microcents"), | |
| output_cost_microcents: inserted("output_cost_microcents"), | |
| total_cost_microcents: inserted("total_cost_microcents"), | |
| avg_duration_ms: inserted("avg_duration_ms"), | |
| p50_duration_ms: inserted("p50_duration_ms"), | |
| p95_duration_ms: inserted("p95_duration_ms"), | |
| avg_ttfb_ms: inserted("avg_ttfb_ms"), | |
| p50_ttfb_ms: inserted("p50_ttfb_ms"), | |
| p95_ttfb_ms: inserted("p95_ttfb_ms"), | |
| avg_output_tps: inserted("avg_output_tps"), | |
| success_count: inserted("success_count"), | |
| error_count: inserted("error_count"), | |
| sample_count: inserted("sample_count"), | |
| rank_by_tokens: inserted("rank_by_tokens"), | |
| rank_by_requests: inserted("rank_by_requests"), | |
| rank_by_cost: inserted("rank_by_cost"), | |
| }, | |
| }) | |
| } | |
| } | |
| async function upsertProviderRows(db: ReturnType<typeof drizzle>, rows: ProviderStatRow[], chunkSize: number) { | |
| const batches = chunks(rows, chunkSize) | |
| console.log(JSON.stringify({ table: "provider_stat", batches: batches.length, chunkSize })) | |
| for (const chunk of batches) { | |
| await db | |
| .insert(providerStat) | |
| .values(chunk) | |
| .onDuplicateKeyUpdate({ | |
| set: { | |
| sessions: inserted("sessions"), | |
| requests: inserted("requests"), | |
| input_tokens: inserted("input_tokens"), | |
| output_tokens: inserted("output_tokens"), | |
| reasoning_tokens: inserted("reasoning_tokens"), | |
| cache_read_tokens: inserted("cache_read_tokens"), | |
| total_tokens: inserted("total_tokens"), | |
| input_cost_microcents: inserted("input_cost_microcents"), | |
| output_cost_microcents: inserted("output_cost_microcents"), | |
| total_cost_microcents: inserted("total_cost_microcents"), | |
| avg_duration_ms: inserted("avg_duration_ms"), | |
| p50_duration_ms: inserted("p50_duration_ms"), | |
| p95_duration_ms: inserted("p95_duration_ms"), | |
| avg_ttfb_ms: inserted("avg_ttfb_ms"), | |
| p50_ttfb_ms: inserted("p50_ttfb_ms"), | |
| p95_ttfb_ms: inserted("p95_ttfb_ms"), | |
| avg_output_tps: inserted("avg_output_tps"), | |
| success_count: inserted("success_count"), | |
| error_count: inserted("error_count"), | |
| sample_count: inserted("sample_count"), | |
| market_share_tokens: inserted("market_share_tokens"), | |
| market_share_requests: inserted("market_share_requests"), | |
| market_share_sessions: inserted("market_share_sessions"), | |
| rank_by_tokens: inserted("rank_by_tokens"), | |
| rank_by_requests: inserted("rank_by_requests"), | |
| rank_by_sessions: inserted("rank_by_sessions"), | |
| rank_by_cost: inserted("rank_by_cost"), | |
| }, | |
| }) | |
| } | |
| } | |
| async function upsertGeoRows(db: ReturnType<typeof drizzle>, rows: GeoStatRow[], chunkSize: number) { | |
| const batches = chunks(rows, chunkSize) | |
| console.log(JSON.stringify({ table: "geo_stat", batches: batches.length, chunkSize })) | |
| for (const chunk of batches) { | |
| await db | |
| .insert(geoStat) | |
| .values(chunk) | |
| .onDuplicateKeyUpdate({ | |
| set: { | |
| continent: inserted("continent"), | |
| sessions: inserted("sessions"), | |
| requests: inserted("requests"), | |
| input_tokens: inserted("input_tokens"), | |
| output_tokens: inserted("output_tokens"), | |
| reasoning_tokens: inserted("reasoning_tokens"), | |
| cache_read_tokens: inserted("cache_read_tokens"), | |
| total_tokens: inserted("total_tokens"), | |
| input_cost_microcents: inserted("input_cost_microcents"), | |
| output_cost_microcents: inserted("output_cost_microcents"), | |
| total_cost_microcents: inserted("total_cost_microcents"), | |
| avg_duration_ms: inserted("avg_duration_ms"), | |
| p50_duration_ms: inserted("p50_duration_ms"), | |
| p95_duration_ms: inserted("p95_duration_ms"), | |
| avg_ttfb_ms: inserted("avg_ttfb_ms"), | |
| p50_ttfb_ms: inserted("p50_ttfb_ms"), | |
| p95_ttfb_ms: inserted("p95_ttfb_ms"), | |
| avg_output_tps: inserted("avg_output_tps"), | |
| success_count: inserted("success_count"), | |
| error_count: inserted("error_count"), | |
| sample_count: inserted("sample_count"), | |
| market_share_tokens: inserted("market_share_tokens"), | |
| market_share_requests: inserted("market_share_requests"), | |
| market_share_sessions: inserted("market_share_sessions"), | |
| rank_by_tokens: inserted("rank_by_tokens"), | |
| rank_by_requests: inserted("rank_by_requests"), | |
| rank_by_sessions: inserted("rank_by_sessions"), | |
| rank_by_cost: inserted("rank_by_cost"), | |
| }, | |
| }) | |
| } | |
| } | |
| function parseImportOptions(args: string[]): ImportOptions { | |
| const flags = parseFlags(args) | |
| const files = inputKeys.reduce<Partial<Record<ImportKey, string[]>>>((result, key) => { | |
| const values = flags.get(key) | |
| if (!values) return result | |
| return { ...result, [key]: values } | |
| }, {}) | |
| return { | |
| dataset: flags.get("dataset")?.[0] ?? "zen", | |
| databaseUrl: flags.get("database-url")?.[0] ?? process.env.DATABASE_URL, | |
| directories: flags.get("dir") ?? flags.get("directory") ?? [], | |
| dryRun: flags.has("dry-run"), | |
| periodStart: parseDateFlag(flags, "period-start"), | |
| upsertChunkSize: parseIntegerFlag(flags, "upsert-chunk-size") ?? DEFAULT_UPSERT_CHUNK_SIZE, | |
| files, | |
| } | |
| } | |
| function parseFlags(args: string[]) { | |
| const result = new Map<string, string[]>() | |
| for (let index = 0; index < args.length; index++) { | |
| const arg = args[index] | |
| if (!arg.startsWith("--")) fail(`Unexpected argument: ${arg}`) | |
| const name = arg.slice(2) | |
| if (name === "dry-run" || name === "include-weekly") { | |
| result.set(name, ["true"]) | |
| continue | |
| } | |
| const nextFlag = args.findIndex((value, valueIndex) => valueIndex > index && value.startsWith("--")) | |
| const values = args.slice(index + 1, nextFlag === -1 ? args.length : nextFlag) | |
| if (values.length === 0) fail(`Missing value for --${name}`) | |
| result.set(name, [...(result.get(name) ?? []), ...values]) | |
| index += values.length | |
| } | |
| return result | |
| } | |
| function parseDateFlag(flags: Map<string, string[]>, name: string) { | |
| const value = flags.get(name)?.[0] | |
| if (!value) return undefined | |
| const date = new Date(value) | |
| if (Number.isNaN(date.getTime())) fail(`Invalid --${name}: ${value}`) | |
| return date | |
| } | |
| function parseIntegerFlag(flags: Map<string, string[]>, name: string) { | |
| const value = flags.get(name)?.[0] | |
| if (!value) return undefined | |
| const parsed = Number(value) | |
| if (!Number.isInteger(parsed) || parsed <= 0) fail(`Invalid --${name}: ${value}`) | |
| return parsed | |
| } | |
| function parseListFlag(flags: Map<string, string[]>, name: string) { | |
| const value = flags.get(name)?.[0] | |
| if (!value) return undefined | |
| if (value === "all") return ["all"] | |
| return value | |
| .split(",") | |
| .map((item) => item.trim()) | |
| .filter(Boolean) | |
| } | |
| function usage(): never { | |
| fail(`Usage: | |
| bun src/honeycomb-backfill.ts queries [--tiers Go,Free,Paid] [--limit 1000] | |
| bun src/honeycomb-backfill.ts import [--dry-run] [--upsert-chunk-size 100] [--database-url URL] --dir downloads | |
| bun src/honeycomb-backfill.ts import [--dry-run] [--upsert-chunk-size 100] [--database-url URL] --model-day file.csv [--model-day more.csv] ...`) | |
| } | |
| function fail(message: string): never { | |
| console.error(message) | |
| process.exit(1) | |
| } | |
Xet Storage Details
- Size:
- 35 kB
- Xet hash:
- df4e8f3c183e651cd1d19c853950e0f69ef93004a99003e1a01440758932ae26
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.