|
|
@@ -26,6 +26,7 @@ import {
|
|
|
VideoCameraOutlined,
|
|
|
ThunderboltOutlined,
|
|
|
} from '@ant-design/icons'
|
|
|
+import DimensionBoostRow from '../components/DimensionBoostRow'
|
|
|
import RecallResultList from '../components/RecallResultList'
|
|
|
import VideoPlayer from '../components/VideoPlayer'
|
|
|
import DeconstructTree, {
|
|
|
@@ -217,6 +218,7 @@ function VideoIdTab() {
|
|
|
|
|
|
/** 视频Tab 不再有顶部维度选择, 维度由解构层级里每条点的"以此召回"按钮直接传入 */
|
|
|
const [topN, setTopN] = useState<number>(10)
|
|
|
+ const [days, setDays] = useState<number | undefined>(undefined)
|
|
|
const recallFilters = useRecallFilters()
|
|
|
const [rankingParams] = useRankingParams()
|
|
|
|
|
|
@@ -290,7 +292,7 @@ function VideoIdTab() {
|
|
|
description: `基于文本 "${preview}"`,
|
|
|
})
|
|
|
try {
|
|
|
- const data = await matchByText({ queryText: trimmed, configCode: finalConfigCode, topN, displayK: topN, ...recallFilters.toParams(), ranking: rankingForRequest(rankingParams, [finalConfigCode]) })
|
|
|
+ const data = await matchByText({ queryText: trimmed, configCode: finalConfigCode, days, topN, displayK: topN, ...recallFilters.toParams(), ranking: rankingForRequest(rankingParams, [finalConfigCode]) })
|
|
|
if (isStale()) return
|
|
|
setRecall(filterOutSelf(data, videoId))
|
|
|
message.success(`召回 ${data.total} 条`)
|
|
|
@@ -300,7 +302,7 @@ function VideoIdTab() {
|
|
|
if (!isStale()) setLoadingRecall(false)
|
|
|
}
|
|
|
},
|
|
|
- [topN, videoId, configCodes, rankingParams],
|
|
|
+ [topN, days, videoId, configCodes, rankingParams],
|
|
|
)
|
|
|
|
|
|
/**
|
|
|
@@ -338,6 +340,7 @@ function VideoIdTab() {
|
|
|
const data = await batchByText({
|
|
|
queryText: allTexts[0],
|
|
|
configCodes: allCodes,
|
|
|
+ days,
|
|
|
displayK: topN,
|
|
|
...recallFilters.toParams(),
|
|
|
ranking: rankingForRequest(rankingParams, allCodes),
|
|
|
@@ -354,7 +357,7 @@ function VideoIdTab() {
|
|
|
} finally {
|
|
|
if (!isStale()) setLoadingRecall(false)
|
|
|
}
|
|
|
- }, [detail, points, ai, configCodes, topN, videoId, rankingParams])
|
|
|
+ }, [detail, points, ai, configCodes, topN, days, videoId, rankingParams])
|
|
|
|
|
|
/** URL 传入 videoId 时, 首次查询结束后自动按"选题"维度召回 (0 点击) */
|
|
|
useEffect(() => {
|
|
|
@@ -385,6 +388,15 @@ function VideoIdTab() {
|
|
|
查询
|
|
|
</Button>
|
|
|
<span style={{ color: '#d9d9d9' }}>|</span>
|
|
|
+ <Text strong>天数</Text>
|
|
|
+ <Select
|
|
|
+ value={days}
|
|
|
+ onChange={setDays}
|
|
|
+ allowClear
|
|
|
+ placeholder="不限"
|
|
|
+ style={{ width: 90 }}
|
|
|
+ options={[3, 7, 15, 30, 180, 365].map((d) => ({ label: `${d}天`, value: d }))}
|
|
|
+ />
|
|
|
<Text strong>TopN</Text>
|
|
|
<InputNumber min={1} max={100} value={topN} onChange={(v) => setTopN(v ?? 100)} style={{ width: 80 }} />
|
|
|
<Tooltip title="遍历所有维度, 各自从解构/AI 取文本, 合并去重">
|
|
|
@@ -636,6 +648,7 @@ function TextRecallTab() {
|
|
|
/** 多选: 空数组 = 全部维度 */
|
|
|
const [selectedCodes, setSelectedCodes] = useState<string[]>(urlConfigCodes)
|
|
|
const [topN, setTopN] = useState<number>(10)
|
|
|
+ const [days, setDays] = useState<number | undefined>(undefined)
|
|
|
const [result, setResult] = useState<RecallResultVO | null>(null)
|
|
|
const [loading, setLoading] = useState(false)
|
|
|
const recallFilters = useRecallFilters()
|
|
|
@@ -700,12 +713,13 @@ function TextRecallTab() {
|
|
|
data = await batchByText({
|
|
|
queryText: trimmed,
|
|
|
configCodes: codes,
|
|
|
+ days,
|
|
|
displayK: topN,
|
|
|
...recallFilters.toParams(),
|
|
|
ranking: rankingForRequest(rankingParams, codes),
|
|
|
})
|
|
|
} else {
|
|
|
- data = await matchByText({ queryText: trimmed, configCode: codes[0], topN, displayK: topN, ...recallFilters.toParams(), ranking: rankingForRequest(rankingParams, [codes[0]]) })
|
|
|
+ data = await matchByText({ queryText: trimmed, configCode: codes[0], days, topN, displayK: topN, ...recallFilters.toParams(), ranking: rankingForRequest(rankingParams, [codes[0]]) })
|
|
|
}
|
|
|
if (isStale()) return
|
|
|
setResult(data)
|
|
|
@@ -719,7 +733,7 @@ function TextRecallTab() {
|
|
|
} finally {
|
|
|
if (!isStale()) setLoading(false)
|
|
|
}
|
|
|
- }, [queryText, selectedCodes, topN, configCodes, rankingParams, recallFilters])
|
|
|
+ }, [queryText, selectedCodes, topN, days, configCodes, rankingParams, recallFilters])
|
|
|
|
|
|
/** 过滤区只选一种模态时,精排区展示对应权重;否则展示全部 */
|
|
|
const rankingPreviewModality = useMemo((): 'ALL' | Modality => {
|
|
|
@@ -770,45 +784,27 @@ function TextRecallTab() {
|
|
|
style={{ minWidth: 320 }}
|
|
|
allowClear
|
|
|
/>
|
|
|
+ <Text style={{ fontSize: 12, color: '#666' }}>天数</Text>
|
|
|
+ <Select
|
|
|
+ value={days}
|
|
|
+ onChange={setDays}
|
|
|
+ allowClear
|
|
|
+ placeholder="不限"
|
|
|
+ style={{ width: 90 }}
|
|
|
+ options={[3, 7, 15, 30, 180, 365].map((d) => ({ label: `${d}天`, value: d }))}
|
|
|
+ />
|
|
|
<Text style={{ fontSize: 12, color: '#666' }}>TopN</Text>
|
|
|
<InputNumber min={1} max={100} value={topN} onChange={(v) => setTopN(v ?? 100)} style={{ width: 80 }} />
|
|
|
<Button type="primary" icon={<SearchOutlined />} loading={loading} onClick={onSubmit}>
|
|
|
召回
|
|
|
</Button>
|
|
|
</Space>
|
|
|
- {boostCodes.length > 0 && (
|
|
|
- <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginTop: 10 }}>
|
|
|
- <Text style={{ fontSize: 12, color: '#666', whiteSpace: 'nowrap' }}>维度 Boost</Text>
|
|
|
- {boostCodes.map((code) => {
|
|
|
- const val = rankingParams.boostsByCode?.[code] ?? rankingParams.deconstructBoost
|
|
|
- const isCustom = code in (rankingParams.boostsByCode ?? {})
|
|
|
- return (
|
|
|
- <div key={code} style={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
|
- <Text style={{ fontSize: 11, color: isCustom ? '#1677ff' : undefined, whiteSpace: 'nowrap' }}>
|
|
|
- {getConfigDisplayLabel(code, configCodes)}
|
|
|
- </Text>
|
|
|
- <InputNumber
|
|
|
- size="small"
|
|
|
- min={0.5}
|
|
|
- max={3}
|
|
|
- step={0.05}
|
|
|
- value={val}
|
|
|
- onChange={(v) => {
|
|
|
- const next = { ...rankingParams.boostsByCode }
|
|
|
- if (typeof v === 'number' && v !== rankingParams.deconstructBoost) {
|
|
|
- next[code] = v
|
|
|
- } else {
|
|
|
- delete next[code]
|
|
|
- }
|
|
|
- setRankingParams({ ...rankingParams, boostsByCode: next })
|
|
|
- }}
|
|
|
- style={{ width: 68 }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- )
|
|
|
- })}
|
|
|
- </div>
|
|
|
- )}
|
|
|
+ <DimensionBoostRow
|
|
|
+ boostCodes={boostCodes}
|
|
|
+ configCodes={configCodes}
|
|
|
+ rankingParams={rankingParams}
|
|
|
+ onChange={setRankingParams}
|
|
|
+ />
|
|
|
<div style={{ marginTop: 10 }}>
|
|
|
<RecallFilterBar
|
|
|
filters={recallFilters.filters}
|