53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
|
|
"""
|
||
|
|
ImpactEvaluator
|
||
|
|
|
||
|
|
Evaluates the breadth of impact a memory has based on associated topics.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from typing import TYPE_CHECKING
|
||
|
|
|
||
|
|
if TYPE_CHECKING:
|
||
|
|
from app.models.memory import UserMemory
|
||
|
|
|
||
|
|
|
||
|
|
class ImpactEvaluator:
|
||
|
|
"""Evaluate the impact breadth of a memory"""
|
||
|
|
|
||
|
|
# Threshold for maximum impact score
|
||
|
|
IMPACT_THRESHOLD = 5 # Number of associated topics for max impact
|
||
|
|
|
||
|
|
def evaluate(self, memory: "UserMemory") -> float:
|
||
|
|
"""Calculate impact score (0.0 - 1.0)
|
||
|
|
|
||
|
|
The more associated topics a memory has, the higher its impact.
|
||
|
|
Topics represent "what this memory is about" — if it touches
|
||
|
|
many aspects of the user's life, it has high impact.
|
||
|
|
"""
|
||
|
|
associated_topics = memory.associated_topics or []
|
||
|
|
if not associated_topics:
|
||
|
|
return 0.0
|
||
|
|
|
||
|
|
# Normalize: IMPACT_THRESHOLD topics = full impact (1.0)
|
||
|
|
raw_score = len(associated_topics) / self.IMPACT_THRESHOLD
|
||
|
|
return min(1.0, raw_score)
|
||
|
|
|
||
|
|
def get_topic_overlap(self, memory_a: "UserMemory", memory_b: "UserMemory") -> float:
|
||
|
|
"""Calculate topic overlap between two memories (0.0 - 1.0)
|
||
|
|
|
||
|
|
Used for finding related memories.
|
||
|
|
"""
|
||
|
|
topics_a = set(memory_a.associated_topics or [])
|
||
|
|
topics_b = set(memory_b.associated_topics or [])
|
||
|
|
|
||
|
|
if not topics_a or not topics_b:
|
||
|
|
return 0.0
|
||
|
|
|
||
|
|
intersection = topics_a & topics_b
|
||
|
|
union = topics_a | topics_b
|
||
|
|
|
||
|
|
return len(intersection) / len(union) if union else 0.0
|
||
|
|
|
||
|
|
def rank_by_impact(self, memories: list["UserMemory"]) -> list["UserMemory"]:
|
||
|
|
"""Rank memories by impact score (descending)"""
|
||
|
|
return sorted(memories, key=lambda m: self.evaluate(m), reverse=True)
|