From d8cb5261b97140b1ee7782f57d99957eade3f0bc Mon Sep 17 00:00:00 2001 From: jialin Date: Thu, 16 Jul 2026 17:30:51 +0800 Subject: [PATCH] feat(user-models): fall back to category icon when no brand logo matches --- src/assets/model_icons/embedding.svg | 24 +++++++++++++ src/assets/model_icons/image.svg | 22 ++++++++++++ src/assets/model_icons/llm.svg | 17 +++++++++ src/assets/model_icons/reranker.svg | 19 +++++++++++ src/assets/model_icons/stt.svg | 18 ++++++++++ src/assets/model_icons/tts.svg | 23 +++++++++++++ src/pages/llmodels/components/model-item.tsx | 19 +++++++++-- src/pages/llmodels/utils/model-logo.ts | 36 +++++++++++++++++--- 8 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 src/assets/model_icons/embedding.svg create mode 100644 src/assets/model_icons/image.svg create mode 100644 src/assets/model_icons/llm.svg create mode 100644 src/assets/model_icons/reranker.svg create mode 100644 src/assets/model_icons/stt.svg create mode 100644 src/assets/model_icons/tts.svg diff --git a/src/assets/model_icons/embedding.svg b/src/assets/model_icons/embedding.svg new file mode 100644 index 00000000..6776c323 --- /dev/null +++ b/src/assets/model_icons/embedding.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/model_icons/image.svg b/src/assets/model_icons/image.svg new file mode 100644 index 00000000..34448241 --- /dev/null +++ b/src/assets/model_icons/image.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/model_icons/llm.svg b/src/assets/model_icons/llm.svg new file mode 100644 index 00000000..cbf12a16 --- /dev/null +++ b/src/assets/model_icons/llm.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/model_icons/reranker.svg b/src/assets/model_icons/reranker.svg new file mode 100644 index 00000000..36377aa6 --- /dev/null +++ b/src/assets/model_icons/reranker.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/model_icons/stt.svg b/src/assets/model_icons/stt.svg new file mode 100644 index 00000000..d0a111c0 --- /dev/null +++ b/src/assets/model_icons/stt.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/model_icons/tts.svg b/src/assets/model_icons/tts.svg new file mode 100644 index 00000000..2640d56a --- /dev/null +++ b/src/assets/model_icons/tts.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pages/llmodels/components/model-item.tsx b/src/pages/llmodels/components/model-item.tsx index bf2202e5..09b8c33f 100644 --- a/src/pages/llmodels/components/model-item.tsx +++ b/src/pages/llmodels/components/model-item.tsx @@ -20,7 +20,11 @@ import { MyModelsStatusValueMap } from '../config'; import { categoryToPathMap } from '../config/button-actions'; -import { getModelLogo } from '../utils/model-logo'; +import { + defaultModelLogo, + getCategoryLogo, + getModelLogo +} from '../utils/model-logo'; const CardWrapper = styled.div` &:hover { @@ -165,6 +169,11 @@ const ModelItem: React.FC<{ navigate(`/playground/chat?model=${modelName}`); }; + // Logo priority: brand logo matched from the name → tinted category + // icon (from model_icons) → generic default image. + const brandLogo = getModelLogo(model.name); + const categoryLogo = brandLogo ? null : getCategoryLogo(model.categories); + // context length const maxToken = useMemo(() => { const meta = model.meta || {}; @@ -194,7 +203,13 @@ const ModelItem: React.FC<{ header={
- + {brandLogo ? ( + + ) : categoryLogo ? ( + + ) : ( + + )} {model.name} = { + llm: 'llm', + embedding: 'embedding', + reranker: 'reranker', + image: 'image', + text_to_speech: 'tts', + speech_to_text: 'stt' +}; + /** - * Resolve a model logo from its name. + * Resolve a category icon (from model_icons) for a model's categories. + * Returns the first matching category icon url, or null when none match. + */ +export const getCategoryLogo = (categories?: string[]): string | null => { + const iconName = categories + ?.map((category) => CATEGORY_ICON_MAP[category]) + .find((name) => name && iconMap[name]); + + return iconName ? iconMap[iconName] : null; +}; + +/** + * Resolve a brand logo from a model name. * 1. Match against the keyword rules in order (first substring hit wins). * 2. Fall back to a direct match where the name contains an icon filename. - * 3. Fall back to the default llm icon. + * 3. Return null when nothing matches — the caller then falls back to a + * category-based icon (see `categoryConfig`) rather than a default image. */ -export const getModelLogo = (modelName?: string): string => { +export const getModelLogo = (modelName?: string): string | null => { const name = (modelName || '').toLowerCase(); const rule = MODEL_ICON_RULES.find(([keyword]) => name.includes(keyword)); @@ -90,5 +118,5 @@ export const getModelLogo = (modelName?: string): string => { .sort((a, b) => b.length - a.length) .find((iconName) => name.includes(iconName)); - return iconMap[directHit || DEFAULT_ICON] || iconMap[DEFAULT_ICON]; + return directHit ? iconMap[directHit] : null; };