YsnHdn commited on
Commit
d32d550
1 Parent(s): baf039a

Add : Adding the french voice feature

Browse files
__pycache__/app.cpython-310.pyc CHANGED
Binary files a/__pycache__/app.cpython-310.pyc and b/__pycache__/app.cpython-310.pyc differ
 
__pycache__/helper_functions.cpython-310.pyc CHANGED
Binary files a/__pycache__/helper_functions.cpython-310.pyc and b/__pycache__/helper_functions.cpython-310.pyc differ
 
app.py CHANGED
@@ -1,16 +1,17 @@
1
  from flask import Flask, render_template,request, redirect,url_for, jsonify , session
2
  from helper_functions import predict_class , inference , predict , align_predictions_with_sentences , load_models , load_fr_models
3
- from helper_functions import predict_fr_class, fr_inference , align_fr_predictions_with_sentences
4
  import fitz # PyMuPDF
5
  import os, shutil
6
  import torch
7
  import tempfile
8
  from pydub import AudioSegment
9
  import logging
 
10
 
11
  app = Flask(__name__)
12
  app.config['UPLOAD_FOLDER'] = 'static/uploads'
13
-
14
  # Global variables for models
15
  global_model = None
16
  global_neptune = None
@@ -18,17 +19,20 @@ global_pipe = None
18
  global_fr_model = None
19
  global_fr_neptune = None
20
  global_fr_pipe = None
21
-
 
22
 
23
 
24
  def init_app():
25
  global global_model, global_neptune, global_pipe
 
 
26
  print("Loading English models...")
27
  global_model, global_neptune, global_pipe = load_models()
28
 
29
- global global_fr_model, global_fr_neptune, global_fr_pipe
30
  print("Loading French models...")
31
- global_fr_model , global_fr_neptune , global_fr_pipe = load_fr_models()
 
32
  print("Models loaded successfully!")
33
 
34
  init_app()
@@ -305,6 +309,7 @@ def treatment_fr():
305
  }
306
  print(predict_class)
307
  print(chart_data)
 
308
  # clear the uploads folder
309
  for filename in os.listdir(app.config['UPLOAD_FOLDER']):
310
  file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
@@ -341,31 +346,44 @@ def sentence_fr():
341
  # Render the initial form page
342
  return render_template('sentence_fr.html')
343
 
 
 
 
344
  @app.route("/voice_fr", methods=['GET', 'POST'])
345
  def slu_fr():
346
- global global_fr_neptune, global_fr_pipe, global_fr_model
347
 
348
  if request.method == 'POST':
349
- logging.debug("Received POST request")
350
  audio_file = request.files.get('audio')
351
 
352
  if audio_file:
353
- logging.debug(f"Received audio file: {audio_file.filename}")
354
 
355
- # Save audio data to a temporary file
356
- with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_audio:
357
- audio_file.save(temp_audio)
358
- temp_audio_path = temp_audio.name
359
-
360
- logging.debug(f"Saved audio to temporary file: {temp_audio_path}")
 
 
 
 
 
 
 
 
 
 
 
361
 
362
  try:
363
- # Transcribe audio using Whisper
364
- result = global_fr_pipe(temp_audio_path)
365
- extracted_text = result["text"]
366
- logging.debug(f"Transcribed text: {extracted_text}")
367
 
368
- # Process the transcribed text
369
  inference_batch, sentences = fr_inference(extracted_text)
370
  predictions = predict(inference_batch, global_fr_neptune)
371
  sentences_prediction = align_fr_predictions_with_sentences(sentences, predictions)
@@ -382,17 +400,17 @@ def slu_fr():
382
 
383
  response_data = {
384
  'extracted_text': extracted_text,
385
- 'class_probabilities' : class_probabilities,
386
  'predicted_class': predicted_class,
387
  'chart_data': chart_data,
388
  'sentences_prediction': sentences_prediction
389
  }
390
- logging.debug(f"Prepared response data: {response_data}")
391
 
392
  return render_template('voice_fr.html',
393
- class_probabilities= class_probabilities,
394
- predicted_class= predicted_class,
395
- chart_data= chart_data,
396
  sentences_prediction=sentences_prediction)
