video_points.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """视频点位解析与序列化 — decode_result / JSON 字段 ↔ 行记录。"""
  2. from __future__ import annotations
  3. import json
  4. from typing import Any
  5. from supply_infra.db.models.multi_demand_video_point import (
  6. POINT_TYPE_INSPIRATION,
  7. POINT_TYPE_KEY,
  8. POINT_TYPE_PURPOSE,
  9. )
  10. _POINT_KEY = "点"
  11. _POINT_DESC_KEY = "点描述"
  12. # decode_result 中的 key → point_type
  13. DECODE_RESULT_KEY_TO_POINT_TYPE = {
  14. "灵感点": POINT_TYPE_INSPIRATION,
  15. "目的点": POINT_TYPE_PURPOSE,
  16. "关键点": POINT_TYPE_KEY,
  17. }
  18. # 原 JSON 列名 → point_type
  19. JSON_FIELD_TO_POINT_TYPE = {
  20. "inspiration_points_json": POINT_TYPE_INSPIRATION,
  21. "purpose_points_json": POINT_TYPE_PURPOSE,
  22. "key_points_json": POINT_TYPE_KEY,
  23. }
  24. # point_type → 原 JSON 列名(API 兼容)
  25. POINT_TYPE_TO_JSON_FIELD = {v: k for k, v in JSON_FIELD_TO_POINT_TYPE.items()}
  26. def _item_to_row(
  27. video_id: str, point_type: str, item: dict[str, Any]
  28. ) -> dict[str, str | None] | None:
  29. point = item.get(_POINT_KEY)
  30. point_desc = item.get(_POINT_DESC_KEY)
  31. if point is None and point_desc is None:
  32. return None
  33. return {
  34. "video_id": video_id,
  35. "point_type": point_type,
  36. "point_data": str(point) if point is not None else None,
  37. "point_desc": str(point_desc) if point_desc is not None else None,
  38. }
  39. def points_from_decode_payload(
  40. video_id: str, payload: dict[str, Any]
  41. ) -> list[dict[str, str | None]]:
  42. """从 decode_result 提取全部点位行。"""
  43. rows: list[dict[str, str | None]] = []
  44. for decode_key, point_type in DECODE_RESULT_KEY_TO_POINT_TYPE.items():
  45. items = payload.get(decode_key)
  46. if not isinstance(items, list):
  47. continue
  48. for item in items:
  49. if not isinstance(item, dict):
  50. continue
  51. row = _item_to_row(video_id, point_type, item)
  52. if row:
  53. rows.append(row)
  54. return rows
  55. def points_from_json_fields(
  56. video_id: str,
  57. *,
  58. inspiration_points_json: str | None = None,
  59. purpose_points_json: str | None = None,
  60. key_points_json: str | None = None,
  61. ) -> list[dict[str, str | None]]:
  62. """从 multi_demand_video_detail 的三个 JSON 列提取点位行。"""
  63. field_values = {
  64. "inspiration_points_json": inspiration_points_json,
  65. "purpose_points_json": purpose_points_json,
  66. "key_points_json": key_points_json,
  67. }
  68. rows: list[dict[str, str | None]] = []
  69. for field, point_type in JSON_FIELD_TO_POINT_TYPE.items():
  70. text = field_values.get(field)
  71. if not text:
  72. continue
  73. try:
  74. items = json.loads(text)
  75. except json.JSONDecodeError:
  76. continue
  77. if not isinstance(items, list):
  78. continue
  79. for item in items:
  80. if not isinstance(item, dict):
  81. continue
  82. row = _item_to_row(video_id, point_type, item)
  83. if row:
  84. rows.append(row)
  85. return rows
  86. def json_fields_from_point_rows(
  87. rows: list[dict[str, Any]],
  88. ) -> dict[str, str | None]:
  89. """将点位行重组为三个 JSON 列(保持 API 兼容)。"""
  90. grouped: dict[str, list[dict[str, str | None]]] = {
  91. POINT_TYPE_INSPIRATION: [],
  92. POINT_TYPE_PURPOSE: [],
  93. POINT_TYPE_KEY: [],
  94. }
  95. for row in rows:
  96. point_type = row.get("point_type")
  97. if point_type not in grouped:
  98. continue
  99. grouped[point_type].append(
  100. {
  101. _POINT_KEY: row.get("point_data"),
  102. _POINT_DESC_KEY: row.get("point_desc"),
  103. }
  104. )
  105. result: dict[str, str | None] = {}
  106. for point_type, field in POINT_TYPE_TO_JSON_FIELD.items():
  107. items = grouped[point_type]
  108. result[field] = (
  109. json.dumps(items, ensure_ascii=False) if items else None
  110. )
  111. return result
  112. def extract_points_json_from_decode(payload: dict[str, Any]) -> dict[str, str | None]:
  113. """从 decode_result 提取灵感点/目的点/关键点 JSON 列(原逻辑)。"""
  114. result: dict[str, str | None] = {}
  115. for decode_key, field in {
  116. k: POINT_TYPE_TO_JSON_FIELD[v]
  117. for k, v in DECODE_RESULT_KEY_TO_POINT_TYPE.items()
  118. }.items():
  119. items = payload.get(decode_key)
  120. if not isinstance(items, list):
  121. result[field] = None
  122. continue
  123. points: list[dict[str, Any]] = []
  124. for item in items:
  125. if not isinstance(item, dict):
  126. continue
  127. point = item.get(_POINT_KEY)
  128. point_desc = item.get(_POINT_DESC_KEY)
  129. if point is None and point_desc is None:
  130. continue
  131. points.append({_POINT_KEY: point, _POINT_DESC_KEY: point_desc})
  132. result[field] = json.dumps(points, ensure_ascii=False) if points else None
  133. return result