mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
refactor(ui): build transformed model rows without in-place mutation
Greptile flagged the per-second fields for extending the transformer's mutate-in-a-loop pattern. Map each raw model to a new object instead so no field is assigned onto a shared reference, and drop the now unused prefer-const suppression for the file
This commit is contained in:
parent
dfc74d3806
commit
a282e3c78c
2 changed files with 60 additions and 80 deletions
|
|
@ -656,11 +656,6 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/app/(dashboard)/models-and-endpoints/utils/modelDataTransformer.ts": {
|
||||
"prefer-const": {
|
||||
"count": 6
|
||||
}
|
||||
},
|
||||
"src/app/(dashboard)/old-usage/_components/usage.tsx": {
|
||||
"local/filename-pascal-case": {
|
||||
"count": 1
|
||||
|
|
|
|||
|
|
@ -11,82 +11,67 @@ export const perSecondCostTiers = (modelInfo: Record<string, unknown> | null | u
|
|||
export const formatPerSecondCost = (cost: number): string =>
|
||||
`$${cost.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 6 })}/s`;
|
||||
|
||||
/**
|
||||
* Utility function to transform raw model data into the format expected by UI components
|
||||
* This creates a new transformed data object without mutating the original
|
||||
*/
|
||||
interface RawLitellmParams {
|
||||
model?: string;
|
||||
custom_llm_provider?: string;
|
||||
api_base?: string;
|
||||
output_cost_per_second?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface RawModelInfo {
|
||||
input_cost_per_token?: number | null;
|
||||
output_cost_per_token?: number | null;
|
||||
output_cost_per_second?: number;
|
||||
max_tokens?: number;
|
||||
max_input_tokens?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface RawModel {
|
||||
litellm_params?: RawLitellmParams;
|
||||
model_info?: RawModelInfo;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const costPerMillionTokens = (costPerToken: number | null | undefined) =>
|
||||
costPerToken == null ? costPerToken : (Number(costPerToken) * 1000000).toFixed(2);
|
||||
|
||||
const resolveProvider = (
|
||||
litellmModelName: string | null | undefined,
|
||||
customLlmProvider: string | null | undefined,
|
||||
getProviderFromModel: (model: string) => string,
|
||||
): string => {
|
||||
if (!litellmModelName) return "-";
|
||||
if (customLlmProvider) return customLlmProvider;
|
||||
const splitModel = litellmModelName.split("/");
|
||||
return splitModel.length === 1 ? getProviderFromModel(litellmModelName) : splitModel[0];
|
||||
};
|
||||
|
||||
const transformModel = (rawModel: RawModel, getProviderFromModel: (model: string) => string) => {
|
||||
const model: RawModel = JSON.parse(JSON.stringify(rawModel));
|
||||
const litellmParams = model?.litellm_params;
|
||||
const modelInfo = model?.model_info;
|
||||
|
||||
return {
|
||||
...model,
|
||||
provider: resolveProvider(litellmParams?.model, litellmParams?.custom_llm_provider, getProviderFromModel),
|
||||
input_cost: modelInfo ? costPerMillionTokens(modelInfo.input_cost_per_token) : null,
|
||||
output_cost: modelInfo ? costPerMillionTokens(modelInfo.output_cost_per_token) : null,
|
||||
output_cost_per_second: litellmParams?.output_cost_per_second ?? modelInfo?.output_cost_per_second ?? null,
|
||||
output_cost_per_second_tiers: perSecondCostTiers(modelInfo),
|
||||
litellm_model_name: litellmParams?.model,
|
||||
max_tokens: modelInfo ? modelInfo.max_tokens : "Undefined",
|
||||
max_input_tokens: modelInfo ? modelInfo.max_input_tokens : "Undefined",
|
||||
api_base: litellmParams?.api_base,
|
||||
cleanedLitellmParams: Object.fromEntries(
|
||||
Object.entries(litellmParams ?? {}).filter(([key]) => key !== "model" && key !== "api_base"),
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
export const transformModelData = (rawModelData: any, getProviderFromModel: (model: string) => string) => {
|
||||
if (!rawModelData?.data) return { data: [] };
|
||||
|
||||
// Deep copy the data to avoid mutating the original
|
||||
const transformedData = JSON.parse(JSON.stringify(rawModelData.data));
|
||||
|
||||
for (let i = 0; i < transformedData.length; i++) {
|
||||
let curr_model = transformedData[i];
|
||||
let litellm_model_name = curr_model?.litellm_params?.model;
|
||||
let custom_llm_provider = curr_model?.litellm_params?.custom_llm_provider;
|
||||
let model_info = curr_model?.model_info;
|
||||
|
||||
let provider = "";
|
||||
let input_cost: any = null;
|
||||
let output_cost: any = null;
|
||||
let max_tokens = "Undefined";
|
||||
let max_input_tokens = "Undefined";
|
||||
let cleanedLitellmParams = {};
|
||||
|
||||
// Check if litellm_model_name is null or undefined
|
||||
if (litellm_model_name) {
|
||||
// Split litellm_model_name based on "/"
|
||||
let splitModel = litellm_model_name.split("/");
|
||||
|
||||
// Get the first element in the split
|
||||
let firstElement = splitModel[0];
|
||||
|
||||
// If there is only one element, default provider to openai
|
||||
provider = custom_llm_provider;
|
||||
if (!provider) {
|
||||
provider = splitModel.length === 1 ? getProviderFromModel(litellm_model_name) : firstElement;
|
||||
}
|
||||
} else {
|
||||
// litellm_model_name is null or undefined, default provider to openai
|
||||
provider = "-";
|
||||
}
|
||||
|
||||
if (model_info) {
|
||||
input_cost = model_info?.input_cost_per_token;
|
||||
output_cost = model_info?.output_cost_per_token;
|
||||
max_tokens = model_info?.max_tokens;
|
||||
max_input_tokens = model_info?.max_input_tokens;
|
||||
}
|
||||
|
||||
if (curr_model?.litellm_params) {
|
||||
cleanedLitellmParams = Object.fromEntries(
|
||||
Object.entries(curr_model?.litellm_params).filter(([key]) => key !== "model" && key !== "api_base"),
|
||||
);
|
||||
}
|
||||
|
||||
transformedData[i].provider = provider;
|
||||
transformedData[i].input_cost = input_cost;
|
||||
transformedData[i].output_cost = output_cost;
|
||||
transformedData[i].output_cost_per_second =
|
||||
curr_model?.litellm_params?.output_cost_per_second ?? model_info?.output_cost_per_second ?? null;
|
||||
transformedData[i].output_cost_per_second_tiers = perSecondCostTiers(model_info);
|
||||
transformedData[i].litellm_model_name = litellm_model_name;
|
||||
|
||||
// Convert Cost in terms of Cost per 1M tokens
|
||||
if (transformedData[i].input_cost != null) {
|
||||
transformedData[i].input_cost = (Number(transformedData[i].input_cost) * 1000000).toFixed(2);
|
||||
}
|
||||
|
||||
if (transformedData[i].output_cost != null) {
|
||||
transformedData[i].output_cost = (Number(transformedData[i].output_cost) * 1000000).toFixed(2);
|
||||
}
|
||||
|
||||
transformedData[i].max_tokens = max_tokens;
|
||||
transformedData[i].max_input_tokens = max_input_tokens;
|
||||
transformedData[i].api_base = curr_model?.litellm_params?.api_base;
|
||||
transformedData[i].cleanedLitellmParams = cleanedLitellmParams;
|
||||
}
|
||||
|
||||
return { data: transformedData };
|
||||
return { data: rawModelData.data.map((rawModel: RawModel) => transformModel(rawModel, getProviderFromModel)) };
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue