Extract Model Table to component (#4871)
* Extract Model Table to component Add provider icons to header rows and installed models Light mode supported Mapping for model name id hints to provider Update DMR to filter chat models by ability since not available via hub API * linting + dev * fix incorrect import
This commit is contained in:
parent
e07963d3fc
commit
607b5faf74
2
.github/workflows/dev-build.yaml
vendored
2
.github/workflows/dev-build.yaml
vendored
@ -6,7 +6,7 @@ concurrency:
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['fix-path-patch'] # put your current branch to create a build. Core team only.
|
||||
branches: ['model-table-component'] # put your current branch to create a build. Core team only.
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'cloud-deployments/*'
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lobehub/icons": "^4.0.3",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@mintplex-labs/piper-tts-web": "^1.0.4",
|
||||
"@phosphor-icons/react": "^2.1.7",
|
||||
|
||||
@ -1,20 +1,15 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import System from "@/models/system";
|
||||
import useProviderEndpointAutoDiscovery from "@/hooks/useProviderEndpointAutoDiscovery";
|
||||
import {
|
||||
ArrowClockwise,
|
||||
CircleNotch,
|
||||
MagnifyingGlass,
|
||||
Info,
|
||||
} from "@phosphor-icons/react";
|
||||
import { CircleNotch, Info } from "@phosphor-icons/react";
|
||||
import strDistance from "js-levenshtein";
|
||||
import { LLM_PREFERENCE_CHANGED_EVENT } from "@/pages/GeneralSettings/LLMPreference";
|
||||
import { DOCKER_MODEL_RUNNER_COMMON_URLS } from "@/utils/constants";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import { Link } from "react-router-dom";
|
||||
import ModelTable from "./ModelTable";
|
||||
import * as Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
import ModelTable from "@/components/lib/ModelTable";
|
||||
import ModelTableLayout from "@/components/lib/ModelTable/layout";
|
||||
import ModelTableLoadingSkeleton from "@/components/lib/ModelTable/loading";
|
||||
|
||||
export default function DockerModelRunnerOptions({ settings }) {
|
||||
const {
|
||||
@ -280,11 +275,12 @@ function DockerModelRunnerModelSelection({
|
||||
});
|
||||
|
||||
const orderedMap = new Map();
|
||||
const installedMap = new Map();
|
||||
mapping
|
||||
.get("installed")
|
||||
.entries()
|
||||
.forEach(([organization, models]) =>
|
||||
orderedMap.set(organization, models)
|
||||
installedMap.set(organization, models)
|
||||
);
|
||||
mapping
|
||||
.get("not installed")
|
||||
@ -292,7 +288,17 @@ function DockerModelRunnerModelSelection({
|
||||
.forEach(([organization, models]) =>
|
||||
orderedMap.set(organization, models)
|
||||
);
|
||||
return Object.fromEntries(orderedMap);
|
||||
|
||||
// Sort the models by organization/creator name alphabetically but keep the installed models at the top
|
||||
return Object.fromEntries(
|
||||
Array.from(installedMap.entries())
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.concat(
|
||||
Array.from(orderedMap.entries()).sort((a, b) =>
|
||||
a[0].localeCompare(b[0])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function handleSetActiveModel(modelId) {
|
||||
@ -303,7 +309,7 @@ function DockerModelRunnerModelSelection({
|
||||
|
||||
const groupedModels = groupModelsByAlias(filteredModels);
|
||||
return (
|
||||
<Layout
|
||||
<ModelTableLayout
|
||||
fetchModels={fetchModels}
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
@ -321,7 +327,7 @@ function DockerModelRunnerModelSelection({
|
||||
value={selectedModelId}
|
||||
/>
|
||||
{loading ? (
|
||||
<LoadingSkeleton />
|
||||
<ModelTableLoadingSkeleton />
|
||||
) : filteredModels.length === 0 ? (
|
||||
<div className="flex flex-col w-full gap-y-2 mt-4">
|
||||
<p className="text-theme-text-secondary text-sm">No models found!</p>
|
||||
@ -341,96 +347,6 @@ function DockerModelRunnerModelSelection({
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
function Layout({
|
||||
children,
|
||||
fetchModels = null,
|
||||
searchQuery = "",
|
||||
setSearchQuery = () => {},
|
||||
loading = false,
|
||||
}) {
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
async function refreshModels() {
|
||||
setIsRefreshing(true);
|
||||
try {
|
||||
await fetchModels?.();
|
||||
} catch {
|
||||
} finally {
|
||||
setIsRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex gap-x-2 items-center pb-[8px]">
|
||||
<label className="text-theme-text-primary text-base font-semibold">
|
||||
Available Models
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-x-[16px]">
|
||||
<div className="relative flex-1 flex-grow">
|
||||
<MagnifyingGlass
|
||||
size={16}
|
||||
weight="bold"
|
||||
color="var(--theme-text-primary)"
|
||||
className="absolute left-[9px] top-[10px] text-theme-settings-input-placeholder peer-focus:invisible"
|
||||
/>
|
||||
<input
|
||||
type="search"
|
||||
placeholder="Search models"
|
||||
value={searchQuery}
|
||||
disabled={loading}
|
||||
className="min-h-[32px] border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5 pl-[30px] py-2 search-input disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
onChange={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setSearchQuery(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!!fetchModels && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={refreshModels}
|
||||
disabled={isRefreshing || loading}
|
||||
className="border-none text-theme-text-secondary text-sm font-medium hover:bg-white/10 light:hover:bg-black/5 rounded-lg px-2 h-full flex items-center gap-x-1 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isRefreshing ? (
|
||||
<CircleNotch className="w-4 h-4 text-theme-text-secondary animate-spin" />
|
||||
) : (
|
||||
<ArrowClockwise
|
||||
weight="bold"
|
||||
className="w-4 h-4 text-theme-text-secondary"
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={`text-sm font-medium ${isRefreshing ? "hidden" : "text-theme-text-secondary"}`}
|
||||
>
|
||||
Refresh Models
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LoadingSkeleton() {
|
||||
return (
|
||||
<div className="flex flex-col w-full gap-y-4">
|
||||
<Skeleton.default
|
||||
height={100}
|
||||
width="100%"
|
||||
count={7}
|
||||
highlightColor="var(--theme-settings-input-active)"
|
||||
baseColor="var(--theme-settings-input-bg)"
|
||||
enableAnimation={true}
|
||||
containerClassName="w-fill flex gap-[8px] flex-col p-0"
|
||||
/>
|
||||
</div>
|
||||
</ModelTableLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,10 +6,12 @@ import {
|
||||
Circle,
|
||||
DotsThreeVertical,
|
||||
CloudArrowDown,
|
||||
CircleNotch,
|
||||
} from "@phosphor-icons/react";
|
||||
import pluralize from "pluralize";
|
||||
import { titleCase } from "text-case";
|
||||
import { humanFileSize } from "@/utils/numbers";
|
||||
import MonoProviderIcon from "../MonoProviderIcon";
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModelDefinition
|
||||
@ -67,18 +69,27 @@ export default function ModelTable({
|
||||
className="text-theme-text-secondary"
|
||||
/>
|
||||
)}
|
||||
<h3 className="flex items-center gap-x-1 text-theme-text-primary text-base font-bold">
|
||||
{titleCase(alias)}
|
||||
<span className="text-theme-text-secondary font-normal text-sm">
|
||||
({totalModels} {pluralize("Model", totalModels)})
|
||||
</span>
|
||||
</h3>
|
||||
<div className="flex items-center gap-x-[4px]">
|
||||
<MonoProviderIcon
|
||||
provider={alias}
|
||||
match="pattern"
|
||||
size={16}
|
||||
className="text-theme-text-primary"
|
||||
/>
|
||||
<p className="flex items-center gap-x-1 text-theme-text-primary text-base font-bold">
|
||||
{titleCase(alias)}
|
||||
<span className="text-theme-text-secondary font-normal text-sm">
|
||||
({totalModels} {pluralize("Model", totalModels)})
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
<div hidden={!showAll} className="mt-[16px]">
|
||||
<div className="w-full flex flex-col gap-y-[8px]">
|
||||
{models.map((model) => (
|
||||
<ModelRow
|
||||
key={model.id}
|
||||
alias={alias}
|
||||
model={model}
|
||||
downloadModel={downloadModel}
|
||||
uninstallModel={uninstallModel}
|
||||
@ -105,7 +116,7 @@ function DeviceTypeTag({ deviceType }) {
|
||||
bgClass + " px-1.5 py-1 rounded-full flex items-center gap-x-1 w-fit"
|
||||
}
|
||||
>
|
||||
<Cpu size={16} weight="bold" className={textClass} />
|
||||
<Cpu size={14} weight="bold" className={textClass} />
|
||||
<p className={textClass + " text-xs"}>{text}</p>
|
||||
</div>
|
||||
);
|
||||
@ -116,32 +127,32 @@ function DeviceTypeTag({ deviceType }) {
|
||||
return (
|
||||
<Wrapper
|
||||
text="CPU"
|
||||
bgClass="bg-blue-600/20"
|
||||
textClass="text-blue-300"
|
||||
bgClass="bg-zinc-800 light:bg-zinc-200"
|
||||
textClass="text-theme-text-primary"
|
||||
/>
|
||||
);
|
||||
case "gpu":
|
||||
return (
|
||||
<Wrapper
|
||||
text="GPU"
|
||||
bgClass="bg-green-600/20"
|
||||
textClass="text-green-300"
|
||||
bgClass="bg-green-800 light:bg-green-200"
|
||||
textClass="text-theme-text-primary"
|
||||
/>
|
||||
);
|
||||
case "npu":
|
||||
return (
|
||||
<Wrapper
|
||||
text="NPU"
|
||||
bgClass="bg-indigo-600/20"
|
||||
textClass="text-indigo-300"
|
||||
bgClass="bg-indigo-800 light:bg-indigo-200"
|
||||
textClass="text-theme-text-primary"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<Wrapper
|
||||
text="CPU"
|
||||
bgClass="bg-blue-600/20"
|
||||
textClass="text-blue-300"
|
||||
bgClass="bg-zinc-800 light:bg-zinc-200"
|
||||
textClass="text-theme-text-primary"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -159,6 +170,7 @@ function DeviceTypeTag({ deviceType }) {
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
function ModelRow({
|
||||
alias,
|
||||
model,
|
||||
downloadModel = null,
|
||||
uninstallModel = null,
|
||||
@ -171,7 +183,7 @@ function ModelRow({
|
||||
const modelRowRef = useRef(null);
|
||||
const [showOptions, setShowOptions] = useState(false);
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [_downloadPercentage, setDownloadPercentage] = useState(0);
|
||||
const [downloadPercentage, setDownloadPercentage] = useState(0);
|
||||
const fileSize =
|
||||
typeof model.size === "number"
|
||||
? humanFileSize(model.size * 1e6, true, 2)
|
||||
@ -187,9 +199,9 @@ function ModelRow({
|
||||
try {
|
||||
if (!downloadModel) return;
|
||||
setProcessing(true);
|
||||
await downloadModel(model.id, fileSize, (percentage) =>
|
||||
setDownloadPercentage(percentage)
|
||||
);
|
||||
await downloadModel(model.id, fileSize, (percentage) => {
|
||||
setDownloadPercentage(percentage);
|
||||
});
|
||||
} catch {
|
||||
} finally {
|
||||
setProcessing(false);
|
||||
@ -233,31 +245,24 @@ function ModelRow({
|
||||
onClick={handleSetActiveModel}
|
||||
>
|
||||
{ui.showRuntime && <DeviceTypeTag deviceType={model.deviceType} />}
|
||||
<p className="text-theme-text-primary text-base px-2">{model.name}</p>
|
||||
{!ui.showRuntime &&
|
||||
model.downloaded &&
|
||||
alias === "Downloaded Models" && (
|
||||
<MonoProviderIcon
|
||||
provider={model.organization}
|
||||
match="pattern"
|
||||
size={16}
|
||||
className="text-theme-text-primary"
|
||||
/>
|
||||
)}
|
||||
<p className="text-theme-text-primary text-base">{model.name}</p>
|
||||
<p className="text-theme-text-secondary opacity-70 text-base">
|
||||
{fileSize}
|
||||
</p>
|
||||
</button>
|
||||
|
||||
<div className="justify-self-start">
|
||||
{isActiveModel && (
|
||||
<div className="flex items-center justify-center gap-x-[10px] whitespace-nowrap">
|
||||
<Circle size={8} weight="fill" className="text-green-500" />
|
||||
<p className="text-theme-text-primary text-sm">Active</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isActiveModel && model.downloaded && !uninstallModel && (
|
||||
<p className="text-theme-text-secondary text-sm italic whitespace-nowrap">
|
||||
Installed
|
||||
</p>
|
||||
)}
|
||||
|
||||
{!model.downloaded && (
|
||||
<p className="text-theme-text-secondary text-sm italic whitespace-nowrap">
|
||||
Not Installed
|
||||
</p>
|
||||
)}
|
||||
<RenderStatus model={model} isActiveModel={isActiveModel} />
|
||||
</div>
|
||||
|
||||
<div className="relative justify-self-end">
|
||||
@ -289,7 +294,7 @@ function ModelRow({
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
{!model.downloaded ? (
|
||||
{!model.downloaded && !processing && (
|
||||
<button
|
||||
type="button"
|
||||
data-tooltip-id="docker-model-runner-install-model-tooltip"
|
||||
@ -305,8 +310,50 @@ function ModelRow({
|
||||
className="text-theme-text-primary"
|
||||
/>
|
||||
</button>
|
||||
) : null}
|
||||
)}
|
||||
{!model.downloaded && processing && (
|
||||
<div className="flex items-center justify-center gap-x-[10px] whitespace-nowrap">
|
||||
{!downloadPercentage && (
|
||||
<CircleNotch
|
||||
size={16}
|
||||
weight="bold"
|
||||
className="text-theme-text-primary animate-spin"
|
||||
/>
|
||||
)}
|
||||
<p className="text-theme-text-secondary text-sm">
|
||||
{downloadPercentage}%
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RenderStatus({ model, isActiveModel }) {
|
||||
if (isActiveModel) {
|
||||
return (
|
||||
<div className="flex items-center justify-center gap-x-[10px] whitespace-nowrap">
|
||||
<Circle size={8} weight="fill" className="text-green-500" />
|
||||
<p className="text-theme-text-primary text-sm">Active</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isActiveModel && model.downloaded) {
|
||||
return (
|
||||
<p className="text-theme-text-secondary text-sm italic whitespace-nowrap">
|
||||
Installed
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
if (!model.downloaded) {
|
||||
return (
|
||||
<p className="text-theme-text-secondary text-sm italic whitespace-nowrap">
|
||||
Not Installed
|
||||
</p>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
80
frontend/src/components/lib/ModelTable/layout.jsx
Normal file
80
frontend/src/components/lib/ModelTable/layout.jsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
ArrowClockwise,
|
||||
CircleNotch,
|
||||
MagnifyingGlass,
|
||||
} from "@phosphor-icons/react";
|
||||
|
||||
export default function ModelTableLayout({
|
||||
children,
|
||||
fetchModels = null,
|
||||
searchQuery = "",
|
||||
setSearchQuery = () => {},
|
||||
loading = false,
|
||||
}) {
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
async function refreshModels() {
|
||||
setIsRefreshing(true);
|
||||
try {
|
||||
await fetchModels?.();
|
||||
} catch {
|
||||
} finally {
|
||||
setIsRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex gap-x-2 items-center pb-[8px]">
|
||||
<label className="text-theme-text-primary text-base font-semibold">
|
||||
Available Models
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-x-[16px]">
|
||||
<div className="relative flex-1 flex-grow">
|
||||
<MagnifyingGlass
|
||||
size={16}
|
||||
weight="bold"
|
||||
color="var(--theme-text-primary)"
|
||||
className="absolute left-[9px] top-[10px] text-theme-settings-input-placeholder peer-focus:invisible"
|
||||
/>
|
||||
<input
|
||||
type="search"
|
||||
placeholder="Search models"
|
||||
value={searchQuery}
|
||||
disabled={loading}
|
||||
className="min-h-[32px] border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5 pl-[30px] py-2 search-input disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
onChange={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setSearchQuery(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!!fetchModels && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={refreshModels}
|
||||
disabled={isRefreshing || loading}
|
||||
className="border-none text-theme-text-secondary text-sm font-medium hover:bg-white/10 light:hover:bg-black/5 rounded-lg px-2 h-full flex items-center gap-x-1 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isRefreshing ? (
|
||||
<CircleNotch className="w-4 h-4 text-theme-text-secondary animate-spin" />
|
||||
) : (
|
||||
<ArrowClockwise
|
||||
weight="bold"
|
||||
className="w-4 h-4 text-theme-text-secondary"
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={`text-sm font-medium ${isRefreshing ? "hidden" : "text-theme-text-secondary"}`}
|
||||
>
|
||||
Refresh Models
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
18
frontend/src/components/lib/ModelTable/loading.jsx
Normal file
18
frontend/src/components/lib/ModelTable/loading.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import * as Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function ModelTableLoadingSkeleton() {
|
||||
return (
|
||||
<div className="flex flex-col w-full gap-y-4 pt-4">
|
||||
<Skeleton.default
|
||||
height={100}
|
||||
width="100%"
|
||||
count={7}
|
||||
highlightColor="var(--theme-settings-input-active)"
|
||||
baseColor="var(--theme-settings-input-bg)"
|
||||
enableAnimation={true}
|
||||
containerClassName="w-fill flex gap-[8px] flex-col p-0"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
97
frontend/src/components/lib/MonoProviderIcon/index.jsx
Normal file
97
frontend/src/components/lib/MonoProviderIcon/index.jsx
Normal file
@ -0,0 +1,97 @@
|
||||
// https://lobehub.com/icons for all the icons
|
||||
import OpenAI from "@lobehub/icons/es/OpenAI/components/Mono";
|
||||
import Anthropic from "@lobehub/icons/es/Anthropic/components/Mono";
|
||||
import Google from "@lobehub/icons/es/Google/components/Mono";
|
||||
import Gemma from "@lobehub/icons/es/Gemma/components/Mono";
|
||||
import Gemini from "@lobehub/icons/es/Gemini/components/Mono";
|
||||
import Microsoft from "@lobehub/icons/es/Microsoft/components/Mono";
|
||||
import Meta from "@lobehub/icons/es/Meta/components/Mono";
|
||||
import Mistral from "@lobehub/icons/es/Mistral/components/Mono";
|
||||
import Azure from "@lobehub/icons/es/Azure/components/Mono";
|
||||
import AzureAI from "@lobehub/icons/es/AzureAI/components/Mono";
|
||||
import DeepSeek from "@lobehub/icons/es/DeepSeek/components/Mono";
|
||||
import HuggingFace from "@lobehub/icons/es/HuggingFace/components/Mono";
|
||||
import Qwen from "@lobehub/icons/es/Qwen/components/Mono";
|
||||
import IBM from "@lobehub/icons/es/IBM/components/Mono";
|
||||
import Bytedance from "@lobehub/icons/es/ByteDance/components/Mono";
|
||||
import Kimi from "@lobehub/icons/es/Kimi/components/Mono";
|
||||
import Snowflake from "@lobehub/icons/es/Snowflake/components/Mono";
|
||||
|
||||
// Direct provider key -> icon mapping for exact matches
|
||||
const providerIcons = {
|
||||
openai: OpenAI,
|
||||
anthropic: Anthropic,
|
||||
google: Google,
|
||||
microsoft: Microsoft,
|
||||
gemma: Gemma,
|
||||
gemini: Gemini,
|
||||
meta: Meta,
|
||||
mistral: Mistral,
|
||||
azure: Azure,
|
||||
azureai: AzureAI,
|
||||
deepseek: DeepSeek,
|
||||
huggingface: HuggingFace,
|
||||
qwen: Qwen,
|
||||
qwq: Qwen,
|
||||
ibm: IBM,
|
||||
bytedance: Bytedance,
|
||||
kimi: Kimi,
|
||||
};
|
||||
|
||||
// Pattern matching rules: regex pattern -> icon component
|
||||
// These are checked in order, first match wins
|
||||
const modelPatterns = [
|
||||
{ pattern: /^gpt/i, icon: OpenAI },
|
||||
{ pattern: /^o\d+/i, icon: OpenAI }, // o1, o3, etc.
|
||||
{ pattern: /^claude-/i, icon: Anthropic },
|
||||
{ pattern: /^gemini-/i, icon: Gemini },
|
||||
{ pattern: /gemma/i, icon: Gemma },
|
||||
{ pattern: /^llama/i, icon: Meta },
|
||||
{
|
||||
pattern: /^(mistral|devstral|mixtral|magistral|codestral|ministral)/i,
|
||||
icon: Mistral,
|
||||
},
|
||||
{ pattern: /^deepseek/i, icon: DeepSeek },
|
||||
{ pattern: /^qwen/i, icon: Qwen },
|
||||
{ pattern: /^qwq/i, icon: Qwen },
|
||||
{ pattern: /^phi/i, icon: Microsoft },
|
||||
{ pattern: /^granite/i, icon: IBM },
|
||||
{ pattern: /^doubao/i, icon: Bytedance },
|
||||
{ pattern: /^moonshot/i, icon: Kimi },
|
||||
{ pattern: /^smol/i, icon: HuggingFace },
|
||||
{ pattern: /^seed/i, icon: Bytedance },
|
||||
{ pattern: /^kimi/i, icon: Kimi },
|
||||
{ pattern: /^snowflake/i, icon: Snowflake },
|
||||
];
|
||||
|
||||
/**
|
||||
* Find icon by matching model name against known patterns
|
||||
* @param {string} modelName - The model name to match
|
||||
* @returns {React.ComponentType|null}
|
||||
*/
|
||||
function findIconByModelName(modelName) {
|
||||
if (!modelName) return null;
|
||||
const match = modelPatterns.find(({ pattern }) => pattern.test(modelName));
|
||||
return match?.icon || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} props - The props of the component.
|
||||
* @param {string} props.provider - The provider key (for exact match) or model name (for pattern match).
|
||||
* @param {('exact'|'pattern')} props.match - Match mode: 'exact' for provider key, 'pattern' for model name matching.
|
||||
* @param {number} props.size - The size of the icon.
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
export default function MonoProviderIcon({
|
||||
provider,
|
||||
match = "exact",
|
||||
size = 24,
|
||||
className = "",
|
||||
}) {
|
||||
let Icon = null;
|
||||
|
||||
if (match === "exact") Icon = providerIcons[provider?.toLowerCase()];
|
||||
else if (match === "pattern") Icon = findIconByModelName(provider);
|
||||
if (!Icon) return null;
|
||||
return <Icon size={size} className={className} />;
|
||||
}
|
||||
@ -15,6 +15,28 @@
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@ant-design/cssinjs@^2.0.0":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-2.0.3.tgz#b6d35b7b00f76fa8a8894d157bc158429ec7b1ca"
|
||||
integrity sha512-HAo8SZ3a6G8v6jT0suCz1270na6EA3obeJWM4uzRijBhdwdoMAXWK2f4WWkwB28yUufsfk3CAhN1coGPQq4kNQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.11.1"
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@emotion/unitless" "^0.7.5"
|
||||
"@rc-component/util" "^1.4.0"
|
||||
clsx "^2.1.1"
|
||||
csstype "^3.1.3"
|
||||
stylis "^4.3.4"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7"
|
||||
integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.28.5"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/code-frame@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465"
|
||||
@ -105,6 +127,17 @@
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/generator@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1"
|
||||
integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.28.6"
|
||||
"@babel/types" "^7.28.6"
|
||||
"@jridgewell/gen-mapping" "^0.3.12"
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271"
|
||||
@ -154,6 +187,14 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-module-imports@^7.16.7":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
|
||||
integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.28.6"
|
||||
"@babel/types" "^7.28.6"
|
||||
|
||||
"@babel/helper-module-imports@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b"
|
||||
@ -278,6 +319,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.5"
|
||||
|
||||
"@babel/parser@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd"
|
||||
integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.6"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.24.5":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz#66bff0248ea0b549972e733516ffad577477bdab"
|
||||
@ -292,6 +340,11 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
|
||||
"@babel/runtime@^7.11.1", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.24.1":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b"
|
||||
integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==
|
||||
|
||||
"@babel/runtime@^7.12.5":
|
||||
version "7.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326"
|
||||
@ -336,6 +389,15 @@
|
||||
"@babel/parser" "^7.27.2"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/template@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57"
|
||||
integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.28.6"
|
||||
"@babel/parser" "^7.28.6"
|
||||
"@babel/types" "^7.28.6"
|
||||
|
||||
"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.8.tgz#6c14ed5232b7549df3371d820fbd9abfcd7dfab7"
|
||||
@ -365,6 +427,19 @@
|
||||
"@babel/types" "^7.28.5"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/traverse@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e"
|
||||
integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.28.6"
|
||||
"@babel/generator" "^7.28.6"
|
||||
"@babel/helper-globals" "^7.28.0"
|
||||
"@babel/parser" "^7.28.6"
|
||||
"@babel/template" "^7.28.6"
|
||||
"@babel/types" "^7.28.6"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.24.9":
|
||||
version "7.24.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.9.tgz#228ce953d7b0d16646e755acf204f4cf3d08cc73"
|
||||
@ -382,6 +457,63 @@
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.28.5"
|
||||
|
||||
"@babel/types@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df"
|
||||
integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.28.5"
|
||||
|
||||
"@emotion/babel-plugin@^11.13.5":
|
||||
version "11.13.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0"
|
||||
integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.16.7"
|
||||
"@babel/runtime" "^7.18.3"
|
||||
"@emotion/hash" "^0.9.2"
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/serialize" "^1.3.3"
|
||||
babel-plugin-macros "^3.1.0"
|
||||
convert-source-map "^1.5.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
stylis "4.2.0"
|
||||
|
||||
"@emotion/cache@^11.11.0", "@emotion/cache@^11.13.5", "@emotion/cache@^11.14.0":
|
||||
version "11.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76"
|
||||
integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/sheet" "^1.4.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
"@emotion/weak-memoize" "^0.4.0"
|
||||
stylis "4.2.0"
|
||||
|
||||
"@emotion/css@^11.11.2":
|
||||
version "11.13.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.13.5.tgz#db2d3be6780293640c082848e728a50544b9dfa4"
|
||||
integrity sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==
|
||||
dependencies:
|
||||
"@emotion/babel-plugin" "^11.13.5"
|
||||
"@emotion/cache" "^11.13.5"
|
||||
"@emotion/serialize" "^1.3.3"
|
||||
"@emotion/sheet" "^1.4.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
|
||||
"@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/hash@^0.9.2":
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b"
|
||||
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
|
||||
|
||||
"@emotion/is-prop-valid@^0.7.3":
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc"
|
||||
@ -394,6 +526,66 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
|
||||
integrity sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==
|
||||
|
||||
"@emotion/memoize@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102"
|
||||
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==
|
||||
|
||||
"@emotion/react@^11.11.4":
|
||||
version "11.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d"
|
||||
integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
"@emotion/babel-plugin" "^11.13.5"
|
||||
"@emotion/cache" "^11.14.0"
|
||||
"@emotion/serialize" "^1.3.3"
|
||||
"@emotion/use-insertion-effect-with-fallbacks" "^1.2.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
"@emotion/weak-memoize" "^0.4.0"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^1.1.3", "@emotion/serialize@^1.3.3":
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8"
|
||||
integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.9.2"
|
||||
"@emotion/memoize" "^0.9.0"
|
||||
"@emotion/unitless" "^0.10.0"
|
||||
"@emotion/utils" "^1.4.2"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/sheet@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c"
|
||||
integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==
|
||||
|
||||
"@emotion/unitless@^0.10.0":
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745"
|
||||
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
|
||||
|
||||
"@emotion/unitless@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/use-insertion-effect-with-fallbacks@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf"
|
||||
integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==
|
||||
|
||||
"@emotion/utils@^1.2.1", "@emotion/utils@^1.4.2":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52"
|
||||
integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==
|
||||
|
||||
"@emotion/weak-memoize@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
|
||||
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
||||
|
||||
"@esbuild-plugins/node-globals-polyfill@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.1.1.tgz#a313ab3efbb2c17c8ce376aa216c627c9b40f9d7"
|
||||
@ -722,6 +914,15 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@lobehub/icons@^4.0.3":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@lobehub/icons/-/icons-4.0.3.tgz#85e14dd2684eed8324d8a0ed77fe8bd54b199504"
|
||||
integrity sha512-gEQI4Y2WmceBjE3l+3VEquZJb56NeCQEiBWtNXOcth28tVF0kL5FEtkXdtzpKuf21DQkFnzB1lb5oOgtEaBGMg==
|
||||
dependencies:
|
||||
antd-style "^4.1.0"
|
||||
lucide-react "^0.469.0"
|
||||
polished "^4.3.1"
|
||||
|
||||
"@microsoft/fetch-event-source@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
|
||||
@ -821,6 +1022,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@rc-component/util@^1.4.0":
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/util/-/util-1.7.0.tgz#c6eb178e0b1c48c5ae6325b21c60aeaf4f3d8d04"
|
||||
integrity sha512-tIvIGj4Vl6fsZFvWSkYw9sAfiCKUXMyhVz6kpKyZbwyZyRPqv2vxYZROdaO1VB4gqTNvUZFXh6i3APUiterw5g==
|
||||
dependencies:
|
||||
is-mobile "^5.0.0"
|
||||
react-is "^18.2.0"
|
||||
|
||||
"@remix-run/router@1.18.0":
|
||||
version "1.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.18.0.tgz#20b033d1f542a100c1d57cfd18ecf442d1784732"
|
||||
@ -966,6 +1175,11 @@
|
||||
dependencies:
|
||||
undici-types "~6.13.0"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
|
||||
integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
|
||||
@ -1073,6 +1287,20 @@ ansi-styles@^6.1.0:
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
||||
|
||||
antd-style@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/antd-style/-/antd-style-4.1.0.tgz#f2a7955946b87c3368e10de18edd5452d8b3058a"
|
||||
integrity sha512-vnPBGg0OVlSz90KRYZhxd89aZiOImTiesF+9MQqN8jsLGZUQTjbP04X9jTdEfsztKUuMbBWg/RmB/wHTakbtMQ==
|
||||
dependencies:
|
||||
"@ant-design/cssinjs" "^2.0.0"
|
||||
"@babel/runtime" "^7.24.1"
|
||||
"@emotion/cache" "^11.11.0"
|
||||
"@emotion/css" "^11.11.2"
|
||||
"@emotion/react" "^11.11.4"
|
||||
"@emotion/serialize" "^1.1.3"
|
||||
"@emotion/utils" "^1.2.1"
|
||||
use-merge-value "^1.2.0"
|
||||
|
||||
any-promise@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
@ -1225,6 +1453,15 @@ available-typed-arrays@^1.0.7:
|
||||
dependencies:
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
babel-plugin-macros@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
|
||||
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
cosmiconfig "^7.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
@ -1414,7 +1651,7 @@ clsx@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
|
||||
clsx@^2.0.0:
|
||||
clsx@^2.0.0, clsx@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
|
||||
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
|
||||
@ -1453,11 +1690,27 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
convert-source-map@^1.5.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
|
||||
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
|
||||
|
||||
convert-source-map@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
cosmiconfig@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
|
||||
integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
|
||||
dependencies:
|
||||
"@types/parse-json" "^4.0.0"
|
||||
import-fresh "^3.2.1"
|
||||
parse-json "^5.0.0"
|
||||
path-type "^4.0.0"
|
||||
yaml "^1.10.0"
|
||||
|
||||
cross-env@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||
@ -1524,6 +1777,11 @@ csstype@^3.0.2:
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
|
||||
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
|
||||
|
||||
csstype@^3.1.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
|
||||
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
|
||||
|
||||
"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
|
||||
@ -1763,6 +2021,13 @@ entities@~3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
|
||||
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
|
||||
integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2, es-abstract@^1.23.3:
|
||||
version "1.23.3"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0"
|
||||
@ -2246,6 +2511,11 @@ fill-range@^7.1.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
|
||||
|
||||
find-up@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
|
||||
@ -2597,7 +2867,7 @@ highlight.js@^11.9.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92"
|
||||
integrity sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==
|
||||
|
||||
hoist-non-react-statics@^3.2.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
hoist-non-react-statics@^3.2.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@ -2701,6 +2971,11 @@ is-array-buffer@^3.0.5:
|
||||
call-bound "^1.0.3"
|
||||
get-intrinsic "^1.2.6"
|
||||
|
||||
is-arrayish@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
|
||||
|
||||
is-async-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
|
||||
@ -2757,6 +3032,13 @@ is-core-module@^2.13.0:
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
is-core-module@^2.16.1:
|
||||
version "2.16.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
|
||||
integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
is-data-view@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f"
|
||||
@ -2834,6 +3116,11 @@ is-map@^2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
|
||||
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
|
||||
|
||||
is-mobile@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-mobile/-/is-mobile-5.0.0.tgz#1e08a0ef2c38a67bff84a52af68d67bcef445333"
|
||||
integrity sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==
|
||||
|
||||
is-negative-zero@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747"
|
||||
@ -3043,6 +3330,11 @@ json-buffer@3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
|
||||
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
|
||||
|
||||
json-parse-even-better-errors@^2.3.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
@ -3292,6 +3584,11 @@ lru-cache@^5.1.1:
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
lucide-react@^0.469.0:
|
||||
version "0.469.0"
|
||||
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.469.0.tgz#f16936ca6521482fef754a7eabb310e6c68e1482"
|
||||
integrity sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==
|
||||
|
||||
markdown-it@^13.0.1:
|
||||
version "13.0.2"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.2.tgz#1bc22e23379a6952e5d56217fbed881e0c94d536"
|
||||
@ -3573,6 +3870,16 @@ parent-module@^1.0.0:
|
||||
dependencies:
|
||||
callsites "^3.0.0"
|
||||
|
||||
parse-json@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
||||
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
error-ex "^1.3.1"
|
||||
json-parse-even-better-errors "^2.3.0"
|
||||
lines-and-columns "^1.1.6"
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||
@ -3596,6 +3903,11 @@ path-scurry@^1.11.1:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
picocolors@^1.0.0, picocolors@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
|
||||
@ -3638,6 +3950,13 @@ pluralize@^8.0.0:
|
||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
|
||||
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
|
||||
|
||||
polished@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/polished/-/polished-4.3.1.tgz#5a00ae32715609f83d89f6f31d0f0261c6170548"
|
||||
integrity sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.17.8"
|
||||
|
||||
possible-typed-array-names@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
|
||||
@ -3848,6 +4167,11 @@ react-is@^17.0.2:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^18.2.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react-jss@^10.9.2:
|
||||
version "10.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-10.10.0.tgz#d08ab3257b0eed01e15d6d8275840055c279b0da"
|
||||
@ -4067,6 +4391,15 @@ resolve@^1.1.7, resolve@^1.22.2:
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
resolve@^1.19.0:
|
||||
version "1.22.11"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262"
|
||||
integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==
|
||||
dependencies:
|
||||
is-core-module "^2.16.1"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
resolve@^2.0.0-next.5:
|
||||
version "2.0.0-next.5"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c"
|
||||
@ -4272,6 +4605,11 @@ source-map-js@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
|
||||
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
|
||||
|
||||
source-map@^0.5.7:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
|
||||
|
||||
source-map@^0.7.4:
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
|
||||
@ -4421,6 +4759,16 @@ strip-json-comments@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
stylis@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
|
||||
integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
|
||||
|
||||
stylis@^4.3.4:
|
||||
version "4.3.6"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320"
|
||||
integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==
|
||||
|
||||
sucrase@^3.32.0:
|
||||
version "3.35.0"
|
||||
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
|
||||
@ -4876,6 +5224,11 @@ use-memo-one@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
|
||||
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==
|
||||
|
||||
use-merge-value@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-merge-value/-/use-merge-value-1.2.0.tgz#45410846c23e490f404c9cbd17d67db9c8c0efcd"
|
||||
integrity sha512-DXgG0kkgJN45TcyoXL49vJnn55LehnrmoHc7MbKi+QDBvr8dsesqws8UlyIWGHMR+JXgxc1nvY+jDGMlycsUcw==
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
@ -5058,6 +5411,11 @@ yallist@^3.0.2:
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yaml@^1.10.0:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
yaml@^2.3.4:
|
||||
version "2.4.5"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e"
|
||||
|
||||
@ -253,11 +253,29 @@ function parseDockerModelRunnerEndpoint(basePath = null, to = "openai") {
|
||||
* @property {string} config?.gguf['*.context_length'] - The context length of the model. will be something like qwen3.context_length
|
||||
*/
|
||||
|
||||
function filterByTask(task = "chat", models = {}) {
|
||||
const possibleEmbed = [{ pattern: /^all-mini/i }, { pattern: /embed/i }];
|
||||
const isEmbedModel = (strTag) =>
|
||||
possibleEmbed.some((p) => p.pattern.test(strTag));
|
||||
const filteredModels = {};
|
||||
for (const [modelName, tags] of Object.entries(models)) {
|
||||
if (task === "chat") {
|
||||
if (isEmbedModel(modelName)) continue;
|
||||
filteredModels[modelName] = tags;
|
||||
} else if (task === "embedding") {
|
||||
if (!isEmbedModel(modelName)) continue;
|
||||
filteredModels[modelName] = tags;
|
||||
}
|
||||
}
|
||||
return filteredModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the remote models from the Docker Hub and cache the results.
|
||||
* @param {'chat' | 'embedding'} task - The task to fetch the models for.
|
||||
* @returns {Promise<Record<string, {id: string, name: string, size: string, organization: string}[]>>}
|
||||
*/
|
||||
async function fetchRemoteModels() {
|
||||
async function fetchRemoteModels(task = "chat") {
|
||||
const cachePath = path.resolve(
|
||||
DockerModelRunnerLLM.cacheFolder,
|
||||
"models.json"
|
||||
@ -271,7 +289,10 @@ async function fetchRemoteModels() {
|
||||
if (fs.existsSync(cachePath) && fs.existsSync(cachedAtPath)) {
|
||||
cacheTime = Number(fs.readFileSync(cachedAtPath, "utf8"));
|
||||
if (Date.now() - cacheTime < DockerModelRunnerLLM.cacheTime)
|
||||
return safeJsonParse(fs.readFileSync(cachePath, "utf8"));
|
||||
return filterByTask(
|
||||
task,
|
||||
safeJsonParse(fs.readFileSync(cachePath, "utf8"))
|
||||
);
|
||||
}
|
||||
|
||||
DockerModelRunnerLLM.slog(`Refreshing remote models from Docker Hub`);
|
||||
@ -367,15 +388,16 @@ async function fetchRemoteModels() {
|
||||
fs.writeFileSync(cachedAtPath, String(Number(new Date())), {
|
||||
encoding: "utf8",
|
||||
});
|
||||
return availableRemoteModels;
|
||||
return filterByTask(task, availableRemoteModels);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will fetch the remote models from the Docker Hub as well
|
||||
* as the local models installed on the system.
|
||||
* @param {string} basePath - The base path of the Docker Model Runner endpoint.
|
||||
* @param {'chat' | 'embedding'} task - The task to fetch the models for.
|
||||
*/
|
||||
async function getDockerModels(basePath = null) {
|
||||
async function getDockerModels(basePath = null, task = "chat") {
|
||||
let availableModels = {};
|
||||
/** @type {Array<DockerRunnerInstalledModel>} */
|
||||
let installedModels = {};
|
||||
@ -393,7 +415,7 @@ async function getDockerModels(basePath = null) {
|
||||
await fetch(dmrUrl.toString())
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
data?.map((model) => {
|
||||
data?.forEach((model) => {
|
||||
const id = model.tags.at(0);
|
||||
// eg: ai/qwen3:latest -> qwen3
|
||||
const tag =
|
||||
@ -411,7 +433,7 @@ async function getDockerModels(basePath = null) {
|
||||
});
|
||||
|
||||
// Now hit the Docker Hub API to get the remote model namespace and root tags
|
||||
const remoteModels = await fetchRemoteModels();
|
||||
const remoteModels = await fetchRemoteModels(task);
|
||||
for (const [modelName, tags] of Object.entries(remoteModels)) {
|
||||
availableModels[modelName] = { tags: [] };
|
||||
for (const tag of tags) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user