Architecture et modèle d'exécution

La session persistante et le client CLI, la socket de contrôle, l'adaptateur de backend Whisper et la cascade d'injection de texte.

Une session persistante, un client qui lui parle

whispskrid lancé sans argument de contrôle démarre une session persistante au premier plan : elle charge la configuration, charge le modèle Whisper une seule fois, ouvre le périphérique de capture, démarre l’écouteur de touche et la socket de contrôle, puis attend.

Appui sur la toucheCapture audioTranscription WhisperCascade d'injectionSocket de contrôle
Le chemin de la voix vers le texte : la capture démarre à l'appui, s'arrête à la relâche, et le tampon complet part en une seule passe à l'adaptateur de backend. La socket de contrôle n'est pas une étape de ce chemin — c'est le canal latéral qu'un raccourci de bureau emprunte pour piloter la session en cours.

Le modèle CTranslate2 met de l’ordre de la seconde à plusieurs secondes à charger selon sa taille et la machine. Le recharger à chaque dictée rendrait l’appui-pour-parler inutilisable : c’est la raison d’être du processus persistant.

whispskrid lancé avec un argument de contrôle (--dictate, --status, --stop…) agit en client : il se connecte à la socket de la session en cours, envoie une commande d’une ligne, imprime la réponse et sort avec un code de retour reflétant OK ou ERR. S’il n’y a pas de session, il le dit et sort en erreur.

Deux voies pour déclencher une dictée

Le même état interne de la session persistante est piloté par un écouteur de touche local et par la socket de contrôle.

  • Écouteur de raccourci local (pynput) — il observe le serveur X. pynput distingue l’appui de la relâche : la sémantique « je parle tant que je tiens » est donc native sur cette voie. Sous Wayland il ne capte que les fenêtres passant par XWayland, jamais une fenêtre Wayland native ; c’est un confort best-effort. Touche par défaut : Maj droit (shift_r), surchargeable par hotkeys.push_to_talk.
  • Sous-commandes CLI via la socket — voie universelle, indépendante du type de session. Un raccourci de bureau ne transmet pas « touche tenue / touche relâchée » : cette voie fonctionne donc en bascule. --dictate démarre la capture, --dictate-stop l’arrête et injecte, --toggle fait l’un ou l’autre selon l’état, --cancel jette la capture en cours sans injecter.

Une capture démarrée par la touche peut être annulée par --cancel, et inversement.

Garde-fou de durée

Seul garde-fou automatique : capture.max_seconds (défaut 300).

Si la touche reste tenue au-delà, la capture s’arrête d’elle-même, ce qui a été enregistré est transcrit et injecté normalement, et un avertissement est journalisé. Ce n’est pas un minuteur de confort — c’est une protection contre une touche bloquée ou un tampon audio qui gonfle sans fin. L’arrêt automatique sur silence (VAD) reste possible plus tard, en option ; la clé vad.enabled est réservée dans le schéma mais n’est pas implémentée en v1.0.1.

L’adaptateur de backend

Un module backend/ expose une interface étroite — load, transcribe(audio, langue), info — pour qu’un second moteur puisse être ajouté plus tard sans toucher au reste.

faster-whisper (CTranslate2) est la seule implémentation livrée en v1.0.1 ; la clé backend.name est réservée mais n’accepte que cette valeur. whisper.cpp est envisagé comme second backend, plus tard.

L’adaptateur instancie WhisperModel avec device (auto : CPU ou CUDA), compute_type (auto : int8 sur CPU, float16 sur CUDA) et download_root pointé sur le dossier de modèles géré. transcribe() est appelé avec beam_size (défaut 5), la langue forcée ou None, et sans filtre VAD ; il concatène les segments rendus et rogne le texte.

Gestion des modèles

Les modèles vivent dans un dossier géré — /usr/share/whispskrid/whisper-models/ et ~/.local/share/whispskrid/whisper-models/ pour une installation par paquet, whisper-models/ à la racine du dépôt pour une installation source.

