system-prompts-and-models-o.../dealix/auto_client_acquisition/revenue_science/churn_model.py
2026-05-01 14:03:52 +03:00

123 lines
3.8 KiB
Python

"""
Churn prediction — flags customers likely to churn within 60 days.
Inputs are signals from the Revenue Memory + Customer Success layer:
- days_since_last_login
- drop in monthly engagement
- support ticket spike
- billing issues
- low NPS
- drop in pipeline added by Dealix
Each signal gets a weight; the composite score is mapped to a band.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
@dataclass
class ChurnPrediction:
customer_id: str
score: float # 0..1 — higher = more likely to churn
band: str # safe / watch / at_risk / critical
drivers: list[str] = field(default_factory=list)
recommended_action_ar: str = ""
confidence: float = 0.7
def predict_churn(
*,
customer_id: str,
days_since_last_login: int = 0,
monthly_engagement_drop_pct: float = 0, # 0..1 (drop vs prior month)
support_tickets_open: int = 0,
billing_failures_last_90d: int = 0,
nps: int | None = None,
pipeline_added_drop_pct: float = 0, # 0..1 (drop vs prior month)
months_as_customer: int = 6,
) -> ChurnPrediction:
"""
Compute churn probability + drivers + recommendation.
Weights tuned to the early-pilot cohort. As more data flows in,
these can be re-fit by the AI Quality module.
"""
score = 0.0
drivers: list[str] = []
# Engagement: huge weight
if days_since_last_login > 30:
score += 0.35
drivers.append(f"لم يدخل المنتج منذ {days_since_last_login} يوم")
elif days_since_last_login > 14:
score += 0.20
drivers.append(f"دخوله متباعد ({days_since_last_login} يوم)")
if monthly_engagement_drop_pct > 0.5:
score += 0.20
drivers.append(f"انخفاض الاستخدام {monthly_engagement_drop_pct*100:.0f}%")
elif monthly_engagement_drop_pct > 0.3:
score += 0.10
# Support tickets
if support_tickets_open >= 3:
score += 0.15
drivers.append(f"{support_tickets_open} تذاكر دعم مفتوحة")
elif support_tickets_open >= 1:
score += 0.05
# Billing
if billing_failures_last_90d >= 2:
score += 0.15
drivers.append("فشل في الدفع متكرر")
elif billing_failures_last_90d >= 1:
score += 0.07
# NPS
if nps is not None:
if nps <= 6:
score += 0.20
drivers.append(f"NPS منخفض ({nps})")
elif nps == 7:
score += 0.05
# Outcome — Dealix's job
if pipeline_added_drop_pct > 0.5:
score += 0.15
drivers.append("Dealix لا يجلب pipeline كما كان")
elif pipeline_added_drop_pct > 0.3:
score += 0.07
# New customers cushion: <3 months gets a -0.1 because honeymoon
if months_as_customer < 3:
score = max(0, score - 0.10)
score = min(1.0, score)
if score >= 0.65:
band = "critical"
action = "اتصل بالعميل اليوم. أعرض QBR + offer to extend pilot. هذا يكلف $0 إذا أنقذناه."
elif score >= 0.45:
band = "at_risk"
action = "حدد call مع decision-maker. أرسل Proof Pack + roadmap للنصف القادم."
elif score >= 0.25:
band = "watch"
action = "راقب أسبوعياً + أرسل insights مخصصة. لا تدخل عاجل."
else:
band = "safe"
action = "صحي — فكّر في expansion / upsell."
confidence = 0.6 if len(drivers) <= 1 else min(0.95, 0.6 + len(drivers) * 0.07)
return ChurnPrediction(
customer_id=customer_id,
score=round(score, 3),
band=band,
drivers=drivers,
recommended_action_ar=action,
confidence=round(confidence, 3),
)