简体   繁体   English

Flask 正在接收 GET 请求而不是 POST

[英]Flask is receiving a GET request instead of POST

I am creating a web app that records audio in the browser and sends it to the flask backend for voice to text transcription and intent classification.我正在创建一个 web 应用程序,它在浏览器中记录音频并将其发送到 flask 后端,用于语音到文本的转录和意图分类。 When I run the code without checking the method (the code for that is commented out) this is what the command line is showing.当我在不检查方法的情况下运行代码时(代码被注释掉),这就是命令行显示的内容。

127.0.0.1 - - [11/Jan/2021 06:50:00] "GET /result HTTP/1.1" 500 -
Traceback (most recent call last):
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\Admin\Desktop\Voice Assistant web\voice_assistant.py", line 22, in result
    file = request.files['audio_data']
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\flask\debughelpers.py", line 96, in __getitem__
    return oldcls.__getitem__(self, key)
  File "C:\Users\Admin\Desktop\Voice Assistant web\virtualenv\lib\site-packages\werkzeug\datastructures.py", line 442, in __getitem__
    raise exceptions.BadRequestKeyError(key)
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'audio_data'
127.0.0.1 - - [11/Jan/2021 06:50:00] "GET /result?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [11/Jan/2021 06:50:00] "GET /result?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [11/Jan/2021 06:50:00] "GET /result?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [11/Jan/2021 06:50:00] "GET /result?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
hello
2021-01-11 06:50:11.906955: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:116] None of the MLIR optimization passes are enabled (registered 2)
There is 78 percent chance that you are trying to get the weather!
127.0.0.1 - - [11/Jan/2021 06:50:13] "POST /result HTTP/1.1" 200 -

As you can see it first tries with GET method and returns an error.如您所见,它首先尝试使用 GET 方法并返回错误。 After that it tries with a POST request and the result is returned in the command line but never displayed in the browser - the error message stays there.之后,它尝试使用 POST 请求,结果在命令行中返回,但从未显示在浏览器中 - 错误消息保留在那里。 When I check if the method is POST or GET it executes the code with GET.当我检查方法是 POST 还是 GET 时,它会使用 GET 执行代码。 How can I make it receive the POST request?如何让它接收 POST 请求?

This is my python code.这是我的 python 代码。

from flask import Flask, render_template, request, redirect, url_for
from werkzeug.utils import secure_filename
import os

from intent_classification import ICModel
from voice_to_text import VTTModel

IC = ICModel()
VTT = VTTModel()

app=Flask(__name__)
app.config['AUDIO_UPLOADS'] = 'audio_file/'

@app.route("/")
def home():
    return render_template("index.html")

@app.route("/result", methods=['POST','GET'])
def result():
    #if(request.method=='POST'):
        print(request.files)
        file = request.files['audio_data']
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['AUDIO_UPLOADS'], filename))
        actual_file = 'audio_file/' + filename
        
        text = VTT.infer(actual_file)
        print(text)
        intent = IC.predict(text)
        print(intent)
        
        os.remove(actual_file)
        
        return render_template("result.html", pred = intent, text = text)
    #else:
        #return redirect(url_for('home'))

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

And this is my html.这是我的 html。

{% extends "base.html" %}

