csprojectworkspace commited on
Commit
71d9dd5
·
verified ·
1 Parent(s): 18ae704

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -56
app.py CHANGED
@@ -9,39 +9,77 @@ import tensorflow as tf
9
  app = Flask(__name__)
10
  CORS(app)
11
 
12
- MODEL_PATH = "CRNN_model_final.h5"
 
 
 
13
 
14
- print("Chargement du modele CRNN...")
15
- model = tf.keras.models.load_model(MODEL_PATH, compile=False)
16
- print("Modele charge!")
17
- print(f"Input shape: {model.input_shape}")
18
- print(f"Output shape: {model.output_shape}")
19
 
20
  SILENCE_CLASSES = [13, 14]
 
 
 
21
 
22
- def predict_single(audio_segment):
23
- """Prediction sur un segment de 1024 echantillons"""
24
- target_length = 1024
25
-
26
- if len(audio_segment) < target_length:
27
- audio_segment = np.pad(audio_segment, (0, target_length - len(audio_segment)), mode='constant')
28
- elif len(audio_segment) > target_length:
29
- # Prendre le milieu
30
- start = (len(audio_segment) - target_length) // 2
31
- audio_segment = audio_segment[start:start + target_length]
32
 
33
  max_val = np.max(np.abs(audio_segment))
34
  if max_val > 0:
35
  audio_segment = audio_segment / max_val
36
 
37
- features = audio_segment.reshape(1, target_length, 1).astype(np.float32)
38
- prediction = model.predict(features, verbose=0)
39
  predicted_class = int(np.argmax(prediction[0]))
40
  confidence = float(np.max(prediction[0]))
41
  label = "silence" if predicted_class in SILENCE_CLASSES else "voice"
42
 
43
  return label, confidence, predicted_class
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  @app.after_request
46
  def after_request(response):
47
  response.headers.add('Access-Control-Allow-Origin', '*')
@@ -51,13 +89,13 @@ def after_request(response):
51
 
52
  @app.route('/', methods=['GET'])
53
  def home():
54
- return jsonify({'message': 'AcoustiTrack API', 'status': 'running'})
55
 
56
  @app.route('/api/health', methods=['GET', 'OPTIONS'])
57
  def health():
58
  if request.method == 'OPTIONS':
59
  return make_response('', 204)
60
- return jsonify({'status': 'ok', 'model': 'CRNN VAD'})
61
 
62
  @app.route('/api/analyze', methods=['POST', 'OPTIONS'])
63
  def analyze():
@@ -78,50 +116,57 @@ def analyze():
78
  n_channels = int(y.shape[0]) if y.ndim > 1 else 1
79
  duration = float(len(y_mono) / sr)
80
 
81
- # Prediction globale sur tout l'audio
82
- vad_label, vad_confidence, pred_class = predict_single(y_mono)
83
-
84
- # Creer timeline avec 10 segments (sans re-prediction)
85
- n_segments = 10
86
- segment_duration = duration / n_segments
87
 
88
  vad_timeline = []
89
- for i in range(n_segments):
90
- start_time = i * segment_duration
91
- end_time = (i + 1) * segment_duration
 
 
 
 
92
 
93
- # Simuler variation basee sur l'energie du segment
94
- start_sample = int(i * len(y_mono) / n_segments)
95
- end_sample = int((i + 1) * len(y_mono) / n_segments)
96
- segment_energy = float(np.mean(y_mono[start_sample:end_sample] ** 2))
97
 
98
- # Si energie faible = silence, sinon = prediction globale
99
- if segment_energy < 0.001:
100
- seg_label = "silence"
101
- seg_conf = 0.95
102
- else:
103
- seg_label = vad_label
104
- seg_conf = float(vad_confidence)
105
 
106
  vad_timeline.append({
107
- 'start': float(round(start_time, 3)),
108
- 'end': float(round(end_time, 3)),
109
- 'label': seg_label,
110
- 'confidence': float(round(seg_conf, 3))
111
  })
112
 
113
- # DOA estimation
114
- doa_angle = float(-25.5 + np.random.randn() * 10)
 
 
 
 
 
 
 
115
  doa_trajectory = []
116
- for i in range(n_segments):
 
 
117
  doa_trajectory.append({
118
- 'time': float(round(i * segment_duration, 2)),
119
- 'angle': float(round(doa_angle + np.random.randn() * 3, 1))
120
  })
