@acarmisc/backstage-plugin-litellm 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/LiteLLMHomeWidget.d.ts +8 -0
- package/dist/index.cjs.js +86 -0
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +96 -0
- package/dist/index.esm.js.map +4 -4
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -955,10 +955,106 @@ init_DashboardHeader();
|
|
|
955
955
|
init_KeysTable();
|
|
956
956
|
init_UsageStats();
|
|
957
957
|
init_TeamUsage();
|
|
958
|
+
|
|
959
|
+
// src/components/LiteLLMHomeWidget.tsx
|
|
960
|
+
init_api();
|
|
961
|
+
import React7, { useState as useState5, useEffect as useEffect2 } from "react";
|
|
962
|
+
import {
|
|
963
|
+
Paper as Paper6,
|
|
964
|
+
Box as Box6,
|
|
965
|
+
Typography as Typography6,
|
|
966
|
+
FormControl as FormControl2,
|
|
967
|
+
Select as Select2,
|
|
968
|
+
MenuItem as MenuItem3,
|
|
969
|
+
Grid as Grid3,
|
|
970
|
+
CircularProgress as CircularProgress5,
|
|
971
|
+
Alert as Alert2
|
|
972
|
+
} from "@mui/material";
|
|
973
|
+
import { AreaChart as AreaChart3, Area as Area3, ResponsiveContainer as ResponsiveContainer3 } from "recharts";
|
|
974
|
+
import { useApi as useApi2 } from "@backstage/core-plugin-api";
|
|
975
|
+
var fmtUsd2 = (n) => `$${(n ?? 0).toFixed(n < 1 ? 4 : 2)}`;
|
|
976
|
+
var fmtInt2 = (n) => (n ?? 0).toLocaleString();
|
|
977
|
+
function presetToDateRange(preset) {
|
|
978
|
+
const end = /* @__PURE__ */ new Date();
|
|
979
|
+
const start = /* @__PURE__ */ new Date();
|
|
980
|
+
if (preset === "today") {
|
|
981
|
+
start.setHours(0, 0, 0, 0);
|
|
982
|
+
} else if (preset === "7d") {
|
|
983
|
+
start.setDate(start.getDate() - 7);
|
|
984
|
+
} else {
|
|
985
|
+
start.setDate(start.getDate() - 30);
|
|
986
|
+
}
|
|
987
|
+
return { start, end };
|
|
988
|
+
}
|
|
989
|
+
var Kpi = ({ label, value }) => /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Typography6, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ React7.createElement(Typography6, { variant: "subtitle1", fontWeight: 600 }, value));
|
|
990
|
+
var LiteLLMHomeWidget = ({
|
|
991
|
+
defaultPeriod = "7d",
|
|
992
|
+
title = "LiteLLM Usage"
|
|
993
|
+
}) => {
|
|
994
|
+
const api = useApi2(liteLlmApiRef);
|
|
995
|
+
const [period, setPeriod] = useState5(defaultPeriod);
|
|
996
|
+
const [loading, setLoading] = useState5(true);
|
|
997
|
+
const [error, setError] = useState5(null);
|
|
998
|
+
const [usage, setUsage] = useState5(null);
|
|
999
|
+
const [keys, setKeys] = useState5([]);
|
|
1000
|
+
useEffect2(() => {
|
|
1001
|
+
let cancelled = false;
|
|
1002
|
+
setLoading(true);
|
|
1003
|
+
setError(null);
|
|
1004
|
+
const { start, end } = presetToDateRange(period);
|
|
1005
|
+
const startDate = start.toISOString().split("T")[0];
|
|
1006
|
+
const endDate = end.toISOString().split("T")[0];
|
|
1007
|
+
Promise.all([api.getUsage(startDate, endDate), api.listKeys()]).then(([usageData, keysData]) => {
|
|
1008
|
+
if (!cancelled) {
|
|
1009
|
+
setUsage(usageData);
|
|
1010
|
+
setKeys(keysData);
|
|
1011
|
+
setLoading(false);
|
|
1012
|
+
}
|
|
1013
|
+
}).catch((err) => {
|
|
1014
|
+
if (!cancelled) {
|
|
1015
|
+
setError(err.message ?? "Failed to load usage data");
|
|
1016
|
+
setLoading(false);
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
return () => {
|
|
1020
|
+
cancelled = true;
|
|
1021
|
+
};
|
|
1022
|
+
}, [api, period]);
|
|
1023
|
+
const dailyData = (usage?.daily_usage ?? []).map((d) => ({
|
|
1024
|
+
date: d.date,
|
|
1025
|
+
spend: d.spend
|
|
1026
|
+
}));
|
|
1027
|
+
const hasSparkline = dailyData.length > 0;
|
|
1028
|
+
return /* @__PURE__ */ React7.createElement(Paper6, { sx: { p: 2 } }, /* @__PURE__ */ React7.createElement(Box6, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ React7.createElement(Typography6, { variant: "h6" }, title), /* @__PURE__ */ React7.createElement(FormControl2, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ React7.createElement(
|
|
1029
|
+
Select2,
|
|
1030
|
+
{
|
|
1031
|
+
value: period,
|
|
1032
|
+
onChange: (e) => setPeriod(e.target.value),
|
|
1033
|
+
displayEmpty: true
|
|
1034
|
+
},
|
|
1035
|
+
/* @__PURE__ */ React7.createElement(MenuItem3, { value: "today" }, "Today"),
|
|
1036
|
+
/* @__PURE__ */ React7.createElement(MenuItem3, { value: "7d" }, "7d"),
|
|
1037
|
+
/* @__PURE__ */ React7.createElement(MenuItem3, { value: "30d" }, "30d")
|
|
1038
|
+
))), loading && /* @__PURE__ */ React7.createElement(Box6, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ React7.createElement(CircularProgress5, { size: 32 })), !loading && error && /* @__PURE__ */ React7.createElement(Alert2, { severity: "error", sx: { mt: 1 } }, error), !loading && !error && /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Grid3, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ React7.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React7.createElement(Kpi, { label: "USD Spent", value: fmtUsd2(usage?.total_spend ?? 0) })), /* @__PURE__ */ React7.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React7.createElement(Kpi, { label: "Tokens In", value: fmtInt2(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ React7.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React7.createElement(Kpi, { label: "Tokens Out", value: fmtInt2(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ React7.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React7.createElement(Kpi, { label: "Keys", value: fmtInt2(keys.length) }))), hasSparkline && /* @__PURE__ */ React7.createElement(Box6, { height: 120 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer3, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(AreaChart3, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ React7.createElement(
|
|
1039
|
+
Area3,
|
|
1040
|
+
{
|
|
1041
|
+
type: "monotone",
|
|
1042
|
+
dataKey: "spend",
|
|
1043
|
+
stroke: "#8884d8",
|
|
1044
|
+
fill: "#8884d8",
|
|
1045
|
+
fillOpacity: 0.3,
|
|
1046
|
+
dot: false,
|
|
1047
|
+
isAnimationActive: false
|
|
1048
|
+
}
|
|
1049
|
+
))))));
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// src/index.ts
|
|
958
1053
|
init_api();
|
|
959
1054
|
export {
|
|
960
1055
|
DashboardHeader,
|
|
961
1056
|
KeysTable,
|
|
1057
|
+
LiteLLMHomeWidget,
|
|
962
1058
|
LiteLLMPage,
|
|
963
1059
|
LiteLlmApi,
|
|
964
1060
|
TeamUsage,
|