"""Les trois frontières de Zonza. Chaque contrat est délibérément minuscule : ce sont les seuls points par lesquels le noyau parle au monde extérieur. Tout ce qui dépend d'un système d'exploitation, d'une bibliothèque d'affichage ou d'un moteur de transcription vit DERRIÈRE l'un d'eux — jamais dans `core.py`, `controller.py` ni `audio_level.py`. """ from typing import Protocol class Transcripteur(Protocol): """Transforme un signal audio en texte.""" def warmup(self) -> None: """Charge le modèle une fois, pour que la première dictée ne traîne pas.""" def transcrire(self, audio) -> str: """Rend le texte d'un tableau numpy float32 mono.""" class Overlay(Protocol): """La fenêtre flottante affichée pendant la dictée.""" def show(self) -> None: """Affiche la fenêtre et démarre l'animation. Thread principal.""" def hide(self) -> None: """Masque la fenêtre et arrête l'animation. Thread principal.""" def set_level(self, level: float) -> None: """Pousse un niveau audio dans [0, 1]. Appelable depuis un thread de fond.""" def set_status(self, text: str) -> None: """Texte affiché dans la bulle. Appelable depuis un thread de fond.""" def rearmer_garde(self, duree_s: float) -> None: """Remplace la durée de vie maximale de la fenêtre. Thread principal.""" class Systeme(Protocol): """Les appels qui diffèrent d'un système d'exploitation à l'autre.""" def jouer_son(self, nom: str) -> None: """Joue « start », « done » ou « error » sans bloquer.""" def modificateurs_enfonces(self) -> bool: """True si une touche modificatrice est physiquement enfoncée.""" def raccourci_defaut(self) -> str: """Raccourci global au format pynput, propre à la plateforme.""" def chemin_log(self) -> str: """Chemin absolu du journal.""" def dossier_donnees(self) -> str: """Dossier des données de l'application (verrou d'instance, réglages).""" def acquerir_verrou_instance(self, chemin: str): """Verrou exclusif non bloquant ; rend le fichier, ou None s'il est pris."""