"""Choisit le moteur de transcription d'après le matériel.""" import ctypes import platform import sys def nom_moteur_pour(plateforme, machine, cuda_disponible): """Décide du moteur. Fonction PURE : aucune interrogation de la machine ici, ce qui rend les quatre configurations testables depuis un seul poste.""" if plateforme.startswith("darwin") and machine in ("arm64", "aarch64"): return "mlx" return "faster-gpu" if cuda_disponible else "faster-cpu" def detecter_moteur(): """Interroge la machine, puis délègue la décision à `nom_moteur_pour`.""" return nom_moteur_pour(sys.platform, platform.machine(), _cuda_disponible()) # Le nom de la bibliothèque partagée CUDA diffère radicalement par plateforme ET # par version : `libcudart.so` (parfois suffixé `.12`, `.11.0`...) sous Linux/macOS, # mais `cudart64_12.dll`, `cudart64_110.dll`... sous Windows, où le numéro de version # est ENCODÉ DANS LE NOM du fichier. `ctypes.util.find_library` ne résout pas ces DLL # versionnées de façon fiable — il cherche un nom canonique qui n'existe pas pour # CUDA sous Windows. On essaie donc une liste explicite de noms candidats, du plus # récent au plus ancien, et on s'arrête au premier qui charge. _NOMS_CUDART_WINDOWS = [ "cudart64_12.dll", "cudart64_110.dll", "cudart64_101.dll", "cudart64_100.dll", ] _NOMS_CUDART_UNIX = [ "libcudart.so", "libcudart.so.12", "libcudart.so.11.0", ] def _cuda_disponible(plateforme=None, charger=None): """Sonde la présence du runtime CUDA en tentant de charger sa bibliothèque partagée. `plateforme` et `charger` sont injectables : ça rend la sonde testable avec une doublure, sans dépendre d'une vraie machine CUDA ni d'un vrai Windows. Ne lève jamais — dans le doute, on rend False.""" plateforme = plateforme if plateforme is not None else sys.platform charger = charger if charger is not None else ctypes.CDLL noms = _NOMS_CUDART_WINDOWS if plateforme.startswith("win") else _NOMS_CUDART_UNIX for nom in noms: try: charger(nom) return True except Exception: continue return False def choisir_transcripteur(nom, modele, langue, amorce): """Rend l'implémentation du contrat Transcripteur portant ce nom.""" if nom == "mlx": from moteur.mlx import TranscripteurMLX return TranscripteurMLX(modele, langue, amorce) raise NotImplementedError(f"Moteur non pris en charge à cette étape : {nom}")