javascript - 无法使用烧瓶和 render_template 选项获取所需的 html 页面
问题描述
我是网络开发的新手,我正在尝试构建一个在线记录器并将一些数据作为音频的反馈(通过单击 index.html 中的上传获得)发送回 results.html
我尝试在我的 python flask app.py 文件中创建一些打印语句,以检查是否在事件中触发了“POST”,它可以工作并在命令提示符中打印我想要的数据列表。但最后它没有重定向到 results.html 而是再次显示 index.html
大部分代码和含义取自
https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/
用 recorder.js 录制语音并将其上传到 python-flask 服务器,但 WAV 文件已损坏
Python 文件
#!/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);
}
索引.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>
结果.html 文件
<!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>
解决方案
模板文件应位于templates
与您的 python 文件位于同一目录级别的文件夹中。
例如
project
|---run.py
|---templates
| |---index.html
| |---results.html
|---static
|---js
|---app.js
推荐阅读
- python - 悬停在 matplotlib 节点上
- algolia - Algolia 如何在规则中添加特定条件时隐藏所有结果?
- laravel - 为 Vue v3 导入 Vue-luxon - this.$luxon 不是函数错误
- android - 如何在不更改 Android 移动 Wi-Fi 设置中的默认 DNS 的情况下以编程方式仅在特定应用上设置 DNS?
- php - 如何禁用我不使用的 PHP 扩展?
- javascript - 解析 XML 时在主线程上同步 XMLHttpRequest
- sql - 如何使用私有过程创建 Oracle 包?
- swift - 自定义类列表,快速更新视图
- c# - 具有混合属性的继承类列表
- python - 发送请求时出现 Content-Type 错误