{% block content %}
    <h1 class="font-bold text-5xl text-white mt-5 mb-10">What is on your mind?</h1>
    <div class="flex items-center">
        <img id="record" src="/static/images/record.jpg" alt="record" 
            width="150px" height="150px" class="rounded-xl mx-10" 
            onClick="startRecording()">
        <img id="stop" src="/static/images/stop.jpg" alt="stop" 
            width="150px" height="150px" class="rounded-xl mx-10"
            onClick="stopRecording()">
    </div>
    <form action="/result" method="POST">
        <input type="submit" id="check" 
            class="rounded-lg bg-green-400 hover:bg-green-600 shadow-lg text-xl text-white font-bold my-6 px-16 py-1"
            onclick="upload()" value="Check intent">
    </form>
    <h2 id="prompt" class="font-bold text-3xl text-white my-10" hidden="true">Listening...</h2>
    <div>
        <h3 class="text-3xl text-white mt-10 mb-5">
            You can request the following:
        </h3>
        <ul class="text-xl text-white text-center">
            <li>adding a song to a playlist</li>
            <li>playing music</li>
            <li>booking a table at a restaurant</li>
            <li>getting the weather</li>
            <li>searching for creative work</li>
            <li>rating a book</li>
            <li>searching for a screening event</li>
        </ul>
    </div>
    <script>
        URL = window.URL || window.webkitURL;
        var gumStream;
        var rec;
        var input;
        var AudioContext = window.AudioContext || window.webkitAudioContext;
        var audioContext = new AudioContext;
        var constraints = {
            audio: true,
            video: false
        } 

        var recordButton = document.getElementById("record");
        var stopButton = document.getElementById("stop");
        var checkButton = document.getElementById("check")
        var promptMessage = document.getElementById("prompt");

        recordButton.disabled=false;
        stopButton.disabled=true;
        checkButton.disabled=true;
        promptMessage.hidden = true;

        function startRecording()
        {
            console.log("Recording started.")
            recordButton.disabled = true;
            stopButton.disabled = false;
            promptMessage.hidden=false;

            navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
                console.log("getUserMedia() success, stream created, initializing Recorder.js ..."); 
                gumStream = stream;
                input = audioContext.createMediaStreamSource(stream);
                rec = new Recorder(input, {
                    numChannels: 1
                }) 
                rec.record()
            }).catch(function(err) {
                recordButton.disabled = false;
                stopButton.disabled = true;
                promptMessage.hidden=true;
            });
        }

        function stopRecording()
        {
            console.log("Recording stopped.")
            stopButton.disabled = true;
            recordButton.disabled = false;
            checkButton.disabled = false;
            promptMessage.hidden=true;
            rec.stop();
            gumStream.getAudioTracks()[0].stop();
        }

        function upload()
        {
            console.log("Audio being exported.")
            checkButton.disabled = true;
            var filename = "audio_recording.wav";
            rec.exportWAV(function(blob) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState == XMLHttpRequest.DONE) {
                        alert(xhr.responseText);
                    }
                }
                var fd = new FormData();
                fd.append('audio_data', blob, filename);
                /* try {
                    let r = await fetch('/result', {method: "POST", body: fd}); 
                    console.log('HTTP response code:',r.status); 
                } catch(e) {
                    console.log(e);
                } */
                var xhr = new XMLHttpRequest();
                xhr.open('POST', '/result', true);
                xhr.send(fd);
            });
        }
    </script>
{% endblock %}

You are right.你说的对。
The form is sent before a transmission via fetch or XMLHttpRequest takes place.该表单在通过 fetch 或 XMLHttpRequest 进行传输之前发送。 You can use the submit event of the form to execute your javascript function.您可以使用表单的提交事件来执行您的 javascript function。 Calling preventDefault prevents the standard behavior of the form.调用preventDefault会阻止表单的标准行为。

 <form onsubmit="upload(event)">
   <input type="submit" value="Check intent" />
 </form>
function upload(evt) {
  evt.preventDefault();
  let filename = "audio_recording.wav";
  rec.exportWAV(function(blob) {
    let fd = new FormData();
    fd.append("audio_data", blob, filename);
    fetch("/result", { method: "POST", body: fd })
      .then(resp => { console.log(resp); })
      .catch(err => { console.error(err); });
  });
}

How would you like to use the server's response?您想如何使用服务器的响应?

Currently you use an ajax function in the browser and send a response from the server in the form of an html page.当前,您在浏览器中使用 ajax function 并以 html 页面的形式从服务器发送响应。 If you would use jsonify you could use the server's response in JSON format on the client side.如果您使用jsonify ,您可以在客户端使用 JSON 格式的服务器响应。
I also recommend that you check whether the audio file has been transferred.我还建议您检查音频文件是否已传输。
The following is a quick and dirty approach.以下是一种快速而肮脏的方法。

from flask import jsonify, make_response # , abort

@app.route('/result', methods=['POST'])
def result():
    print(request.files)
    af = request.files.get('audio_data')
    if not af: # if 'audio_data' not in request.files
        # see also abort(400, description='missing audio data')
        return make_response(jsonify(error='missing audio data'), 400)

    # ... process your audio file here ...

    return jsonify(text="lorem ipsum", intent="no-idea");
fetch('/result', { method: "POST", body: fd })
  .then(resp => resp.json())
  .then(data => {
    if ("error" in data) {
      console.error(data.error);
    } else {
      console.log(data);
      let elem;
      if (elem = document.getElementById("output")) elem.innerHTML = data.text;
      if (elem = document.getElementById("intent")) elem.innerHTML = data.intent;
    }
  })
  .catch(err => { console.error(err); });

Depending on your requirements, you should take a look at theWeb Speech API .根据您的要求,您应该查看Web 语音 API

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM