Ver código fonte

修改可视化页面

xueyiming 2 dias atrás
pai
commit
c399f1fe17

+ 4 - 0
api/app.py

@@ -276,6 +276,7 @@ def video_discovery_runs(
     biz_dt: str | None = Query(default=None, pattern=r"^\d{8}$"),
     biz_dt: str | None = Query(default=None, pattern=r"^\d{8}$"),
     status: Literal["running", "finished", "failed"] | None = None,
     status: Literal["running", "finished", "failed"] | None = None,
     keyword: str | None = Query(default=None, max_length=256),
     keyword: str | None = Query(default=None, max_length=256),
+    aweme_id: str | None = Query(default=None, max_length=64),
     limit: int = Query(default=20, ge=1, le=100),
     limit: int = Query(default=20, ge=1, le=100),
     offset: int = Query(default=0, ge=0),
     offset: int = Query(default=0, ge=0),
 ) -> dict:
 ) -> dict:
@@ -284,6 +285,7 @@ def video_discovery_runs(
         biz_dt=biz_dt,
         biz_dt=biz_dt,
         status=status,
         status=status,
         keyword=keyword,
         keyword=keyword,
+        aweme_id=aweme_id,
         limit=limit,
         limit=limit,
         offset=offset,
         offset=offset,
     )
     )
@@ -322,6 +324,7 @@ def video_discovery_candidates(
     run_id: str,
     run_id: str,
     bucket: str | None = Query(default=None, max_length=24),
     bucket: str | None = Query(default=None, max_length=24),
     keyword: str | None = Query(default=None, max_length=256),
     keyword: str | None = Query(default=None, max_length=256),
+    aweme_id: str | None = Query(default=None, max_length=64),
     limit: int = Query(default=20, ge=1, le=100),
     limit: int = Query(default=20, ge=1, le=100),
     offset: int = Query(default=0, ge=0),
     offset: int = Query(default=0, ge=0),
 ) -> dict:
 ) -> dict:
@@ -330,6 +333,7 @@ def video_discovery_candidates(
         run_id,
         run_id,
         bucket=bucket,
         bucket=bucket,
         keyword=keyword,
         keyword=keyword,
+        aweme_id=aweme_id,
         limit=limit,
         limit=limit,
         offset=offset,
         offset=offset,
     )
     )

+ 20 - 0
api/services/video_discovery_records.py

@@ -95,6 +95,7 @@ def _serialize_search_candidate(row: VideoDiscoveryCandidate) -> dict[str, Any]:
         "temporal_status": row.temporal_status,
         "temporal_status": row.temporal_status,
         "gate_status": row.gate_status,
         "gate_status": row.gate_status,
         "reject_reason_code": row.reject_reason_code,
         "reject_reason_code": row.reject_reason_code,
+        "decision_reason": row.decision_reason,
     }
     }
 
 
 
 
@@ -178,6 +179,9 @@ def _serialize_candidate(row: VideoDiscoveryCandidate) -> dict[str, Any]:
         "elder_score": _number(row.elder_score),
         "elder_score": _number(row.elder_score),
         "share_score": _number(row.share_score),
         "share_score": _number(row.share_score),
         "value_score": _number(row.value_score),
         "value_score": _number(row.value_score),
+        "detail_fetch_status": row.detail_fetch_status,
+        "content_portrait_fetch_status": row.content_portrait_fetch_status,
+        "account_portrait_fetch_status": row.account_portrait_fetch_status,
         "decision_reason": row.decision_reason,
         "decision_reason": row.decision_reason,
         "decision_bucket": row.decision_bucket,
         "decision_bucket": row.decision_bucket,
         "aigc_crawler_plan_id": row.aigc_crawler_plan_id,
         "aigc_crawler_plan_id": row.aigc_crawler_plan_id,
@@ -235,6 +239,7 @@ def list_video_discovery_runs(
     biz_dt: str | None = None,
     biz_dt: str | None = None,
     status: str | None = None,
     status: str | None = None,
     keyword: str | None = None,
     keyword: str | None = None,
+    aweme_id: str | None = None,
     limit: int = 20,
     limit: int = 20,
     offset: int = 0,
     offset: int = 0,
 ) -> dict[str, Any]:
 ) -> dict[str, Any]:
@@ -257,6 +262,16 @@ def list_video_discovery_runs(
                     ),
                     ),
                 )
                 )
             )
             )
