delivery_config.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. """Account-level bidding and placement config parsed from Feishu/DB."""
  2. from __future__ import annotations
  3. from dataclasses import dataclass
  4. BID_MODE_AVERAGE_COST = "average_cost"
  5. BID_MODE_MAX_CONVERSION = "max_conversion"
  6. @dataclass(frozen=True)
  7. class PlacementConfig:
  8. automatic_site_enabled: bool
  9. site_set: list[str]
  10. _BID_SCENE_VALUES = {
  11. "": BID_MODE_AVERAGE_COST,
  12. "平均成本": BID_MODE_AVERAGE_COST,
  13. "稳定成本": BID_MODE_AVERAGE_COST,
  14. "最大转化量": BID_MODE_MAX_CONVERSION,
  15. "最大转化量出价": BID_MODE_MAX_CONVERSION,
  16. "average_cost": BID_MODE_AVERAGE_COST,
  17. "max_conversion": BID_MODE_MAX_CONVERSION,
  18. # 兼容已经同步过的旧值。
  19. "BID_SCENE_NORMAL_AVERAGE": BID_MODE_AVERAGE_COST,
  20. "BID_SCENE_NORMAL_MAX": BID_MODE_MAX_CONVERSION,
  21. }
  22. _PLACEMENT_GROUPS = {
  23. "微信朋友圈": ["SITE_SET_MOMENTS"],
  24. "朋友圈": ["SITE_SET_MOMENTS"],
  25. "微信公众号与小程序": ["SITE_SET_WECHAT", "SITE_SET_WECHAT_PLUGIN"],
  26. "微信公众号": ["SITE_SET_WECHAT"],
  27. "微信插件": ["SITE_SET_WECHAT_PLUGIN"],
  28. "搜索场景": ["SITE_SET_SEARCH_SCENE"],
  29. "腾讯平台与内容媒体": [
  30. "SITE_SET_TENCENT_NEWS",
  31. "SITE_SET_TENCENT_VIDEO",
  32. "SITE_SET_KANDIAN",
  33. "SITE_SET_QQ_MUSIC_GAME",
  34. ],
  35. "腾讯营销联盟": ["SITE_SET_MOBILE_UNION"],
  36. }
  37. def parse_bid_scene(raw: object) -> str:
  38. text = str(raw or "").strip()
  39. if text in _BID_SCENE_VALUES:
  40. return _BID_SCENE_VALUES[text]
  41. raise ValueError(f"未知出价方式:{raw}")
  42. def parse_placement_config(raw: object) -> PlacementConfig | None:
  43. text = str(raw or "").strip()
  44. if not text:
  45. return None
  46. if text.upper() == "AIM+":
  47. return PlacementConfig(automatic_site_enabled=True, site_set=[])
  48. site_set: list[str] = []
  49. for part in text.replace(",", ",").split(","):
  50. name = part.strip()
  51. if not name:
  52. continue
  53. values = _PLACEMENT_GROUPS.get(name)
  54. if values is None:
  55. raise ValueError(f"未知投放版位:{name}")
  56. for value in values:
  57. if value not in site_set:
  58. site_set.append(value)
  59. if not site_set:
  60. raise ValueError(f"投放版位为空:{raw}")
  61. return PlacementConfig(automatic_site_enabled=False, site_set=site_set)