Dictée vocale 100% locale pour macOS (MLX-Whisper + cercle pulsant)
Go to file
Ralph Mayola 68e1f336c8 Le peripherique audio ne peut plus geler l'interface
Le halo s'est fige une seconde fois, bloque sur « Je vous ecoute… », forme d'onde
plate, process a 0 % CPU. Une autre application (Loom) tenait le micro : le
stream.stop() de PortAudio s'est bloque. Or toggle() s'executait sur le thread
principal Cocoa — toute l'interface a gele avec lui.

Et le garde-fou pose le matin meme etait inoperant PAR CONSTRUCTION : c'est un
NSTimer, il vit sur la boucle d'evenements que le blocage venait justement d'arreter.
Un garde-fou qui depend de ce qu'il est cense sauver ne sauve rien.

Desormais, le chemin appele depuis le thread principal ne touche PLUS JAMAIS au
peripherique : ouverture et fermeture du flux partent en tache de fond, le thread
principal ne fait que changer l'etat et rafraichir l'overlay. Deux tests verrouillent
la regle avec un recorder qui leve si on l'appelle depuis le mauvais endroit.

S'ajoute une garde COURTE (20 s) armee des l'arret : passe ce point il ne reste que
la transcription, quelques secondes ; laisser 210 s de halo, c'est « fige » pour
l'utilisateur meme si le code finit par se rattraper.

Prouve en reproduisant la panne — un stop() qui ne rend jamais la main : l'interface
continue de battre (6, 12, 24 battements) et le halo se ferme seul. Avant, le
compteur serait reste fige.

69 tests passent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 12:14:47 +02:00
assets Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant) 2026-06-12 23:57:59 +02:00
launcher fix: icône barre de menu sur Tahoe — stub libpython + abandon de rumps 2026-06-13 00:54:44 +02:00
tests Le peripherique audio ne peut plus geler l'interface 2026-08-21 12:14:47 +02:00
.gitignore Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant) 2026-06-12 23:57:59 +02:00
app.py Zonza ne se lance plus qu'une fois a la fois 2026-08-21 00:25:05 +02:00
audio_level.py L'overlay devient une barre de dictee au lieu d'un cercle 2026-08-21 00:46:56 +02:00
build_app.sh fix: icône barre de menu sur Tahoe — stub libpython + abandon de rumps 2026-06-13 00:54:44 +02:00
conftest.py Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant) 2026-06-12 23:57:59 +02:00
controller.py Le peripherique audio ne peut plus geler l'interface 2026-08-21 12:14:47 +02:00
core.py Le peripherique audio ne peut plus geler l'interface 2026-08-21 12:14:47 +02:00
engine.py Attend le relachement des touches avant de coller 2026-08-21 01:42:44 +02:00
LICENSE Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant) 2026-06-12 23:57:59 +02:00
pulse_window.py Le peripherique audio ne peut plus geler l'interface 2026-08-21 12:14:47 +02:00
README.md Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant) 2026-06-12 23:57:59 +02:00
requirements.txt fix: icône barre de menu sur Tahoe — stub libpython + abandon de rumps 2026-06-13 00:54:44 +02:00

Zonza 🎙️

Dictée vocale 100% locale pour macOS (Apple Silicon). Appuie sur un raccourci, un cercle pulse au rythme de ta voix, et ton texte est transcrit puis collé dans l'app active. Inspiré de Superwhisper — open source, hors-ligne, rien ne quitte ta machine.

  • Transcription locale : MLX-Whisper medium (français), aucun envoi réseau.
  • Cercle pulsant : une fenêtre flottante visualise tes intonations en temps réel.
  • Barre de menu : l'app vit dans la barre de menu macOS (jamais dans le Dock).
  • Toggle Cmd+Ctrl+D : démarre / arrête la dictée.

Installation

git clone ssh://git@git.mrtechlab.cloud:2222/rmayola/zonza.git
cd zonza
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
./build_app.sh        # installe /Applications/Zonza.app (lanceur lié à ce dépôt)

Zonza.app est un lanceur léger : il exécute le code via le venv du dépôt (MLX y tourne nativement, là où py2app/PyInstaller échouent sur les shaders Metal). Ne supprime donc ni le dossier du dépôt ni .venv. C'est aussi l'unique chemin de build — on ne construit jamais dans /tmp ni dans le dépôt, pour ne laisser aucune entrée fantôme dans LaunchServices (cause historique d'icônes en double).

Au tout premier lancement, l'app télécharge le modèle Whisper (~512 Mo, une seule fois).

Permissions macOS

Réglages Système → Confidentialité et sécurité :

  • Microphone — popup automatique au 1er enregistrement.
  • Surveillance de l'entrée / Accessibilité — pour la hotkey globale et le collage (Cmd+V simulé). Si non accordée, le texte reste dans le presse-papier : fais Cmd+V à la main.

Usage

  • L'icône 🎙️ apparaît dans la barre de menu (🔴 enregistrement, transcription).
  • Cmd+Ctrl+D : le cercle apparaît, parle.
  • Cmd+Ctrl+D : transcription + collage dans l'app active.
  • Menu : activer/désactiver les sons, quitter.
  • Sécurité : arrêt automatique après 2 minutes d'enregistrement.

Lancer depuis les sources (développement)

source .venv/bin/activate
python3 app.py

Configuration

Édite CONFIG dans core.py : model, language, hotkey, sounds, min_duration_s, max_duration_s, fps, circle_base_radius, circle_amplitude, circle_color_rgb, level_gain, level_attack, level_release, wave_rings, wave_speed.

Tests

.venv/bin/python -m pytest tests/ -v

Architecture

  • core.py — config + utilitaires purs (seuil durée, nettoyage texte).
  • audio_level.py — niveau RMS du micro (alimente l'animation).
  • engine.py — capture, transcription MLX-Whisper, collage, sons.
  • pulse_window.py — fenêtre Cocoa + cercle pulsant + anneaux d'onde.
  • controller.py — machine à états, branche audio → animation → transcription.
  • app.py — app de barre de menu (point d'entrée).

L'icône de l'app est générée par script : python assets/make_icon.py && ./assets/make_icns.sh.

Licence

MIT — voir LICENSE.