"""Execution des requetes IA en arriere-plan : aucun appel reseau ne doit jamais bloquer le thread Qt.""" from __future__ import annotations from PySide6.QtCore import QThread, Signal from app.ai.provider import AIError, AIProvider KIND_EXPLAIN = "explain" KIND_DIAGNOSE = "diagnose" KIND_SOLUTION = "solution" KIND_GENERATE = "generate" KIND_ASK = "ask" KIND_TEST = "test" class AIRequestWorker(QThread): """Une requete = un worker jetable. L'annulation est cooperative : la requete HTTP en cours (bornee par son timeout) va a son terme, mais le signal de resultat peut etre ignore par l'appelant (voir AIPanel).""" finished_ok = Signal(str) finished_error = Signal(str) def __init__(self, provider: AIProvider, kind: str, payload: str, context: str = "", parent=None): super().__init__(parent) self.provider = provider self.kind = kind self.payload = payload self.context = context def run(self) -> None: try: result = self._execute() self.finished_ok.emit(result) except AIError as exc: self.finished_error.emit(str(exc)) except Exception as exc: # noqa: BLE001 - ne jamais laisser un thread planter silencieusement self.finished_error.emit(f"Erreur inattendue : {exc}") def _execute(self) -> str: if self.kind == KIND_EXPLAIN: return self.provider.explain_output(self.payload) if self.kind == KIND_DIAGNOSE: return self.provider.diagnose(self.payload) if self.kind == KIND_SOLUTION: return self.provider.propose_solution(self.payload) if self.kind == KIND_GENERATE: return self.provider.generate_command(self.payload) if self.kind == KIND_ASK: return self.provider.ask(self.payload, context=self.context) if self.kind == KIND_TEST: return self.provider.chat([{"role": "user", "content": "Reponds uniquement 'OK'."}]) raise AIError(f"Type de requete IA inconnu : {self.kind}")