test_platform_observable_performance.py 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from __future__ import annotations
  2. from content_agent.business_modules.content_discovery.platform_observable_performance import (
  3. performance_score,
  4. )
  5. # M11:平台表现改"量级分 + 收缩后比例分"(配置驱动 observable_performance)。
  6. # 三平台按真实字段可得性走不同 component:抖音互动间比例 / 快手 per 播放真互动率 / 视频号仅点赞量级。
  7. def test_douyin_v2_volume_plus_inter_metric_ratios():
  8. result = performance_score(
  9. {"digg_count": 100000, "comment_count": 1000, "share_count": 500, "collect_count": 1000},
  10. "douyin",
  11. )
  12. assert 0 <= result["platform_performance_score"] <= 100
  13. assert [row["field"] for row in result["platform_performance_components"]] == [
  14. "total_interaction",
  15. "share_ratio",
  16. "collect_ratio",
  17. "comment_ratio",
  18. ]
  19. assert result["platform_performance_components"][0]["type"] == "absolute"
  20. assert result["platform_performance_components"][1]["type"] == "ratio"
  21. # play_count 抖音天然缺失仍如实上报
  22. assert {
  23. "field": "statistics.play_count",
  24. "missing_type": "natural_platform_missing",
  25. "platform": "douyin",
  26. "evidence": "跨平台字段映射.json",
  27. } in result["missing_observable_fields"]
  28. assert "platform_heat" not in result
  29. def test_kuaishou_v2_per_view_rates_no_share():
  30. result = performance_score(
  31. {"play_count": 10000, "digg_count": 2000, "comment_count": 200, "share_count": 100, "collect_count": 100},
  32. "kuaishou",
  33. )
  34. # 快手:播放量级 + 三个 per 播放真互动率;无转发项(share 恒 0)
  35. assert [row["field"] for row in result["platform_performance_components"]] == [
  36. "play_count",
  37. "like_rate",
  38. "collect_rate",
  39. "comment_rate",
  40. ]
  41. assert result["platform_performance_score"] is not None
  42. assert result["missing_observable_fields"] == [] # play 在 → 比例分母不缺
  43. def test_kuaishou_missing_play_count_marks_ratio_denominator_missing():
  44. # 快手缺 play_count → per 播放比例分母为 0 → 记 runtime_missing、只剩播放量级一项
  45. result = performance_score({"digg_count": 2000, "comment_count": 200, "collect_count": 100}, "kuaishou")
  46. runtime_missing = [
  47. row for row in result["missing_observable_fields"] if row.get("missing_type") == "runtime_missing"
  48. ]
  49. assert {row["field"] for row in runtime_missing} == {"like_rate", "collect_rate", "comment_rate"}
  50. assert [row["field"] for row in result["platform_performance_components"]] == ["play_count"]
  51. def test_shipinhao_only_digg_volume():
  52. result = performance_score({"digg_count": 500}, "shipinhao")
  53. assert [row["field"] for row in result["platform_performance_components"]] == ["digg_count"]
  54. assert result["platform_performance_components"][0]["type"] == "absolute"
  55. assert {row["field"] for row in result["missing_observable_fields"]} == {
  56. "statistics.comment_count",
  57. "statistics.share_count",
  58. "statistics.collect_count",
  59. "statistics.play_count",
  60. }
  61. def test_ratio_shrinkage_pulls_low_sample_toward_prior():
  62. # 抖音转发率:小样本(3 赞 1 转=33%)被收缩拉回正常,不给虚高分;大样本真高比例保留。
  63. low = performance_score({"digg_count": 3, "share_count": 1, "comment_count": 0, "collect_count": 0}, "douyin")
  64. high = performance_score({"digg_count": 100000, "share_count": 35000, "comment_count": 5000, "collect_count": 50000}, "douyin")
  65. low_share = next(c for c in low["platform_performance_components"] if c["field"] == "share_ratio")
  66. high_share = next(c for c in high["platform_performance_components"] if c["field"] == "share_ratio")
  67. assert low_share["raw_ratio"] > 0.3 # 原始 33%
  68. assert low_share["shrunk_ratio"] < 0.15 # 收缩后被拉回(prior 0.12 附近)
  69. assert low_share["normalized_score"] < 60
  70. assert high_share["normalized_score"] == 100 # 真·高转发占满