feat(server): 归因v2——paid_social渠道与fb+付费medium优先规则

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-18 22:41:58 +08:00
parent be0b53bce4
commit 52a8a72e3a
4 changed files with 66 additions and 10 deletions
+15 -3
View File
@@ -29,6 +29,9 @@ _AD_FAMILIES = {
"bing": "bing", "bingads": "bing", "microsoftads": "bing",
"yandex": "yandex", "yandexads": "yandex", "директ": "yandex",
}
_FB_FAMILY = "meta" # fb 家族名(_AD_FAMILIES 归一结果):fb+付费 medium → paid_social
# 点击参数 → 付费渠道(v2):fbclid 属社交广告(Meta),其余(gclid/msclkid/yclid)搜索广告
_PAID_PARAM_CHANNELS = {"fbclid": "paid_social"}
# UTM 标签 ↔ 平台名别名(家族表之外的零散别名);baidu 恒等仅为可读
_UTM_ALIASES = {"tt": "tiktok",
"wa": "whatsapp", "g": "google", "baidu": "baidu", "百度": "baidu"}
@@ -157,7 +160,8 @@ def classify(*, referrer_url: str = "", utm: dict | None = None,
paid = _paid_param(landing_path, referrer_url)
if paid:
out.update(channel="paid_search", platform=paid[1],
out.update(channel=_PAID_PARAM_CHANNELS.get(paid[0], "paid_search"),
platform=paid[1],
evidence_kind="observed_referrer", resolution="resolved",
detail={"click_param": paid[0]})
elif host:
@@ -199,8 +203,16 @@ def classify(*, referrer_url: str = "", utm: dict | None = None,
"utm_evidence": {
"channel": _utm_channel(utm_source), "platform": utm_source,
"evidence_kind": "utm_label"}}
else: # 无 referrer 观察 → 仅标签:按 utm_source 归类显示,状态诚实标注
out.update(channel=_utm_channel(utm_source), platform=utm_source,
else: # 无 referrer 观察 → 仅标签:按 utm_source/utm_medium 归类显示,状态诚实标注
medium = str(utm.get("utm_medium") or "").strip().lower()
channel = _utm_channel(utm_source)
if medium in C.PAID_MEDIUMS:
if _canon(utm_source) == _FB_FAMILY:
channel = "paid_social" # fb 家族 + 付费 medium(实测主导 paid+fb)
elif medium not in C.SOCIAL_MEDIUMS:
channel = "paid_search" # 非 fb + 搜索系付费 medium(cpc/ppc/paid…)
# 非 fb + 纯社交 medium 不判付费——防误伤自然社交,保持 _utm_channel 走向
out.update(channel=channel, platform=utm_source,
evidence_kind="utm_label", resolution="label_only")
# 应用内浏览器 UA:有来源 → 作为 surface 叠加;无任何来源 → 本身就是来源