mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): i18n for cost tracking utils and hooks
This commit is contained in:
parent
65f3306f46
commit
08f5303270
6 changed files with 231 additions and 69 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import i18n from "@/lib/i18n";
|
||||
import { CostEstimateResponse } from "../types";
|
||||
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
||||
import { MultiModelResult } from "./types";
|
||||
|
|
@ -16,44 +17,45 @@ const formatRequestsForExport = (value: number | null | undefined): string => {
|
|||
};
|
||||
|
||||
const generateModelSection = (result: CostEstimateResponse): string => {
|
||||
const t = i18n.t.bind(i18n);
|
||||
return `
|
||||
<div class="model-section">
|
||||
<h3>${result.model} ${result.provider ? `<span class="provider">(${result.provider})</span>` : ""}</h3>
|
||||
|
||||
|
||||
<div class="meta">
|
||||
<p><strong>Input Tokens per Request:</strong> ${formatRequestsForExport(result.input_tokens)}</p>
|
||||
<p><strong>Output Tokens per Request:</strong> ${formatRequestsForExport(result.output_tokens)}</p>
|
||||
${result.num_requests_per_day ? `<p><strong>Requests per Day:</strong> ${formatRequestsForExport(result.num_requests_per_day)}</p>` : ""}
|
||||
${result.num_requests_per_month ? `<p><strong>Requests per Month:</strong> ${formatRequestsForExport(result.num_requests_per_month)}</p>` : ""}
|
||||
<p><strong>${t("costTracking.multiExportUtils.inputTokensPerRequest")}</strong> ${formatRequestsForExport(result.input_tokens)}</p>
|
||||
<p><strong>${t("costTracking.multiExportUtils.outputTokensPerRequest")}</strong> ${formatRequestsForExport(result.output_tokens)}</p>
|
||||
${result.num_requests_per_day ? `<p><strong>${t("costTracking.multiExportUtils.requestsPerDay")}</strong> ${formatRequestsForExport(result.num_requests_per_day)}</p>` : ""}
|
||||
${result.num_requests_per_month ? `<p><strong>${t("costTracking.multiExportUtils.requestsPerMonth")}</strong> ${formatRequestsForExport(result.num_requests_per_month)}</p>` : ""}
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Cost Type</th>
|
||||
<th>Per Request</th>
|
||||
${result.daily_cost !== null ? "<th>Daily</th>" : ""}
|
||||
${result.monthly_cost !== null ? "<th>Monthly</th>" : ""}
|
||||
<th>${t("costTracking.multiExportUtils.colCostType")}</th>
|
||||
<th>${t("costTracking.multiExportUtils.colPerRequest")}</th>
|
||||
${result.daily_cost !== null ? `<th>${t("costTracking.multiExportUtils.colDaily")}</th>` : ""}
|
||||
${result.monthly_cost !== null ? `<th>${t("costTracking.multiExportUtils.colMonthly")}</th>` : ""}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Input Cost</td>
|
||||
<td>${t("costTracking.multiExportUtils.inputCost")}</td>
|
||||
<td class="cost-value">${formatCostForExport(result.input_cost_per_request)}</td>
|
||||
${result.daily_cost !== null ? `<td class="cost-value">${formatCostForExport(result.daily_input_cost)}</td>` : ""}
|
||||
${result.monthly_cost !== null ? `<td class="cost-value">${formatCostForExport(result.monthly_input_cost)}</td>` : ""}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Output Cost</td>
|
||||
<td>${t("costTracking.multiExportUtils.outputCost")}</td>
|
||||
<td class="cost-value">${formatCostForExport(result.output_cost_per_request)}</td>
|
||||
${result.daily_cost !== null ? `<td class="cost-value">${formatCostForExport(result.daily_output_cost)}</td>` : ""}
|
||||
${result.monthly_cost !== null ? `<td class="cost-value">${formatCostForExport(result.monthly_output_cost)}</td>` : ""}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Margin/Fee</td>
|
||||
<td>${t("costTracking.multiExportUtils.marginFee")}</td>
|
||||
<td class="cost-value">${formatCostForExport(result.margin_cost_per_request)}</td>
|
||||
${result.daily_cost !== null ? `<td class="cost-value">${formatCostForExport(result.daily_margin_cost)}</td>` : ""}
|
||||
${result.monthly_cost !== null ? `<td class="cost-value">${formatCostForExport(result.monthly_margin_cost)}</td>` : ""}
|
||||
</tr>
|
||||
<tr class="total-row">
|
||||
<td>Total</td>
|
||||
<td>${t("common.total")}</td>
|
||||
<td class="cost-value">${formatCostForExport(result.cost_per_request)}</td>
|
||||
${result.daily_cost !== null ? `<td class="cost-value">${formatCostForExport(result.daily_cost)}</td>` : ""}
|
||||
${result.monthly_cost !== null ? `<td class="cost-value">${formatCostForExport(result.monthly_cost)}</td>` : ""}
|
||||
|
|
@ -64,9 +66,10 @@ const generateModelSection = (result: CostEstimateResponse): string => {
|
|||
};
|
||||
|
||||
export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
|
||||
const t = i18n.t.bind(i18n);
|
||||
const printWindow = window.open("", "_blank");
|
||||
if (!printWindow) {
|
||||
alert("Please allow popups to export PDF");
|
||||
alert(t("costTracking.multiExportUtils.popupBlockedAlert"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -193,22 +196,22 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LLM Cost Estimate Report</h1>
|
||||
<p style="color: #666; margin-top: -20px; margin-bottom: 30px;">${modelCount} model${modelCount !== 1 ? "s" : ""} configured</p>
|
||||
|
||||
<h1>${t("costTracking.multiExportUtils.reportTitle")}</h1>
|
||||
<p style="color: #666; margin-top: -20px; margin-bottom: 30px;">${t("costTracking.multiExportUtils.modelCount", { count: modelCount })}</p>
|
||||
|
||||
<div class="summary-box">
|
||||
<h2>Combined Totals</h2>
|
||||
<h2>${t("costTracking.multiExportUtils.combinedTotals")}</h2>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-item">
|
||||
<div class="label">Total Per Request</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.totalPerRequest")}</div>
|
||||
<div class="value blue">${formatCostForExport(multiResult.totals.cost_per_request)}</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">Total Daily</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.totalDaily")}</div>
|
||||
<div class="value green">${formatCostForExport(multiResult.totals.daily_cost)}</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">Total Monthly</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.totalMonthly")}</div>
|
||||
<div class="value purple">${formatCostForExport(multiResult.totals.monthly_cost)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -217,15 +220,15 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
|
|||
? `
|
||||
<div class="summary-grid" style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #ddd;">
|
||||
<div class="summary-item">
|
||||
<div class="label">Margin/Request</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.marginPerRequest")}</div>
|
||||
<div class="value" style="color: #faad14;">${formatCostForExport(multiResult.totals.margin_per_request)}</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">Daily Margin</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.dailyMargin")}</div>
|
||||
<div class="value" style="color: #faad14;">${formatCostForExport(multiResult.totals.daily_margin)}</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">Monthly Margin</div>
|
||||
<div class="label">${t("costTracking.multiExportUtils.monthlyMargin")}</div>
|
||||
<div class="value" style="color: #faad14;">${formatCostForExport(multiResult.totals.monthly_margin)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -234,11 +237,11 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
|
|||
}
|
||||
</div>
|
||||
|
||||
<h2>Model Breakdown</h2>
|
||||
<h2>${t("costTracking.multiExportUtils.modelBreakdown")}</h2>
|
||||
${validEntries.map((e) => generateModelSection(e.result!)).join("")}
|
||||
|
||||
<div class="footer">
|
||||
<p>Generated by LiteLLM Pricing Calculator on ${new Date().toLocaleString()}</p>
|
||||
<p>${t("costTracking.multiExportUtils.generatedOn", { date: new Date().toLocaleString() })}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -252,36 +255,39 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
|
|||
};
|
||||
|
||||
export const exportMultiToCSV = (multiResult: MultiModelResult): void => {
|
||||
const t = i18n.t.bind(i18n);
|
||||
const validEntries = multiResult.entries.filter((e) => e.result !== null);
|
||||
|
||||
const rows: string[][] = [["LLM Multi-Model Cost Estimate Report"], ["Generated", new Date().toLocaleString()], [""]];
|
||||
const rows: string[][] = [
|
||||
[t("costTracking.multiExportUtils.csvReportTitle")],
|
||||
[t("costTracking.multiExportUtils.csvGenerated"), new Date().toLocaleString()],
|
||||
[""],
|
||||
];
|
||||
|
||||
// Summary section
|
||||
rows.push(
|
||||
["COMBINED TOTALS"],
|
||||
["Total Per Request", multiResult.totals.cost_per_request.toString()],
|
||||
["Total Daily", multiResult.totals.daily_cost?.toString() || "-"],
|
||||
["Total Monthly", multiResult.totals.monthly_cost?.toString() || "-"],
|
||||
["Margin Per Request", multiResult.totals.margin_per_request.toString()],
|
||||
["Daily Margin", multiResult.totals.daily_margin?.toString() || "-"],
|
||||
["Monthly Margin", multiResult.totals.monthly_margin?.toString() || "-"],
|
||||
[t("costTracking.multiExportUtils.csvCombinedTotals")],
|
||||
[t("costTracking.multiExportUtils.csvTotalPerRequest"), multiResult.totals.cost_per_request.toString()],
|
||||
[t("costTracking.multiExportUtils.csvTotalDaily"), multiResult.totals.daily_cost?.toString() || "-"],
|
||||
[t("costTracking.multiExportUtils.csvTotalMonthly"), multiResult.totals.monthly_cost?.toString() || "-"],
|
||||
[t("costTracking.multiExportUtils.csvMarginPerRequest"), multiResult.totals.margin_per_request.toString()],
|
||||
[t("costTracking.multiExportUtils.csvDailyMargin"), multiResult.totals.daily_margin?.toString() || "-"],
|
||||
[t("costTracking.multiExportUtils.csvMonthlyMargin"), multiResult.totals.monthly_margin?.toString() || "-"],
|
||||
[""],
|
||||
);
|
||||
|
||||
// Summary table header
|
||||
rows.push([
|
||||
"Model",
|
||||
"Provider",
|
||||
"Input Tokens",
|
||||
"Output Tokens",
|
||||
"Requests/Day",
|
||||
"Requests/Month",
|
||||
"Cost/Request",
|
||||
"Daily Cost",
|
||||
"Monthly Cost",
|
||||
"Input Cost/Req",
|
||||
"Output Cost/Req",
|
||||
"Margin/Req",
|
||||
t("costTracking.multiExportUtils.csvColModel"),
|
||||
t("costTracking.multiExportUtils.csvColProvider"),
|
||||
t("costTracking.multiExportUtils.csvColInputTokens"),
|
||||
t("costTracking.multiExportUtils.csvColOutputTokens"),
|
||||
t("costTracking.multiExportUtils.csvColRequestsPerDay"),
|
||||
t("costTracking.multiExportUtils.csvColRequestsPerMonth"),
|
||||
t("costTracking.multiExportUtils.csvColCostPerRequest"),
|
||||
t("costTracking.multiExportUtils.csvColDailyCost"),
|
||||
t("costTracking.multiExportUtils.csvColMonthlyCost"),
|
||||
t("costTracking.multiExportUtils.csvColInputCostPerReq"),
|
||||
t("costTracking.multiExportUtils.csvColOutputCostPerReq"),
|
||||
t("costTracking.multiExportUtils.csvColMarginPerReq"),
|
||||
]);
|
||||
|
||||
// Add each model's data
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TextInput, Icon, Text } from "@tremor/react";
|
||||
import { TrashIcon, PencilAltIcon, CheckIcon, XIcon } from "@heroicons/react/outline";
|
||||
import { SimpleTable } from "../common_components/simple_table";
|
||||
|
|
@ -21,6 +22,7 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
onMarginChange,
|
||||
onRemoveProvider,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [editingProvider, setEditingProvider] = useState<string | null>(null);
|
||||
const [editPercentage, setEditPercentage] = useState<string>("");
|
||||
const [editFixedAmount, setEditFixedAmount] = useState<string>("");
|
||||
|
|
@ -106,12 +108,12 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
data={data}
|
||||
columns={[
|
||||
{
|
||||
header: "Provider",
|
||||
header: t("costTracking.providerMarginTable.colProvider"),
|
||||
cell: (row) => {
|
||||
if (row.provider === "global") {
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="font-medium">Global (All Providers)</span>
|
||||
<span className="font-medium">{t("costTracking.providerMarginTable.globalProviderLabel")}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -121,7 +123,7 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
{logo && (
|
||||
<img
|
||||
src={logo}
|
||||
alt={`${displayName} logo`}
|
||||
alt={t("costTracking.providerMarginTable.logoAlt", { displayName })}
|
||||
className="w-5 h-5"
|
||||
onError={(e) => handleImageError(e, displayName)}
|
||||
/>
|
||||
|
|
@ -132,7 +134,7 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
header: "Margin",
|
||||
header: t("costTracking.providerMarginTable.colMargin"),
|
||||
cell: (row) => (
|
||||
<div className="flex items-center gap-2">
|
||||
{editingProvider === row.provider ? (
|
||||
|
|
@ -184,7 +186,7 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
width: "350px",
|
||||
},
|
||||
{
|
||||
header: "Actions",
|
||||
header: t("costTracking.providerMarginTable.colActions"),
|
||||
cell: (row) => {
|
||||
const displayName = row.provider === "global" ? "Global" : getProviderDisplayInfo(row.provider).displayName;
|
||||
return (
|
||||
|
|
@ -200,7 +202,7 @@ const ProviderMarginTable: React.FC<ProviderMarginTableProps> = ({
|
|||
},
|
||||
]}
|
||||
getRowKey={(row) => row.provider}
|
||||
emptyMessage="No provider margins configured"
|
||||
emptyMessage={t("costTracking.providerMarginTable.emptyMessage")}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { DiscountConfig } from "./types";
|
||||
|
|
@ -20,6 +21,7 @@ export interface UseDiscountConfigReturn {
|
|||
}
|
||||
|
||||
export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseDiscountConfigReturn {
|
||||
const { t } = useTranslation();
|
||||
const [discountConfig, setDiscountConfig] = useState<DiscountConfig>({});
|
||||
|
||||
const fetchDiscountConfig = useCallback(async () => {
|
||||
|
|
@ -43,7 +45,7 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching discount config:", error);
|
||||
NotificationsManager.fromBackend("Failed to fetch discount configuration");
|
||||
NotificationsManager.fromBackend(t("costTracking.useDiscountConfig.fetchFailed"));
|
||||
}
|
||||
}, [accessToken]);
|
||||
|
||||
|
|
@ -63,7 +65,7 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
});
|
||||
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Discount configuration updated successfully");
|
||||
NotificationsManager.success(t("costTracking.useDiscountConfig.updateSuccess"));
|
||||
await fetchDiscountConfig();
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
|
|
@ -72,7 +74,7 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating discount config:", error);
|
||||
NotificationsManager.fromBackend("Failed to update discount configuration");
|
||||
NotificationsManager.fromBackend(t("costTracking.useDiscountConfig.updateFailed"));
|
||||
}
|
||||
},
|
||||
[accessToken, fetchDiscountConfig],
|
||||
|
|
@ -81,26 +83,28 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
const handleAddProvider = useCallback(
|
||||
async (selectedProvider: string | undefined, newDiscount: string): Promise<boolean> => {
|
||||
if (!selectedProvider || !newDiscount) {
|
||||
NotificationsManager.fromBackend("Please select a provider and enter discount percentage");
|
||||
NotificationsManager.fromBackend(t("costTracking.useDiscountConfig.selectProviderAndDiscount"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const percentageValue = parseFloat(newDiscount);
|
||||
if (isNaN(percentageValue) || percentageValue < 0 || percentageValue > 100) {
|
||||
NotificationsManager.fromBackend("Discount must be between 0% and 100%");
|
||||
NotificationsManager.fromBackend(t("costTracking.useDiscountConfig.invalidDiscountRange"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const providerValue = getProviderBackendValue(selectedProvider);
|
||||
|
||||
if (!providerValue) {
|
||||
NotificationsManager.fromBackend("Invalid provider selected");
|
||||
NotificationsManager.fromBackend(t("costTracking.useDiscountConfig.invalidProvider"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (discountConfig[providerValue]) {
|
||||
NotificationsManager.fromBackend(
|
||||
`Discount for ${Providers[selectedProvider as keyof typeof Providers]} already exists. Edit it in the table above.`,
|
||||
t("costTracking.useDiscountConfig.discountAlreadyExists", {
|
||||
providerName: Providers[selectedProvider as keyof typeof Providers],
|
||||
}),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { MarginConfig } from "./types";
|
||||
|
|
@ -30,6 +31,7 @@ export interface AddMarginParams {
|
|||
}
|
||||
|
||||
export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMarginConfigReturn {
|
||||
const { t } = useTranslation();
|
||||
const [marginConfig, setMarginConfig] = useState<MarginConfig>({});
|
||||
|
||||
const fetchMarginConfig = useCallback(async () => {
|
||||
|
|
@ -53,7 +55,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching margin config:", error);
|
||||
NotificationsManager.fromBackend("Failed to fetch margin configuration");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.fetchFailed"));
|
||||
}
|
||||
}, [accessToken]);
|
||||
|
||||
|
|
@ -73,7 +75,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
});
|
||||
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Margin configuration updated successfully");
|
||||
NotificationsManager.success(t("costTracking.useMarginConfig.updateSuccess"));
|
||||
await fetchMarginConfig();
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
|
|
@ -82,7 +84,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating margin config:", error);
|
||||
NotificationsManager.fromBackend("Failed to update margin configuration");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.updateFailed"));
|
||||
}
|
||||
},
|
||||
[accessToken, fetchMarginConfig],
|
||||
|
|
@ -93,7 +95,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
const { selectedProvider, marginType, percentageValue, fixedAmountValue } = params;
|
||||
|
||||
if (!selectedProvider) {
|
||||
NotificationsManager.fromBackend("Please select a provider");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.selectProvider"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +105,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
} else {
|
||||
const backendValue = getProviderBackendValue(selectedProvider);
|
||||
if (!backendValue) {
|
||||
NotificationsManager.fromBackend("Invalid provider selected");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.invalidProvider"));
|
||||
return false;
|
||||
}
|
||||
providerValue = backendValue;
|
||||
|
|
@ -112,7 +114,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
if (marginConfig[providerValue]) {
|
||||
const displayName =
|
||||
providerValue === "global" ? "Global" : Providers[selectedProvider as keyof typeof Providers];
|
||||
NotificationsManager.fromBackend(`Margin for ${displayName} already exists. Edit it in the table above.`);
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.marginAlreadyExists", { displayName }));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -120,14 +122,14 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
if (marginType === "percentage") {
|
||||
const percentValue = parseFloat(percentageValue);
|
||||
if (isNaN(percentValue) || percentValue < 0 || percentValue > 1000) {
|
||||
NotificationsManager.fromBackend("Percentage must be between 0% and 1000%");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.invalidPercentageRange"));
|
||||
return false;
|
||||
}
|
||||
marginValue = percentValue / 100;
|
||||
} else {
|
||||
const fixedValue = parseFloat(fixedAmountValue);
|
||||
if (isNaN(fixedValue) || fixedValue < 0) {
|
||||
NotificationsManager.fromBackend("Fixed amount must be non-negative");
|
||||
NotificationsManager.fromBackend(t("costTracking.useMarginConfig.invalidFixedAmount"));
|
||||
return false;
|
||||
}
|
||||
marginValue = { fixed_amount: fixedValue };
|
||||
|
|
|
|||
|
|
@ -4793,6 +4793,80 @@
|
|||
"multiExportDropdown": {
|
||||
"exportAsPdf": "Export as PDF",
|
||||
"exportAsCsv": "Export as CSV"
|
||||
},
|
||||
"multiExportUtils": {
|
||||
"popupBlockedAlert": "Please allow popups to export PDF",
|
||||
"reportTitle": "LLM Cost Estimate Report",
|
||||
"modelCount_one": "{{count}} model configured",
|
||||
"modelCount_other": "{{count}} models configured",
|
||||
"combinedTotals": "Combined Totals",
|
||||
"totalPerRequest": "Total Per Request",
|
||||
"totalDaily": "Total Daily",
|
||||
"totalMonthly": "Total Monthly",
|
||||
"marginPerRequest": "Margin/Request",
|
||||
"dailyMargin": "Daily Margin",
|
||||
"monthlyMargin": "Monthly Margin",
|
||||
"modelBreakdown": "Model Breakdown",
|
||||
"generatedOn": "Generated by LiteLLM Pricing Calculator on {{date}}",
|
||||
"inputTokensPerRequest": "Input Tokens per Request:",
|
||||
"outputTokensPerRequest": "Output Tokens per Request:",
|
||||
"requestsPerDay": "Requests per Day:",
|
||||
"requestsPerMonth": "Requests per Month:",
|
||||
"colCostType": "Cost Type",
|
||||
"colPerRequest": "Per Request",
|
||||
"colDaily": "Daily",
|
||||
"colMonthly": "Monthly",
|
||||
"inputCost": "Input Cost",
|
||||
"outputCost": "Output Cost",
|
||||
"marginFee": "Margin/Fee",
|
||||
"csvReportTitle": "LLM Multi-Model Cost Estimate Report",
|
||||
"csvGenerated": "Generated",
|
||||
"csvCombinedTotals": "COMBINED TOTALS",
|
||||
"csvTotalPerRequest": "Total Per Request",
|
||||
"csvTotalDaily": "Total Daily",
|
||||
"csvTotalMonthly": "Total Monthly",
|
||||
"csvMarginPerRequest": "Margin Per Request",
|
||||
"csvDailyMargin": "Daily Margin",
|
||||
"csvMonthlyMargin": "Monthly Margin",
|
||||
"csvColModel": "Model",
|
||||
"csvColProvider": "Provider",
|
||||
"csvColInputTokens": "Input Tokens",
|
||||
"csvColOutputTokens": "Output Tokens",
|
||||
"csvColRequestsPerDay": "Requests/Day",
|
||||
"csvColRequestsPerMonth": "Requests/Month",
|
||||
"csvColCostPerRequest": "Cost/Request",
|
||||
"csvColDailyCost": "Daily Cost",
|
||||
"csvColMonthlyCost": "Monthly Cost",
|
||||
"csvColInputCostPerReq": "Input Cost/Req",
|
||||
"csvColOutputCostPerReq": "Output Cost/Req",
|
||||
"csvColMarginPerReq": "Margin/Req"
|
||||
},
|
||||
"providerMarginTable": {
|
||||
"colProvider": "Provider",
|
||||
"colMargin": "Margin",
|
||||
"colActions": "Actions",
|
||||
"globalProviderLabel": "Global (All Providers)",
|
||||
"logoAlt": "{{displayName}} logo",
|
||||
"emptyMessage": "No provider margins configured"
|
||||
},
|
||||
"useDiscountConfig": {
|
||||
"fetchFailed": "Failed to fetch discount configuration",
|
||||
"updateFailed": "Failed to update discount configuration",
|
||||
"updateSuccess": "Discount configuration updated successfully",
|
||||
"selectProviderAndDiscount": "Please select a provider and enter discount percentage",
|
||||
"invalidDiscountRange": "Discount must be between 0% and 100%",
|
||||
"invalidProvider": "Invalid provider selected",
|
||||
"discountAlreadyExists": "Discount for {{providerName}} already exists. Edit it in the table above."
|
||||
},
|
||||
"useMarginConfig": {
|
||||
"fetchFailed": "Failed to fetch margin configuration",
|
||||
"updateFailed": "Failed to update margin configuration",
|
||||
"updateSuccess": "Margin configuration updated successfully",
|
||||
"selectProvider": "Please select a provider",
|
||||
"invalidProvider": "Invalid provider selected",
|
||||
"marginAlreadyExists": "Margin for {{displayName}} already exists. Edit it in the table above.",
|
||||
"invalidPercentageRange": "Percentage must be between 0% and 1000%",
|
||||
"invalidFixedAmount": "Fixed amount must be non-negative"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4793,6 +4793,80 @@
|
|||
"multiExportDropdown": {
|
||||
"exportAsPdf": "导出为 PDF",
|
||||
"exportAsCsv": "导出为 CSV"
|
||||
},
|
||||
"multiExportUtils": {
|
||||
"popupBlockedAlert": "请允许弹出窗口以导出 PDF",
|
||||
"reportTitle": "LLM 成本估算报告",
|
||||
"modelCount_one": "已配置 {{count}} 个模型",
|
||||
"modelCount_other": "已配置 {{count}} 个模型",
|
||||
"combinedTotals": "合计",
|
||||
"totalPerRequest": "每次请求总计",
|
||||
"totalDaily": "每日总计",
|
||||
"totalMonthly": "每月总计",
|
||||
"marginPerRequest": "利润率/请求",
|
||||
"dailyMargin": "每日利润率",
|
||||
"monthlyMargin": "每月利润率",
|
||||
"modelBreakdown": "模型明细",
|
||||
"generatedOn": "由 LiteLLM 价格计算器生成于 {{date}}",
|
||||
"inputTokensPerRequest": "每次请求输入 Token:",
|
||||
"outputTokensPerRequest": "每次请求输出 Token:",
|
||||
"requestsPerDay": "每日请求数:",
|
||||
"requestsPerMonth": "每月请求数:",
|
||||
"colCostType": "成本类型",
|
||||
"colPerRequest": "每次请求",
|
||||
"colDaily": "每日",
|
||||
"colMonthly": "每月",
|
||||
"inputCost": "输入成本",
|
||||
"outputCost": "输出成本",
|
||||
"marginFee": "利润率/费用",
|
||||
"csvReportTitle": "LLM 多模型成本估算报告",
|
||||
"csvGenerated": "生成时间",
|
||||
"csvCombinedTotals": "合计",
|
||||
"csvTotalPerRequest": "每次请求总计",
|
||||
"csvTotalDaily": "每日总计",
|
||||
"csvTotalMonthly": "每月总计",
|
||||
"csvMarginPerRequest": "每次请求利润率",
|
||||
"csvDailyMargin": "每日利润率",
|
||||
"csvMonthlyMargin": "每月利润率",
|
||||
"csvColModel": "模型",
|
||||
"csvColProvider": "提供商",
|
||||
"csvColInputTokens": "输入 Token",
|
||||
"csvColOutputTokens": "输出 Token",
|
||||
"csvColRequestsPerDay": "请求数/天",
|
||||
"csvColRequestsPerMonth": "请求数/月",
|
||||
"csvColCostPerRequest": "成本/请求",
|
||||
"csvColDailyCost": "每日成本",
|
||||
"csvColMonthlyCost": "每月成本",
|
||||
"csvColInputCostPerReq": "输入成本/请求",
|
||||
"csvColOutputCostPerReq": "输出成本/请求",
|
||||
"csvColMarginPerReq": "利润率/请求"
|
||||
},
|
||||
"providerMarginTable": {
|
||||
"colProvider": "提供商",
|
||||
"colMargin": "利润率",
|
||||
"colActions": "操作",
|
||||
"globalProviderLabel": "全局(所有提供商)",
|
||||
"logoAlt": "{{displayName}} 徽标",
|
||||
"emptyMessage": "未配置提供商利润率"
|
||||
},
|
||||
"useDiscountConfig": {
|
||||
"fetchFailed": "获取折扣配置失败",
|
||||
"updateFailed": "更新折扣配置失败",
|
||||
"updateSuccess": "折扣配置已成功更新",
|
||||
"selectProviderAndDiscount": "请选择提供商并输入折扣百分比",
|
||||
"invalidDiscountRange": "折扣必须在 0% 到 100% 之间",
|
||||
"invalidProvider": "所选提供商无效",
|
||||
"discountAlreadyExists": "{{providerName}} 的折扣已存在,请在上方表格中编辑。"
|
||||
},
|
||||
"useMarginConfig": {
|
||||
"fetchFailed": "获取利润率配置失败",
|
||||
"updateFailed": "更新利润率配置失败",
|
||||
"updateSuccess": "利润率配置已成功更新",
|
||||
"selectProvider": "请选择提供商",
|
||||
"invalidProvider": "所选提供商无效",
|
||||
"marginAlreadyExists": "{{displayName}} 的利润率已存在,请在上方表格中编辑。",
|
||||
"invalidPercentageRange": "百分比必须在 0% 到 1000% 之间",
|
||||
"invalidFixedAmount": "固定金额不能为负数"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue