diff --git a/model/model_meta.go b/model/model_meta.go
index 53b00f28..63b6800e 100644
--- a/model/model_meta.go
+++ b/model/model_meta.go
@@ -38,6 +38,7 @@ type Model struct {
Id int `json:"id"`
ModelName string `json:"model_name" gorm:"size:128;not null;uniqueIndex:uk_model_name,priority:1"`
Description string `json:"description,omitempty" gorm:"type:text"`
+ Icon string `json:"icon,omitempty" gorm:"type:varchar(128)"`
Tags string `json:"tags,omitempty" gorm:"type:varchar(255)"`
VendorID int `json:"vendor_id,omitempty" gorm:"index"`
Endpoints string `json:"endpoints,omitempty" gorm:"type:text"`
diff --git a/model/pricing.go b/model/pricing.go
index 2b3920ba..c5fbff36 100644
--- a/model/pricing.go
+++ b/model/pricing.go
@@ -16,6 +16,7 @@ import (
type Pricing struct {
ModelName string `json:"model_name"`
Description string `json:"description,omitempty"`
+ Icon string `json:"icon,omitempty"`
Tags string `json:"tags,omitempty"`
VendorID int `json:"vendor_id,omitempty"`
QuotaType int `json:"quota_type"`
@@ -272,6 +273,7 @@ func updatePricing() {
continue
}
pricing.Description = meta.Description
+ pricing.Icon = meta.Icon
pricing.Tags = meta.Tags
pricing.VendorID = meta.VendorID
}
diff --git a/web/src/components/table/model-pricing/modal/components/ModelHeader.jsx b/web/src/components/table/model-pricing/modal/components/ModelHeader.jsx
index 63475819..c5302ea5 100644
--- a/web/src/components/table/model-pricing/modal/components/ModelHeader.jsx
+++ b/web/src/components/table/model-pricing/modal/components/ModelHeader.jsx
@@ -29,9 +29,19 @@ const CARD_STYLES = {
};
const ModelHeader = ({ modelData, vendorsMap = {}, t }) => {
- // 获取模型图标(使用供应商图标)
+ // 获取模型图标(优先模型图标,其次供应商图标)
const getModelIcon = () => {
- // 优先使用供应商图标
+ // 1) 优先使用模型自定义图标
+ if (modelData?.icon) {
+ return (
+
+
+ {getLobeHubIcon(modelData.icon, 32)}
+
+
+ );
+ }
+ // 2) 退化为供应商图标
if (modelData?.vendor_icon) {
return (
diff --git a/web/src/components/table/model-pricing/view/card/PricingCardView.jsx b/web/src/components/table/model-pricing/view/card/PricingCardView.jsx
index 516d43e5..a849dbaa 100644
--- a/web/src/components/table/model-pricing/view/card/PricingCardView.jsx
+++ b/web/src/components/table/model-pricing/view/card/PricingCardView.jsx
@@ -81,7 +81,17 @@ const PricingCardView = ({
);
}
- // 优先使用供应商图标
+ // 1) 优先使用模型自定义图标
+ if (model.icon) {
+ return (
+
+
+ {getLobeHubIcon(model.icon, 32)}
+
+
+ );
+ }
+ // 2) 退化为供应商图标
if (model.vendor_icon) {
return (
diff --git a/web/src/components/table/models/ModelsColumnDefs.js b/web/src/components/table/models/ModelsColumnDefs.js
index ef433553..6514e752 100644
--- a/web/src/components/table/models/ModelsColumnDefs.js
+++ b/web/src/components/table/models/ModelsColumnDefs.js
@@ -33,6 +33,17 @@ function renderTimestamp(timestamp) {
return <>{timestamp2string(timestamp)}>;
}
+// Render model icon column: prefer model.icon, then fallback to vendor icon
+const renderModelIconCol = (record, vendorMap) => {
+ const iconKey = record?.icon || vendorMap[record?.vendor_id]?.icon;
+ if (!iconKey) return '-';
+ return (
+
+ {getLobeHubIcon(iconKey, 20)}
+
+ );
+};
+
// Render vendor column with icon
const renderVendorTag = (vendorId, vendorMap, t) => {
if (!vendorId || !vendorMap[vendorId]) return '-';
@@ -222,6 +233,13 @@ export const getModelsColumns = ({
vendorMap,
}) => {
return [
+ {
+ title: t('图标'),
+ dataIndex: 'icon',
+ width: 70,
+ align: 'center',
+ render: (text, record) => renderModelIconCol(record, vendorMap),
+ },
{
title: t('模型名称'),
dataIndex: 'model_name',
diff --git a/web/src/components/table/models/modals/EditModelModal.jsx b/web/src/components/table/models/modals/EditModelModal.jsx
index f2f50018..cacb639e 100644
--- a/web/src/components/table/models/modals/EditModelModal.jsx
+++ b/web/src/components/table/models/modals/EditModelModal.jsx
@@ -33,6 +33,7 @@ import {
Row,
} from '@douyinfe/semi-ui';
import { Save, X, FileText } from 'lucide-react';
+import { IconLink } from '@douyinfe/semi-icons';
import { API, showError, showSuccess } from '../../../../helpers';
import { useTranslation } from 'react-i18next';
import { useIsMobile } from '../../../../hooks/common/useIsMobile';
@@ -112,6 +113,7 @@ const EditModelModal = (props) => {
const getInitValues = () => ({
model_name: props.editingModel?.model_name || '',
description: '',
+ icon: '',
tags: [],
vendor_id: undefined,
vendor: '',
@@ -314,6 +316,27 @@ const EditModelModal = (props) => {
/>
+
+
+ {t('图标使用@lobehub/icons库,如:OpenAI、Claude.Color,支持链式参数:OpenAI.Avatar.type={\'platform\'}、OpenRouter.Avatar.shape={\'square\'},查询所有可用图标请 ')}
+ }
+ underline
+ >
+ {t('请点击我')}
+
+
+ }
+ showClear
+ />
+
+