Haseeb949/fluenta-backend
0
1# ml_utils.py2import os3import numpy as np4from pydub import AudioSegment5import librosa6import soundfile as sf7 8SAMPLE_RATE = 160009 10def to_wav_mono16(in_path, out_path, target_sr=SAMPLE_RATE):11 """Convert to mono WAV 16-bit PCM and resample to SAMPLE_RATE."""12 audio = AudioSegment.from_file(in_path)13 audio = audio.set_frame_rate(target_sr).set_channels(1).set_sample_width(2)14 audio.export(out_path, format="wav")15 return out_path16 17def load_audio_mono(path, sr=SAMPLE_RATE):18 y, sr = librosa.load(path, sr=sr, mono=True)19 return y, sr20 21def trim_silence(y, top_db=30):22 intervals = librosa.effects.split(y, top_db=top_db)23 if len(intervals) == 0:24 return y25 parts = [y[start:end] for start, end in intervals]26 return np.concatenate(parts)27 28def extract_mfcc(y, sr=SAMPLE_RATE, n_mfcc=20, hop_length=512):29 mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=n_mfcc, hop_length=hop_length)30 # shape: (n_mfcc, t). We return mean+std for simple vector input31 feat = np.concatenate([mfcc.mean(axis=1), mfcc.std(axis=1)])32 return feat.astype(np.float32)33 34class ModelWrapper:35 """Replace predict() with your model code. Keep interface same: returns dict."""36 def __init__(self, model_path=None):37 self.model_path = model_path38 # TODO: load Torch/TF/ONNX model here if available39 self.model = None40 41 def predict_from_features(self, features):42 # placeholder: if mean MFCC amplitude > threshold say "Stutter"43 score = float(np.tanh(np.abs(features).mean()) ) # dummy 0..1-ish44 label = "Stutter" if score > 0.4 else "NoStutter"45 events = [] # e.g. [{"t":1.2,"type":"repeat"}]46 return {"label": label, "confidence": score, "events": events}47 48 def predict_from_file(self, audio_path):49 # full pipeline: convert -> load -> trim -> extract -> predict50 tmp = audio_path51 if not audio_path.lower().endswith(".wav"):52 tmp = audio_path + ".wav"53 to_wav_mono16(audio_path, tmp)54 y, sr = load_audio_mono(tmp)55 y = trim_silence(y)56 feats = extract_mfcc(y, sr)57 return self.predict_from_features(feats)58 