Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant)
Reconstruction propre de l'ancien projet Dictée. Bundle id neuf (cloud.mrtechlab.zonza), chemin de build unique vers /Applications (plus jamais de builds /tmp enregistrés dans LaunchServices). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import numpy as np
|
||||
|
||||
from audio_level import compute_rms, shape_level
|
||||
|
||||
|
||||
def test_silence_is_zero():
|
||||
frames = np.zeros(1000, dtype="float32")
|
||||
assert compute_rms(frames) == 0.0
|
||||
|
||||
|
||||
def test_empty_is_zero():
|
||||
frames = np.zeros(0, dtype="float32")
|
||||
assert compute_rms(frames) == 0.0
|
||||
|
||||
|
||||
def test_full_scale_is_one():
|
||||
# signal constant à l'amplitude max → RMS normalisé proche de 1.0
|
||||
frames = np.ones(1000, dtype="float32")
|
||||
assert compute_rms(frames) == 1.0
|
||||
|
||||
|
||||
def test_result_is_bounded():
|
||||
# même un signal qui dépasse [-1, 1] reste borné à 1.0
|
||||
frames = np.full(1000, 5.0, dtype="float32")
|
||||
level = compute_rms(frames)
|
||||
assert 0.0 <= level <= 1.0
|
||||
|
||||
|
||||
def test_louder_gives_higher_level():
|
||||
quiet = np.full(1000, 0.1, dtype="float32")
|
||||
loud = np.full(1000, 0.5, dtype="float32")
|
||||
assert compute_rms(loud) > compute_rms(quiet)
|
||||
|
||||
|
||||
def test_shape_level_zero_stays_zero():
|
||||
assert shape_level(0.0, gain=8.0) == 0.0
|
||||
|
||||
|
||||
def test_shape_level_boosts_quiet_voice():
|
||||
# un RMS vocal typique (~0.05) doit devenir nettement perceptible après mise en forme
|
||||
shaped = shape_level(0.05, gain=8.0)
|
||||
assert shaped > 0.3
|
||||
|
||||
|
||||
def test_shape_level_is_bounded():
|
||||
# un niveau déjà fort reste borné à 1.0 (pas de débordement)
|
||||
assert shape_level(0.9, gain=8.0) == 1.0
|
||||
|
||||
|
||||
def test_shape_level_monotonic():
|
||||
assert shape_level(0.2, gain=8.0) > shape_level(0.05, gain=8.0)
|
||||
|
||||
|
||||
def test_shape_level_gain_zero_is_zero():
|
||||
# gain nul → aucune réaction
|
||||
assert shape_level(0.5, gain=0.0) == 0.0
|
||||
@@ -0,0 +1,61 @@
|
||||
from core import CONFIG, validate_config, is_long_enough, clean_transcript
|
||||
|
||||
|
||||
def test_config_has_required_keys():
|
||||
for key in ("model", "language", "hotkey", "sounds", "min_duration_s", "sample_rate"):
|
||||
assert key in CONFIG
|
||||
|
||||
|
||||
def test_config_defaults():
|
||||
assert CONFIG["language"] == "fr"
|
||||
assert CONFIG["min_duration_s"] == 0.3
|
||||
assert CONFIG["sample_rate"] == 16000
|
||||
|
||||
|
||||
def test_validate_config_accepts_default():
|
||||
validate_config(CONFIG) # ne doit pas lever
|
||||
|
||||
|
||||
def test_validate_config_rejects_bad_duration():
|
||||
import pytest
|
||||
bad = dict(CONFIG, min_duration_s=-1)
|
||||
with pytest.raises(ValueError):
|
||||
validate_config(bad)
|
||||
|
||||
|
||||
def test_is_long_enough_true():
|
||||
# 1 seconde d'audio à 16000 Hz = 16000 échantillons
|
||||
assert is_long_enough(16000, sample_rate=16000, min_duration_s=0.3) is True
|
||||
|
||||
|
||||
def test_is_long_enough_false_too_short():
|
||||
# 0.1 s = 1600 échantillons < seuil 0.3 s
|
||||
assert is_long_enough(1600, sample_rate=16000, min_duration_s=0.3) is False
|
||||
|
||||
|
||||
def test_is_long_enough_empty():
|
||||
assert is_long_enough(0, sample_rate=16000, min_duration_s=0.3) is False
|
||||
|
||||
|
||||
def test_clean_transcript_trims():
|
||||
assert clean_transcript(" bonjour ") == "bonjour"
|
||||
|
||||
|
||||
def test_clean_transcript_collapses_internal_whitespace():
|
||||
assert clean_transcript("crée moi un\noutil") == "crée moi un outil"
|
||||
|
||||
|
||||
def test_clean_transcript_empty_stays_empty():
|
||||
assert clean_transcript(" ") == ""
|
||||
|
||||
|
||||
def test_config_has_ui_keys():
|
||||
for key in ("fps", "circle_base_radius", "circle_amplitude", "circle_color_rgb"):
|
||||
assert key in CONFIG
|
||||
|
||||
|
||||
def test_config_ui_defaults():
|
||||
assert CONFIG["fps"] == 30
|
||||
assert CONFIG["circle_base_radius"] > 0
|
||||
assert CONFIG["circle_amplitude"] > 0
|
||||
assert len(CONFIG["circle_color_rgb"]) == 3
|
||||
Reference in New Issue
Block a user