Files
Geniusia_v2/geniusia2/core/session_manager.py
2026-03-05 00:20:25 +01:00

199 lines
6.5 KiB
Python

#!/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
}