"""Affiche une commande proposee par l'assistant IA : jamais executee automatiquement, seulement copiable ou inseree dans le terminal (sans Entree) apres verification par l'utilisateur.""" from __future__ import annotations import re from PySide6.QtWidgets import ( QApplication, QDialog, QHBoxLayout, QLabel, QPushButton, QTextEdit, QVBoxLayout, ) _CODE_BLOCK_RE = re.compile(r"```(?:[a-zA-Z0-9_+-]*\n)?(.*?)```", re.DOTALL) def extract_command(response: str) -> str: """Prend le contenu du premier bloc de code s'il y en a un (le prompt systeme en demande un), sinon la reponse entiere : mieux vaut proposer un texte un peu trop large que perdre silencieusement la commande.""" match = _CODE_BLOCK_RE.search(response) text = match.group(1) if match else response return text.strip() class AICommandDialog(QDialog): def __init__(self, response: str, dangerous_labels: list[str] | None = None, parent=None): super().__init__(parent) self.setWindowTitle("Commande generee par l'assistant IA") self.setMinimumSize(520, 360) self.command = extract_command(response) self.insert_requested = False layout = QVBoxLayout(self) if dangerous_labels: warning = QLabel( "⚠ Commande potentiellement destructive : " + ", ".join(dangerous_labels) ) warning.setWordWrap(True) warning.setStyleSheet("color: #c0392b; font-weight: bold;") layout.addWidget(warning) layout.addWidget(QLabel("Reponse complete de l'assistant :")) self.response_view = QTextEdit(response) self.response_view.setReadOnly(True) layout.addWidget(self.response_view, 1) layout.addWidget(QLabel("Commande proposee (celle qui sera copiee/inseree) :")) self.command_view = QTextEdit(self.command) self.command_view.setFixedHeight(70) layout.addWidget(self.command_view) self.status_label = QLabel("Cette commande ne sera jamais executee automatiquement.") self.status_label.setObjectName("statusLabel") layout.addWidget(self.status_label) btn_row = QHBoxLayout() self.copy_btn = QPushButton("Copier") self.insert_btn = QPushButton("Inserer dans le terminal") self.cancel_btn = QPushButton("Annuler") for b in (self.copy_btn, self.insert_btn, self.cancel_btn): btn_row.addWidget(b) layout.addLayout(btn_row) self.copy_btn.clicked.connect(self._copy) self.insert_btn.clicked.connect(self._insert) self.cancel_btn.clicked.connect(self.reject) def _current_command(self) -> str: # l'utilisateur peut corriger la commande proposee avant de l'utiliser return self.command_view.toPlainText().strip() def _copy(self) -> None: QApplication.clipboard().setText(self._current_command()) self.status_label.setText("Copie dans le presse-papiers.") def _insert(self) -> None: self.command = self._current_command() self.insert_requested = True self.accept()