diff --git a/ui/litellm-dashboard/src/components/public_model_hub.tsx b/ui/litellm-dashboard/src/components/public_model_hub.tsx index 0421e62d50d..fd6ada836a3 100644 --- a/ui/litellm-dashboard/src/components/public_model_hub.tsx +++ b/ui/litellm-dashboard/src/components/public_model_hub.tsx @@ -5,6 +5,7 @@ import { Button, Card, Text, Title } from "@tremor/react"; import { Modal, Select, Tabs, Tag, Tooltip } from "antd"; import { Copy, Info } from "lucide-react"; import React, { useEffect, useMemo, useState } from "react"; +import { Trans, useTranslation } from "react-i18next"; import { ModelDataTable } from "./model_dashboard/table"; import NotificationsManager from "./molecules/notifications_manager"; import Navbar from "./navbar"; @@ -96,6 +97,7 @@ interface PublicModelHubProps { } const PublicModelHub: React.FC = ({ accessToken, isEmbedded = false }) => { + const { t } = useTranslation(); const [modelHubData, setModelHubData] = useState(null); const [agentHubData, setAgentHubData] = useState(null); const [mcpHubData, setMcpHubData] = useState(null); @@ -114,7 +116,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const [selectedFeatures, setSelectedFeatures] = useState([]); const [selectedAgentSkills, setSelectedAgentSkills] = useState([]); const [selectedMcpTransports, setSelectedMcpTransports] = useState([]); - const [serviceStatus, setServiceStatus] = useState("I'm alive! ✓"); + const [serviceStatusKey, setServiceStatusKey] = useState("publicModelHub.serviceAlive"); const [isModalVisible, setIsModalVisible] = useState(false); const [isAgentModalVisible, setIsAgentModalVisible] = useState(false); const [isMcpModalVisible, setIsMcpModalVisible] = useState(false); @@ -144,7 +146,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded setModelHubData(Array.isArray(_modelHubData) ? _modelHubData : []); } catch (error) { console.error("There was an error fetching the public model data", error); - setServiceStatus("Service unavailable"); + setServiceStatusKey("publicModelHub.serviceUnavailable"); } finally { setLoading(false); } @@ -488,7 +490,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); - NotificationsManager.success("Copied to clipboard!"); + NotificationsManager.success(t("publicModelHub.copiedToClipboard")); }; const formatCapabilityName = (key: string) => { @@ -510,7 +512,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded }; const formatTokens = (tokens: number | undefined) => { - if (!tokens) return "N/A"; + if (!tokens) return t("publicModelHub.na"); if (tokens >= 1000) { return `${(tokens / 1000).toFixed(0)}K`; } @@ -521,12 +523,12 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const limits = []; if (rpm) limits.push(`RPM: ${rpm.toLocaleString()}`); if (tpm) limits.push(`TPM: ${tpm.toLocaleString()}`); - return limits.length > 0 ? limits.join(", ") : "N/A"; + return limits.length > 0 ? limits.join(", ") : t("publicModelHub.na"); }; const publicModelHubColumns = (): ColumnDef[] => [ { - header: "Model Name", + header: t("publicModelHub.colModelName"), accessorKey: "model_group", enableSorting: true, cell: ({ row }) => ( @@ -546,7 +548,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 150, }, { - header: "Providers", + header: t("publicModelHub.colProviders"), accessorKey: "providers", enableSorting: true, cell: ({ row }) => { @@ -578,7 +580,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 120, }, { - header: "Mode", + header: t("publicModelHub.colMode"), accessorKey: "mode", enableSorting: true, cell: ({ row }) => { @@ -599,14 +601,14 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded return (
{getModeIcon(mode || "")} - {mode || "Chat"} + {mode || t("publicModelHub.modeChat")}
); }, size: 100, }, { - header: "Max Input", + header: t("publicModelHub.colMaxInput"), accessorKey: "max_input_tokens", enableSorting: true, cell: ({ row }) => {formatTokens(row.original.max_input_tokens)}, @@ -616,7 +618,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded }, }, { - header: "Max Output", + header: t("publicModelHub.colMaxOutput"), accessorKey: "max_output_tokens", enableSorting: true, cell: ({ row }) => {formatTokens(row.original.max_output_tokens)}, @@ -626,12 +628,12 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded }, }, { - header: "Input $/1M", + header: t("publicModelHub.colInputCost"), accessorKey: "input_cost_per_token", enableSorting: true, cell: ({ row }) => { const cost = row.original.input_cost_per_token; - return {cost ? formatCost(cost) : "Free"}; + return {cost ? formatCost(cost) : t("publicModelHub.free")}; }, size: 100, meta: { @@ -639,12 +641,12 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded }, }, { - header: "Output $/1M", + header: t("publicModelHub.colOutputCost"), accessorKey: "output_cost_per_token", enableSorting: true, cell: ({ row }) => { const cost = row.original.output_cost_per_token; - return {cost ? formatCost(cost) : "Free"}; + return {cost ? formatCost(cost) : t("publicModelHub.free")}; }, size: 100, meta: { @@ -652,7 +654,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded }, }, { - header: "Features", + header: t("publicModelHub.colFeatures"), accessorKey: "supports_vision", enableSorting: false, cell: ({ row }) => { @@ -685,7 +687,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded -
All Features:
+
{t("publicModelHub.allFeatures")}
{features.map((feature, index) => (
• {feature} @@ -709,7 +711,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 120, }, { - header: "Health Status", + header: t("publicModelHub.colHealthStatus"), accessorKey: "health_status", enableSorting: true, cell: ({ row }) => { @@ -717,11 +719,11 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const tagColor = original.health_status === "healthy" ? "green" : original.health_status === "unhealthy" ? "red" : "default"; const responseTimeLabel = original.health_response_time - ? `Response Time: ${Number(original.health_response_time).toFixed(2)}ms` - : "N/A"; + ? t("publicModelHub.responseTime", { time: Number(original.health_response_time).toFixed(2) }) + : t("publicModelHub.na"); const lastCheckedLabel = original.health_checked_at - ? `Last Checked: ${new Date(original.health_checked_at).toLocaleString()}` - : "N/A"; + ? t("publicModelHub.lastChecked", { time: new Date(original.health_checked_at).toLocaleString() }) + : t("publicModelHub.na"); return ( = ({ accessToken, isEmbedded } > - {original.health_status ?? "Unknown"} + {original.health_status ?? t("common.unknown")} ); @@ -741,7 +743,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 100, }, { - header: "Limits", + header: t("publicModelHub.colLimits"), accessorKey: "rpm", enableSorting: true, cell: ({ row }) => { @@ -754,7 +756,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const publicAgentHubColumns = (): ColumnDef[] => [ { - header: "Agent Name", + header: t("publicModelHub.colAgentName"), accessorKey: "name", enableSorting: true, cell: ({ row }) => ( @@ -774,7 +776,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 150, }, { - header: "Description", + header: t("common.description"), accessorKey: "description", enableSorting: false, cell: ({ row }) => { @@ -789,14 +791,14 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 250, }, { - header: "Version", + header: t("publicModelHub.colVersion"), accessorKey: "version", enableSorting: true, cell: ({ row }) => {row.original.version}, size: 80, }, { - header: "Provider", + header: t("publicModelHub.colProvider"), accessorKey: "provider", enableSorting: false, cell: ({ row }) => { @@ -811,7 +813,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 120, }, { - header: "Skills", + header: t("publicModelHub.colSkills"), accessorKey: "skills", enableSorting: false, cell: ({ row }) => { @@ -838,7 +840,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded -
All Skills:
+
{t("publicModelHub.allSkills")}
{skills.map((skill, index) => (
• {skill.name} @@ -862,7 +864,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 150, }, { - header: "Capabilities", + header: t("publicModelHub.colCapabilities"), accessorKey: "capabilities", enableSorting: false, cell: ({ row }) => { @@ -891,7 +893,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded const publicMCPHubColumns = (): ColumnDef[] => [ { - header: "Server Name", + header: t("publicModelHub.colServerName"), accessorKey: "server_name", enableSorting: true, cell: ({ row }) => ( @@ -911,7 +913,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 150, }, { - header: "Description", + header: t("common.description"), accessorKey: "mcp_info.description", enableSorting: false, cell: ({ row }) => { @@ -926,7 +928,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 250, }, { - header: "URL", + header: t("publicModelHub.colUrl"), accessorKey: "url", enableSorting: false, cell: ({ row }) => { @@ -947,7 +949,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 200, }, { - header: "Transport", + header: t("publicModelHub.colTransport"), accessorKey: "transport", enableSorting: true, cell: ({ row }) => { @@ -961,7 +963,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded size: 100, }, { - header: "Auth Type", + header: t("publicModelHub.colAuthType"), accessorKey: "auth_type", enableSorting: true, cell: ({ row }) => { @@ -994,23 +996,21 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded {/* Embedded Explainer - only shown when embedded in dashboard */} {isEmbedded && (
-

- These are models, agents, and MCP servers your proxy admin has indicated are available in your company. -

+

{t("publicModelHub.embeddedExplainer")}

)} {/* About Section - only shown when not embedded */} {!isEmbedded && ( - About + {t("publicModelHub.aboutTitle")}

- {customDocsDescription ? customDocsDescription : "Proxy Server to call 100+ LLMs in the OpenAI format."} + {customDocsDescription ? customDocsDescription : t("publicModelHub.aboutDescription")}

🔧 - Built with litellm: v{litellmVersion} + {t("publicModelHub.builtWith", { version: litellmVersion })}
@@ -1019,7 +1019,9 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded {/* Useful Links - only shown when not embedded */} {usefulLinks && Object.keys(usefulLinks).length > 0 && ( - Useful Links + + {t("publicModelHub.usefulLinksTitle")} +
{Object.entries(usefulLinks || {}) .map(([title, value]) => { @@ -1046,9 +1048,13 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded {/* Health and Endpoint Status - only shown when not embedded */} {!isEmbedded && ( - Health and Endpoint Status + + {t("publicModelHub.healthStatusTitle")} +
- Service status: {serviceStatus} + + {t("publicModelHub.serviceStatus", { status: t(serviceStatusKey) })} +
)} @@ -1057,20 +1063,17 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded {/* Models Tab */} - +
- Available Models + {t("publicModelHub.availableModels")}
{/* Filters */}
- Search Models: - + {t("publicModelHub.searchModelsLabel")} +
@@ -1078,7 +1081,7 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded setSearchTerm(e.target.value)} className="border border-gray-300 rounded-lg pl-10 pr-4 py-2 w-full text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white" @@ -1086,12 +1089,12 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded
- Provider: + {t("publicModelHub.filterProvider")}
- Mode: + {t("publicModelHub.filterMode")}
- Features: + {t("publicModelHub.filterFeatures")} setAgentSearchTerm(e.target.value)} className="border border-gray-300 rounded-lg pl-10 pr-4 py-2 w-full text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white" @@ -1207,12 +1217,12 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded
- Skills: + {t("publicModelHub.filterSkills")} setMcpSearchTerm(e.target.value)} className="border border-gray-300 rounded-lg pl-10 pr-4 py-2 w-full text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white" @@ -1271,12 +1286,14 @@ const PublicModelHub: React.FC = ({ accessToken, isEmbedded
- Transport: + + {t("publicModelHub.filterTransport")} +