-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsession_manager.py
More file actions
77 lines (66 loc) · 3.08 KB
/
Copy pathsession_manager.py
File metadata and controls
77 lines (66 loc) · 3.08 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
import json
import os
import re
from datetime import datetime
from typing import Dict, Any, List
class SessionManager:
"""
Manages dual-storage session data:
1. A .jsonl file for high-performance, append-only raw logs.
2. A .json file for the structured session abstract and metadata.
"""
def __init__(self, history_dir: str = "history"):
self.history_dir = history_dir
os.makedirs(self.history_dir, exist_ok=True)
self.session_id = self._generate_session_id()
# File paths
self.log_file = os.path.join(self.history_dir, f"session_{self.session_id}_log.jsonl")
self.abstract_file = os.path.join(self.history_dir, f"session_{self.session_id}_abstract.json")
# Initialize the abstract structure
self.abstract_data = {
"session_id": self.session_id,
"start_time": datetime.now().isoformat(),
"last_updated": datetime.now().isoformat(),
"total_turns": 0,
"dominant_emotion": "Unknown",
"session_summary": "Session started. No summary available yet.",
"key_topics": []
}
# Write the initial abstract file
self._save_abstract()
print(f"[System] Session {self.session_id} initialized.")
def _generate_session_id(self) -> int:
"""Finds the highest existing session number and increments it."""
existing_files = [f for f in os.listdir(self.history_dir) if f.startswith("session_")]
nums = [int(re.search(r'session_(\d+)', f).group(1)) for f in existing_files if re.search(r'session_(\d+)', f)]
return max(nums) + 1 if nums else 1
def log_turn(self, role: str, content: str, phase: str = None) -> None:
"""
O(1) append to the raw log file. This will never block your chat loop.
"""
turn_data = {
"timestamp": datetime.now().isoformat(),
"role": role,
"content": content,
"detected_phase": phase
}
with open(self.log_file, "a", encoding="utf-8") as f:
f.write(json.dumps(turn_data) + "\n")
# Update metadata counters
if role == "user":
self.abstract_data["total_turns"] += 1
def update_abstract(self, summary: str, dominant_emotion: str, topics: List[str]) -> None:
"""
Updates and overwrites the structured standard .json file.
Call this periodically (e.g., every 5 turns) or at the end of the session,
NOT on every single message, to save I/O overhead.
"""
self.abstract_data["last_updated"] = datetime.now().isoformat()
self.abstract_data["session_summary"] = summary
self.abstract_data["dominant_emotion"] = dominant_emotion
self.abstract_data["key_topics"] = topics
self._save_abstract()
def _save_abstract(self) -> None:
"""Writes the abstract dictionary to a standard, readable JSON format."""
with open(self.abstract_file, "w", encoding="utf-8") as f:
json.dump(self.abstract_data, f, indent=4)