- Léa se présente comme "assistante basée sur l'intelligence artificielle" - Dialog consentement avant enregistrement (capture écran/clavier) - Rétention logs 180 jours (Article 12 + 26(6)) - Bouton ARRÊT D'URGENCE toujours visible (Article 14) - Transparence mode autonome explicite (Article 50) - Rapport conformité AI Act en français (docs/CONFORMITE_AI_ACT.md) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
3.2 KiB
Python
75 lines
3.2 KiB
Python
# agent_v1/session/storage.py
|
|
"""
|
|
Gestionnaire de stockage local robuste pour Agent V1.
|
|
Gère le chiffrement des données au repos et l'auto-nettoyage du disque.
|
|
"""
|
|
|
|
import os
|
|
import shutil
|
|
import time
|
|
import logging
|
|
from pathlib import Path
|
|
from datetime import datetime, timedelta
|
|
|
|
logger = logging.getLogger("session_storage")
|
|
|
|
class SessionStorage:
|
|
def __init__(self, base_dir: Path, max_size_gb: int = 5, retention_days: int = 180):
|
|
"""Gestionnaire de stockage local pour les sessions Agent V1.
|
|
|
|
Args:
|
|
base_dir: Dossier racine de stockage des sessions.
|
|
max_size_gb: Taille maximale du stockage local (Go).
|
|
retention_days: Duree de retention en jours. Defaut = 180 (6 mois),
|
|
minimum requis par le Reglement IA (Article 12 — journalisation
|
|
automatique, Article 26(6) — conservation des logs).
|
|
"""
|
|
self.base_dir = base_dir
|
|
self.max_size_bytes = max_size_gb * 1024 * 1024 * 1024
|
|
self.retention_days = retention_days
|
|
self.base_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def get_session_dir(self, session_id: str) -> Path:
|
|
"""Retourne et crée le dossier pour une session."""
|
|
session_path = self.base_dir / session_id
|
|
session_path.mkdir(exist_ok=True)
|
|
(session_path / "shots").mkdir(exist_ok=True)
|
|
return session_path
|
|
|
|
def run_auto_cleanup(self):
|
|
"""Lance le nettoyage automatique basé sur l'âge et la taille."""
|
|
logger.info("🧹 Lancement du nettoyage automatique du stockage local...")
|
|
self._cleanup_by_age()
|
|
self._cleanup_by_size()
|
|
|
|
def _cleanup_by_age(self):
|
|
"""Supprime les sessions plus vieilles que retention_days."""
|
|
threshold = datetime.now() - timedelta(days=self.retention_days)
|
|
for session_path in self.base_dir.iterdir():
|
|
if session_path.is_dir():
|
|
mtime = datetime.fromtimestamp(session_path.stat().st_mtime)
|
|
if mtime < threshold:
|
|
logger.info(f"🗑️ Purge session ancienne : {session_path.name}")
|
|
shutil.rmtree(session_path)
|
|
|
|
def _cleanup_by_size(self):
|
|
"""Supprime les sessions les plus anciennes si la taille totale dépasse max_size_bytes."""
|
|
sessions = []
|
|
total_size = 0
|
|
for session_path in self.base_dir.iterdir():
|
|
if session_path.is_dir():
|
|
size = sum(f.stat().st_size for f in session_path.rglob('*') if f.is_file())
|
|
sessions.append((session_path, session_path.stat().st_mtime, size))
|
|
total_size += size
|
|
|
|
if total_size > self.max_size_bytes:
|
|
logger.warning(f"⚠️ Stockage saturé ({total_size/1e9:.2f} GB). Purge nécessaire.")
|
|
# Trier par date de modif (plus ancien d'abord)
|
|
sessions.sort(key=lambda x: x[1])
|
|
for path, _, size in sessions:
|
|
if total_size <= self.max_size_bytes * 0.8: # On libère jusqu'à 80% du max
|
|
break
|
|
logger.info(f"🗑️ Purge session pour libérer de l'espace : {path.name} ({size/1e6:.1f} MB)")
|
|
shutil.rmtree(path)
|
|
total_size -= size
|