121
 
122
- voice_count = sum(1 for f in vad_timeline if f['label'] == 'voice')
123
- voice_ratio = float(voice_count / n_segments)
124
-
125
  mean_y = float(np.mean(y_mono ** 2))
126
  snr = float(round(10 * np.log10(mean_y / 1e-10), 1)) if mean_y > 0 else 0.0
127
 
@@ -131,17 +176,17 @@ def analyze():
131
  'channels': n_channels,
132
  'sampleRate': int(sr),
133
  'duration': float(round(duration, 2)),
134
- 'samples': int(len(y_mono))
 
135
  },
136
  'vad': {
137
  'prediction': vad_label,
138
- 'confidence': float(round(vad_confidence, 3)),
139
- 'predicted_class': int(pred_class),
140
  'timeline': vad_timeline
141
  },
142
  'doa': {
143
  'angle': float(round(doa_angle, 1)),
144
- 'confidence': 0.89,
145
  'trajectory': doa_trajectory
146
  },
147
  'metrics': {
 
9
  app = Flask(__name__)
10
  CORS(app)
11
 
12
+ # Load VAD model
13
+ print("Chargement du modele VAD (CRNN)...")
14
+ model_vad = tf.keras.models.load_model("CRNN_model_final.h5", compile=False)
15
+ print(f"VAD Input: {model_vad.input_shape}, Output: {model_vad.output_shape}")
16
 
17
+ # Load DOA model
18
+ print("Chargement du modele DOA...")
19
+ model_doa = tf.keras.models.load_model("model_keras.h5", compile=False)
20
+ print(f"DOA Input: {model_doa.input_shape}, Output: {model_doa.output_shape}")
 
21
 
22
  SILENCE_CLASSES = [13, 14]
23
+ VAD_SEGMENT_SIZE = 1024
24
+ DOA_FEATURES = 34
25
+ DOA_TIMESTEPS = 675
26
 
27
+ def predict_vad(audio_segment):
28
+ if len(audio_segment) < VAD_SEGMENT_SIZE:
29
+ audio_segment = np.pad(audio_segment, (0, VAD_SEGMENT_SIZE - len(audio_segment)), mode='constant')
30
+ elif len(audio_segment) > VAD_SEGMENT_SIZE:
31
+ start = (len(audio_segment) - VAD_SEGMENT_SIZE) // 2
32
+ audio_segment = audio_segment[start:start + VAD_SEGMENT_SIZE]
 
 
 
 
33
 
34
  max_val = np.max(np.abs(audio_segment))
35
  if max_val > 0:
36
  audio_segment = audio_segment / max_val
37
 
38
+ features = audio_segment.reshape(1, VAD_SEGMENT_SIZE, 1).astype(np.float32)
39
+ prediction = model_vad.predict(features, verbose=0)
40
  predicted_class = int(np.argmax(prediction[0]))
41
  confidence = float(np.max(prediction[0]))
42
  label = "silence" if predicted_class in SILENCE_CLASSES else "voice"
43
 
44
  return label, confidence, predicted_class
45
 
46
+ def predict_doa(audio, sr):
47
+ """
48
+ Prediction DOA
49
+ Input attendu: (batch, 34, 675)
50
+ Output: (batch, 34) - angles ou probabilites
51
+ """
52
+ # Extraire des features audio (MFCC ou autre)
53
+ # Le modele attend 34 features x 675 timesteps
54
+
55
+ # Calculer MFCCs (34 coefficients)
56
+ n_mfcc = 34
57
+ mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=n_mfcc)
58
+
59
+ # Ajuster la longueur temporelle a 675
60
+ if mfccs.shape[1] < DOA_TIMESTEPS:
61
+ mfccs = np.pad(mfccs, ((0, 0), (0, DOA_TIMESTEPS - mfccs.shape[1])), mode='constant')
62
+ else:
63
+ mfccs = mfccs[:, :DOA_TIMESTEPS]
64
+
65
+ # Normaliser
66
+ mfccs = (mfccs - np.mean(mfccs)) / (np.std(mfccs) + 1e-8)
67
+
68
+ # Reshape: (1, 34, 675)
69
+ features = mfccs.reshape(1, DOA_FEATURES, DOA_TIMESTEPS).astype(np.float32)
70
+
71
+ # Prediction
72
+ prediction = model_doa.predict(features, verbose=0)
73
+
74
+ # Output: 34 valeurs - prendre l'indice max comme angle
75
+ # Supposons que les 34 sorties correspondent a des angles de -90 a +90 degres
76
+ angles = np.linspace(-90, 90, 34)
77
+ predicted_idx = int(np.argmax(prediction[0]))
78
+ predicted_angle = float(angles[predicted_idx])
79
+ confidence = float(np.max(prediction[0]))
80
+
81
+ return predicted_angle, confidence, prediction[0].tolist()
82
+
83
  @app.after_request
