Grey3000 commited on
Commit
c564d8b
·
1 Parent(s): cafaed5

Add application file

Browse files
Files changed (8) hide show
  1. app.py +81 -0
  2. model.h5 +3 -0
  3. requirements.txt +0 -0
  4. runtime.txt +1 -0
  5. scaler.pkl +3 -0
  6. templates/.gitkeep +0 -0
  7. templates/index.html +113 -0
  8. templates/style.css +54 -0
app.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ x = st.slider('Select a value')
4
+ st.write(x, 'squared is', x * x)
5
+
6
+ # app.py
7
+ import os
8
+ from flask import Flask, request, jsonify, render_template
9
+ import librosa
10
+ import numpy as np
11
+ import tensorflow as tf
12
+ from sklearn.preprocessing import StandardScaler
13
+ import joblib
14
+
15
+ app = Flask(__name__)
16
+
17
+ # Load the trained model
18
+ model = tf.keras.models.load_model('model.h5')
19
+
20
+ # Load the scaler - you'll need to save this during training
21
+ # Add this after your training code:
22
+ # joblib.dump(scaler, 'scaler.pkl')
23
+ scaler = joblib.load('scaler.pkl')
24
+
25
+ def extract_features(audio_file):
26
+ y, sr = librosa.load(audio_file)
27
+
28
+ mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
29
+ spectral_centroid = librosa.feature.spectral_centroid(y=y, sr=sr)
30
+ spectral_bandwidth = librosa.feature.spectral_bandwidth(y=y, sr=sr)
31
+ spectral_rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)
32
+ zero_crossing_rate = librosa.feature.zero_crossing_rate(y)
33
+
34
+ features = np.concatenate([
35
+ np.mean(mfccs, axis=1),
36
+ [np.mean(spectral_centroid)],
37
+ [np.mean(spectral_bandwidth)],
38
+ [np.mean(spectral_rolloff)],
39
+ [np.mean(zero_crossing_rate)]
40
+ ])
41
+
42
+ return features.reshape(1, -1)
43
+
44
+ @app.route('/')
45
+ def home():
46
+ return render_template('index.html')
47
+
48
+ @app.route('/predict', methods=['POST'])
49
+ def predict():
50
+ try:
51
+ if 'file' not in request.files:
52
+ return jsonify({'error': 'No file provided'}), 400
53
+
54
+ file = request.files['file']
55
+ if file.filename == '':
56
+ return jsonify({'error': 'No file selected'}), 400
57
+
58
+ if not file.filename.endswith('.wav'):
59
+ return jsonify({'error': 'Please upload a WAV file'}), 400
60
+
61
+ # Extract features
62
+ features = extract_features(file)
63
+
64
+ # Scale features
65
+ scaled_features = scaler.transform(features)
66
+
67
+ # Make prediction
68
+ prediction = model.predict(scaled_features)
69
+ gender = "Female" if prediction[0][0] < 0.5 else "Male"
70
+ confidence = float(prediction[0][0] if prediction[0][0] > 0.5 else 1 - prediction[0][0])
71
+
72
+ return jsonify({
73
+ 'prediction': gender,
74
+ 'confidence': f"{confidence * 100:.2f}%"
75
+ })
76
+
77
+ except Exception as e:
78
+ return jsonify({'error': str(e)}), 500
79
+
80
+ if __name__ == '__main__':
81
+ app.run(debug=True)
model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f26461701b89642a4b6b3fdfb4bffef2deddd3d6407fec8f79d081a81038f88c
3
+ size 88880
requirements.txt ADDED
Binary file (2.13 kB). View file
 
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.9.9
scaler.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:741e3f3a3b430bcfd7e6d3cf285a740b5efa7587ba17d4e24728fdb7762ae826
3
+ size 1567
templates/.gitkeep ADDED
File without changes
templates/index.html ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- templates/index.html -->
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Voice Gender Classification</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ </head>
10
+ <body class="bg-gray-100 min-h-screen">
11
+ <div class="container mx-auto px-4 py-8">
12
+ <div class="max-w-md mx-auto bg-white rounded-lg shadow-lg p-6">
13
+ <h1 class="text-2xl font-bold text-center mb-6">Voice Gender Classification</h1>
14
+
15
+ <div class="mb-6">
16
+ <div class="flex items-center justify-center w-full">
17
+ <label class="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100">
18
+ <div class="flex flex-col items-center justify-center pt-5 pb-6">
19
+ <svg class="w-8 h-8 mb-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
20
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"/>
21
+ </svg>
22
+ <p class="mb-2 text-sm text-gray-500"><span class="font-semibold">Click to upload</span> or drag and drop</p>
23
+ <p class="text-xs text-gray-500">WAV files only</p>
24
+ </div>
25
+ <input id="file-upload" type="file" class="hidden" accept=".wav" />
26
+ </label>
27
+ </div>
28
+ </div>
29
+
30
+ <div id="selected-file" class="mb-4 text-center text-gray-600 hidden">
31
+ Selected file: <span id="filename"></span>
32
+ </div>
33
+
34
+ <button id="predict-btn" class="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 disabled:bg-gray-400 disabled:cursor-not-allowed" disabled>
35
+ Predict Gender
36
+ </button>
37
+
38
+ <div id="result" class="mt-6 text-center hidden">
39
+ <div class="mb-2">
40
+ <span class="font-bold">Predicted Gender:</span>
41
+ <span id="gender" class="ml-2"></span>
42
+ </div>
43
+ <div>
44
+ <span class="font-bold">Confidence:</span>
45
+ <span id="confidence" class="ml-2"></span>
46
+ </div>
47
+ </div>
48
+
49
+ <div id="error" class="mt-4 text-red-500 text-center hidden"></div>
50
+ </div>
51
+ </div>
52
+
53
+ <script>
54
+ const fileUpload = document.getElementById('file-upload');
55
+ const selectedFile = document.getElementById('selected-file');
56
+ const filename = document.getElementById('filename');
57
+ const predictBtn = document.getElementById('predict-btn');
58
+ const result = document.getElementById('result');
59
+ const gender = document.getElementById('gender');
60
+ const confidence = document.getElementById('confidence');
61
+ const error = document.getElementById('error');
62
+
63
+ fileUpload.addEventListener('change', (e) => {
64
+ const file = e.target.files[0];
65
+ if (file) {
66
+ filename.textContent = file.name;
67
+ selectedFile.classList.remove('hidden');
68
+ predictBtn.disabled = false;
69
+ result.classList.add('hidden');
70
+ error.classList.add('hidden');
71
+ }
72
+ });
73
+
74
+ predictBtn.addEventListener('click', async () => {
75
+ const file = fileUpload.files[0];
76
+ if (!file) return;
77
+
78
+ const formData = new FormData();
79
+ formData.append('file', file);
80
+
81
+ predictBtn.disabled = true;
82
+ predictBtn.textContent = 'Processing...';
83
+
84
+ try {
85
+ const response = await fetch('/predict', {
86
+ method: 'POST',
87
+ body: formData
88
+ });
89
+
90
+ const data = await response.json();
91
+
92
+ if (response.ok) {
93
+ result.classList.remove('hidden');
94
+ error.classList.add('hidden');
95
+ gender.textContent = data.prediction;
96
+ confidence.textContent = data.confidence;
97
+ } else {
98
+ error.textContent = data.error;
99
+ error.classList.remove('hidden');
100
+ result.classList.add('hidden');
101
+ }
102
+ } catch (err) {
103
+ error.textContent = 'An error occurred while processing the request';
104
+ error.classList.remove('hidden');
105
+ result.classList.add('hidden');
106
+ }
107
+
108
+ predictBtn.disabled = false;
109
+ predictBtn.textContent = 'Predict Gender';
110
+ });
111
+ </script>
112
+ </body>
113
+ </html>
templates/style.css ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Reset some default styles */
2
+ body, html {
3
+ margin: 0;
4
+ padding: 0;
5
+ font-family: Arial, sans-serif;
6
+ }
7
+
8
+ /* Container styles */
9
+ .container {
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ padding: 2rem;
13
+ }
14
+
15
+ /* Header styles */
16
+ h1 {
17
+ text-align: center;
18
+ margin-bottom: 2rem;
19
+ }
20
+
21
+ /* Button styles */
22
+ button {
23
+ background-color: #4CAF50;
24
+ border: none;
25
+ color: white;
26
+ padding: 0.75rem 1.5rem;
27
+ text-align: center;
28
+ text-decoration: none;
29
+ display: inline-block;
30
+ font-size: 16px;
31
+ margin: 0.5rem;
32
+ cursor: pointer;
33
+ border-radius: 4px;
34
+ }
35
+
36
+ button#record-btn {
37
+ background-color: #f44336;
38
+ }
39
+
40
+ button:hover {
41
+ opacity: 0.8;
42
+ }
43
+
44
+ /* Status and result styles */
45
+ #status, #result {
46
+ margin-top: 1rem;
47
+ padding: 1rem;
48
+ border: 1px solid #ccc;
49
+ border-radius: 4px;
50
+ }
51
+
52
+ #result {
53
+ background-color: #f1f1f1;
54
+ }