DL_FINAL_EXAMEN / src /audio.py
Your NameBOLLO22
Ajout du projet complet de BOLLO
c6b0fdb
Raw
History Blame Contribute Delete
2.92 kB
"""Chargement, validation et prétraitement audio partagé par toutes les interfaces."""
from __future__ import annotations
from pathlib import Path # Rend les chemins fiables sous Windows, Linux et macOS.
# librosa décode WAV/MP3 et réalise le rééchantillonnage demandé par le modèle.
import librosa
# NumPy représente le signal audio sous forme de tableau de nombres réels.
import numpy as np
from src.errors import AudioValidationError
# Wav2Vec2 français attend précisément 16 000 valeurs (échantillons) par seconde.
TARGET_SAMPLE_RATE = 16_000
# La limite de l'énoncé protège l'API contre un traitement trop long ou trop coûteux.
MAX_DURATION_SECONDS = 5 * 60
# Seuls les deux formats explicitement autorisés par l'énoncé sont acceptés.
SUPPORTED_EXTENSIONS = {".wav", ".mp3"}
def load_and_preprocess_audio(audio_path: str | Path) -> np.ndarray:
"""Retourne un signal mono normalisé à 16 kHz prêt pour Wav2Vec2.
Wav2Vec2 a été entraîné sur des signaux mono à 16 kHz : imposer ce format
évite les incohérences entre les fichiers WAV/MP3 envoyés par les clients.
"""
# Convertir la chaîne en Path permet ensuite de vérifier extension, existence et taille.
path = Path(audio_path)
if path.suffix.lower() not in SUPPORTED_EXTENSIONS:
raise AudioValidationError("Format non supporté : utilisez un fichier .wav ou .mp3.")
# Un fichier vide est rejeté avant de demander à librosa de le décoder.
if not path.is_file() or path.stat().st_size == 0:
raise AudioValidationError("Le fichier audio est introuvable ou vide.")
try:
# mono=True mélange les canaux ; sr=16000 effectue le rééchantillonnage.
samples, sample_rate = librosa.load(path, sr=TARGET_SAMPLE_RATE, mono=True)
except Exception as exc:
raise AudioValidationError("Impossible de décoder ce fichier audio.") from exc
# Après le chargement, la durée est le nombre d'échantillons divisé par la fréquence.
duration = len(samples) / sample_rate
if duration == 0:
raise AudioValidationError("Le fichier audio ne contient aucun échantillon.")
if duration > MAX_DURATION_SECONDS:
raise AudioValidationError("La durée maximale autorisée est de 5 minutes.")
# Le pic mesure l'amplitude la plus forte ; il sert à détecter le silence puis normaliser.
peak = float(np.max(np.abs(samples)))
# Un seuil non nul rejette les enregistrements silencieux/bruités sans écraser
# leur amplitude lors de la normalisation.
if peak < 1e-4:
raise AudioValidationError("Audio silencieux : aucune voix exploitable n'a été détectée.")
# La normalisation ramène le pic à 1.0 sans modifier le contenu relatif du signal.
# float32 est le type attendu par PyTorch et réduit l'occupation mémoire par rapport à float64.
return (samples / peak).astype(np.float32)