Initial commit
This commit is contained in:
696
geniusia2/core/suggestion_manager.py
Normal file
696
geniusia2/core/suggestion_manager.py
Normal file
@@ -0,0 +1,696 @@
|
||||
"""
|
||||
Gestionnaire de suggestions pour le Mode Assisté.
|
||||
Gère les suggestions en temps réel, les scores de confiance et les timeouts.
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any, Optional, Callable, List
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Lock
|
||||
|
||||
from .learning_manager import LearningManager
|
||||
from .embeddings_manager import EmbeddingsManager
|
||||
from .logger import Logger
|
||||
from .workflow_matcher import WorkflowMatcher, WorkflowMatch
|
||||
|
||||
|
||||
class SuggestionManager:
|
||||
"""
|
||||
Gestionnaire de suggestions pour le Mode Assisté.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
learning_manager: LearningManager,
|
||||
embeddings_manager: EmbeddingsManager,
|
||||
logger: Logger,
|
||||
config: Dict[str, Any],
|
||||
workflow_matcher: Optional[WorkflowMatcher] = None
|
||||
):
|
||||
"""
|
||||
Initialise le gestionnaire de suggestions.
|
||||
|
||||
Args:
|
||||
learning_manager: Gestionnaire d'apprentissage
|
||||
embeddings_manager: Gestionnaire d'embeddings
|
||||
logger: Logger
|
||||
config: Configuration
|
||||
workflow_matcher: Matcher de workflows (optionnel)
|
||||
"""
|
||||
self.learning_manager = learning_manager
|
||||
self.embeddings_manager = embeddings_manager
|
||||
self.logger = logger
|
||||
self.config = config
|
||||
|
||||
# WorkflowMatcher pour la détection de workflows
|
||||
self.workflow_matcher = workflow_matcher or WorkflowMatcher(logger, config)
|
||||
|
||||
# Configuration
|
||||
self.similarity_threshold = config.get("assist", {}).get(
|
||||
"similarity_threshold", 0.75
|
||||
)
|
||||
self.suggestion_timeout = config.get("assist", {}).get(
|
||||
"suggestion_timeout", 10.0 # secondes
|
||||
)
|
||||
self.workflow_confidence_threshold = config.get("workflow", {}).get(
|
||||
"min_confidence", 0.80 # 80% par défaut
|
||||
)
|
||||
|
||||
# État actuel
|
||||
self.current_suggestion: Optional[Dict[str, Any]] = None
|
||||
self.suggestion_lock = Lock()
|
||||
self.suggestion_start_time: Optional[datetime] = None
|
||||
|
||||
# Tracking des rejets par workflow
|
||||
self.workflow_rejections: Dict[str, int] = {} # workflow_id -> count
|
||||
self.workflow_priority_adjustments: Dict[str, float] = {} # workflow_id -> multiplier
|
||||
|
||||
# Callbacks
|
||||
self.on_suggestion_created: Optional[Callable] = None
|
||||
self.on_suggestion_accepted: Optional[Callable] = None
|
||||
self.on_suggestion_rejected: Optional[Callable] = None
|
||||
self.on_suggestion_timeout: Optional[Callable] = None
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_manager_initialized",
|
||||
"similarity_threshold": self.similarity_threshold,
|
||||
"timeout": self.suggestion_timeout,
|
||||
"workflow_confidence_threshold": self.workflow_confidence_threshold
|
||||
})
|
||||
|
||||
def find_suggestion(self, context: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Recherche une suggestion basée sur le contexte actuel.
|
||||
|
||||
Args:
|
||||
context: Contexte actuel (embedding, fenêtre, etc.)
|
||||
|
||||
Returns:
|
||||
Suggestion ou None
|
||||
"""
|
||||
# D'abord, vérifier s'il y a un workflow en cours
|
||||
workflow_suggestion = self._check_workflow_suggestion(context)
|
||||
if workflow_suggestion:
|
||||
return workflow_suggestion
|
||||
|
||||
# Sinon, recherche classique par embedding
|
||||
embedding = context.get("embedding")
|
||||
|
||||
if embedding is None:
|
||||
return None
|
||||
|
||||
# Rechercher dans FAISS
|
||||
results = self.embeddings_manager.search_similar(embedding, k=3)
|
||||
|
||||
if not results:
|
||||
return None
|
||||
|
||||
# Filtrer par seuil de similarité
|
||||
best_match = results[0]
|
||||
|
||||
if best_match["similarity"] < self.similarity_threshold:
|
||||
return None
|
||||
|
||||
# Récupérer les métadonnées
|
||||
metadata = best_match["metadata"]
|
||||
task_id = metadata.get("task_id")
|
||||
|
||||
if not task_id:
|
||||
return None
|
||||
|
||||
# Charger la tâche
|
||||
task = self.learning_manager.load_task(task_id)
|
||||
|
||||
if not task:
|
||||
return None
|
||||
|
||||
# Créer la suggestion
|
||||
suggestion = {
|
||||
"type": "action", # Type de suggestion
|
||||
"task_id": task_id,
|
||||
"task_name": task.task_name,
|
||||
"action_type": metadata.get("action_type", "unknown"),
|
||||
"description": metadata.get("description", ""),
|
||||
"similarity": best_match["similarity"],
|
||||
"confidence": self._calculate_confidence(best_match, task),
|
||||
"metadata": metadata,
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_found",
|
||||
"task_id": task_id,
|
||||
"similarity": best_match["similarity"],
|
||||
"confidence": suggestion["confidence"]
|
||||
})
|
||||
|
||||
return suggestion
|
||||
|
||||
def _check_workflow_suggestion(self, context: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Vérifie s'il y a un workflow en cours qui correspond au contexte.
|
||||
|
||||
Args:
|
||||
context: Contexte actuel
|
||||
|
||||
Returns:
|
||||
Suggestion de workflow ou None
|
||||
"""
|
||||
# Récupérer l'event_capture depuis le contexte
|
||||
event_capture = context.get("event_capture")
|
||||
if not event_capture:
|
||||
return None
|
||||
|
||||
# Récupérer les workflows détectés
|
||||
workflows = event_capture.get_workflows()
|
||||
if not workflows:
|
||||
return None
|
||||
|
||||
# Récupérer la session courante
|
||||
current_session = event_capture.session_manager.current_session
|
||||
if not current_session or not current_session.actions:
|
||||
return None
|
||||
|
||||
# Comparer avec les workflows connus
|
||||
for workflow in workflows:
|
||||
# Vérifier si on est au début d'un workflow
|
||||
match_score = self._match_workflow_start(current_session.actions, workflow)
|
||||
|
||||
if match_score >= 0.8: # 80% de correspondance
|
||||
# Calculer quelle est la prochaine étape
|
||||
next_step_index = len(current_session.actions)
|
||||
|
||||
if next_step_index < len(workflow.steps):
|
||||
next_step = workflow.steps[next_step_index]
|
||||
|
||||
# Créer une suggestion de workflow
|
||||
suggestion = {
|
||||
"type": "workflow", # Type workflow
|
||||
"workflow_id": workflow.workflow_id,
|
||||
"workflow_name": workflow.name,
|
||||
"current_step": next_step_index,
|
||||
"total_steps": len(workflow.steps),
|
||||
"next_action": {
|
||||
"action_type": next_step.action_type,
|
||||
"description": next_step.target_description,
|
||||
"position": next_step.position
|
||||
},
|
||||
"remaining_steps": len(workflow.steps) - next_step_index,
|
||||
"confidence": workflow.confidence * match_score,
|
||||
"repetitions": workflow.repetitions,
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "workflow_suggestion_found",
|
||||
"workflow_id": workflow.workflow_id,
|
||||
"step": next_step_index,
|
||||
"confidence": suggestion["confidence"]
|
||||
})
|
||||
|
||||
return suggestion
|
||||
|
||||
return None
|
||||
|
||||
def _match_workflow_start(self, current_actions: list, workflow) -> float:
|
||||
"""
|
||||
Calcule le score de correspondance entre les actions courantes et le début d'un workflow.
|
||||
|
||||
Args:
|
||||
current_actions: Actions de la session courante
|
||||
workflow: Workflow à comparer
|
||||
|
||||
Returns:
|
||||
Score de correspondance (0-1)
|
||||
"""
|
||||
if not current_actions or not workflow.steps:
|
||||
return 0.0
|
||||
|
||||
# Comparer les N premières actions
|
||||
n = min(len(current_actions), len(workflow.steps))
|
||||
matches = 0
|
||||
|
||||
for i in range(n):
|
||||
action = current_actions[i]
|
||||
step = workflow.steps[i]
|
||||
|
||||
# Comparer le type d'action
|
||||
if action.get("action_type") == step.action_type:
|
||||
matches += 1
|
||||
|
||||
# Bonus si même fenêtre
|
||||
if action.get("window") == step.window:
|
||||
matches += 0.5
|
||||
|
||||
# Score normalisé
|
||||
max_score = n * 1.5 # 1 pour le type + 0.5 pour la fenêtre
|
||||
return matches / max_score if max_score > 0 else 0.0
|
||||
|
||||
def _calculate_confidence(
|
||||
self,
|
||||
match: Dict[str, Any],
|
||||
task: Any
|
||||
) -> float:
|
||||
"""
|
||||
Calcule le score de confiance pour une suggestion.
|
||||
|
||||
Args:
|
||||
match: Résultat de recherche FAISS
|
||||
task: Profil de tâche
|
||||
|
||||
Returns:
|
||||
Score de confiance (0-1)
|
||||
"""
|
||||
# Similarité visuelle
|
||||
vision_score = match["similarity"]
|
||||
|
||||
# Performance historique
|
||||
historical_score = task.concordance_rate if hasattr(task, "concordance_rate") else 0.5
|
||||
|
||||
# Formule : 70% vision + 30% historique
|
||||
confidence = 0.7 * vision_score + 0.3 * historical_score
|
||||
|
||||
return max(0.0, min(1.0, confidence))
|
||||
|
||||
def create_suggestion(self, context: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Crée une nouvelle suggestion si applicable.
|
||||
|
||||
Args:
|
||||
context: Contexte actuel
|
||||
|
||||
Returns:
|
||||
True si suggestion créée
|
||||
"""
|
||||
with self.suggestion_lock:
|
||||
# Vérifier qu'il n'y a pas déjà une suggestion active
|
||||
if self.current_suggestion is not None:
|
||||
return False
|
||||
|
||||
# Rechercher une suggestion
|
||||
suggestion = self.find_suggestion(context)
|
||||
|
||||
if suggestion is None:
|
||||
return False
|
||||
|
||||
# Vérifier le seuil de confiance
|
||||
if suggestion["confidence"] < self.similarity_threshold:
|
||||
return False
|
||||
|
||||
# Créer la suggestion
|
||||
self.current_suggestion = suggestion
|
||||
self.suggestion_start_time = datetime.now()
|
||||
|
||||
# Callback
|
||||
if self.on_suggestion_created:
|
||||
self.on_suggestion_created(suggestion)
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_created",
|
||||
"task_id": suggestion["task_id"],
|
||||
"confidence": suggestion["confidence"]
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
def accept_suggestion(self) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Accepte la suggestion actuelle.
|
||||
|
||||
Returns:
|
||||
Suggestion acceptée ou None
|
||||
"""
|
||||
with self.suggestion_lock:
|
||||
if self.current_suggestion is None:
|
||||
return None
|
||||
|
||||
suggestion = self.current_suggestion
|
||||
self.current_suggestion = None
|
||||
self.suggestion_start_time = None
|
||||
|
||||
# Si c'est une suggestion de workflow, tracker l'acceptation
|
||||
if suggestion.get("type") == "workflow":
|
||||
workflow_id = suggestion.get("workflow_id")
|
||||
if workflow_id:
|
||||
self._track_workflow_acceptance(workflow_id)
|
||||
|
||||
# Mettre à jour les statistiques (pour les suggestions d'action)
|
||||
if suggestion.get("task_id"):
|
||||
self.learning_manager.confirm_action({
|
||||
"type": "accept",
|
||||
"task_id": suggestion["task_id"]
|
||||
})
|
||||
|
||||
# Callback
|
||||
if self.on_suggestion_accepted:
|
||||
self.on_suggestion_accepted(suggestion)
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_accepted",
|
||||
"suggestion_type": suggestion.get("type"),
|
||||
"workflow_id": suggestion.get("workflow_id"),
|
||||
"task_id": suggestion.get("task_id")
|
||||
})
|
||||
|
||||
return suggestion
|
||||
|
||||
def reject_suggestion(self) -> bool:
|
||||
"""
|
||||
Rejette la suggestion actuelle.
|
||||
|
||||
Returns:
|
||||
True si suggestion rejetée
|
||||
"""
|
||||
with self.suggestion_lock:
|
||||
if self.current_suggestion is None:
|
||||
return False
|
||||
|
||||
suggestion = self.current_suggestion
|
||||
self.current_suggestion = None
|
||||
self.suggestion_start_time = None
|
||||
|
||||
# Si c'est une suggestion de workflow, tracker le rejet
|
||||
if suggestion.get("type") == "workflow":
|
||||
workflow_id = suggestion.get("workflow_id")
|
||||
if workflow_id:
|
||||
self._track_workflow_rejection(workflow_id)
|
||||
|
||||
# Mettre à jour les statistiques (pour les suggestions d'action)
|
||||
if suggestion.get("task_id"):
|
||||
self.learning_manager.confirm_action({
|
||||
"type": "reject",
|
||||
"task_id": suggestion["task_id"]
|
||||
})
|
||||
|
||||
# Callback
|
||||
if self.on_suggestion_rejected:
|
||||
self.on_suggestion_rejected(suggestion)
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_rejected",
|
||||
"suggestion_type": suggestion.get("type"),
|
||||
"workflow_id": suggestion.get("workflow_id"),
|
||||
"task_id": suggestion.get("task_id")
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
def check_timeout(self) -> bool:
|
||||
"""
|
||||
Vérifie si la suggestion actuelle a expiré.
|
||||
|
||||
Returns:
|
||||
True si timeout
|
||||
"""
|
||||
with self.suggestion_lock:
|
||||
if self.current_suggestion is None:
|
||||
return False
|
||||
|
||||
if self.suggestion_start_time is None:
|
||||
return False
|
||||
|
||||
elapsed = (datetime.now() - self.suggestion_start_time).total_seconds()
|
||||
|
||||
if elapsed >= self.suggestion_timeout:
|
||||
# Timeout
|
||||
suggestion = self.current_suggestion
|
||||
self.current_suggestion = None
|
||||
self.suggestion_start_time = None
|
||||
|
||||
# Callback
|
||||
if self.on_suggestion_timeout:
|
||||
self.on_suggestion_timeout(suggestion)
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "suggestion_timeout",
|
||||
"task_id": suggestion["task_id"],
|
||||
"elapsed": elapsed
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_current_suggestion(self) -> Optional[Dict[str, Any]]:
|
||||
"""Retourne la suggestion actuelle."""
|
||||
with self.suggestion_lock:
|
||||
return self.current_suggestion
|
||||
|
||||
def clear_suggestion(self):
|
||||
"""Efface la suggestion actuelle."""
|
||||
with self.suggestion_lock:
|
||||
self.current_suggestion = None
|
||||
self.suggestion_start_time = None
|
||||
|
||||
def get_stats(self) -> Dict[str, Any]:
|
||||
"""Retourne les statistiques du gestionnaire."""
|
||||
return {
|
||||
"has_active_suggestion": self.current_suggestion is not None,
|
||||
"similarity_threshold": self.similarity_threshold,
|
||||
"timeout": self.suggestion_timeout,
|
||||
"workflow_rejections": len(self.workflow_rejections),
|
||||
"workflows_with_adjusted_priority": len(self.workflow_priority_adjustments)
|
||||
}
|
||||
|
||||
def check_workflow_match(
|
||||
self,
|
||||
session_actions: List[Dict[str, Any]],
|
||||
workflows: List[Dict[str, Any]]
|
||||
) -> Optional[WorkflowMatch]:
|
||||
"""
|
||||
Vérifie périodiquement si les actions courantes correspondent à un workflow connu.
|
||||
|
||||
Cette méthode doit être appelée régulièrement (ex: toutes les 2s) en mode Assist
|
||||
pour détecter les correspondances de workflows.
|
||||
|
||||
Args:
|
||||
session_actions: Liste des actions de la session courante
|
||||
workflows: Liste des workflows connus
|
||||
|
||||
Returns:
|
||||
Meilleure correspondance si trouvée, None sinon
|
||||
"""
|
||||
if not session_actions or not workflows:
|
||||
return None
|
||||
|
||||
# Vérifier qu'il n'y a pas déjà une suggestion active
|
||||
with self.suggestion_lock:
|
||||
if self.current_suggestion is not None:
|
||||
return None
|
||||
|
||||
# Utiliser le WorkflowMatcher pour trouver les correspondances
|
||||
matches = self.workflow_matcher.match_current_session(
|
||||
session_actions,
|
||||
workflows
|
||||
)
|
||||
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
# Appliquer les ajustements de priorité basés sur les rejets
|
||||
adjusted_matches = []
|
||||
for match in matches:
|
||||
adjusted_confidence = self._apply_priority_adjustment(match)
|
||||
|
||||
# Créer un nouveau match avec la confiance ajustée
|
||||
adjusted_match = WorkflowMatch(
|
||||
workflow_id=match.workflow_id,
|
||||
workflow_name=match.workflow_name,
|
||||
confidence=adjusted_confidence,
|
||||
matched_steps=match.matched_steps,
|
||||
total_steps=match.total_steps,
|
||||
remaining_steps=match.remaining_steps,
|
||||
current_step_index=match.current_step_index
|
||||
)
|
||||
adjusted_matches.append(adjusted_match)
|
||||
|
||||
# Trier à nouveau par confiance ajustée
|
||||
adjusted_matches.sort(key=lambda m: m.confidence, reverse=True)
|
||||
|
||||
# Trouver le meilleur match
|
||||
best_match = self.workflow_matcher.find_best_match(adjusted_matches)
|
||||
|
||||
if best_match:
|
||||
self.logger.log_action({
|
||||
"action": "workflow_match_found",
|
||||
"workflow_id": best_match.workflow_id,
|
||||
"workflow_name": best_match.workflow_name,
|
||||
"confidence": best_match.confidence,
|
||||
"matched_steps": best_match.matched_steps,
|
||||
"remaining_steps": len(best_match.remaining_steps)
|
||||
})
|
||||
|
||||
return best_match
|
||||
|
||||
def create_workflow_suggestion(
|
||||
self,
|
||||
workflow_match: WorkflowMatch
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Crée une suggestion de workflow avec les détails des étapes restantes.
|
||||
|
||||
Args:
|
||||
workflow_match: Correspondance de workflow trouvée
|
||||
|
||||
Returns:
|
||||
Suggestion créée ou None si impossible
|
||||
"""
|
||||
with self.suggestion_lock:
|
||||
# Vérifier qu'il n'y a pas déjà une suggestion active
|
||||
if self.current_suggestion is not None:
|
||||
return None
|
||||
|
||||
# Vérifier le seuil de confiance
|
||||
if workflow_match.confidence < self.workflow_confidence_threshold:
|
||||
self.logger.log_action({
|
||||
"action": "workflow_suggestion_rejected_low_confidence",
|
||||
"workflow_id": workflow_match.workflow_id,
|
||||
"confidence": workflow_match.confidence,
|
||||
"threshold": self.workflow_confidence_threshold
|
||||
})
|
||||
return None
|
||||
|
||||
# Créer la suggestion avec les détails des étapes
|
||||
suggestion = {
|
||||
"type": "workflow",
|
||||
"workflow_id": workflow_match.workflow_id,
|
||||
"workflow_name": workflow_match.workflow_name,
|
||||
"confidence": workflow_match.confidence,
|
||||
"current_step": workflow_match.current_step_index,
|
||||
"total_steps": workflow_match.total_steps,
|
||||
"matched_steps": workflow_match.matched_steps,
|
||||
"remaining_steps": workflow_match.remaining_steps,
|
||||
"next_steps_preview": workflow_match.remaining_steps[:3], # 3 prochaines étapes
|
||||
"created_at": datetime.now(),
|
||||
"timeout": self.suggestion_timeout
|
||||
}
|
||||
|
||||
# Enregistrer la suggestion
|
||||
self.current_suggestion = suggestion
|
||||
self.suggestion_start_time = datetime.now()
|
||||
|
||||
# Callback
|
||||
if self.on_suggestion_created:
|
||||
self.on_suggestion_created(suggestion)
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "workflow_suggestion_created",
|
||||
"workflow_id": workflow_match.workflow_id,
|
||||
"workflow_name": workflow_match.workflow_name,
|
||||
"confidence": workflow_match.confidence,
|
||||
"remaining_steps": len(workflow_match.remaining_steps)
|
||||
})
|
||||
|
||||
return suggestion
|
||||
|
||||
def _apply_priority_adjustment(self, match: WorkflowMatch) -> float:
|
||||
"""
|
||||
Applique l'ajustement de priorité basé sur les rejets précédents.
|
||||
|
||||
Args:
|
||||
match: Correspondance de workflow
|
||||
|
||||
Returns:
|
||||
Confiance ajustée
|
||||
"""
|
||||
workflow_id = match.workflow_id
|
||||
|
||||
# Récupérer le multiplicateur d'ajustement
|
||||
adjustment = self.workflow_priority_adjustments.get(workflow_id, 1.0)
|
||||
|
||||
# Appliquer l'ajustement
|
||||
adjusted_confidence = match.confidence * adjustment
|
||||
|
||||
# S'assurer que la confiance reste dans [0, 1]
|
||||
adjusted_confidence = max(0.0, min(1.0, adjusted_confidence))
|
||||
|
||||
if adjustment != 1.0:
|
||||
self.logger.log_action({
|
||||
"action": "priority_adjustment_applied",
|
||||
"workflow_id": workflow_id,
|
||||
"original_confidence": match.confidence,
|
||||
"adjusted_confidence": adjusted_confidence,
|
||||
"adjustment_multiplier": adjustment
|
||||
})
|
||||
|
||||
return adjusted_confidence
|
||||
|
||||
def _track_workflow_rejection(self, workflow_id: str):
|
||||
"""
|
||||
Enregistre un rejet de workflow et ajuste la priorité si nécessaire.
|
||||
|
||||
Après 3 rejets, la priorité du workflow est réduite (confiance * 0.9).
|
||||
|
||||
Args:
|
||||
workflow_id: ID du workflow rejeté
|
||||
"""
|
||||
# Incrémenter le compteur de rejets
|
||||
current_rejections = self.workflow_rejections.get(workflow_id, 0)
|
||||
current_rejections += 1
|
||||
self.workflow_rejections[workflow_id] = current_rejections
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "workflow_rejection_tracked",
|
||||
"workflow_id": workflow_id,
|
||||
"total_rejections": current_rejections
|
||||
})
|
||||
|
||||
# Après 3 rejets, ajuster la priorité
|
||||
if current_rejections >= 3:
|
||||
# Réduire la confiance de 10% à chaque tranche de 3 rejets
|
||||
adjustment_factor = 0.9 ** (current_rejections // 3)
|
||||
self.workflow_priority_adjustments[workflow_id] = adjustment_factor
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "workflow_priority_adjusted",
|
||||
"workflow_id": workflow_id,
|
||||
"rejections": current_rejections,
|
||||
"new_adjustment_factor": adjustment_factor
|
||||
})
|
||||
|
||||
def _track_workflow_acceptance(self, workflow_id: str):
|
||||
"""
|
||||
Enregistre une acceptation de workflow et améliore la priorité.
|
||||
|
||||
Args:
|
||||
workflow_id: ID du workflow accepté
|
||||
"""
|
||||
# Réduire le compteur de rejets (récompenser les acceptations)
|
||||
current_rejections = self.workflow_rejections.get(workflow_id, 0)
|
||||
if current_rejections > 0:
|
||||
current_rejections = max(0, current_rejections - 2) # Réduire de 2
|
||||
self.workflow_rejections[workflow_id] = current_rejections
|
||||
|
||||
# Recalculer l'ajustement de priorité
|
||||
if current_rejections >= 3:
|
||||
adjustment_factor = 0.9 ** (current_rejections // 3)
|
||||
self.workflow_priority_adjustments[workflow_id] = adjustment_factor
|
||||
else:
|
||||
# Retirer l'ajustement si moins de 3 rejets
|
||||
if workflow_id in self.workflow_priority_adjustments:
|
||||
del self.workflow_priority_adjustments[workflow_id]
|
||||
|
||||
self.logger.log_action({
|
||||
"action": "workflow_acceptance_tracked",
|
||||
"workflow_id": workflow_id,
|
||||
"remaining_rejections": current_rejections
|
||||
})
|
||||
|
||||
def on_workflow_detected(self, workflow: Dict[str, Any]):
|
||||
"""
|
||||
Callback appelé quand un workflow est détecté.
|
||||
Peut créer une suggestion immédiate si le workflow est pertinent.
|
||||
|
||||
Args:
|
||||
workflow: Workflow détecté
|
||||
"""
|
||||
self.logger.log_action({
|
||||
"action": "workflow_detected_in_suggestion_manager",
|
||||
"workflow_id": workflow.get("workflow_id"),
|
||||
"workflow_name": workflow.get("name"),
|
||||
"confidence": workflow.get("confidence")
|
||||
})
|
||||
|
||||
# Pour l'instant, on log seulement
|
||||
# Dans le futur, on pourrait créer une suggestion proactive
|
||||
# basée sur le workflow détecté
|
||||
Reference in New Issue
Block a user