397
 
398
  except Exception as e:
@@ -400,15 +418,15 @@ def slu_fr():
400
  return jsonify({'error': str(e)}), 500
401
 
402
  finally:
403
- # Remove temporary file
404
  os.unlink(temp_audio_path)
405
 
406
  else:
407
  logging.error("No audio file received")
408
  return jsonify({'error': 'No audio file received'}), 400
409
 
410
- # For GET request
411
- logging.debug("Received GET request")
412
  return render_template('voice_fr.html',
413
  class_probabilities={},
414
  predicted_class=[""],
 
1
  from flask import Flask, render_template,request, redirect,url_for, jsonify , session
2
  from helper_functions import predict_class , inference , predict , align_predictions_with_sentences , load_models , load_fr_models
3
+ from helper_functions import predict_fr_class, fr_inference , align_fr_predictions_with_sentences , transcribe_speech
4
  import fitz # PyMuPDF
5
  import os, shutil
6
  import torch
7
  import tempfile
8
  from pydub import AudioSegment
9
  import logging
10
+ import torchaudio
11
 
12
  app = Flask(__name__)
13
  app.config['UPLOAD_FOLDER'] = 'static/uploads'
14
+ device = "cpu"
15
  # Global variables for models
16
  global_model = None
17
  global_neptune = None
 
19
  global_fr_model = None
20
  global_fr_neptune = None
21
  global_fr_pipe = None
22
+ global_fr_wav2vec2_processor = None
23
+ global_fr_wav2vec2_model = None
24
 
25
 
26
  def init_app():
27
  global global_model, global_neptune, global_pipe
28
+ global global_fr_model, global_fr_neptune, global_fr_wav2vec2_processor, global_fr_wav2vec2_model
29
+
30
  print("Loading English models...")
31
  global_model, global_neptune, global_pipe = load_models()
32
 
 
33
  print("Loading French models...")
34
+ global_fr_model, global_fr_neptune, global_fr_wav2vec2_processor, global_fr_wav2vec2_model = load_fr_models()
35
+
36
  print("Models loaded successfully!")
37
 
38
  init_app()
 
309
  }
310
  print(predict_class)
311
  print(chart_data)
312
+ print(sentences)
313
  # clear the uploads folder
314
  for filename in os.listdir(app.config['UPLOAD_FOLDER']):
315
  file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
 
346
  # Render the initial form page
347
  return render_template('sentence_fr.html')
348
 
349
+ from pydub import AudioSegment
350
+ import io
351
+
352
  @app.route("/voice_fr", methods=['GET', 'POST'])
353
  def slu_fr():
354
+ global global_fr_neptune, global_fr_model, global_fr_wav2vec2_processor, global_fr_wav2vec2_model
355
 
356
  if request.method == 'POST':
357
+ logging.info("Received POST request for /voice_fr")
358
  audio_file = request.files.get('audio')
359
 
360
  if audio_file:
361
+ logging.info(f"Received audio file: {audio_file.filename}")
362
 
363
+ # Lire le contenu du fichier audio
364
+ audio_data = audio_file.read()
365
+
366
+ # Convertir l'audio en WAV si nécessaire
367
+ try:
368
+ audio = AudioSegment.from_file(io.BytesIO(audio_data))
369
+ audio = audio.set_frame_rate(16000).set_channels(1)
370
+
371
+ # Sauvegarder l'audio converti dans un fichier temporaire
372
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_audio:
373
+ audio.export(temp_audio.name, format="wav")
374
+ temp_audio_path = temp_audio.name
375
+
376
+ logging.info(f"Converted and saved audio to temporary file: {temp_audio_path}")
377
+ except Exception as e:
378
+ logging.error(f"Error converting audio: {str(e)}")
379
+ return jsonify({'error': 'Unable to process audio file'}), 400
380
 
381
  try:
382
+ # Transcrire l'audio en utilisant la fonction de helper_functions
383
+ extracted_text = transcribe_speech(temp_audio_path, global_fr_wav2vec2_processor, global_fr_wav2vec2_model)
384
+ logging.info(f"Transcribed text: {extracted_text}")
 
