-1

I am new to web development, I am trying to build an online recorder and send some data back as feedback from the audio(obtained by the click on upload in index.html) to results.html

I tried to make some print statements in my python flask app.py file to check if "POST" is fired on the event, it works and prints the list of data that I wanted in command prompt. But at the end it not redirecting to results.html and instead, it shows again index.html

majority of the code and implications are taken from

https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/

Record voice with recorder.js and upload it to python-flask server, but WAV file is broken

Python file

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
from flask import request
from flask import render_template
import os
import random
import datetime
from detections import clean_dir,get_speech_info
from shutil import copyfile
import numpy as np
import json
from flask import Flask, redirect, url_for, request

app = Flask(__name__)

questions = ['Tell Me About Yourself.',
'Why Should We Hire You?',
' What is Your Greatest Strength?',
'What is Your Greatest Weakness?',
'What Are Your Salary Expectations?',
'How Do You Handle Stress and Pressure?',
'Describe a Difficult Work Situation or Project and How You Handled It.',
'What Are Your Goals for The Future?',
]


@app.route('/<usr>',methods = ['GET'])  
def user(usr):
    return f"<h1>hello {usr}</h1>"

data = np.zeros((6))

@app.route("/", methods=['POST', 'GET'])
def index():
    num1 = random.randint(0, len(questions)-1)
    ques = questions[num1]
    

    if request.method == "POST":
        f  = request.files['audio_data']
        basepath = os.path.dirname(__file__)
        x = str(datetime.datetime.now()).replace(" ", "").replace(":","").replace(".","-")+'.wav'

        clean_dir(basepath+'/audio/')

        with open('audio/'+x, 'wb') as audio:
            f.save(audio)
        
        print('file uploaded successfully')

        global data
        data = np.array(get_speech_info(basepath+'/rough')[0])

        clean_dir(basepath+'/rough/')
        print(data,'post is fired')
        return render_template('results.html', data=data)

    else:
        print(data,'basic file')
        return render_template("index.html",q = ques)

if __name__ == "__main__":
    app.run(debug = True)

JavaScript

//webkitURL is deprecated but nevertheless
URL = window.URL || window.webkitURL;

var gumStream;                      //stream from getUserMedia()
var rec;                            //Recorder.js object
var input;                          //MediaStreamAudioSourceNode we'll be recording

// shim for AudioContext when it's not avb.
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext //audio context to help us record

var recordButton = document.getElementById("recordButton");
var stopButton = document.getElementById("stopButton");
var pauseButton = document.getElementById("pauseButton");

//add events to those 2 buttons
recordButton.addEventListener("click", startRecording);
stopButton.addEventListener("click", stopRecording);
pauseButton.addEventListener("click", pauseRecording);

window.onload = function () { console.log({{ val }}) };
    function sendData() {
        var str = 'This is some data';
        $.ajax({
            url: '/newData',
            type: 'POST',
            data: str,
            success: function (res) { console.log(res) }, 
              // res is the response from the server 
              // (from return request.data)
            error: function (error) { console.log(error) }
        })
    }



function startRecording() {
    console.log("recordButton clicked");

    /*
        Simple constraints object, for more advanced audio features see
        https://addpipe.com/blog/audio-constraints-getusermedia/
    */

    var constraints = { audio: true, video:false }

    /*
        Disable the record button until we get a success or fail from getUserMedia()
    */

    recordButton.disabled = true;
    stopButton.disabled = false;
    pauseButton.disabled = false

    /*
        We're using the standard promise based getUserMedia()
        https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
    */

    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
        console.log("getUserMedia() success, stream created, initializing Recorder.js ...");

        /*
            create an audio context after getUserMedia is called
            sampleRate might change after getUserMedia is called, like it does on macOS when recording through AirPods
            the sampleRate defaults to the one set in your OS for your playback device

        */
        audioContext = new AudioContext();

        //update the format
        document.getElementById("formats").innerHTML="Format: 1 channel pcm @ "+audioContext.sampleRate/1000+"kHz"

        /*  assign to gumStream for later use  */
        gumStream = stream;

        /* use the stream */
        input = audioContext.createMediaStreamSource(stream);

        /*
            Create the Recorder object and configure to record mono sound (1 channel)
            Recording 2 channels  will double the file size
        */
        rec = new Recorder(input,{numChannels:1})

        //start the recording process
        rec.record()

        console.log("Recording started");

    }).catch(function(err) {
        //enable the record button if getUserMedia() fails
        recordButton.disabled = false;
        stopButton.disabled = true;
        pauseButton.disabled = true
    });
}

function pauseRecording(){
    console.log("pauseButton clicked rec.recording=",rec.recording );
    if (rec.recording){
        //pause
        rec.stop();
        pauseButton.innerHTML="Resume";
    }else{
        //resume
        rec.record()
        pauseButton.innerHTML="Pause";

    }
}

function stopRecording() {
    console.log("stopButton clicked");

    //disable the stop button, enable the record too allow for new recordings
    stopButton.disabled = true;
    recordButton.disabled = false;
    pauseButton.disabled = true;

    //reset button just in case the recording is stopped while paused
    pauseButton.innerHTML="Pause";

    //tell the recorder to stop the recording
    rec.stop();

    //stop microphone access
    gumStream.getAudioTracks()[0].stop();

    //create the wav blob and pass it on to createDownloadLink
    rec.exportWAV(createDownloadLink);
}

