Explorar o código

Show review items in final assets column

Sam Lee hai 4 semanas
pai
achega
d15f8ad545

+ 18 - 1
content_agent/flow_ledger_service.py

@@ -494,7 +494,11 @@ class FlowLedgerService:
             "pool_count": counts.get("入池", 0),
             "review_count": counts.get("待复看", 0),
             "reject_count": counts.get("淘汰", 0),
-            "headline": f"已沉淀 {counts.get('入池', 0)} 条内容" if counts.get("入池", 0) else "暂无可沉淀内容",
+            "headline": _asset_headline(
+                counts.get("入池", 0),
+                counts.get("待复看", 0),
+                counts.get("淘汰", 0),
+            ),
         }
 
     def _video_summary(self, videos: list[dict[str, Any]]) -> dict[str, Any]:
@@ -700,6 +704,19 @@ def _rule_headline(actions: Counter[str], total: int) -> str:
     return "本轮没有可沉淀内容"
 
 
+def _asset_headline(pool_count: int, review_count: int, reject_count: int) -> str:
+    parts = []
+    if pool_count:
+        parts.append(f"入池 {pool_count} 条")
+    if review_count:
+        parts.append(f"待复看 {review_count} 条")
+    if parts:
+        return ",".join(parts)
+    if reject_count:
+        return f"没有入池,淘汰 {reject_count} 条"
+    return "暂无可沉淀内容"
+
+
 def _effect_label(status: str) -> str:
     return {
         "success": "已找到可用结果",

+ 33 - 1
tests/test_flow_ledger_api.py

@@ -143,6 +143,18 @@ def test_flow_ledger_api_returns_business_v4_ledger(tmp_path, monkeypatch):
                 "statistics": {},
                 "raw_payload": {},
             },
+            {
+                "run_id": run_id,
+                "policy_run_id": policy_run_id,
+                "content_discovery_id": "content_003",
+                "platform_content_id": "douyin_003",
+                "search_query_id": "q_003",
+                "platform": "douyin",
+                "description": "情绪放松练习视频",
+                "author_display_name": "心理教练",
+                "statistics": {},
+                "raw_payload": {},
+            },
         ],
     )
     service.runtime.append_jsonl(
@@ -207,6 +219,23 @@ def test_flow_ledger_api_returns_business_v4_ledger(tmp_path, monkeypatch):
                     },
                 },
                 "raw_payload": {},
+            },
+            {
+                "run_id": run_id,
+                "policy_run_id": policy_run_id,
+                "decision_id": "decision_003",
+                "search_query_id": "q_003",
+                "decision_target_id": "content_003",
+                "decision_action": "KEEP_CONTENT_FOR_REVIEW",
+                "decision_reason_code": "v4_score_review_needed",
+                "score": 62,
+                "scorecard": {
+                    "total_score": 62,
+                    "query_relevance_score": 95,
+                    "platform_performance_score": 29,
+                },
+                "decision_replay_data": {"allow_walk": False},
+                "raw_payload": {},
             }
         ],
     )
@@ -242,7 +271,7 @@ def test_flow_ledger_api_returns_business_v4_ledger(tmp_path, monkeypatch):
             "run_id": run_id,
             "policy_run_id": policy_run_id,
             "content_assets": [{"decision_id": "decision_001", "platform_content_id": "douyin_001"}],
-            "review_records": [],
+            "review_records": [{"decision_id": "decision_003", "platform_content_id": "douyin_003"}],
             "reject_records": [],
             "summary": {},
         },
@@ -274,6 +303,9 @@ def test_flow_ledger_api_returns_business_v4_ledger(tmp_path, monkeypatch):
     assert piaoquan["source"]["label"] == "票圈帖子具体的点"
     assert "帖子 ID:post_888" in piaoquan["source"]["details"]
     assert "内容点 ID:point_456" in piaoquan["source"]["details"]
+    assert piaoquan["asset_summary"]["pool_count"] == 0
+    assert piaoquan["asset_summary"]["review_count"] == 1
+    assert piaoquan["asset_summary"]["headline"] == "待复看 1 条"
     category = next(item for item in ledger["rows"] if item["id"] == "q_004")
     assert "分类树:Pattern 执行 581" in category["source"]["details"]
     assert "分类路径:/理念/观念/个人观念/人生观" in category["source"]["details"]

+ 2 - 1
web2/features/LedgerPage.tsx

@@ -6,6 +6,7 @@ import { useMemo, useState } from "react";
 import { AppShell } from "@/components/AppShell";
 import { EmptyState, ErrorState, LoadingState } from "@/components/StateBlocks";
 import {
+  assetDetailText,
   assetSummaryText,
   compactScoreItemsText,
   platformLabel,
@@ -215,7 +216,7 @@ function AssetCell({ row }: { row: FlowLedgerRow }) {
     <td className="asset-cell">
       <div className="cell-stack">
         <strong>{assetSummaryText(row)}</strong>
-        <span className="muted">{row.finalAssets.assetCount ? "已进入后续内容池" : "这轮没有内容进入后续使用"}</span>
+        <span className="muted">{assetDetailText(row)}</span>
       </div>
     </td>
   );

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

@@ -207,12 +207,28 @@ export function walkSummaryText(row: FlowLedgerRow): string {
 }
 
 export function assetSummaryText(row: FlowLedgerRow): string {
-  if (row.finalAssets.assetCount || row.finalAssets.finalCount) {
-    return `已沉淀 ${row.finalAssets.assetCount || row.finalAssets.finalCount} 条内容`;
-  }
+  const pool = row.finalAssets.assetCount || row.finalAssets.finalCount || 0;
+  const review = row.finalAssets.reviewCount || 0;
+  const reject = row.finalAssets.rejectCount || 0;
+  const parts = [];
+  if (pool) parts.push(`入池 ${pool} 条`);
+  if (review) parts.push(`待复看 ${review} 条`);
+  if (parts.length) return parts.join(",");
+  if (reject) return `没有入池,淘汰 ${reject} 条`;
   return "暂无可沉淀内容";
 }
 
+export function assetDetailText(row: FlowLedgerRow): string {
+  const pool = row.finalAssets.assetCount || row.finalAssets.finalCount || 0;
+  const review = row.finalAssets.reviewCount || 0;
+  const reject = row.finalAssets.rejectCount || 0;
+  if (pool && review) return "入池内容可后续使用,待复看需要人工确认";
+  if (pool) return "已进入后续内容池";
+  if (review) return "需人工确认后,再决定是否进入后续使用";
+  if (reject) return "本轮内容已淘汰,没有进入后续使用";
+  return "这轮没有内容进入后续使用";
+}
+
 export function clueText(row: FlowLedgerRow): string {
   const clue = asRecord(row.query.clue);
   const queries = textList(clue.generated_queries);