Browse Source

🔍 feat: Show matched model names & counts for non-exact model rules

Summary
-------
1. **Backend**
   • `model/model_meta.go`
     – Add `MatchedModels []string` and `MatchedCount int` (ignored by GORM) to expose matching details in API responses.
   • `controller/model_meta.go`
     – When processing prefix/suffix/contains rules in `fillModelExtra`, collect every matched model name, fill `MatchedModels`, and calculate `MatchedCount`.

2. **Frontend**
   • `web/src/components/table/models/ModelsColumnDefs.js`
     – Import `Tooltip`.
     – Enhance `renderNameRule` to:
       – Display tag text like “前缀 5个模型” for non-exact rules.
       – Show a tooltip listing all matched model names on hover.

Impact
------
Users now see the total number of concrete models aggregated under each prefix/suffix/contains rule and can inspect the exact list via tooltip, improving transparency in model management.
t0ng7u 4 months ago
parent
commit
c8f7aa76e7

+ 10 - 0
controller/model_meta.go

@@ -183,6 +183,9 @@ func fillModelExtra(m *model.Model) {
 	// 非精确匹配:计算并集
 	pricings := model.GetPricing()
 
+	// 匹配到的模型名称集合
+	matchedNames := make([]string, 0)
+
 	// 端点去重集合
 	endpointSet := make(map[constant.EndpointType]struct{})
 	// 已绑定渠道去重集合
@@ -206,6 +209,9 @@ func fillModelExtra(m *model.Model) {
 			continue
 		}
 
+		// 记录匹配到的模型名称
+		matchedNames = append(matchedNames, p.ModelName)
+
 		// 收集端点
 		for _, et := range p.SupportedEndpointTypes {
 			endpointSet[et] = struct{}{}
@@ -265,4 +271,8 @@ func fillModelExtra(m *model.Model) {
 	} else {
 		m.QuotaType = -1
 	}
+
+	// 设置匹配信息
+	m.MatchedModels = matchedNames
+	m.MatchedCount = len(matchedNames)
 }

+ 3 - 0
model/model_meta.go

@@ -51,6 +51,9 @@ type Model struct {
 	EnableGroups  []string       `json:"enable_groups,omitempty" gorm:"-"`
 	QuotaType     int            `json:"quota_type" gorm:"-"`
 	NameRule      int            `json:"name_rule" gorm:"default:0"`
+
+	MatchedModels []string `json:"matched_models,omitempty" gorm:"-"`
+	MatchedCount  int      `json:"matched_count,omitempty" gorm:"-"`
 }
 
 // Insert 创建新的模型元数据记录

+ 22 - 6
web/src/components/table/models/ModelsColumnDefs.js

@@ -18,7 +18,7 @@ For commercial licensing, please contact [email protected]
 */
 
 import React from 'react';
-import { Button, Space, Tag, Typography, Modal } from '@douyinfe/semi-ui';
+import { Button, Space, Tag, Typography, Modal, Tooltip } from '@douyinfe/semi-ui';
 import {
   timestamp2string,
   getLobeHubIcon,
@@ -208,8 +208,8 @@ const renderOperations = (text, record, setEditingModel, setShowEdit, manageMode
   );
 };
 
-// 名称匹配类型渲染
-const renderNameRule = (rule, t) => {
+// 名称匹配类型渲染(带匹配数量 Tooltip)
+const renderNameRule = (rule, record, t) => {
   const map = {
     0: { color: 'green', label: t('精确') },
     1: { color: 'blue', label: t('前缀') },
@@ -218,11 +218,27 @@ const renderNameRule = (rule, t) => {
   };
   const cfg = map[rule];
   if (!cfg) return '-';
-  return (
+
+  let label = cfg.label;
+  if (rule !== 0 && record.matched_count) {
+    label = `${cfg.label} ${record.matched_count}${t('个模型')}`;
+  }
+
+  const tagElement = (
     <Tag color={cfg.color} size="small" shape='circle'>
-      {cfg.label}
+      {label}
     </Tag>
   );
+
+  if (rule === 0 || !record.matched_models || record.matched_models.length === 0) {
+    return tagElement;
+  }
+
+  return (
+    <Tooltip content={record.matched_models.join(', ')} showArrow>
+      {tagElement}
+    </Tooltip>
+  );
 };
 
 export const getModelsColumns = ({
@@ -253,7 +269,7 @@ export const getModelsColumns = ({
     {
       title: t('匹配类型'),
       dataIndex: 'name_rule',
-      render: (val) => renderNameRule(val, t),
+      render: (val, record) => renderNameRule(val, record, t),
     },
     {
       title: t('描述'),