Haseeb949/fluenta-backend
0
1# -*- coding: utf-8 -*-2"""FlaskAPI.ipynb3 4Automatically generated by Colab.5 6Original file is located at7 https://colab.research.google.com/drive/1uihvsfycjhZr7FmzC4x3yC8hZX0ChuKV8"""9 10import os11import numpy as np12import librosa13!pip install noisereduce==2.0.114import noisereduce as nr15import joblib16from flask import Flask, request, jsonify17from datetime import datetime18!pip install flask pyngrok librosa noisereduce scikit-learn joblib19!python app.py20!apt install ffmpeg21!pip install pydub22from pydub import AudioSegment23 24from google.colab import files25uploaded = files.upload()26 27# Load model28MODEL_PATH = "/content/drive/MyDrive/Fluenta_Models/stutter_model_final.pkl"29SCALER_PATH = "/content/drive/MyDrive/Fluenta_Models/scaler_final.pkl"30FEATURE_COUNT_PATH = "/content/drive/MyDrive/Fluenta_Models/feature_count.pkl"31 32model = joblib.load(MODEL_PATH)33scaler = joblib.load(SCALER_PATH)34feature_count = joblib.load(FEATURE_COUNT_PATH)35 36# Flask App37app = Flask(__name__)38predictions_log = []39def preprocess_audio(audio, sr):40 audio, _ = librosa.effects.trim(audio, top_db=20)41 audio = librosa.util.normalize(audio)42 try:43 audio = nr.reduce_noise(y=audio, sr=sr, prop_decrease=0.8)44 except:45 pass46 if sr != 16000:47 audio = librosa.resample(audio, orig_sr=sr, target_sr=16000)48 sr = 1600049 min_length = int(0.5 * sr)50 if len(audio) < min_length:51 audio = np.pad(audio, (0, min_length - len(audio)), mode='constant')52 return audio, sr53 54# Feature Extraction55def extract_features(file_path):56 try:57 audio, sr = librosa.load(file_path, sr=None)58 audio, sr = preprocess_audio(audio, sr)59 60 features = []61 mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=20)62 features.extend(np.mean(mfccs.T, axis=0))63 features.extend(np.std(mfccs.T, axis=0))64 65 spectral_centroids = librosa.feature.spectral_centroid(y=audio, sr=sr)[0]66 spectral_rolloff = librosa.feature.spectral_rolloff(y=audio, sr=sr)[0]67 zcr = librosa.feature.zero_crossing_rate(audio)[0]68 chroma = librosa.feature.chroma_stft(y=audio, sr=sr)69 rms = librosa.feature.rms(y=audio)[0]70 71 features += [np.mean(spectral_centroids), np.std(spectral_centroids),72 np.mean(spectral_rolloff), np.std(spectral_rolloff),73 np.mean(zcr), np.std(zcr),74 *np.mean(chroma.T, axis=0),75 np.mean(rms), np.std(rms)]76 77 return np.array(features)78 except Exception as e:79 print(f"Feature extraction error: {e}")80 return None81 82# Prediction Endpoint83@app.route('/predict', methods=['POST'])84def predict():85 if 'file' not in request.files:86 return jsonify({'error': 'No audio file uploaded'}), 40087 88 file = request.files['file']89 filename = file.filename90 filepath = f"/tmp/{filename}"91 file.save(filepath)92 93 #Convert any non-WAV file to WAV automatically94 if not filename.lower().endswith(".wav"):95 wav_path = f"/tmp/converted.wav"96 try:97 sound = AudioSegment.from_file(filepath)98 sound.export(wav_path, format="wav")99 os.remove(filepath)100 filepath = wav_path101 print(f"Converted {filename} to WAV format.")102 except Exception as e:103 return jsonify({"error": f"File conversion failed: {e}"}), 500104 105 # Extract features106 features = extract_features(filepath)107 os.remove(filepath)108 109 if features is None:110 return jsonify({'error': 'Feature extraction failed'}), 500111 112 if len(features) != feature_count:113 return jsonify({'error': f'Feature count mismatch. Expected {feature_count}, got {len(features)}'}), 500114 115 features_scaled = scaler.transform([features])116 prediction = model.predict(features_scaled)[0]117 proba = model.predict_proba(features_scaled)[0] if hasattr(model, 'predict_proba') else None118 119 result_label = "Stutter" if prediction == 1 else "Non Stutter"120 confidence = round(float(proba[prediction]) * 100, 2) if proba is not None else None121 fluency_score = round(100 - confidence, 2) if result_label == "Stutter" else confidence122 123 feedback = (124 "Severe stuttering detected. Fluency score: 0%. Try to relax and slow down."125 if fluency_score <= 25 else126 "Moderate stuttering detected. Keep practicing!"127 if fluency_score <= 75 else128 "Great job! No stutter detected. Fluency score: 100%."129 )130 131 result = {132 "prediction": result_label,133 "confidence": confidence,134 "fluency_score": fluency_score,135 "feedback": feedback136 }137 138 # Track prediction139 predictions_log.append({140 "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),141 "filename": filename,142 "prediction": result_label,143 "confidence": confidence144 })145 146 return jsonify(result)147 148# Stats Endpoint149@app.route('/stats')150def stats():151 if not predictions_log:152 return jsonify({"message": "No predictions yet"})153 154 total = len(predictions_log)155 stutter_count = sum(1 for p in predictions_log if p["prediction"] == "Stutter")156 157 return jsonify({158 "total_predictions": total,159 "stutter_predictions": stutter_count,160 "fluent_predictions": total - stutter_count,161 "stutter_percentage": round(stutter_count / total * 100, 2)162 })163 164!ngrok config add-authtoken 33HVMsJ3w9V3ztrSLmbVKi0ZdMS_5orXJd2WC1qHP8A21YMwH165 166# Run with ngrok167from pyngrok import ngrok168 169@app.route('/')170def home():171 return jsonify({"message": "Enhanced Stuttering Detection API is running!"})172 173if __name__ == '__main__':174 public_url = ngrok.connect(5000)175 print(f"\n๐ Public URL: {public_url}\n")176 app.run(port=5000)177 178!killall ngrok179!pkill -f ngrok180ngrok.kill()181!rm -rf /root/.ngrok2/ngrok.yml