84
  def after_request(response):
85
  response.headers.add('Access-Control-Allow-Origin', '*')
 
89
 
90
  @app.route('/', methods=['GET'])
91
  def home():
92
+ return jsonify({'message': 'AcoustiTrack API', 'status': 'running', 'models': ['VAD', 'DOA']})
93
 
94
  @app.route('/api/health', methods=['GET', 'OPTIONS'])
95
  def health():
96
  if request.method == 'OPTIONS':
97
  return make_response('', 204)
98
+ return jsonify({'status': 'ok', 'model': 'CRNN VAD + CNN DOA'})
99
 
100
  @app.route('/api/analyze', methods=['POST', 'OPTIONS'])
101
  def analyze():
 
116
  n_channels = int(y.shape[0]) if y.ndim > 1 else 1
117
  duration = float(len(y_mono) / sr)
118
 
119
+ # VAD prediction
120
+ total_segments = len(y_mono) // VAD_SEGMENT_SIZE
121
+ max_segments = min(total_segments, 20)
122
+ if max_segments == 0:
123
+ max_segments = 1
124
+ step = max(1, total_segments // max_segments)
125
 
126
  vad_timeline = []
127
+ voice_count = 0
128
+ all_confidences = []
129
+
130
+ for i in range(max_segments):
131
+ segment_index = i * step
132
+ start_sample = segment_index * VAD_SEGMENT_SIZE
133
+ end_sample = start_sample + VAD_SEGMENT_SIZE
134
 
135
+ if end_sample > len(y_mono):
136
+ break
 
 
137
 
138
+ segment = y_mono[start_sample:end_sample]
139
+ label, confidence, _ = predict_vad(segment)
140
+
141
+ if label == "voice":
142
+ voice_count += 1
143
+ all_confidences.append(confidence)
 
144
 
145
  vad_timeline.append({
146
+ 'start': float(round(start_sample / sr, 3)),
147
+ 'end': float(round(end_sample / sr, 3)),
148
+ 'label': label,
149
+ 'confidence': float(round(confidence, 3))
150
  })
151
 
152
+ n_analyzed = len(vad_timeline)
153
+ voice_ratio = float(voice_count / n_analyzed) if n_analyzed > 0 else 0.0
154
+ vad_label = "voice" if voice_ratio > 0.5 else "silence"
155
+ avg_vad_confidence = float(np.mean(all_confidences)) if all_confidences else 0.0
156
+
157
+ # DOA prediction
158
+ doa_angle, doa_confidence, doa_probs = predict_doa(y_mono, sr)
159
+
160
+ # DOA trajectory (based on segments)
161
  doa_trajectory = []
162
+ for i, seg in enumerate(vad_timeline):
163
+ # Slight variation around predicted angle
164
+ angle_variation = doa_angle + np.random.randn() * 2
165
  doa_trajectory.append({
166
+ 'time': seg['start'],
167
+ 'angle': float(round(angle_variation, 1))
168
  })
169
 
 
 
 
170
  mean_y = float(np.mean(y_mono ** 2))
171
  snr = float(round(10 * np.log10(mean_y / 1e-10), 1)) if mean_y > 0 else 0.0
172
 
 
176
  'channels': n_channels,
177
  'sampleRate': int(sr),
178
  'duration': float(round(duration, 2)),
179
+ 'samples': int(len(y_mono)),
180
+ 'segments_analyzed': n_analyzed
181
  },
182
  'vad': {
183
  'prediction': vad_label,
184
+ 'confidence': float(round(avg_vad_confidence, 3)),
 
185
  'timeline': vad_timeline
186
  },
187
  'doa': {
188
  'angle': float(round(doa_angle, 1)),
189
+ 'confidence': float(round(doa_confidence, 3)),
190
  'trajectory': doa_trajectory
191
  },
192
  'metrics': {