# main.py from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.responses import JSONResponse from pydantic import BaseModel import librosa import numpy as np import tempfile import os import warnings import matplotlib.pyplot as plt warnings.filterwarnings("ignore", category=UserWarning, module='librosa') app = FastAPI() def extract_audio_features(audio_file_path): # Load the audio file and extract features y, sr = librosa.load(audio_file_path, sr=None) f0, voiced_flag, voiced_probs = librosa.pyin(y, fmin=75, fmax=600) f0 = f0[~np.isnan(f0)] energy = librosa.feature.rms(y=y)[0] mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13) onset_env = librosa.onset.onset_strength(y=y, sr=sr) tempo, _ = librosa.beat.beat_track(onset_envelope=onset_env, sr=sr) speech_rate = tempo / 60 return f0, energy, speech_rate, mfccs, y, sr def analyze_voice_stress(audio_file_path): f0, energy, speech_rate, mfccs, y, sr = extract_audio_features(audio_file_path) mean_f0 = np.mean(f0) std_f0 = np.std(f0) mean_energy = np.mean(energy) std_energy = np.std(energy) gender = 'male' if mean_f0 < 165 else 'female' norm_mean_f0 = 110 if gender == 'male' else 220 norm_std_f0 = 20 norm_mean_energy = 0.02 norm_std_energy = 0.005 norm_speech_rate = 4.4 norm_std_speech_rate = 0.5 z_f0 = (mean_f0 - norm_mean_f0) / norm_std_f0 z_energy = (mean_energy - norm_mean_energy) / norm_std_energy z_speech_rate = (speech_rate - norm_speech_rate) / norm_std_speech_rate stress_score = (0.4 * z_f0) + (0.4 * z_speech_rate) + (0.2 * z_energy) stress_level = float(1 / (1 + np.exp(-stress_score)) * 100) categories = ["Very Low Stress", "Low Stress", "Moderate Stress", "High Stress", "Very High Stress"] category_idx = min(int(stress_level / 20), 4) stress_category = categories[category_idx] return {"stress_level": stress_level, "category": stress_category, "gender": gender} class StressResponse(BaseModel): stress_level: float category: str gender: str @app.post("/analyze-stress/", response_model=StressResponse) async def analyze_stress(file: UploadFile = File(...)): if not file.filename.endswith(".wav"): raise HTTPException(status_code=400, detail="Only .wav files are supported.") with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_file: temp_file.write(await file.read()) temp_file_path = temp_file.name try: result = analyze_voice_stress(temp_file_path) return JSONResponse(content=result) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) finally: os.remove(temp_file_path) if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)