payloads.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. """Deterministic payload assembly for decoded creation knowledge."""
  2. from __future__ import annotations
  3. import json
  4. from typing import Any
  5. from decode_content.contracts import DIM_ATTRIBUTE_BY_TYPE
  6. TYPE2ATTR = DIM_ATTRIBUTE_BY_TYPE
  7. def _post_value(post: Any, key: str, default: Any = "") -> Any:
  8. if isinstance(post, dict):
  9. return post.get(key, default)
  10. return getattr(post, key, default)
  11. def build_content(knowledge: dict[str, Any]) -> str | dict[str, Any]:
  12. t = knowledge.get("type")
  13. if t == "how":
  14. lines = [f"目标:{knowledge.get('purpose', '')}"]
  15. for idx, step in enumerate(knowledge.get("steps", []), 1):
  16. intent = step.get("intent") or step.get("purpose") or ""
  17. label = f"步骤{idx}" + (f"(目的:{intent})" if intent else "")
  18. lines.extend(
  19. [
  20. label,
  21. f" 输入:{step.get('input', '')}",
  22. f" 指引:{step.get('directive', '')}",
  23. f" 产出:{step.get('output', '')}",
  24. ]
  25. )
  26. return "\n".join(lines)
  27. if t == "what":
  28. return {
  29. "name": knowledge.get("title") or "",
  30. "kind": knowledge.get("kind"),
  31. "维度拆分规则": knowledge.get("维度拆分规则") if knowledge.get("kind") == "子集" else None,
  32. "body": [
  33. {
  34. "item_name": item.get("item_name", ""),
  35. "item_desc": item.get("item_desc", ""),
  36. "作用域": item.get("作用域") or [],
  37. }
  38. for item in (knowledge.get("body") or [])
  39. ],
  40. }
  41. return knowledge.get("阐述") or knowledge.get("desc") or ""
  42. def _payload_content(knowledge: dict[str, Any]) -> str:
  43. content = build_content(knowledge)
  44. return content if isinstance(content, str) else json.dumps(content, ensure_ascii=False)
  45. def _add_scopes(scopes: list[dict[str, str]], seen: set[tuple[str, str]], items: list[dict[str, Any]]) -> None:
  46. for item in items:
  47. scope_type = item.get("scope_type")
  48. value = item.get("value")
  49. if not (scope_type and value):
  50. continue
  51. key = (scope_type, value)
  52. if key in seen:
  53. continue
  54. seen.add(key)
  55. scopes.append({"scope_type": scope_type, "value": value})
  56. def collect_payload_scopes(knowledge: dict[str, Any]) -> list[dict[str, str]]:
  57. scopes: list[dict[str, str]] = []
  58. seen: set[tuple[str, str]] = set()
  59. if knowledge.get("type") == "how":
  60. for step in knowledge.get("steps", []):
  61. _add_scopes(scopes, seen, step.get("作用域", []))
  62. else:
  63. _add_scopes(scopes, seen, knowledge.get("作用域", []))
  64. return scopes
  65. def build_payload(post: Any, knowledge: dict[str, Any], how_titles: dict[str, str] | None = None) -> dict[str, Any]:
  66. how_titles = how_titles or {}
  67. t = knowledge.get("type")
  68. ext = [
  69. {"key": "业务阶段", "type": "str", "value": stage}
  70. for stage in (knowledge.get("业务阶段") or [])
  71. ]
  72. if t == "what" and knowledge.get("概要"):
  73. ext.append({"key": "概要", "type": "str", "value": knowledge["概要"]})
  74. if t == "how":
  75. creation_stages: list[str] = []
  76. seen_stages: set[str] = set()
  77. for step in knowledge.get("steps", []):
  78. stage = step.get("创作阶段")
  79. if stage and stage not in seen_stages:
  80. seen_stages.add(stage)
  81. creation_stages.append(stage)
  82. ext.extend({"key": "创作阶段", "type": "str", "value": stage} for stage in creation_stages)
  83. ext.extend(
  84. {"key": "动作", "type": "str", "value": step["动作"]}
  85. for step in knowledge.get("steps", [])
  86. if step.get("动作")
  87. )
  88. if knowledge.get("role") == "组件" and knowledge.get("parent"):
  89. parent = knowledge["parent"]
  90. ext.append(
  91. {
  92. "key": "出自",
  93. "type": "str",
  94. "value": f"{how_titles.get(parent.get('how_id'), parent.get('how_id'))} 第{parent.get('step')}步",
  95. }
  96. )
  97. return {
  98. "source": {
  99. "id": _post_value(post, "id"),
  100. "source_type": "post",
  101. "title": _post_value(post, "title") or "",
  102. "author": _post_value(post, "author_name") or "",
  103. "source_metadata": {
  104. "platform": _post_value(post, "platform"),
  105. "url": _post_value(post, "url"),
  106. },
  107. },
  108. "title": knowledge.get("title"),
  109. "content": _payload_content(knowledge),
  110. "dim_creations": ["创作"],
  111. "dim_attributes": [TYPE2ATTR.get(t, "how工序")],
  112. "scopes": collect_payload_scopes(knowledge),
  113. "custom_ext": ext,
  114. }
  115. def build_payloads(post: Any, knowledges: list[dict[str, Any]]) -> list[dict[str, Any]]:
  116. how_titles = {k.get("id"): k.get("title") for k in knowledges if k.get("type") == "how"}
  117. return [build_payload(post, knowledge, how_titles) for knowledge in knowledges]