385
 
386
+ # Traiter le texte transcrit
387
  inference_batch, sentences = fr_inference(extracted_text)
388
  predictions = predict(inference_batch, global_fr_neptune)
389
  sentences_prediction = align_fr_predictions_with_sentences(sentences, predictions)
 
400
 
401
  response_data = {
402
  'extracted_text': extracted_text,
403
+ 'class_probabilities': class_probabilities,
404
  'predicted_class': predicted_class,
405
  'chart_data': chart_data,
406
  'sentences_prediction': sentences_prediction
407
  }
408
+ logging.info(f"Prepared response data: {response_data}")
409
 
410
  return render_template('voice_fr.html',
411
+ class_probabilities=class_probabilities,
412
+ predicted_class=predicted_class,
413
+ chart_data=chart_data,
414
  sentences_prediction=sentences_prediction)
415
 
416
  except Exception as e:
 
418
  return jsonify({'error': str(e)}), 500
419
 
420
  finally:
421
+ # Supprimer le fichier temporaire
422
  os.unlink(temp_audio_path)
423
 
424
  else:
425
  logging.error("No audio file received")
426
  return jsonify({'error': 'No audio file received'}), 400
427
 
428
+ # Pour la requête GET
429
+ logging.info("Received GET request for /voice_fr")
430
  return render_template('voice_fr.html',
431
  class_probabilities={},
432
  predicted_class=[""],
helper_functions.py CHANGED
@@ -11,6 +11,10 @@ from FrModel import FR_BERT
11
  from Model import tokenizer , mult_token_id , cls_token_id , pad_token_id , max_pred , maxlen , sep_token_id
12
  from FrModel import fr_tokenizer , fr_mult_token_id , fr_cls_token_id , fr_pad_token_id , fr_sep_token_id
13
  from transformers import pipeline
 
 
 
 
14
 
15
  device = "cpu"
16
  # Load the model
@@ -48,17 +52,12 @@ def load_fr_models():
48
  model_save_path = "fr_neptune/fr_neptune/model.pt"
49
  fr_neptune.load_state_dict(torch.load(model_save_path, map_location=torch.device('cpu')))
50
  fr_neptune.to(device)
51
- print("Loading speech recognition pipeline...")
52
- pipe = pipeline(
53
- "automatic-speech-recognition",
54
- model="openai/whisper-tiny.en",
55
- chunk_length_s=30,
56
- device=device,
57
- )
58
- print(pipe)
59
- return fr_model , fr_neptune , pipe
60
 
61
- fr_class_labels = {0: ('Physics', 'primary', '#0f6fec'), 1: ('AI','cyan', '#0dcaf0'),
62
  2: ('economies', 'warning' , '#f7c32e'), 3: ('environments','success' , '#0cbc87'),
63
  4: ('sports', 'orange', '#fd7e14')}
64
  class_labels = {
@@ -395,7 +394,7 @@ def prepare_fr_text(tokens_splitted: BatchEncoding):
395
  input_ids_a = [token for token in input_ids_a.view(-1).tolist() if token != pad_token_id]
396
  input_ids_b = []
397
  input_ids = [fr_cls_token_id] + [fr_mult_token_id] + input_ids_a + [fr_sep_token_id] + [fr_mult_token_id] + input_ids_b + [fr_sep_token_id]
398
- text_input_a = fr_tokenizer.decode(input_ids_a)
399
  sentences.append(text_input_a)
400
  segment_ids = [0] * (1 + 1 + len(input_ids_a) + 1) + [1] * (1 + len(input_ids_b) + 1)
401
 
@@ -426,8 +425,8 @@ def prepare_fr_text(tokens_splitted: BatchEncoding):
426
  input_ids_b = [token for token in input_ids_b.view(-1).tolist() if token != pad_token_id]
427
  input_ids = [fr_cls_token_id] + [fr_mult_token_id] + input_ids_a + [fr_sep_token_id] + [fr_mult_token_id] + input_ids_b + [fr_sep_token_id]
428
  segment_ids = [0] * (1 + 1 + len(input_ids_a) + 1) + [1] * (1 + len(input_ids_b) + 1)
429
- text_input_a = fr_tokenizer.decode(input_ids_a)
430
- text_input_b = fr_tokenizer.decode(input_ids_b)
431
  sentences.append(text_input_a)
432
  sentences.append(text_input_b)
433
 
@@ -542,4 +541,63 @@ def add_fr_special_tokens_at_beginning_and_end(input_id_chunks: list[Tensor], ma
542
  # adding CLS (token id 101) and SEP (token id 102) tokens
543
  input_id_chunks[i] = torch.cat([Tensor([5]), input_id_chunks[i], Tensor([6])])
544
  # adding attention masks corresponding to special tokens
545
- mask_chunks[i] = torch.cat([Tensor([1]), mask_chunks[i], Tensor([1])])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  from Model import tokenizer , mult_token_id , cls_token_id , pad_token_id , max_pred , maxlen , sep_token_id
12
  from FrModel import fr_tokenizer , fr_mult_token_id , fr_cls_token_id , fr_pad_token_id , fr_sep_token_id
13
  from transformers import pipeline
14
+ from transformers import AutoModelForCTC, Wav2Vec2Processor
15
+ import torchaudio
16
+ import logging
17
+ import soundfile as sf
18
 
19
  device = "cpu"
20
  # Load the model
 
52
  model_save_path = "fr_neptune/fr_neptune/model.pt"
53
  fr_neptune.load_state_dict(torch.load(model_save_path, map_location=torch.device('cpu')))
54
  fr_neptune.to(device)
55
+ print("Loading Wav2Vec2 model for French...")
56
+ wav2vec2_processor = Wav2Vec2Processor.from_pretrained("bhuang/asr-wav2vec2-french")
57
+ wav2vec2_model = AutoModelForCTC.from_pretrained("bhuang/asr-wav2vec2-french").to(device)
58
+ return fr_model, fr_neptune, wav2vec2_processor, wav2vec2_model
 
 
 
 
 
59
 
60
+ fr_class_labels = {0: ('Physics', 'primary', '#478ce6'), 1: ('AI','cyan', '#0dcaf0'),
61
  2: ('economies', 'warning' , '#f7c32e'), 3: ('environments','success' , '#0cbc87'),
62
  4: ('sports', 'orange', '#fd7e14')}
63
  class_labels = {
 
394
  input_ids_a = [token for token in input_ids_a.view(-1).tolist() if token != pad_token_id]
395
  input_ids_b = []
396
  input_ids = [fr_cls_token_id] + [fr_mult_token_id] + input_ids_a + [fr_sep_token_id] + [fr_mult_token_id] + input_ids_b + [fr_sep_token_id]
397
+ text_input_a = fr_tokenizer.decode(input_ids_a , skip_special_tokens=True)
398
  sentences.append(text_input_a)
399
  segment_ids = [0] * (1 + 1 + len(input_ids_a) + 1) + [1] * (1 + len(input_ids_b) + 1)
400
 
 
425
  input_ids_b = [token for token in input_ids_b.view(-1).tolist() if token != pad_token_id]
426
  input_ids = [fr_cls_token_id] + [fr_mult_token_id] + input_ids_a + [fr_sep_token_id] + [fr_mult_token_id] + input_ids_b + [fr_sep_token_id]
427
  segment_ids = [0] * (1 + 1 + len(input_ids_a) + 1) + [1] * (1 + len(input_ids_b) + 1)
428
+ text_input_a = fr_tokenizer.decode(input_ids_a , skip_special_tokens=True)
429
+ text_input_b = fr_tokenizer.decode(input_ids_b, skip_special_tokens=True)
430
  sentences.append(text_input_a)
431
  sentences.append(text_input_b)
432
 
 
541
  # adding CLS (token id 101) and SEP (token id 102) tokens
542
  input_id_chunks[i] = torch.cat([Tensor([5]), input_id_chunks[i], Tensor([6])])
543
  # adding attention masks corresponding to special tokens
544
+ mask_chunks[i] = torch.cat([Tensor([1]), mask_chunks[i], Tensor([1])])
545
+
546
+ def transcribe_speech(audio_path, wav2vec2_processor, wav2vec2_model):
547
+ logging.info(f"Starting transcription of {audio_path}")
548
+
549
+ try:
550
+ # Try loading with torchaudio first
551
+ waveform, sample_rate = torchaudio.load(audio_path)
552
+ waveform = waveform.squeeze().numpy()
553
+ logging.info(f"Audio loaded with torchaudio. Shape: {waveform.shape}, Sample rate: {sample_rate}")
554
+ except Exception as e:
555
+ logging.warning(f"torchaudio failed to load the audio. Trying with soundfile. Error: {str(e)}")
556
+ try:
557
+ # If torchaudio fails, try with soundfile
558
+ waveform, sample_rate = sf.read(audio_path)
559
+ waveform = torch.from_numpy(waveform).float()
560
+ logging.info(f"Audio loaded with soundfile. Shape: {waveform.shape}, Sample rate: {sample_rate}")
561
+ except Exception as e:
562
+ logging.error(f"Both torchaudio and soundfile failed to load the audio. Error: {str(e)}")
563
+ raise ValueError("Unable to load the audio file.")
564
+
565
+ # Ensure waveform is 1D
566
+ if waveform.ndim > 1:
567
+ waveform = np.mean(waveform, axis=0) # Changed from axis=1 to axis=0
568
+ logging.info(f"Waveform reduced to 1D. New shape: {waveform.shape}")
569
+
570
+ # Resample if necessary
571
+ if sample_rate != wav2vec2_processor.feature_extractor.sampling_rate:
572
+ resampler = torchaudio.transforms.Resample(sample_rate, wav2vec2_processor.feature_extractor.sampling_rate)
573
+ waveform = resampler(torch.from_numpy(waveform).float())
574
+ logging.info(f"Audio resampled to {wav2vec2_processor.feature_extractor.sampling_rate}Hz")
575
+
576
+ # Normalize
577
+ try:
578
+ input_values = wav2vec2_processor(waveform, sampling_rate=wav2vec2_processor.feature_extractor.sampling_rate, return_tensors="pt").input_values
579
+ logging.info(f"Input values shape after processing: {input_values.shape}")
580
+ except Exception as e:
581
+ logging.error(f"Error during audio processing: {str(e)}")
582
+ raise
583
+
584
+ # Ensure input_values is 2D (batch_size, sequence_length)
585
+ input_values = input_values.squeeze()
586
+ if input_values.dim() == 0: # If it's a scalar, unsqueeze twice
587
+ input_values = input_values.unsqueeze(0).unsqueeze(0)
588
+ elif input_values.dim() == 1: # If it's 1D, unsqueeze once
589
+ input_values = input_values.unsqueeze(0)
590
+ logging.info(f"Final input values shape: {input_values.shape}")
591
+
592
+ try:
593
+ with torch.inference_mode():
594
+ logits = wav2vec2_model(input_values.to(device)).logits
595
+ logging.info(f"Model inference successful. Logits shape: {logits.shape}")
596
+ except Exception as e:
597
+ logging.error(f"Error during model inference: {str(e)}")
598
+ raise
599
+
600
+ predicted_ids = torch.argmax(logits, dim=-1)
601
+ predicted_sentence = wav2vec2_processor.batch_decode(predicted_ids)
602
+ logging.info(f"Transcription complete. Result: {predicted_sentence[0]}")
603
+ return predicted_sentence[0]
static/css/style2.css CHANGED
@@ -35,7 +35,7 @@
35
  --bs-gray-700: #495057;
36
  --bs-gray-800: #343a40;
37
  --bs-gray-900: #212529;
38
- --bs-primary: #0f6fec;
39
  --bs-secondary: #14191e;
40
  --bs-success: #0cbc87;
41
  --bs-info: #4f9ef8;
@@ -17332,7 +17332,7 @@ html[data-theme=dark] .light-mode-item {
17332
  border-bottom: 0 !important;
17333
  }
17334
 
17335
- .bg-primary {
17336
  --bs-bg-opacity: 1;
17337
  background-color: #72AB5A !important;
17338
  }
 
35
  --bs-gray-700: #495057;
36
  --bs-gray-800: #343a40;
37
  --bs-gray-900: #212529;
38
+ --bs-primary: #478ce6;
39
  --bs-secondary: #14191e;
40
  --bs-success: #0cbc87;
41
  --bs-info: #4f9ef8;
 
17332
  border-bottom: 0 !important;
17333
  }
17334
 
17335
+ .bg-chat {
17336
  --bs-bg-opacity: 1;
17337
  background-color: #72AB5A !important;
17338
  }
static/js/sentence.js CHANGED
@@ -182,7 +182,7 @@ function createUserMessageElement(message) {
182
  userMessageContainer.classList.add('d-flex', 'flex-column', 'align-items-end');
183
  // Add message content
184
  var userMessageContent = document.createElement('div');
185
- userMessageContent.classList.add('bg-primary', 'text-white', 'p-2', 'px-3', 'rounded-2', 'mw-80');
186
  var userMessageText = document.createTextNode(message);
187
  userMessageContent.appendChild(userMessageText);
188
  userMessageContainer.appendChild(userMessageContent);
 
182
  userMessageContainer.classList.add('d-flex', 'flex-column', 'align-items-end');
183
  // Add message content
184
  var userMessageContent = document.createElement('div');
185
+ userMessageContent.classList.add('bg-chat', 'text-white', 'p-2', 'px-3', 'rounded-2', 'mw-80');
186
  var userMessageText = document.createTextNode(message);
187
  userMessageContent.appendChild(userMessageText);
188
  userMessageContainer.appendChild(userMessageContent);
static/js/sentence_fr.js CHANGED
@@ -182,7 +182,7 @@ function createUserMessageElement(message) {
182
  userMessageContainer.classList.add('d-flex', 'flex-column', 'align-items-end');
183
  // Add message content
184
  var userMessageContent = document.createElement('div');
185
- userMessageContent.classList.add('bg-primary', 'text-white', 'p-2', 'px-3', 'rounded-2', 'mw-80');
186
  var userMessageText = document.createTextNode(message);
187
  userMessageContent.appendChild(userMessageText);
188
  userMessageContainer.appendChild(userMessageContent);
 
182
  userMessageContainer.classList.add('d-flex', 'flex-column', 'align-items-end');
183
  // Add message content
184
  var userMessageContent = document.createElement('div');
185
+ userMessageContent.classList.add('bg-chat', 'text-white', 'p-2', 'px-3', 'rounded-2', 'mw-80');
186
  var userMessageText = document.createTextNode(message);
187
  userMessageContent.appendChild(userMessageText);
188
  userMessageContainer.appendChild(userMessageContent);
static/js/voice_fr.js ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const reset = document.getElementById("reset");
2
+ const currentClassProbabilitiesList = document.getElementById("class-probabilities");
3
+ const currentPredictedClass = document.getElementById('predicted-class');
4
+ const staticDiv = document.getElementById("static");
5
+ const dynamicDiv = document.getElementById("dynamic");
6
+ var chartData;
7
+
8
+ let mediaRecorder;
9
+ let audioChunks = [];
10
+
11
+ document.addEventListener('DOMContentLoaded', function() {
12
+ loadResults();
13
+ attachEventListeners();
14
+ });
15
+
16
+ function attachEventListeners() {
17
+ document.getElementById('startRecord').addEventListener('click', startRecording);
18
+ document.getElementById('stopRecord').addEventListener('click', stopRecording);
19
+ document.getElementById('uploadAudio').addEventListener('click', handleAudioUpload);
20
+ }
21
+
22
+ function initializeChart(data, backgroundColor, borderColor) {
23
+ const canvas = document.getElementById('bestSellers');
24
+
25
+ // Destroy existing chart if it exists
26
+ const existingChart = Chart.getChart(canvas);
27
+ if (existingChart) {
28
+ existingChart.destroy();
29
+ }
30
+
31
+ // Clear the canvas
32
+ const context = canvas.getContext('2d');
33
+ context.clearRect(0, 0, canvas.width, canvas.height);
34
+
35
+ data = data.map(function (element) {
36
+ return parseFloat(element).toFixed(2);
37
+ });
38
+
39
+ new Chart(canvas, {
40
+ type: 'doughnut',
41
+ data: {
42
+ datasets: [{
43
+ data: data,
44
+ backgroundColor: backgroundColor,
45
+ borderColor: borderColor,
46
+ borderWidth: 1
47
+
48
+ }]
49
+ },
50
+ options: {
51
+ responsive: true,
52
+ cutout: '80%',
53
+ plugins: {
54
+ legend: {
55
+ display: true,
56
+ },
57
+ tooltip: {
58
+ enabled: false
59
+ }
60
+ },
61
+ layout: {
62
+ padding: 0
63
+ },
64
+ elements: {
65
+ arc: {
66
+ borderWidth: 0
67
+ }
68
+ },
69
+ plugins: {
70
+ datalabels: {
71
+ display: false,
72
+ align: 'center',
73
+ anchor: 'center'
74
+ }
75
+ }
76
+ }
77
+ });
78
+ }
79
+
80
+ function loadResults() {
81
+ fetch('/voice_fr')
82
+ .then(response => response.text())
83
+ .then(html => {
84
+ const responseDOM = new DOMParser().parseFromString(html, "text/html");
85
+ const classProbabilitiesList = responseDOM.getElementById("class-probabilities");
86
+ currentClassProbabilitiesList.innerHTML = classProbabilitiesList.innerHTML;
87
+ const PredictedClass = responseDOM.getElementById("predicted-class")
88
+ currentPredictedClass.innerHTML = PredictedClass.innerHTML;
89
+
90
+ var canvasElement = responseDOM.querySelector('.bestSellers');
91
+ console.log(canvasElement);
92
+ chartData = canvasElement.getAttribute('data-chart');
93
+ console.log(chartData);
94
+ if (chartData) {
95
+ var parsedChartData = JSON.parse(chartData);
96
+ var data = parsedChartData.datasets[0].data.slice(0, 5);
97
+ var backgroundColor = parsedChartData.datasets[0].backgroundColor.slice(0, 5);
98
+ var borderColor = parsedChartData.datasets[0].borderColor.slice(0, 5);
99
+ var labels = parsedChartData.labels.slice(0, 5);
100
+
101
+ initializeChart(data, backgroundColor, borderColor, labels);
102
+ }
103
+ })
104
+ .catch(error => console.error('Error:', error));
105
+ }
106
+
107
+ function startRecording() {
108
+ navigator.mediaDevices.getUserMedia({ audio: true })
109
+ .then(stream => {
110
+ mediaRecorder = new MediaRecorder(stream);
111
+ mediaRecorder.start();
112
+
113
+ audioChunks = [];
114
+ mediaRecorder.addEventListener("dataavailable", event => {
115
+ audioChunks.push(event.data);
116
+ });
117
+
118
+ document.getElementById('startRecord').disabled = true;
119
+ document.getElementById('stopRecord').disabled = false;
120
+ });
121
+ }
122
+
123
+ function stopRecording() {
124
+ mediaRecorder.stop();
125
+ document.getElementById('startRecord').disabled = false;
126
+ document.getElementById('stopRecord').disabled = true;
127
+
128
+ mediaRecorder.addEventListener("stop", () => {
129
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
130
+ sendAudioToServer(audioBlob);
131
+ });
132
+ }
133
+
134
+ function handleAudioUpload() {
135
+ const fileInput = document.getElementById('audioFileInput');
136
+ if (fileInput.files.length > 0) {
137
+ const file = fileInput.files[0];
138
+ sendAudioToServer(file);
139
+ } else {
140
+ console.error('No file selected');
141
+ }
142
+ }
143
+
144
+ function sendAudioToServer(audioData) {
145
+ const formData = new FormData();
146
+
147
+ // Créer un nouveau Blob avec le type MIME audio/wav
148
+ const audioBlob = new Blob([audioData], { type: 'audio/wav' });
149
+
150
+ formData.append('audio', audioBlob, 'recorded_audio.wav');
151
+
152
+ document.getElementById('loadingIndicator').style.display = 'block';
153
+
154
+ // Effacer le graphique existant
155
+ const canvas = document.getElementById('bestSellers');
156
+ const existingChart = Chart.getChart(canvas);
157
+ if (existingChart) {
158
+ existingChart.destroy();
159
+ }
160
+ const context = canvas.getContext('2d');
161
+ context.clearRect(0, 0, canvas.width, canvas.height);
162
+
163
+ fetch('/voice_fr', {
164
+ method: 'POST',
165
+ body: formData
166
+ })
167
+ .then(response => response.text())
168
+ .then(html => {
169
+ const parser = new DOMParser();
170
+ const newDocument = parser.parseFromString(html, 'text/html');
171
+
172
+ // Update other parts of the page as before
173
+ // Update only the necessary parts of the page
174
+ document.getElementById('class-probabilities').innerHTML = newDocument.getElementById('class-probabilities').innerHTML;
175
+ document.getElementById('predicted-class').innerHTML = newDocument.getElementById('predicted-class').innerHTML;
176
+ document.getElementById('transcribedText').innerHTML = newDocument.getElementById('transcribedText').innerHTML;
177
+ document.getElementById('classifiedText').innerHTML = newDocument.getElementById('classifiedText').innerHTML;
178
+ dynamicDiv.classList.remove('d-none');
179
+ staticDiv.classList.add('d-none');
180
+ // Update chart
181
+ const newCanvasElement = newDocument.querySelector('.bestSellers');
182
+ if (newCanvasElement) {
183
+ const newChartData = newCanvasElement.getAttribute('data-chart');
184
+ if (newChartData) {
185
+ const parsedChartData = JSON.parse(newChartData);
186
+ initializeChart(
187
+ parsedChartData.datasets[0].data.slice(0, 5),
188
+ parsedChartData.datasets[0].backgroundColor.slice(0, 5),
189
+ parsedChartData.datasets[0].borderColor.slice(0, 5),
190
+ parsedChartData.labels.slice(0, 5)
191
+ );
192
+ }
193
+ }
194
+
195
+ document.getElementById('loadingIndicator').style.display = 'none';
196
+ })
197
+ .catch(error => {
198
+ console.error('Error:', error);
199
+ document.getElementById('loadingIndicator').style.display = 'none';
200
+ });
201
+ }
202
+ fetch('/voice_fr', {
203
+ method: 'POST',
204
+ body: formData
205
+ })
206
+ .then(response => response.text())
207
+ .then(html => {
208
+ const parser = new DOMParser();
209
+ const newDocument = parser.parseFromString(html, 'text/html');
210
+
211
+
212
+
213
+ // Update chart
214
+ const newCanvasElement = newDocument.querySelector('.bestSellers');
215
+ if (newCanvasElement) {
216
+ const newChartData = newCanvasElement.getAttribute('data-chart');
217
+ if (newChartData) {
218
+ const parsedChartData = JSON.parse(newChartData);
219
+ initializeChart(
220
+ parsedChartData.datasets[0].data.slice(0, 5),
221
+ parsedChartData.datasets[0].backgroundColor.slice(0, 5),
222
+ parsedChartData.datasets[0].borderColor.slice(0, 5),
223
+ parsedChartData.labels.slice(0, 5)
224
+ );
225
+ }
226
+ }
227
+
228
+ document.getElementById('loadingIndicator').style.display = 'none';
229
+ })
230
+ .catch(error => {
231
+ console.error('Error:', error);
232
+ document.getElementById('loadingIndicator').style.display = 'none';
233
+ });
templates/voice_fr.html CHANGED
@@ -228,7 +228,7 @@
228
  </div>
229
 
230
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
231
- <script src="../static/js/voice.js" type="text/javascript"></script>
232
  <script src="../static/js/vendor.bundle.base.js"></script>
233
  </body>
234
 
 
228
  </div>
229
 
230
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
231
+ <script src="../static/js/voice_fr.js" type="text/javascript"></script>
232
  <script src="../static/js/vendor.bundle.base.js"></script>
233
  </body>
234