luojunhui 7 часов назад
Родитель
Сommit
e0c7cd466f

+ 0 - 1
.env.development

@@ -1,2 +1 @@
 VITE_API_BASE_URL=/videoVector
-#VITE_API_BASE_URL=/manager/vectorRecallProxy

+ 2 - 14
src/components/ArticleRecallTab.tsx

@@ -30,21 +30,10 @@ import {
 } from '../api/configCodes'
 import { useRecallFilters, RecallFilterBar } from './RecallFilterBar'
 import RankingWeightsPanel from './RankingWeightsPanel'
+import RecallFormSection from './RecallFormSection'
 
 const { Text, Paragraph } = Typography
 
-function RecallFormSection({ title, extra, children }: { title: string; extra?: React.ReactNode; children: React.ReactNode }) {
-  return (
-    <div>
-      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
-        <Text strong style={{ fontSize: 13 }}>{title}</Text>
-        {extra}
-      </div>
-      {children}
-    </div>
-  )
-}
-
 export default function ArticleRecallTab() {
   const [articleId, setArticleId] = useState('')
   const [articleInfo, setArticleInfo] = useState<ArticleBasicVO | null>(null)
@@ -160,7 +149,7 @@ export default function ArticleRecallTab() {
       <Card size="small" bodyStyle={{ padding: 16 }}>
         <Space direction="vertical" size={16} style={{ width: '100%' }}>
           {/* 长文ID + 召回维度 + TopN + 召回按钮 */}
-          <RecallFormSection title="长文查询">
+          <RecallFormSection title="长文查询" noBorder>
             <Space wrap size={[12, 8]}>
               <Text strong>长文ID</Text>
               <Input
@@ -216,7 +205,6 @@ export default function ArticleRecallTab() {
                           }
                           setRankingParams({ ...rankingParams, boostsByCode: next })
                         }}
-                        onPressEnter={onSubmit}
                         style={{ width: 68 }}
                       />
                     </div>

+ 2 - 14
src/components/MaterialRecallTab.tsx

@@ -29,21 +29,10 @@ import {
 } from '../api/configCodes'
 import { useRecallFilters, RecallFilterBar } from './RecallFilterBar'
 import RankingWeightsPanel from './RankingWeightsPanel'
+import RecallFormSection from './RecallFormSection'
 
 const { Text } = Typography
 
-function RecallFormSection({ title, extra, children }: { title: string; extra?: React.ReactNode; children: React.ReactNode }) {
-  return (
-    <div>
-      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
-        <Text strong style={{ fontSize: 13 }}>{title}</Text>
-        {extra}
-      </div>
-      {children}
-    </div>
-  )
-}
-
 export default function MaterialRecallTab() {
   const [materialId, setMaterialId] = useState('')
   const [materialInfo, setMaterialInfo] = useState<MaterialBasicVO | null>(null)
@@ -166,7 +155,7 @@ export default function MaterialRecallTab() {
       <Card size="small" bodyStyle={{ padding: 16 }}>
         <Space direction="vertical" size={16} style={{ width: '100%' }}>
           {/* 素材ID + 召回维度 + TopN + 召回按钮 */}
-          <RecallFormSection title="素材查询">
+          <RecallFormSection title="素材查询" noBorder>
             <Space wrap size={[12, 8]}>
               <Text strong>素材ID</Text>
               <Input
@@ -222,7 +211,6 @@ export default function MaterialRecallTab() {
                           }
                           setRankingParams({ ...rankingParams, boostsByCode: next })
                         }}
-                        onPressEnter={onSubmit}
                         style={{ width: 68 }}
                       />
                     </div>

+ 2 - 1
src/components/RankingSettingsButton.tsx

@@ -32,8 +32,9 @@ const FORMULA_VIDEO = `综合得分 = c × (α × sim_norm + (1-α) × rov_norm)
   c = deconstructBoost (选题/灵感点/关键点/目的点) / 1.0 (其他维度)
 先按 simThreshold 硬筛 (sim < 阈值剔除), 再按综合分排序.`
 
-const FORMULA_MATERIAL = `综合得分 = (wSim×sim_norm + wCtr×ctr + wViral×viral + wRoi×roi) / totalW
+const FORMULA_MATERIAL = `综合得分 = α × sim_norm + (1-α) × qualityScore
   sim_norm = clip((sim - simThreshold) / (1 - simThreshold), 0, 1)
