Initial commit
This commit is contained in:
198
geniusia2/core/session_manager.py
Normal file
198
geniusia2/core/session_manager.py
Normal file
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SessionManager - Segmente les actions en sessions pour détecter les workflows
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Dict, Any, Optional, Callable
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class Session:
|
||||
"""Représente une session d'actions utilisateur."""
|
||||
session_id: str
|
||||
start_time: datetime
|
||||
end_time: Optional[datetime] = None
|
||||
actions: List[Dict[str, Any]] = field(default_factory=list)
|
||||
window: Optional[str] = None
|
||||
|
||||
@property
|
||||
def duration(self) -> timedelta:
|
||||
"""Durée de la session."""
|
||||
if self.end_time:
|
||||
return self.end_time - self.start_time
|
||||
return datetime.now() - self.start_time
|
||||
|
||||
@property
|
||||
def action_count(self) -> int:
|
||||
"""Nombre d'actions dans la session."""
|
||||
return len(self.actions)
|
||||
|
||||
|
||||
class SessionManager:
|
||||
"""
|
||||
Gestionnaire de sessions pour segmenter les actions en sessions.
|
||||
Une session = groupe d'actions dans une fenêtre de temps.
|
||||
"""
|
||||
|
||||
def __init__(self, logger, config: Dict[str, Any]):
|
||||
"""
|
||||
Initialise le gestionnaire de sessions.
|
||||
|
||||
Args:
|
||||
logger: Logger pour journalisation
|
||||
config: Configuration globale
|
||||
"""
|
||||
self.logger = logger
|
||||
self.config = config
|
||||
|
||||
# Configuration
|
||||
self.session_timeout = config.get("workflow", {}).get(
|
||||
"session_timeout", 300 # 5 minutes par défaut
|
||||
)
|
||||
|
||||
# Session courante
|
||||
self.current_session: Optional[Session] = None
|
||||
|
||||
# Historique des sessions
|
||||
self.sessions: List[Session] = []
|
||||
|
||||
# Callback pour session complétée
|
||||
self.on_session_completed: Optional[Callable] = None
|
||||
|
||||
if self.logger:
|
||||
self.logger.log_action({
|
||||
"action": "session_manager_initialized",
|
||||
"session_timeout": self.session_timeout
|
||||
})
|
||||
|
||||
def add_action(self, action: Dict[str, Any]):
|
||||
"""
|
||||
Ajoute une action à la session courante.
|
||||
Crée une nouvelle session si nécessaire.
|
||||
|
||||
Args:
|
||||
action: Action à ajouter
|
||||
"""
|
||||
# Vérifier si on doit créer une nouvelle session
|
||||
if self.should_start_new_session(action):
|
||||
self.finalize_current_session()
|
||||
self.start_new_session(action)
|
||||
|
||||
# Ajouter l'action à la session courante
|
||||
if self.current_session:
|
||||
self.current_session.actions.append(action)
|
||||
|
||||
def should_start_new_session(self, action: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Détermine si une nouvelle session doit être créée.
|
||||
|
||||
Args:
|
||||
action: Action à évaluer
|
||||
|
||||
Returns:
|
||||
True si nouvelle session nécessaire
|
||||
"""
|
||||
# Pas de session courante
|
||||
if not self.current_session:
|
||||
return True
|
||||
|
||||
# Vérifier le timeout
|
||||
if self.current_session.actions:
|
||||
last_action = self.current_session.actions[-1]
|
||||
last_time = last_action.get("timestamp")
|
||||
|
||||
if last_time:
|
||||
if isinstance(last_time, str):
|
||||
last_time = datetime.fromisoformat(last_time)
|
||||
|
||||
current_time = action.get("timestamp")
|
||||
if isinstance(current_time, str):
|
||||
current_time = datetime.fromisoformat(current_time)
|
||||
elif not current_time:
|
||||
current_time = datetime.now()
|
||||
|
||||
time_gap = (current_time - last_time).total_seconds()
|
||||
|
||||
if time_gap > self.session_timeout:
|
||||
return True
|
||||
|
||||
# Changement de fenêtre majeur
|
||||
current_window = action.get("window")
|
||||
if current_window and self.current_session.window:
|
||||
if current_window != self.current_session.window:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def start_new_session(self, first_action: Dict[str, Any]):
|
||||
"""
|
||||
Démarre une nouvelle session.
|
||||
|
||||
Args:
|
||||
first_action: Première action de la session
|
||||
"""
|
||||
session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
|
||||
timestamp = first_action.get("timestamp")
|
||||
if isinstance(timestamp, str):
|
||||
timestamp = datetime.fromisoformat(timestamp)
|
||||
elif not timestamp:
|
||||
timestamp = datetime.now()
|
||||
|
||||
self.current_session = Session(
|
||||
session_id=session_id,
|
||||
start_time=timestamp,
|
||||
window=first_action.get("window")
|
||||
)
|
||||
|
||||
if self.logger:
|
||||
self.logger.log_action({
|
||||
"action": "session_started",
|
||||
"session_id": session_id,
|
||||
"window": first_action.get("window")
|
||||
})
|
||||
|
||||
def finalize_current_session(self):
|
||||
"""Finalise la session courante."""
|
||||
if not self.current_session:
|
||||
return
|
||||
|
||||
# Marquer la fin
|
||||
self.current_session.end_time = datetime.now()
|
||||
|
||||
# Ajouter à l'historique
|
||||
self.sessions.append(self.current_session)
|
||||
|
||||
# Callback (l'Orchestrator loggera avec plus de détails)
|
||||
if self.on_session_completed:
|
||||
self.on_session_completed(self.current_session)
|
||||
|
||||
# Réinitialiser
|
||||
self.current_session = None
|
||||
|
||||
def force_finalize_session(self):
|
||||
"""Force la finalisation de la session courante."""
|
||||
self.finalize_current_session()
|
||||
|
||||
def get_recent_sessions(self, n: int = 10) -> List[Session]:
|
||||
"""
|
||||
Retourne les N sessions les plus récentes.
|
||||
|
||||
Args:
|
||||
n: Nombre de sessions à retourner
|
||||
|
||||
Returns:
|
||||
Liste des sessions récentes
|
||||
"""
|
||||
return self.sessions[-n:] if len(self.sessions) >= n else self.sessions
|
||||
|
||||
def get_stats(self) -> Dict[str, Any]:
|
||||
"""Retourne les statistiques des sessions."""
|
||||
return {
|
||||
"total_sessions": len(self.sessions),
|
||||
"current_session_actions": self.current_session.action_count if self.current_session else 0,
|
||||
"avg_session_duration": sum(s.duration.total_seconds() for s in self.sessions) / len(self.sessions) if self.sessions else 0,
|
||||
"avg_actions_per_session": sum(s.action_count for s in self.sessions) / len(self.sessions) if self.sessions else 0
|
||||
}
|
||||
Reference in New Issue
Block a user