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