+  qualityScore = (wCtr×ctr + wViral×viral + wRoi×roi) / (wCtr+wViral+wRoi)
 先按 simThreshold 硬筛, 再按综合分排序.`
 
 const FORMULA_LEGACY = `${FORMULA_VIDEO}

+ 29 - 0
src/components/RecallFormSection.tsx

@@ -0,0 +1,29 @@
+import type { ReactNode } from 'react'
+import { Typography } from 'antd'
+
+const { Text } = Typography
+
+export default function RecallFormSection({
+  title,
+  extra,
+  children,
+  noBorder = false,
+}: {
+  title: string
+  extra?: ReactNode
+  children: ReactNode
+  noBorder?: boolean
+}) {
+  return (
+    <div style={{
+      borderTop: noBorder ? undefined : '1px solid #f0f0f0',
+      paddingTop: noBorder ? 0 : 12,
+    }}>
+      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+        <Text strong style={{ fontSize: 13 }}>{title}</Text>
+        {extra}
+      </div>
+      {children}
+    </div>
+  )
+}

+ 3 - 23
src/pages/RecallTestPage.tsx

@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import {
   Tabs,
   Card,
@@ -37,6 +37,7 @@ import MaterialRecallTab from '../components/MaterialRecallTab'
 import ArticleRecallTab from '../components/ArticleRecallTab'
 import { useRecallFilters, RecallFilterBar } from '../components/RecallFilterBar'
 import RankingWeightsPanel from '../components/RankingWeightsPanel'
+import RecallFormSection from '../components/RecallFormSection'
 import type { Modality } from '../api/types'
 import { DEFAULT_RANKING_PARAMS } from '../utils/scoring'
 import { toHttps } from '../utils/url'
@@ -746,7 +747,7 @@ function TextRecallTab() {
     <Space direction="vertical" size={16} style={{ width: '100%' }}>
       <Card size="small" bodyStyle={{ padding: 16 }}>
         <Space direction="vertical" size={16} style={{ width: '100%' }}>
-          <RecallFormSection title="召回文本">
+          <RecallFormSection title="召回文本" noBorder>
             <TextArea
               placeholder="请输入查询文本(选题、灵感点描述等)"
               value={queryText}
@@ -801,7 +802,6 @@ function TextRecallTab() {
                           }
                           setRankingParams({ ...rankingParams, boostsByCode: next })
                         }}
-                        onPressEnter={onSubmit}
                         style={{ width: 68 }}
                       />
                     </div>
@@ -847,23 +847,3 @@ function TextRecallTab() {
     </Space>
   )
 }
-
-function RecallFormSection({
-  title,
-  extra,
-  children,
-}: {
-  title: string
-  extra?: ReactNode
-  children: ReactNode
-}) {
-  return (
-    <div style={{ borderTop: title === '召回文本' ? undefined : '1px solid #f0f0f0', paddingTop: title === '召回文本' ? 0 : 12 }}>
-      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
-        <Text strong>{title}</Text>
-        {extra}
-      </div>
-      {children}
-    </div>
-  )
-}

+ 5 - 1
src/utils/scoring.ts

@@ -72,7 +72,7 @@ const clip01 = (x: number) => Math.max(0, Math.min(1, x))
 function materialQualityFromDetail(
   item: VideoMatchEnrichedVO,
 ): RecallSignals['quality'] | undefined {
-  const q = item.materialDetail?.quality ?? item.quality
+  const q = item.materialDetail?.quality
   if (!q) return undefined
   const ctr = q.conversionEfficiencyScore
   const viral = q.viralScore
@@ -220,6 +220,10 @@ function loadFromStorage(): RankingParams {
     if (parsed.rovClipHigh === undefined && typeof parsed.rovP95 === 'number') {
       parsed.rovClipHigh = parsed.rovP95
     }
+    // 清理已迁移/废弃的字段,避免脏数据残留
+    delete parsed.rovP5
+    delete parsed.rovP95
+    delete parsed.wSim
 
     return {
       ...DEFAULT_RANKING_PARAMS,