Merge pull request #20462 from BerriAI/litellm_model_info_cost

[Fix] UI - Model Info Page: Fix Input and Output Labels
This commit is contained in:
yuneng-jiang
2026-02-06 12:34:34 -08:00
committed by GitHub
2 changed files with 416 additions and 155 deletions
@@ -1,59 +1,36 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render, waitFor } from "@testing-library/react";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React, { ReactNode } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import ModelInfoView from "./model_info_view";
import NotificationsManager from "./molecules/notifications_manager";
import * as networking from "./networking";
vi.mock("../../utils/dataUtils", () => ({
copyToClipboard: vi.fn().mockResolvedValue(true),
}));
vi.mock("./molecules/notifications_manager", () => ({
default: {
success: vi.fn(),
error: vi.fn(),
info: vi.fn(),
fromBackend: vi.fn(),
},
}));
vi.mock("./networking", () => ({
modelInfoV1Call: vi.fn().mockResolvedValue({
data: [
{
model_name: "GPT-4",
litellm_params: {
model: "gpt-4",
api_base: "https://api.openai.com/v1",
custom_llm_provider: "openai",
},
model_info: {
id: "123",
created_by: "123",
db_model: true,
input_cost_per_token: 0.00003,
output_cost_per_token: 0.00006,
},
},
],
}),
credentialGetCall: vi.fn().mockResolvedValue({
credential_name: "test-credential",
credential_values: {},
credential_info: {},
}),
getGuardrailsList: vi.fn().mockResolvedValue({
guardrails: [{ guardrail_name: "content_filter" }, { guardrail_name: "toxicity_filter" }],
}),
tagListCall: vi.fn().mockResolvedValue({
test_tag: {
name: "test_tag",
description: "A test tag",
},
production_tag: {
name: "production_tag",
description: "Production ready models",
},
}),
testConnectionRequest: vi.fn().mockResolvedValue({
status: "success",
}),
modelPatchUpdateCall: vi.fn().mockResolvedValue({}),
modelDeleteCall: vi.fn().mockResolvedValue({}),
modelInfoV1Call: vi.fn(),
credentialGetCall: vi.fn(),
getGuardrailsList: vi.fn(),
tagListCall: vi.fn(),
testConnectionRequest: vi.fn(),
modelPatchUpdateCall: vi.fn(),
modelDeleteCall: vi.fn(),
credentialCreateCall: vi.fn(),
}));
// Mock the useModelsInfo hook since it uses React Query
const mockUseModelsInfo = vi.fn();
const mockUseModelHub = vi.fn();
@@ -62,12 +39,21 @@ vi.mock("@/app/(dashboard)/hooks/models/useModels", () => ({
useModelHub: (...args: any[]) => mockUseModelHub(...args),
}));
// Mock the useModelCostMap hook
const mockUseModelCostMap = vi.fn();
vi.mock("@/app/(dashboard)/hooks/models/useModelCostMap", () => ({
useModelCostMap: (...args: any[]) => mockUseModelCostMap(...args),
}));
const mockNotificationsManager = vi.mocked(NotificationsManager);
const mockModelInfoV1Call = vi.mocked(networking.modelInfoV1Call);
const mockCredentialGetCall = vi.mocked(networking.credentialGetCall);
const mockGetGuardrailsList = vi.mocked(networking.getGuardrailsList);
const mockTagListCall = vi.mocked(networking.tagListCall);
const mockTestConnectionRequest = vi.mocked(networking.testConnectionRequest);
const mockModelPatchUpdateCall = vi.mocked(networking.modelPatchUpdateCall);
const mockModelDeleteCall = vi.mocked(networking.modelDeleteCall);
const mockCredentialCreateCall = vi.mocked(networking.credentialCreateCall);
describe("ModelInfoView", () => {
let queryClient: QueryClient;
@@ -88,6 +74,16 @@ describe("ModelInfoView", () => {
},
};
const DEFAULT_ADMIN_PROPS = {
modelId: "123",
onClose: vi.fn(),
accessToken: "test-token",
userID: "123",
userRole: "Admin",
onModelUpdate: vi.fn(),
modelAccessGroups: ["group1", "group2"],
};
beforeEach(() => {
queryClient = new QueryClient({
defaultOptions: {
@@ -98,7 +94,6 @@ describe("ModelInfoView", () => {
});
vi.clearAllMocks();
// Set up default mocks
mockUseModelsInfo.mockReturnValue({
data: {
data: [defaultModelData],
@@ -120,89 +115,170 @@ describe("ModelInfoView", () => {
isLoading: false,
error: null,
});
mockModelInfoV1Call.mockResolvedValue({
data: [defaultModelData],
});
mockCredentialGetCall.mockResolvedValue({
credential_name: "test-credential",
credential_values: {},
credential_info: {},
});
mockGetGuardrailsList.mockResolvedValue({
guardrails: [{ guardrail_name: "content_filter" }, { guardrail_name: "toxicity_filter" }],
});
mockTagListCall.mockResolvedValue({
test_tag: {
name: "test_tag",
description: "A test tag",
models: [],
created_at: "2024-01-01T00:00:00Z",
updated_at: "2024-01-01T00:00:00Z",
},
production_tag: {
name: "production_tag",
description: "Production ready models",
models: [],
created_at: "2024-01-01T00:00:00Z",
updated_at: "2024-01-01T00:00:00Z",
},
});
mockTestConnectionRequest.mockResolvedValue({
status: "success",
});
mockModelPatchUpdateCall.mockResolvedValue({});
mockModelDeleteCall.mockResolvedValue({});
mockCredentialCreateCall.mockResolvedValue({});
});
const wrapper = ({ children }: { children: ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
const DEFAULT_ADMIN_PROPS = {
modelId: "123",
onClose: () => {},
accessToken: "123",
userID: "123",
userRole: "Admin",
onModelUpdate: () => {},
modelAccessGroups: [],
};
describe("Edit Model", () => {
it("should render the model info view", async () => {
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("Model Settings")).toBeInTheDocument();
});
});
it("should not render an edit settings button if the model is not a DB model", async () => {
const nonDbModelData = {
...defaultModelData,
model_info: {
...defaultModelData.model_info,
db_model: false,
},
};
mockUseModelsInfo.mockReturnValue({
data: {
data: [nonDbModelData],
},
isLoading: false,
error: null,
});
const { queryByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(queryByText("Edit Settings")).not.toBeInTheDocument();
});
});
it("should render tags in the edit model", async () => {
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("Tags")).toBeInTheDocument();
});
});
it("should render the litellm params in the edit model", async () => {
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("LiteLLM Params")).toBeInTheDocument();
});
});
});
it("should render a test connection button", async () => {
const { getByTestId } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
it("should render", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByTestId("test-connection-button")).toBeInTheDocument();
expect(screen.getByText("Model Settings")).toBeInTheDocument();
});
});
it("should render a reuse credentials button", async () => {
const { getByTestId } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
it("should display loading state when model data is loading", () => {
mockUseModelsInfo.mockReturnValue({
data: null,
isLoading: true,
error: null,
});
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
expect(screen.getByText("Loading...")).toBeInTheDocument();
});
it("should display not found message when model data is not available", async () => {
mockUseModelsInfo.mockReturnValue({
data: {
data: [],
},
isLoading: false,
error: null,
});
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByTestId("reuse-credentials-button")).toBeInTheDocument();
expect(screen.getByText("Model not found")).toBeInTheDocument();
});
});
it("should render a delete model button", async () => {
const { getByTestId } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
it("should display model name in the header", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByTestId("delete-model-button")).toBeInTheDocument();
expect(screen.getByText(/Public Model Name:/)).toBeInTheDocument();
});
});
it("should render a disabled delete model button if the model is not a DB model", async () => {
it("should display back button that calls onClose when clicked", async () => {
const mockOnClose = vi.fn();
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} onClose={mockOnClose} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Model Settings")).toBeInTheDocument();
});
const backButton = screen.getByRole("button", { name: /back to models/i });
await user.click(backButton);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it("should display test connection button", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /test connection/i })).toBeInTheDocument();
});
});
it("should test connection when test connection button is clicked", async () => {
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Model Settings")).toBeInTheDocument();
});
const testButton = screen.getByRole("button", { name: /test connection/i });
await user.click(testButton);
await waitFor(() => {
expect(mockTestConnectionRequest).toHaveBeenCalled();
expect(mockNotificationsManager.success).toHaveBeenCalledWith("Connection test successful!");
});
});
it("should display error notification when connection test fails", async () => {
const user = userEvent.setup();
mockTestConnectionRequest.mockRejectedValue(new Error("Connection failed"));
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Model Settings")).toBeInTheDocument();
});
const testButton = screen.getByRole("button", { name: /test connection/i });
await user.click(testButton);
await waitFor(() => {
expect(mockNotificationsManager.error).toHaveBeenCalled();
});
});
it("should display reuse credentials button for admin users", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /re-use credentials/i })).toBeInTheDocument();
});
});
it("should disable reuse credentials button for non-admin users", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} userRole="User" />, { wrapper });
await waitFor(() => {
const button = screen.getByRole("button", { name: /re-use credentials/i });
expect(button).toBeDisabled();
});
});
it("should display delete model button", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /delete model/i })).toBeInTheDocument();
});
});
it("should disable delete button when model is not a DB model", async () => {
const nonDbModelData = {
...defaultModelData,
model_info: {
@@ -219,13 +295,14 @@ describe("ModelInfoView", () => {
error: null,
});
const { getByTestId } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByTestId("delete-model-button")).toBeDisabled();
const deleteButton = screen.getByRole("button", { name: /delete model/i });
expect(deleteButton).toBeDisabled();
});
});
it("should render a disabled delete model button if the user is not an admin and model is not created by the user", async () => {
it("should disable delete button when user is not admin and did not create the model", async () => {
const nonCreatedByUserModelData = {
...defaultModelData,
model_info: {
@@ -242,18 +319,177 @@ describe("ModelInfoView", () => {
error: null,
});
const NON_CREATED_BY_USER_ADMIN_PROPS = {
...DEFAULT_ADMIN_PROPS,
userRole: "User",
};
const { getByTestId } = render(<ModelInfoView {...NON_CREATED_BY_USER_ADMIN_PROPS} />, { wrapper });
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} userRole="User" />, { wrapper });
await waitFor(() => {
expect(getByTestId("delete-model-button")).toBeDisabled();
const deleteButton = screen.getByRole("button", { name: /delete model/i });
expect(deleteButton).toBeDisabled();
});
});
it("should render health check model field for wildcard routes", async () => {
it("should display overview and raw JSON tabs", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("tab", { name: /overview/i })).toBeInTheDocument();
expect(screen.getByRole("tab", { name: /raw json/i })).toBeInTheDocument();
});
});
it("should display model information in overview tab", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Provider")).toBeInTheDocument();
expect(screen.getByText("LiteLLM Model")).toBeInTheDocument();
expect(screen.getByText("Pricing")).toBeInTheDocument();
});
});
it("should display edit settings button when user can edit model", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
});
it("should not display edit settings button when model is not a DB model", async () => {
const nonDbModelData = {
...defaultModelData,
model_info: {
...defaultModelData.model_info,
db_model: false,
},
};
mockUseModelsInfo.mockReturnValue({
data: {
data: [nonDbModelData],
},
isLoading: false,
error: null,
});
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.queryByRole("button", { name: /edit settings/i })).not.toBeInTheDocument();
});
});
it("should enter edit mode when edit settings button is clicked", async () => {
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
const editButton = screen.getByRole("button", { name: /edit settings/i });
await user.click(editButton);
await waitFor(() => {
expect(screen.getByRole("button", { name: /save changes/i })).toBeInTheDocument();
expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
});
});
it("should display form fields in edit mode", async () => {
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
const editButton = screen.getByRole("button", { name: /edit settings/i });
await user.click(editButton);
await waitFor(() => {
expect(screen.getByPlaceholderText("Enter model name")).toBeInTheDocument();
expect(screen.getByPlaceholderText("Enter LiteLLM model name")).toBeInTheDocument();
});
});
it("should allow editing model name in edit mode", async () => {
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
const editButton = screen.getByRole("button", { name: /edit settings/i });
await user.click(editButton);
const modelNameInput = await screen.findByPlaceholderText("Enter model name");
await user.clear(modelNameInput);
await user.type(modelNameInput, "Updated Model Name");
expect(modelNameInput).toHaveValue("Updated Model Name");
});
it("should cancel editing when cancel button is clicked", async () => {
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
const editButton = screen.getByRole("button", { name: /edit settings/i });
await user.click(editButton);
await waitFor(() => {
expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
});
const cancelButton = screen.getByRole("button", { name: /cancel/i });
await user.click(cancelButton);
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
expect(screen.queryByRole("button", { name: /save changes/i })).not.toBeInTheDocument();
});
});
it("should save model changes when save button is clicked", async () => {
const user = userEvent.setup();
const mockOnModelUpdate = vi.fn();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} onModelUpdate={mockOnModelUpdate} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
const editButton = screen.getByRole("button", { name: /edit settings/i });
await user.click(editButton);
await waitFor(() => {
expect(screen.getByRole("button", { name: /save changes/i })).toBeInTheDocument();
});
const saveButton = screen.getByRole("button", { name: /save changes/i });
await user.click(saveButton);
await waitFor(() => {
expect(mockModelPatchUpdateCall).toHaveBeenCalled();
expect(mockNotificationsManager.success).toHaveBeenCalledWith("Model settings updated successfully");
expect(mockOnModelUpdate).toHaveBeenCalled();
});
});
it("should display tags section", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Tags")).toBeInTheDocument();
});
});
it("should display LiteLLM Params section", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("LiteLLM Params")).toBeInTheDocument();
});
});
it("should display health check model field for wildcard models", async () => {
const wildcardModelData = {
...defaultModelData,
litellm_params: {
@@ -270,38 +506,71 @@ describe("ModelInfoView", () => {
error: null,
});
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("Model Settings")).toBeInTheDocument();
});
await waitFor(() => {
expect(getByText("Health Check Model")).toBeInTheDocument();
expect(screen.getByText("Health Check Model")).toBeInTheDocument();
});
});
it("should not render health check model field for non-wildcard routes", async () => {
const { queryByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
it("should not display health check model field for non-wildcard models", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(queryByText("Model Settings")).toBeInTheDocument();
});
await waitFor(() => {
expect(queryByText("Health Check Model")).not.toBeInTheDocument();
expect(screen.getByText("Model Settings")).toBeInTheDocument();
expect(screen.queryByText("Health Check Model")).not.toBeInTheDocument();
});
});
describe("View Model", () => {
it("should render the model info view", async () => {
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("Model Settings")).toBeInTheDocument();
});
it("should display edit auto router button for auto router models", async () => {
const autoRouterModelData = {
...defaultModelData,
litellm_params: {
...defaultModelData.litellm_params,
auto_router_config: {},
},
};
mockUseModelsInfo.mockReturnValue({
data: {
data: [autoRouterModelData],
},
isLoading: false,
error: null,
});
it("should render tags in the view model", async () => {
const { getByText } = render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(getByText("Tags")).toBeInTheDocument();
});
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit auto router/i })).toBeInTheDocument();
});
});
it("should display model access groups field", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Model Access Groups")).toBeInTheDocument();
});
});
it("should display guardrails field", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText("Guardrails")).toBeInTheDocument();
});
});
it("should display pricing information", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText(/Input:/)).toBeInTheDocument();
expect(screen.getByText(/Output:/)).toBeInTheDocument();
});
});
it("should display created at and created by information", async () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByText(/Created At/)).toBeInTheDocument();
expect(screen.getByText(/Created By/)).toBeInTheDocument();
});
});
});
@@ -136,11 +136,9 @@ export default function ModelInfoView({
useEffect(() => {
const getExistingCredential = async () => {
console.log("accessToken, ", accessToken);
if (!accessToken) return;
if (usingExistingCredential) return;
let existingCredentialResponse = await credentialGetCall(accessToken, null, modelId);
console.log("existingCredentialResponse, ", existingCredentialResponse);
setExistingCredential({
credential_name: existingCredentialResponse["credential_name"],
credential_values: existingCredentialResponse["credential_values"],
@@ -153,7 +151,6 @@ export default function ModelInfoView({
// Only fetch if we don't have modelData yet
if (modelData) return;
let modelInfoResponse = await modelInfoV1Call(accessToken, modelId);
console.log("modelInfoResponse, ", modelInfoResponse);
let specificModelData = modelInfoResponse.data[0];
if (specificModelData && !specificModelData.litellm_model_name) {
specificModelData = {
@@ -201,7 +198,6 @@ export default function ModelInfoView({
}, [accessToken, modelId]);
const handleReuseCredential = async (values: any) => {
console.log("values, ", values);
if (!accessToken) return;
let credentialItem = {
credential_name: values.credential_name,
@@ -212,7 +208,6 @@ export default function ModelInfoView({
};
NotificationsManager.info("Storing credential..");
let credentialResponse = await credentialCreateCall(accessToken, credentialItem);
console.log("credentialResponse, ", credentialResponse);
NotificationsManager.success("Credential stored successfully");
};
@@ -221,8 +216,6 @@ export default function ModelInfoView({
if (!accessToken) return;
setIsSaving(true);
console.log("values.model_name, ", values.model_name);
// Parse LiteLLM extra params from JSON text area
let parsedExtraParams: Record<string, any> = {};
try {
@@ -412,7 +405,6 @@ export default function ModelInfoView({
}
};
const isWildcardModel = modelData.litellm_model_name.includes("*");
console.log("isWildcardModel, ", isWildcardModel);
return (
<div className="p-4">
@@ -657,7 +649,7 @@ export default function ModelInfoView({
? (localModelData.litellm_params?.input_cost_per_token * 1_000_000).toFixed(4)
: localModelData?.model_info?.input_cost_per_token
? (localModelData.model_info.input_cost_per_token * 1_000_000).toFixed(4)
: null}
: "Not Set"}
</div>
)}
</div>
@@ -674,7 +666,7 @@ export default function ModelInfoView({
? (localModelData.litellm_params.output_cost_per_token * 1_000_000).toFixed(4)
: localModelData?.model_info?.output_cost_per_token
? (localModelData.model_info.output_cost_per_token * 1_000_000).toFixed(4)
: null}
: "Not Set"}
</div>
)}
</div>