-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory_retrieval.py
More file actions
108 lines (95 loc) · 3.66 KB
/
Copy pathmemory_retrieval.py
File metadata and controls
108 lines (95 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from __future__ import annotations
"""
Semantic retrieval helpers for Azurro Memory Vault.
Given a candidate entry, return top episodic memories (bets/skips) and
top lessons/notes that are most relevant for Sentry.
"""
from typing import Any, Dict, List
from memory_embeddings import embed_text
from memory_db import is_configured, query_similar
def _build_query_text(entry: dict, window_name: str | None = None) -> str:
name = entry.get("name") or "?"
league = entry.get("league") or ""
score = entry.get("score") or "? - ?"
target = entry.get("target_line") or "?"
odds = entry.get("odds")
shots = entry.get("total_shots")
corners = entry.get("total_corners")
fouls = entry.get("fouls")
preds = entry.get("predictions_text") or ""
parts: list[str] = []
parts.append(f"Match: {name} ({league})")
if window_name:
parts.append(f"Window: {window_name}")
parts.append(f"Score: {score}, Line: {target}, Odds: {odds}")
parts.append(f"Stats: shots={shots}, corners={corners}, fouls={fouls}")
if preds:
parts.append(f"Predictions: {preds}")
return " | ".join(str(p) for p in parts if p)
def get_relevant_memories_for_entry(
entry: dict,
*,
window_name: str | None = None,
top_k_episodes: int = 8,
top_k_lessons: int = 6,
) -> Dict[str, List[Dict[str, Any]]]:
"""
Return dict with 'episodes' and 'lessons' lists for this entry.
Each item contains text, league, window_name, distance, and basic features.
"""
if not is_configured():
return {"episodes": [], "lessons": []}
league = (entry.get("league") or "") or None
query_text = _build_query_text(entry, window_name)
emb = embed_text(query_text)
# Episodes: bets + skips (kind filter applied in code)
raw_eps = query_similar(emb, top_k=top_k_episodes * 2, league=league, window_name=window_name)
episodes: List[Dict[str, Any]] = []
for r in raw_eps:
if r.get("kind") not in ("bet", "skip"):
continue
episodes.append(
{
"id": str(r.get("id")),
"kind": r.get("kind"),
"created_at": r.get("created_at"),
"league": r.get("league"),
"window_name": r.get("window_name"),
"text": r.get("text"),
"features": r.get("features_json") or {},
"distance": float(r.get("distance") or 0.0),
}
)
if len(episodes) >= top_k_episodes:
break
# Lessons/notes
lessons: List[Dict[str, Any]] = []
for lesson_kind in ("lesson", "note", "weekly_theme"):
raw_lessons = query_similar(
emb,
top_k=top_k_lessons * 2,
kind=lesson_kind,
league=league,
window_name=window_name,
)
for r in raw_lessons:
lessons.append(
{
"id": str(r.get("id")),
"kind": r.get("kind"),
"created_at": r.get("created_at"),
"league": r.get("league"),
"window_name": r.get("window_name"),
"text": r.get("text"),
"features": r.get("features_json") or {},
"distance": float(r.get("distance") or 0.0),
}
)
# Deduplicate by id and take best distances
by_id: Dict[str, Dict[str, Any]] = {}
for l in lessons:
lid = l["id"]
if lid not in by_id or l["distance"] < by_id[lid]["distance"]:
by_id[lid] = l
lessons = sorted(by_id.values(), key=lambda x: x["distance"])[:top_k_lessons]
return {"episodes": episodes, "lessons": lessons}