Quellcode durchsuchen

feat(web2): 补显被去重的取词来源 + 来源标签单一真相源

- LedgerPage 新增 DeducedSourceRows:首轮三源(需求池直出/票圈点/分类叶子)里
  有需求素材却被 CFA 去重未入库的来源,补一行占位+标注"与前面来源重复,此处不显示"
  (修 high_weight_category 需求看不到分类树来源的问题,纯展示层,不改 CFA)。
- "从需求单的 pattern 词来" 文案改为 "从需求池直出"。
- 来源类型标签抽成 format.ts 的 SOURCE_TYPE_LABELS 单一常量,
  business.ts 的 SOURCE_LABELS/METHOD_LABELS 与 format.ts label() 统一 spread 复用,
  改文案只改一处(原先散在 3 份 map)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sam Lee vor 2 Wochen
Ursprung
Commit
52975ffd49
3 geänderte Dateien mit 53 neuen und 13 gelöschten Zeilen
  1. 40 0
      web2/features/LedgerPage.tsx
  2. 3 9
      web2/lib/flow-ledger/business.ts
  3. 10 4
      web2/lib/flow-ledger/format.ts

+ 40 - 0
web2/features/LedgerPage.tsx

@@ -98,6 +98,7 @@ export function LedgerPage({ runId }: { runId: string }) {
                   {rows.map((row) => (
                     <QueryGroupRows key={row.id} runId={runId} row={row} />
                   ))}
+                  <DeducedSourceRows rows={rows} demand={ledger.demandSummary} />
                 </tbody>
               </table>
             </section>
@@ -276,6 +277,45 @@ function sourceKindClass(kind: string): string {
   return "unknown";
 }
 
+// 首轮取词三源:需求池直出(seed_term)/ 票圈帖子的点(query_seed_point)/ 分类叶子(category_leaf_element)。
+const FIRST_ROUND_SOURCE_TYPES = ["seed_term", "query_seed_point", "category_leaf_element"];
+
+function sourceTypeHasMaterial(type: string, demand?: DemandSummary): boolean {
+  if (!demand) return false;
+  if (type === "seed_term") return demand.seedTerms.length > 0;
+  if (type === "category_leaf_element") return demand.categoryPaths.length > 0;
+  if (type === "query_seed_point") return demand.extractedPoints.length > 0;
+  return false;
+}
+
+// CFA 取词时同一个词只搜一次,后命中的来源被去重丢弃(不入库),前端看不到。
+// 这里据需求素材补出"被去重的来源"占位行:那行留空 + 标注与前面哪些来源重复。
+function DeducedSourceRows({ rows, demand }: { rows: FlowLedgerRow[]; demand?: DemandSummary }) {
+  const present = new Set(rows.map((row) => row.source.sourceKind));
+  const shownLabels = FIRST_ROUND_SOURCE_TYPES.filter((type) => present.has(type)).map((type) => sourceLabel(type));
+  const deduped = FIRST_ROUND_SOURCE_TYPES.filter(
+    (type) => !present.has(type) && sourceTypeHasMaterial(type, demand)
+  );
+  if (!deduped.length) return null;
+  return (
+    <>
+      {deduped.map((type) => (
+        <tr className="ledger-row deduped-source-row" key={`deduped-${type}`}>
+          <td className="source-cell sticky-source">
+            <div className="cell-stack">
+              <span className={`source-kind-badge ${sourceKindClass(type)}`}>{sourceLabel(type)}</span>
+              <span className="muted">(此处留空)</span>
+            </div>
+          </td>
+          <td className="muted deduped-source-note" colSpan={4}>
+            这是「{sourceLabel(type)}」来源,搜索词与前面的{shownLabels.join(" / ") || "已展示"}来源重复(同词只搜一次),所以此处不单独显示。
+          </td>
+        </tr>
+      ))}
+    </>
+  );
+}
+
 function VideoDecisionCell({ video }: { video: VideoRef | null }) {
   if (!video) {
     return (

+ 3 - 9
web2/lib/flow-ledger/business.ts

@@ -1,5 +1,5 @@
 import type { FlowLedgerRow, ScoreItem, VideoRef } from "./types";
-import { asRecord, textList } from "./format";
+import { asRecord, SOURCE_TYPE_LABELS, textList } from "./format";
 
 export type BusinessTone = "neutral" | "good" | "warn" | "bad" | "info";
 
@@ -27,10 +27,7 @@ const REASON_LABELS: Record<string, string> = {
 };
 
 const SOURCE_LABELS: Record<string, string> = {
-  seed_term: "从需求单的 pattern 词来",
-  piaoquan_topic_point: "票圈帖子具体的点",
-  query_seed_point: "票圈帖子具体的点",
-  category_leaf_element: "分类叶子元素",
+  ...SOURCE_TYPE_LABELS,
   pattern_itemset: "来自需求 Pattern",
   pattern_search_query: "来自需求 Pattern",
   pattern_seed_ref: "来自需求 Pattern",
@@ -41,10 +38,7 @@ const SOURCE_LABELS: Record<string, string> = {
 };
 
 const METHOD_LABELS: Record<string, string> = {
-  seed_term: "从需求单的 pattern 词来",
-  piaoquan_topic_point: "票圈帖子具体的点",
-  query_seed_point: "票圈帖子具体的点",
-  category_leaf_element: "分类叶子元素",
+  ...SOURCE_TYPE_LABELS,
   query_next_page: "翻页继续找",
   tag_query: "从视频标签继续游走",
   author_works: "从作者继续游走",

+ 10 - 4
web2/lib/flow-ledger/format.ts

@@ -40,12 +40,18 @@ export function compactCountMap(counts: Record<string, number>, limit = 3): stri
   return entries.slice(0, limit).map(([key, value]) => `${label(key)} ${value}`).join(" · ");
 }
 
+// 首轮取词「来源类型」标签的唯一真相源。sourceLabel / methodLabel / label 都从这里取,
+// 改文案只改这一处(避免之前散在 3 份 map 里、改一个要改 3 处)。
+export const SOURCE_TYPE_LABELS: Record<string, string> = {
+  seed_term: "从需求池直出",
+  piaoquan_topic_point: "票圈帖子具体的点",
+  query_seed_point: "票圈帖子具体的点",
+  category_leaf_element: "分类叶子元素"
+};
+
 export function label(value: string): string {
   const labels: Record<string, string> = {
-    seed_term: "从需求单的 pattern 词来",
-    piaoquan_topic_point: "票圈帖子具体的点",
-    query_seed_point: "票圈帖子具体的点",
-    category_leaf_element: "分类叶子元素",
+    ...SOURCE_TYPE_LABELS,
     item_single: "使用原始需求词",
     tag_query: "从视频标签继续游走",
     author_works: "从作者继续游走",