La résolution d’un nom court (base) parcourt ces emplacements dans l’ordre. Le cache Hugging Face par défaut de faster-whisper n’est qu’un ultime repli : l’outil doit démarrer hors ligne une fois le modèle présent. whispskrid --download-model [NOM] télécharge le modèle demandé dans le dossier utilisateur, vérifie qu’il se charge, et sort ; le postinst du paquet propose ce téléchargement au premier lancement si aucun modèle n’est là.

Injection de texte : un collage par le presse-papiers, avec cascade de moteurs

Une fois le texte transcrit et post-traité, la couche d’injection le place dans le presse-papiers et simule un collage. Le moteur est choisi une seule fois au démarrage.

VoieOutilsCondition
Premierydotool + wl-clipboardFrappe au niveau du pilote (/dev/uinput) via le démon ydotoold ; codes de touches dépendants de la disposition du clavier ; appartenance au groupe input requise.
Secondxdotool + xclipVoie standard. La détection de la fenêtre (combinaison de collage pour terminal) n’existe que sur cette voie — ydotool n’a pas de notion de fenêtre ciblée.
Sinonmode dégradéAucune frappe envoyée ; le texte transcrit reste dans le terminal pour le reste de la session.

Le moteur de frappe a besoin d’un outil de presse-papiers à ses côtés : wl-clipboard sous Wayland — requis même sur le repli ydotool — et xclip sous X11. Le paquet Debian tire wl-clipboard et recommande xclip ; une installation depuis les sources les ajoute elle-même. Sans cela, le texte transcrit n’atteint jamais le presse-papiers et le collage réinsère le dernier contenu copié à la main.

Le contenu précédent du presse-papiers est relu puis restauré après le collage (réglable par clipboard.restore, actif par défaut). Un contenu non textuel — image, fichiers — est laissé intact. Sous Wayland avec une application GTK, la restauration peut devancer la lecture du presse-papiers par la fenêtre ; clipboard.defer_restore diffère la restauration à la fin de la session pour que le collage ne reprenne jamais l’ancien contenu.

Si aucun moteur adapté à la session courante ne fonctionne, l’outil ne plante pas et n’abandonne rien en silence : il passe en mode dégradé. Le texte transcrit continue de s’afficher dans le terminal et la frappe automatique est désactivée pour le reste de la session, plutôt que d’être retentée — sans succès — à chaque dictée. Quelques fenêtres refusent aussi le collage — certaines applications Java, des champs protégés ; à la première de ces situations, l’outil passe de la même façon en mode dégradé.

La socket de contrôle

Une session en cours ouvre une socket Unix privée à $XDG_RUNTIME_DIR/whispskrid.sock (mode 0600). La même commande appelée avec --dictate, --dictate-stop, --toggle, --cancel, --status ou --stop se connecte à cette socket au lieu de démarrer une seconde session.

C’est ce qui fait fonctionner les raccourcis de bureau partout sous Wayland, y compris pour les fenêtres Wayland natives que l’écouteur pynput ne voit jamais. Le protocole est en lignes de texte, une commande par ligne, réponse préfixée OK ou ERR ; une commande inconnue répond ERR unknown-command. Il n’y a pas de sleep / wake : WhispSkrid n’a pas d’état de veille.

Une seule session tourne par utilisateur à la fois ; une socket laissée par un plantage est détectée et remplacée au démarrage suivant.

Langue de l’interface et langue de dictée

Ce sont deux réglages distincts.

Langue de l'interface

Les chaînes de l’outil lui-même passent par la chaîne GNU gettext — catalogues .po compilés en .mo, extraits du source Python. Quatre langues : anglais, français, allemand, espagnol.

Langue de dictée

-l fr force la langue passée à Whisper pour cette session ; sans argument, default_language puis l’autodétection de Whisper. Aucune configuration par langue au-delà de ce choix.

Whisper ponctue et met les majuscules de phrase seul. Le post-traitement de WhispSkrid se limite au rognage des blancs de bord et à une capitale forcée sur la première lettre du texte injecté. Aucune table de substitution, aucune règle par langue.

Voir le dépôt du projet pour le code, et Guides pour démarrer.