mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 17:52:31 +03:00
* fix(usage): reset logs and show provider names in analytics * refactor(db): extract usage purge routines to cleanup module (file-size cap) Move the generic delete-all/delete-before-cutoff table helpers and the call-log-artifact purge helpers out of cleanup.ts into a new cleanup/usagePurge.ts submodule, so this PR's growth in cleanup.ts stays under the file-size gate cap once combined with other in-flight changes to the same file. Pure extraction — resetUsageHistory delegates to the same logic, now imported instead of inlined; no behavior change. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(db): hoist reset targets table + derive total via reduce (max-lines-per-function) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * refactor(api): move analytics provider-name enrichment into lib (file-size cap) src/app/api/usage/analytics/route.ts is a frozen file-size-capped file (baseline: 942 lines, zero headroom on this branch). The provider display-name enrichment added for the byProvider breakdown (id -> name/ prefix lookup via provider_nodes) pushed it to 971 lines, tripping the check:file-size ratchet. Move the new getProviderDisplayName/getProviderDisplayNames helpers, plus the byProvider row-building they modified, into a new leaf module src/lib/usage/providerDisplayNames.ts (buildByProviderRows). The route now just imports and calls it. No behavior change: same lookup, same fallback to the raw provider id, same row shape. Net effect: route.ts drops from 941 (pre-change) to 930 lines (-11), comfortably restoring headroom instead of exceeding the frozen cap. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(usage): fall back to static catalog name in provider display resolution Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
89 lines
3.0 KiB
TypeScript
89 lines
3.0 KiB
TypeScript
/**
|
|
* Provider display-name resolution for the usage analytics `byProvider`
|
|
* breakdown (`src/app/api/usage/analytics/route.ts`).
|
|
*
|
|
* Raw `usage_history.provider` values are internal provider ids (e.g. a
|
|
* dynamic compatible-provider uuid-suffixed id). This module maps those ids
|
|
* to the friendly `name`/`prefix` configured on the matching `provider_nodes`
|
|
* row, falling back to the raw id when no node matches, so analytics rows
|
|
* show a readable label instead of an internal id.
|
|
*
|
|
* @module lib/usage/providerDisplayNames
|
|
*/
|
|
import { getProviderNodes } from "@/models";
|
|
import { getProviderById } from "@/shared/constants/providers";
|
|
|
|
function toStringValue(value: unknown, fallback = ""): string {
|
|
return typeof value === "string" && value.trim().length > 0 ? value : fallback;
|
|
}
|
|
|
|
function roundCost(value: number): number {
|
|
return Math.round(value * 1_000_000) / 1_000_000;
|
|
}
|
|
|
|
function getProviderDisplayName(
|
|
provider: unknown,
|
|
providerDisplayNames: Map<string, string>
|
|
): string {
|
|
const rawProvider = toStringValue(provider, "unknown");
|
|
// Configured node name wins; static catalog covers built-ins (e.g. codex →
|
|
// "OpenAI Codex") the nodes table doesn't know about; raw id is the last resort.
|
|
return (
|
|
providerDisplayNames.get(rawProvider) || getProviderById(rawProvider)?.name || rawProvider
|
|
);
|
|
}
|
|
|
|
async function getProviderDisplayNames(): Promise<Map<string, string>> {
|
|
const displayNames = new Map<string, string>();
|
|
const providerNodes = (await getProviderNodes()) as Array<{
|
|
id?: unknown;
|
|
name?: unknown;
|
|
prefix?: unknown;
|
|
}>;
|
|
|
|
for (const node of providerNodes) {
|
|
const id = toStringValue(node.id);
|
|
if (!id) continue;
|
|
|
|
const displayName = toStringValue(node.name) || toStringValue(node.prefix) || id;
|
|
displayNames.set(id, displayName);
|
|
}
|
|
|
|
return displayNames;
|
|
}
|
|
|
|
export interface ByProviderRow {
|
|
provider: string;
|
|
requests: number;
|
|
promptTokens: number;
|
|
completionTokens: number;
|
|
totalTokens: number;
|
|
avgLatencyMs: number;
|
|
successRatePct: number | string;
|
|
cost: number;
|
|
}
|
|
|
|
/**
|
|
* Builds the `byProvider` analytics rows, resolving each row's raw provider
|
|
* id to its configured display name.
|
|
*/
|
|
export async function buildByProviderRows(
|
|
providerRows: Array<Record<string, unknown>>,
|
|
providerCostByProvider: Map<string, number>
|
|
): Promise<ByProviderRow[]> {
|
|
const providerDisplayNames = await getProviderDisplayNames();
|
|
return providerRows.map((row) => ({
|
|
provider: getProviderDisplayName(row.provider, providerDisplayNames),
|
|
requests: Number(row.requests),
|
|
promptTokens: Number(row.promptTokens),
|
|
completionTokens: Number(row.completionTokens),
|
|
totalTokens: Number(row.totalTokens),
|
|
avgLatencyMs: Math.round(Number(row.avgLatencyMs)),
|
|
successRatePct:
|
|
Number(row.requests) > 0
|
|
? Number((Number(row.successfulRequests) / Number(row.requests)) * 100).toFixed(2)
|
|
: 0,
|
|
cost: roundCost(providerCostByProvider.get(toStringValue(row.provider)) || 0),
|
|
}));
|
|
}
|