function createDownloadLink(blob) {

    var url = URL.createObjectURL(blob);
    var au = document.createElement('audio');
    var li = document.createElement('li');
    var link = document.createElement('a');

    //name of .wav file to use during upload and download (without extendion)
    var filename = new Date().toISOString();

    //add controls to the <audio> element
    au.controls = true;
    au.src = url;

    //save to disk link
    link.href = url;
    link.download = filename+".wav"; //download forces the browser to donwload the file using the  filename
    link.innerHTML = "Save to disk";

    //add the new audio element to li
    li.appendChild(au);

    //add the filename to the li
    li.appendChild(document.createTextNode(filename+".wav "))

    //add the save to disk link to li
    li.appendChild(link);

    //upload link
    var upload = document.createElement('a');
    upload.href="/";
    upload.innerHTML = "Predict";
    upload.addEventListener("click", function(event){
          var xhr=new XMLHttpRequest();
          xhr.onload=function(e) {
              if(this.readyState === 4) {
                  console.log("Server returned: ",e.target.responseText);
              }
          };
          var fd=new FormData();
          fd.append("audio_data",blob, filename);
          xhr.open("POST","/",true);
          xhr.send(fd);
    })
    li.appendChild(document.createTextNode (" "))//add a space in between
    li.appendChild(upload)//add the upload link to li

    //add the li element to the ol
    recordingsList.appendChild(li);
}

Index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Simple Recorder.js demo with record, stop and pause - addpipe.com</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
  <script src="https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">



</head>

<body>
  <nav class="navbar navbar-dark bg-primary">
    <a class="navbar-brand" href="#">
      My Prosodic Features
    </a>
  </nav>

  <div id ="controls" class="container">
  <div class="row">
    <div class="col-sm">
      <div class="jumbotron">
        <h1 class="display-4">Hello, People!</h1>
        <p class="lead">This is a simple unit,since its campus placement season I wanted to help my friends to know about their prosodic skills.</p>
        <p class='lead'>I have used python libraries like librosa and PRAAT for speech processing techniques along with Tensorflow for detection of certain tasks</p>

        <hr class="my-4">
        <p>We just wanted you know that the results are not 100% accurate, but it provides you some idea about your presentation and speaking skills.</p>
        <p>What we do is give some random question and you try to answer it. Make sure you limit yourself upto 1 minute for a preparation time so that you can perform well in real interviews. </p>
        <!-- <p class="lead">
        <a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a>
      </p> -->
      </div>
    </div>
    <div  class="col-sm">
      <div class="col-sm">
        <div class="jumbotron">
          <h1 class="display-4"> Question</h1>
          <p class = 'lead'>{{ q }}</p>

          <p class = 'lead'>
            <ol>
            <li>Click on Record button</li>
            <li>Speak for 5 minutes</li>
            <li>Click on upload button</li>
            </ol>
            <hr class="my-4">

          </p>

                  <button id="recordButton">Record</button>
                  <button id="pauseButton" disabled>Pause</button>
                  <button id="stopButton" disabled>Stop</button>
                  <div id="formats">Format: start recording to see sample rate</div>
                  <p><strong>Recordings:</strong></p>
                  <ol id="recordingsList"></ol>

        </div>
      </div>

    </div>

  </div>

</div>
  <!-- <div id="controls">
    <button id="recordButton">Record</button>
    <button id="pauseButton" disabled>Pause</button>
    <button id="stopButton" disabled>Stop</button>
  </div>
  <div id="formats">Format: start recording to see sample rate</div>
  <p><strong>Recordings:</strong></p>
  <ol id="recordingsList"></ol> -->
  <!-- inserting these scripts at the end to be able to use all the elements in the DOM -->
  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>

  <script src="https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js"></script>
  
  <script src={{ url_for('static', filename='js/app.js') }}></script>

</body>

</html>

results.html file

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
  <script src="https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">

</head>

<!-- nsyll, npause, dur (s), phonationtime (s), speechrate (nsyll/dur), articulation rate (nsyll / phonationtime), -->

<body>
    <table class="table">
        <thead class="thead-dark">
          <tr>
            <th scope="col">#</th>
            <th scope="col">Feature</th>
            <th scope="col">Result</th>
            <th scope="col">Average Result</th>
          </tr>
        </thead>
        <tbody>

          <tr>
            <th scope="row">1</th>
            <td>nsyll</td>
            <td>{{ data[0] }}</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>npause</td>
            <td>{{ data[1] }}</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>dur</td>
            <td>{{ data[2] }}</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">4</th>
            <td>phonationtime</td>
            <td>{{ data[3] }}</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">5</th>
            <td>speechrate</td>
            <td>{{ data[4] }}</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">6</th>
            <td>articulation rate</td>
            <td>{{ data[5] }}</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>
</body>

1 Answers1

0

The template files should be in a folder called templates on the same directory level as your python file.

For example

project
|---run.py
|---templates
|   |---index.html
|   |---results.html
|---static
    |---js
        |---app.js
Nimantha
  • 6,405
  • 6
  • 28
  • 69