+        normalized_aweme_id = (aweme_id or "").strip()
+        if normalized_aweme_id:
+            conditions.append(
+                select(VideoDiscoveryCandidate.id)
+                .where(
+                    VideoDiscoveryCandidate.run_id == VideoDiscoveryRun.run_id,
+                    VideoDiscoveryCandidate.aweme_id == normalized_aweme_id,
+                )
+                .exists()
+            )
 
 
         total_stmt = select(func.count(VideoDiscoveryRun.id))
         total_stmt = select(func.count(VideoDiscoveryRun.id))
         rows_stmt = select(VideoDiscoveryRun)
         rows_stmt = select(VideoDiscoveryRun)
@@ -372,6 +387,7 @@ def list_video_discovery_searches(
                         VideoDiscoveryCandidate.temporal_status,
                         VideoDiscoveryCandidate.temporal_status,
                         VideoDiscoveryCandidate.gate_status,
                         VideoDiscoveryCandidate.gate_status,
                         VideoDiscoveryCandidate.reject_reason_code,
                         VideoDiscoveryCandidate.reject_reason_code,
+                        VideoDiscoveryCandidate.decision_reason,
                     )
                     )
                 )
                 )
                 .where(VideoDiscoveryCandidate.search_id.in_(candidates_by_search))
                 .where(VideoDiscoveryCandidate.search_id.in_(candidates_by_search))
@@ -399,6 +415,7 @@ def list_video_discovery_candidates(
     *,
     *,
     bucket: str | None = None,
     bucket: str | None = None,
     keyword: str | None = None,
     keyword: str | None = None,
+    aweme_id: str | None = None,
     limit: int = 20,
     limit: int = 20,
     offset: int = 0,
     offset: int = 0,
 ) -> dict[str, Any] | None:
 ) -> dict[str, Any] | None:
@@ -415,6 +432,9 @@ def list_video_discovery_candidates(
         conditions = [VideoDiscoveryCandidate.run_id == run_id]
         conditions = [VideoDiscoveryCandidate.run_id == run_id]
         if bucket:
         if bucket:
             conditions.append(VideoDiscoveryCandidate.decision_bucket == bucket)
             conditions.append(VideoDiscoveryCandidate.decision_bucket == bucket)
+        normalized_aweme_id = (aweme_id or "").strip()
+        if normalized_aweme_id:
+            conditions.append(VideoDiscoveryCandidate.aweme_id == normalized_aweme_id)
         normalized_keyword = (keyword or "").strip().lower()
         normalized_keyword = (keyword or "").strip().lower()
         if normalized_keyword:
         if normalized_keyword:
             pattern = f"%{normalized_keyword}%"
             pattern = f"%{normalized_keyword}%"

+ 31 - 0
tests/api/test_video_discovery_records.py

@@ -223,6 +223,37 @@ def test_lists_searches_and_candidates_with_filters(monkeypatch) -> None:
     assert candidates["items"][0]["relevance_score"] == 0.91
     assert candidates["items"][0]["relevance_score"] == 0.91
 
 
 
 
+def test_lists_runs_by_candidate_aweme_id(monkeypatch) -> None:
+    factory = _patch_sessions(monkeypatch)
+    _seed(factory)
+
+    response = records_service.list_video_discovery_runs(
+        aweme_id="aweme-1",
+        limit=20,
+        offset=0,
+    )
+    assert response["total"] == 1
+    assert response["items"][0]["run_id"] == "find-001"
+
+    missing = records_service.list_video_discovery_runs(
+        aweme_id="missing-id",
+        limit=20,
+        offset=0,
+    )
+    assert missing["total"] == 0
+    assert missing["items"] == []
+
+    candidates = records_service.list_video_discovery_candidates(
+        "find-001",
+        aweme_id="aweme-1",
+        limit=20,
+        offset=0,
+    )
+    assert candidates is not None
+    assert candidates["total"] == 1
+    assert candidates["items"][0]["aweme_id"] == "aweme-1"
+
+
 def test_record_children_return_none_for_missing_run(monkeypatch) -> None:
 def test_record_children_return_none_for_missing_run(monkeypatch) -> None:
     _patch_sessions(monkeypatch)
     _patch_sessions(monkeypatch)
 
 

+ 10 - 2
web/src/api/videoDiscoveryRecords.ts

@@ -26,6 +26,7 @@ export function fetchVideoDiscoveryRuns(params: {
   bizDt?: string
   bizDt?: string
   status?: string
   status?: string
   keyword?: string
   keyword?: string
+  awemeId?: string
   limit: number
   limit: number
   offset: number
   offset: number
 }): Promise<PagedResponse<VideoDiscoveryRunRecord>> {
 }): Promise<PagedResponse<VideoDiscoveryRunRecord>> {
@@ -33,6 +34,7 @@ export function fetchVideoDiscoveryRuns(params: {
     biz_dt: params.bizDt,
     biz_dt: params.bizDt,
     status: params.status,
     status: params.status,
     keyword: params.keyword,
     keyword: params.keyword,
+    aweme_id: params.awemeId,
     limit: params.limit,
     limit: params.limit,
     offset: params.offset,
     offset: params.offset,
   })}`).then((response) => readJson(response, '加载找视频运行失败'))
   })}`).then((response) => readJson(response, '加载找视频运行失败'))
