QRcheckin / src /scoring.py
Corin1998's picture
Update src/scoring.py
bba81e5 verified
from datetime import datetime, timedelta
from sqlmodel import select
from .models import Visit, TokenBalance
from .db import get_session
# 重みは適宜調整
W_RECENCY = 0.5
W_FREQUENCY = 0.3
W_POINTS = 0.2 # 総ポイント寄与(名称だけ修正)
def calc_score(user_id: int) -> float:
now = datetime.utcnow()
with get_session() as s:
visits = s.exec(
select(Visit).where(Visit.user_id == user_id).order_by(Visit.created_at.desc())
).all()
if not visits:
return 0.0
last_visit = visits[0].created_at
days_since = (now - last_visit).days
# 最近度:30日で線形減衰(0〜1)
recency_score = max(0.0, 1.0 - days_since / 30.0)
# 頻度:直近90日で10回来店で満点(0〜1)
recent_90 = now - timedelta(days=90)
freq_score = min(
1.0,
len([v for v in visits if v.created_at > recent_90]) / 10.0
)
# ポイント寄与:合計1000ptで満点(0〜1)
balances = s.exec(select(TokenBalance).where(TokenBalance.user_id == user_id)).all()
points_amount = sum(tb.amount for tb in balances)
points_score = min(1.0, points_amount / 1000.0)
return W_RECENCY * recency_score + W_FREQUENCY * freq_score + W_POINTS * points_score
def segment(score: float) -> str:
if score >= 0.75:
return "loyal"
if score >= 0.4:
return "active"
if score > 0.0:
return "at-risk"
return "new"