"""视频点位解析与序列化 — decode_result / JSON 字段 ↔ 行记录。""" from __future__ import annotations import json from typing import Any from supply_infra.db.models.multi_demand_video_point import ( POINT_TYPE_INSPIRATION, POINT_TYPE_KEY, POINT_TYPE_PURPOSE, ) _POINT_KEY = "点" _POINT_DESC_KEY = "点描述" # decode_result 中的 key → point_type DECODE_RESULT_KEY_TO_POINT_TYPE = { "灵感点": POINT_TYPE_INSPIRATION, "目的点": POINT_TYPE_PURPOSE, "关键点": POINT_TYPE_KEY, } # 原 JSON 列名 → point_type JSON_FIELD_TO_POINT_TYPE = { "inspiration_points_json": POINT_TYPE_INSPIRATION, "purpose_points_json": POINT_TYPE_PURPOSE, "key_points_json": POINT_TYPE_KEY, } # point_type → 原 JSON 列名(API 兼容) POINT_TYPE_TO_JSON_FIELD = {v: k for k, v in JSON_FIELD_TO_POINT_TYPE.items()} def _item_to_row( video_id: str, point_type: str, item: dict[str, Any] ) -> dict[str, str | None] | None: point = item.get(_POINT_KEY) point_desc = item.get(_POINT_DESC_KEY) if point is None and point_desc is None: return None return { "video_id": video_id, "point_type": point_type, "point_data": str(point) if point is not None else None, "point_desc": str(point_desc) if point_desc is not None else None, } def points_from_decode_payload( video_id: str, payload: dict[str, Any] ) -> list[dict[str, str | None]]: """从 decode_result 提取全部点位行。""" rows: list[dict[str, str | None]] = [] for decode_key, point_type in DECODE_RESULT_KEY_TO_POINT_TYPE.items(): items = payload.get(decode_key) if not isinstance(items, list): continue for item in items: if not isinstance(item, dict): continue row = _item_to_row(video_id, point_type, item) if row: rows.append(row) return rows def points_from_json_fields( video_id: str, *, inspiration_points_json: str | None = None, purpose_points_json: str | None = None, key_points_json: str | None = None, ) -> list[dict[str, str | None]]: """从 multi_demand_video_detail 的三个 JSON 列提取点位行。""" field_values = { "inspiration_points_json": inspiration_points_json, "purpose_points_json": purpose_points_json, "key_points_json": key_points_json, } rows: list[dict[str, str | None]] = [] for field, point_type in JSON_FIELD_TO_POINT_TYPE.items(): text = field_values.get(field) if not text: continue try: items = json.loads(text) except json.JSONDecodeError: continue if not isinstance(items, list): continue for item in items: if not isinstance(item, dict): continue row = _item_to_row(video_id, point_type, item) if row: rows.append(row) return rows def json_fields_from_point_rows( rows: list[dict[str, Any]], ) -> dict[str, str | None]: """将点位行重组为三个 JSON 列(保持 API 兼容)。""" grouped: dict[str, list[dict[str, str | None]]] = { POINT_TYPE_INSPIRATION: [], POINT_TYPE_PURPOSE: [], POINT_TYPE_KEY: [], } for row in rows: point_type = row.get("point_type") if point_type not in grouped: continue grouped[point_type].append( { _POINT_KEY: row.get("point_data"), _POINT_DESC_KEY: row.get("point_desc"), } ) result: dict[str, str | None] = {} for point_type, field in POINT_TYPE_TO_JSON_FIELD.items(): items = grouped[point_type] result[field] = ( json.dumps(items, ensure_ascii=False) if items else None ) return result def extract_points_json_from_decode(payload: dict[str, Any]) -> dict[str, str | None]: """从 decode_result 提取灵感点/目的点/关键点 JSON 列(原逻辑)。""" result: dict[str, str | None] = {} for decode_key, field in { k: POINT_TYPE_TO_JSON_FIELD[v] for k, v in DECODE_RESULT_KEY_TO_POINT_TYPE.items() }.items(): items = payload.get(decode_key) if not isinstance(items, list): result[field] = None continue points: list[dict[str, Any]] = [] for item in items: if not isinstance(item, dict): continue point = item.get(_POINT_KEY) point_desc = item.get(_POINT_DESC_KEY) if point is None and point_desc is None: continue points.append({_POINT_KEY: point, _POINT_DESC_KEY: point_desc}) result[field] = json.dumps(points, ensure_ascii=False) if points else None return result