@@ -54,9 +56,15 @@ export function fetchVideoDiscoverySearches(
 
 
 export function fetchVideoDiscoveryCandidates(
 export function fetchVideoDiscoveryCandidates(
   runId: string,
   runId: string,
-  params: { bucket?: string; keyword?: string; limit: number; offset: number },
+  params: { bucket?: string; keyword?: string; awemeId?: string; limit: number; offset: number },
 ): Promise<PagedResponse<VideoDiscoveryCandidateRecord>> {
 ): Promise<PagedResponse<VideoDiscoveryCandidateRecord>> {
   return fetch(
   return fetch(
-    `/api/video-discovery/runs/${encodeURIComponent(runId)}/candidates${queryString(params)}`,
+    `/api/video-discovery/runs/${encodeURIComponent(runId)}/candidates${queryString({
+      bucket: params.bucket,
+      keyword: params.keyword,
+      aweme_id: params.awemeId,
+      limit: params.limit,
+      offset: params.offset,
+    })}`,
   ).then((response) => readJson(response, '加载候选视频失败'))
   ).then((response) => readJson(response, '加载候选视频失败'))
 }
 }

+ 20 - 0
web/src/types/videoDiscoveryRecords.ts

@@ -20,6 +20,8 @@ export interface VideoDiscoveryRunRecord {
   rejected_count: number
   rejected_count: number
   pending_count: number
   pending_count: number
   stop_reason: string | null
   stop_reason: string | null
+  rule_version?: string | null
+  rule_config?: JsonValue
   create_time: string | null
   create_time: string | null
   update_time: string | null
   update_time: string | null
 }
 }
@@ -64,10 +66,16 @@ export interface VideoDiscoverySearchCandidate {
   comment_count: number | null
   comment_count: number | null
   collect_count: number | null
   collect_count: number | null
   share_count: number | null
   share_count: number | null
+  duration_seconds?: number | null
+  content_50_plus_ratio?: number | null
+  account_50_plus_ratio?: number | null
   relevance_score: number | null
   relevance_score: number | null
   elder_score: number | null
   elder_score: number | null
   share_score: number | null
   share_score: number | null
   value_score: number | null
   value_score: number | null
+  decision_reason?: string | null
+  gate_status?: string | null
+  reject_reason_code?: string | null
 }
 }
 
 
 export interface VideoDiscoveryCandidateRecord {
 export interface VideoDiscoveryCandidateRecord {
@@ -100,6 +108,18 @@ export interface VideoDiscoveryCandidateRecord {
   aigc_produce_plan_id: string | null
   aigc_produce_plan_id: string | null
   aigc_publish_plan_id: string | null
   aigc_publish_plan_id: string | null
   aigc_plan_label: string | null
   aigc_plan_label: string | null
+  duration_seconds?: number | null
+  publish_at?: string | null
+  content_50_plus_ratio?: number | null
+  account_50_plus_ratio?: number | null
+  content_portrait_status?: string | null
+  account_portrait_status?: string | null
+  gate_status?: string | null
+  gate_results?: JsonValue
+  reject_reason_code?: string | null
+  detail_fetch_status?: string | null
+  content_portrait_fetch_status?: string | null
+  account_portrait_fetch_status?: string | null
   create_time: string | null
   create_time: string | null
   update_time: string | null
   update_time: string | null
 }
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 520 - 1340
web/src/views/FindAgentRecordsView.vue


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff