Преглед изворни кода

🚀 feat(pricing): clarify “auto” group routing chain and exclude it from price table

Detailed changes
Backend
• `controller/pricing.go` now includes `auto_groups` in `/api/pricing` response, sourced from `setting.AutoGroups`.

Frontend
• `useModelPricingData.js`
  – Parses `auto_groups` and exposes `autoGroups` state.
• `PricingPage.jsx` → `ModelDetailSideSheet.jsx` → `ModelPricingTable.jsx`
  – Thread `autoGroups` through component tree.
• `ModelPricingTable.jsx`
  – Removes deprecated `getGroupDescription` / `Tooltip`.
  – Filters out `auto` when building price table rows.
  – Renders a descriptive banner: “auto 分组调用链路 → auto → group1 → …”, clarifying fallback order without showing prices.
• Minor i18n tweak: adds `auto分组调用链路` key for the banner text.

Why
Users were confused by the “auto” tag appearing alongside regular groups with no price.
This change:
1. Makes the routing chain explicit.
2. Keeps the pricing table focused on billable groups.

No breaking API changes; existing clients can ignore the new `auto_groups` field.
t0ng7u пре 7 месеци
родитељ
комит
1690b05629

+ 2 - 1
controller/pricing.go

@@ -42,9 +42,10 @@ func GetPricing(c *gin.Context) {
 		"success":      true,
 		"data":         pricing,
 		"vendors":      model.GetVendors(),
-		        "group_ratio":  groupRatio,
+		"group_ratio":  groupRatio,
         "usable_group": usableGroup,
         "supported_endpoint": model.GetSupportedEndpointMap(),
+        "auto_groups": setting.AutoGroups,
     })
 }
 

+ 1 - 1
web/src/components/table/model-pricing/layout/PricingPage.jsx

@@ -72,7 +72,6 @@ const PricingPage = () => {
         visible={pricingData.showModelDetail}
         onClose={pricingData.closeModelDetail}
         modelData={pricingData.selectedModel}
-        selectedGroup={pricingData.selectedGroup}
         groupRatio={pricingData.groupRatio}
         usableGroup={pricingData.usableGroup}
         currency={pricingData.currency}
@@ -81,6 +80,7 @@ const PricingPage = () => {
         showRatio={allProps.showRatio}
         vendorsMap={pricingData.vendorsMap}
         endpointMap={pricingData.endpointMap}
+        autoGroups={pricingData.autoGroups}
         t={pricingData.t}
       />
     </div>

+ 2 - 2
web/src/components/table/model-pricing/modal/ModelDetailSideSheet.jsx

@@ -39,7 +39,6 @@ const ModelDetailSideSheet = ({
   visible,
   onClose,
   modelData,
-  selectedGroup,
   groupRatio,
   currency,
   tokenUnit,
@@ -48,6 +47,7 @@ const ModelDetailSideSheet = ({
   usableGroup,
   vendorsMap,
   endpointMap,
+  autoGroups,
   t,
 }) => {
   const isMobile = useIsMobile();
@@ -86,13 +86,13 @@ const ModelDetailSideSheet = ({
             <ModelEndpoints modelData={modelData} endpointMap={endpointMap} t={t} />
             <ModelPricingTable
               modelData={modelData}
-              selectedGroup={selectedGroup}
               groupRatio={groupRatio}
               currency={currency}
               tokenUnit={tokenUnit}
               displayPrice={displayPrice}
               showRatio={showRatio}
               usableGroup={usableGroup}
+              autoGroups={autoGroups}
               t={t}
             />
           </>

+ 26 - 27
web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx

@@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
 */
 
 import React from 'react';
-import { Card, Avatar, Typography, Table, Tag, Tooltip } from '@douyinfe/semi-ui';
+import { Card, Avatar, Typography, Table, Tag } from '@douyinfe/semi-ui';
 import { IconCoinMoneyStroked } from '@douyinfe/semi-icons';
 import { calculateModelPrice } from '../../../../../helpers';
 
@@ -26,34 +26,24 @@ const { Text } = Typography;
 
 const ModelPricingTable = ({
   modelData,
-  selectedGroup,
   groupRatio,
   currency,
   tokenUnit,
   displayPrice,
   showRatio,
   usableGroup,
+  autoGroups = [],
   t,
 }) => {
-  // 获取分组介绍
-  const getGroupDescription = (groupName) => {
-    const descriptions = {
-      'default': t('默认分组,适用于普通用户'),
-      'ssvip': t('超级VIP分组,享受最优惠价格'),
-      'openai官-优质': t('OpenAI官方优质分组,最快最稳,支持o1、realtime等'),
-      'origin': t('企业分组,OpenAI&Claude官方原价,不升价本分组稳定性可用性'),
-      'vip': t('VIP分组,享受优惠价格'),
-      'premium': t('高级分组,稳定可靠'),
-      'enterprise': t('企业级分组,专业服务'),
-    };
-    return descriptions[groupName] || t('用户分组');
-  };
-
   const renderGroupPriceTable = () => {
-    const availableGroups = Object.keys(usableGroup || {}).filter(g => g !== '');
-    if (availableGroups.length === 0) {
-      availableGroups.push('default');
-    }
+    // 仅展示模型可用的分组:模型 enable_groups 与用户可用分组的交集
+    const modelEnableGroups = Array.isArray(modelData?.enable_groups)
+      ? modelData.enable_groups
+      : [];
+    const availableGroups = Object.keys(usableGroup || {})
+      .filter(g => g !== '')
+      .filter(g => g !== 'auto')
+      .filter(g => modelEnableGroups.includes(g));
 
     // 准备表格数据
     const tableData = availableGroups.map(group => {
@@ -72,7 +62,6 @@ const ModelPricingTable = ({
       return {
         key: group,
         group: group,
-        description: getGroupDescription(group),
         ratio: groupRatioValue,
         billingType: modelData?.quota_type === 0 ? t('按量计费') : t('按次计费'),
         inputPrice: modelData?.quota_type === 0 ? priceData.inputPrice : '-',
@@ -86,12 +75,10 @@ const ModelPricingTable = ({
       {
         title: t('分组'),
         dataIndex: 'group',
-        render: (text, record) => (
-          <Tooltip content={record.description} position="top">
-            <Tag color="white" size="small" shape="circle" className="cursor-help">
-              {text}{t('分组')}
-            </Tag>
-          </Tooltip>
+        render: (text) => (
+          <Tag color="white" size="small" shape="circle">
+            {text}{t('分组')}
+          </Tag>
         ),
       },
     ];
@@ -182,6 +169,18 @@ const ModelPricingTable = ({
           <div className="text-xs text-gray-600">{t('不同用户分组的价格信息')}</div>
         </div>
       </div>
+      {autoGroups && autoGroups.length > 0 && (
+        <div className="flex flex-wrap items-center gap-1 mb-4">
+          <span className="text-sm text-gray-600">{t('auto分组调用链路')}</span>
+          <span className="text-sm">→</span>
+          {autoGroups.map((g, idx) => (
+            <React.Fragment key={g}>
+              <Tag color="white" size="small" shape="circle">{g}{t('分组')}</Tag>
+              {idx < autoGroups.length - 1 && <span className="text-sm">→</span>}
+            </React.Fragment>
+          ))}
+        </div>
+      )}
       {renderGroupPriceTable()}
     </Card>
   );

+ 4 - 1
web/src/hooks/model-pricing/useModelPricingData.js

@@ -49,6 +49,7 @@ export const useModelPricingData = () => {
   const [groupRatio, setGroupRatio] = useState({});
   const [usableGroup, setUsableGroup] = useState({});
   const [endpointMap, setEndpointMap] = useState({});
+  const [autoGroups, setAutoGroups] = useState([]);
 
   const [statusState] = useContext(StatusContext);
   const [userState] = useContext(UserContext);
@@ -160,7 +161,7 @@ export const useModelPricingData = () => {
     setLoading(true);
     let url = '/api/pricing';
     const res = await API.get(url);
-    const { success, message, data, vendors, group_ratio, usable_group, supported_endpoint } = res.data;
+    const { success, message, data, vendors, group_ratio, usable_group, supported_endpoint, auto_groups } = res.data;
     if (success) {
       setGroupRatio(group_ratio);
       setUsableGroup(usable_group);
@@ -174,6 +175,7 @@ export const useModelPricingData = () => {
       }
       setVendorsMap(vendorMap);
       setEndpointMap(supported_endpoint || {});
+      setAutoGroups(auto_groups || []);
       setModelsFormat(data, group_ratio, vendorMap);
     } else {
       showError(message);
@@ -282,6 +284,7 @@ export const useModelPricingData = () => {
     groupRatio,
     usableGroup,
     endpointMap,
+    autoGroups,
 
     // 计算属性
     priceRate,