41 lines
1.2 KiB
Python
41 lines
1.2 KiB
Python
from __future__ import annotations
|
|
|
|
from django.db import transaction
|
|
|
|
from .models import ProfileRevision, SearchProfile
|
|
|
|
|
|
@transaction.atomic
|
|
def save_profile_revision(profile: SearchProfile, *, reason: str) -> ProfileRevision:
|
|
latest = profile.revisions.order_by("-version").first()
|
|
next_version = (latest.version if latest else 0) + 1
|
|
if profile.version != next_version:
|
|
profile.version = next_version
|
|
profile.save(update_fields=["version", "updated_at"])
|
|
return ProfileRevision.objects.create(
|
|
profile=profile,
|
|
version=next_version,
|
|
snapshot=profile.snapshot(),
|
|
reason=reason,
|
|
)
|
|
|
|
|
|
@transaction.atomic
|
|
def apply_feedback_delta(
|
|
profile: SearchProfile,
|
|
feature: str,
|
|
delta: float,
|
|
*,
|
|
min_weight: float = 0.0,
|
|
max_weight: float = 40.0,
|
|
) -> SearchProfile:
|
|
if not profile.learning_enabled:
|
|
return profile
|
|
weights = dict(profile.weights)
|
|
current = float(weights.get(feature, 0.0))
|
|
weights[feature] = round(max(min_weight, min(max_weight, current + delta)), 2)
|
|
profile.weights = weights
|
|
profile.save(update_fields=["weights", "updated_at"])
|
|
save_profile_revision(profile, reason=f"feedback_delta:{feature}:{delta:+.2f}")
|
|
return profile
|