Upload layer2_episodic_binding.py with huggingface_hub
Browse files- layer2_episodic_binding.py +154 -0
layer2_episodic_binding.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
from collections import Counter
|
| 3 |
+
|
| 4 |
+
class EpisodePalace:
|
| 5 |
+
"""セッション固有のエピソード宮殿を管理"""
|
| 6 |
+
|
| 7 |
+
def __init__(self, session_id: str):
|
| 8 |
+
self.session_id = session_id
|
| 9 |
+
self.rooms = []
|
| 10 |
+
self.spatial_coordinates = []
|
| 11 |
+
self.reasoning_paths = []
|
| 12 |
+
|
| 13 |
+
def _calculate_room_position(self, turn_number: int) -> tuple:
|
| 14 |
+
"""ターン数から宮殿内の位置を計算"""
|
| 15 |
+
x = min(100, (turn_number - 1) * 25)
|
| 16 |
+
y = 50 if turn_number > 1 else 0
|
| 17 |
+
z = 0
|
| 18 |
+
return (x, y, z)
|
| 19 |
+
|
| 20 |
+
def add_turn(self, user_input: str, llm_response: str, metadata: dict):
|
| 21 |
+
"""ターンを宮殿に追加"""
|
| 22 |
+
turn_number = len(self.rooms) + 1
|
| 23 |
+
room_coordinate = self._calculate_room_position(turn_number)
|
| 24 |
+
|
| 25 |
+
turn_record = {
|
| 26 |
+
"turn_number": turn_number,
|
| 27 |
+
"room_coordinate": room_coordinate,
|
| 28 |
+
"timestamp": datetime.now().isoformat(),
|
| 29 |
+
"user_input": user_input,
|
| 30 |
+
"llm_response": llm_response,
|
| 31 |
+
"referenced_db_coordinates": metadata.get("referenced_coords", []),
|
| 32 |
+
"referenced_web_results": metadata.get("web_results", []),
|
| 33 |
+
"reasoning_path": metadata.get("reasoning_path", []),
|
| 34 |
+
"confidence_scores": metadata.get("confidence_scores", [])
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
self.rooms.append(turn_record)
|
| 38 |
+
self.spatial_coordinates.append(room_coordinate)
|
| 39 |
+
self.reasoning_paths.append(metadata.get("reasoning_path", []))
|
| 40 |
+
|
| 41 |
+
return room_coordinate
|
| 42 |
+
|
| 43 |
+
def _aggregate_referenced_coords(self, turns: list) -> list:
|
| 44 |
+
"""ターンから参照座標を集約"""
|
| 45 |
+
all_coords = [tuple(c) for turn in turns for c in turn["referenced_db_coordinates"]]
|
| 46 |
+
coord_counts = Counter(all_coords)
|
| 47 |
+
sorted_coords = sorted(coord_counts.items(), key=lambda x: x[1], reverse=True)
|
| 48 |
+
return [coord for coord, count in sorted_coords[:5]]
|
| 49 |
+
|
| 50 |
+
def _extract_key_concepts(self, turns: list) -> list:
|
| 51 |
+
"""ターンから主要概念を抽出"""
|
| 52 |
+
concepts = set()
|
| 53 |
+
for turn in turns:
|
| 54 |
+
response_text = turn["llm_response"]
|
| 55 |
+
words = response_text.split()
|
| 56 |
+
for word in words:
|
| 57 |
+
if len(word) > 2:
|
| 58 |
+
concepts.add(word)
|
| 59 |
+
return list(concepts)[:10]
|
| 60 |
+
|
| 61 |
+
def _construct_trajectory(self, turns: list) -> list:
|
| 62 |
+
# このメソッドの具体的な実装は設計書にないため、プレースホルダーとします
|
| 63 |
+
return [turn.get("reasoning_path", []) for turn in turns]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_recent_context(self, num_turns: int = 5) -> dict:
|
| 67 |
+
"""最近のターンから文脈を取得"""
|
| 68 |
+
recent_turns = self.rooms[-num_turns:]
|
| 69 |
+
|
| 70 |
+
context = {
|
| 71 |
+
"recent_turns": recent_turns,
|
| 72 |
+
"referenced_coordinates": self._aggregate_referenced_coords(recent_turns),
|
| 73 |
+
"key_concepts": self._extract_key_concepts(recent_turns),
|
| 74 |
+
"reasoning_trajectory": self._construct_trajectory(recent_turns)
|
| 75 |
+
}
|
| 76 |
+
return context
|
| 77 |
+
|
| 78 |
+
class EpisodeDBReferenceTracker:
|
| 79 |
+
"""エピソード宮殿がグローバルDB空間を参照するのを追跡"""
|
| 80 |
+
|
| 81 |
+
def __init__(self, episode_palace, db_interface):
|
| 82 |
+
self.episode_palace = episode_palace
|
| 83 |
+
self.db_interface = db_interface
|
| 84 |
+
self.reference_map = {}
|
| 85 |
+
|
| 86 |
+
def record_reference(self, turn_number: int, db_coordinates: list, confidence: float):
|
| 87 |
+
"""参照を記録"""
|
| 88 |
+
if turn_number > len(self.episode_palace.rooms):
|
| 89 |
+
return
|
| 90 |
+
|
| 91 |
+
room_coord = self.episode_palace.rooms[turn_number - 1]["room_coordinate"]
|
| 92 |
+
|
| 93 |
+
if room_coord not in self.reference_map:
|
| 94 |
+
self.reference_map[room_coord] = []
|
| 95 |
+
|
| 96 |
+
reference_record = {
|
| 97 |
+
"timestamp": datetime.now().isoformat(),
|
| 98 |
+
"db_coordinates": db_coordinates,
|
| 99 |
+
"confidence": confidence,
|
| 100 |
+
}
|
| 101 |
+
self.reference_map[room_coord].append(reference_record)
|
| 102 |
+
|
| 103 |
+
def build_trust_chain(self, turn_number: int) -> list:
|
| 104 |
+
"""参照チェーンから信頼度チェーンを構築"""
|
| 105 |
+
if turn_number > len(self.episode_palace.rooms):
|
| 106 |
+
return []
|
| 107 |
+
|
| 108 |
+
room_coord = self.episode_palace.rooms[turn_number - 1]["room_coordinate"]
|
| 109 |
+
|
| 110 |
+
if room_coord not in self.reference_map:
|
| 111 |
+
return []
|
| 112 |
+
|
| 113 |
+
references = self.reference_map[room_coord]
|
| 114 |
+
trust_chain = []
|
| 115 |
+
|
| 116 |
+
for ref in references:
|
| 117 |
+
db_coords_list = ref["db_coordinates"]
|
| 118 |
+
for db_coord in db_coords_list:
|
| 119 |
+
db_certainty = self.db_interface.get_certainty(db_coord)
|
| 120 |
+
trust_record = {
|
| 121 |
+
"db_coordinates": db_coord,
|
| 122 |
+
"reference_confidence": ref["confidence"],
|
| 123 |
+
"db_certainty": db_certainty,
|
| 124 |
+
"combined_trust": ref["confidence"] * db_certainty
|
| 125 |
+
}
|
| 126 |
+
trust_chain.append(trust_record)
|
| 127 |
+
|
| 128 |
+
return trust_chain
|
| 129 |
+
|
| 130 |
+
if __name__ == '__main__':
|
| 131 |
+
# --- モックDBインターフェース ---
|
| 132 |
+
class MockDB:
|
| 133 |
+
def get_certainty(self, db_coordinates):
|
| 134 |
+
certainty_map = {(28, 35, 15): 0.95, (28, 55, 15): 0.85}
|
| 135 |
+
rounded_coords = (int(db_coordinates[0]), int(db_coordinates[1]), int(db_coordinates[2]))
|
| 136 |
+
return certainty_map.get(rounded_coords, 0.5)
|
| 137 |
+
|
| 138 |
+
# --- 実行例 ---
|
| 139 |
+
palace = EpisodePalace("session-001")
|
| 140 |
+
tracker = EpisodeDBReferenceTracker(palace, MockDB())
|
| 141 |
+
|
| 142 |
+
# ターン1
|
| 143 |
+
palace.add_turn("心筋梗塞とは?", "心臓の筋肉に血流が...", {"referenced_coords": [(28, 55, 15)]})
|
| 144 |
+
tracker.record_reference(turn_number=1, db_coordinates=[(28, 55, 15)], confidence=0.9)
|
| 145 |
+
|
| 146 |
+
# ターン2
|
| 147 |
+
palace.add_turn("診断方法は?", "心電図や血液検査で...", {"referenced_coords": [(28, 35, 15)]})
|
| 148 |
+
tracker.record_reference(turn_number=2, db_coordinates=[(28, 35, 15)], confidence=0.95)
|
| 149 |
+
|
| 150 |
+
print("\n--- Context for next turn (after 2 turns) ---")
|
| 151 |
+
print(palace.get_recent_context())
|
| 152 |
+
|
| 153 |
+
print("\n--- Trust chain for turn 2 ---")
|
| 154 |
+
print(tracker.build_trust_chain(turn_number=2))
|