在烧瓶方法内运行while循环

时间:2019-08-20 12:47:58

标签: python flask chatbot

我正在使用聊天机器人,我想将聊天机器人模型链接到Web UI(index.html)。我是烧瓶和python的新手。我需要从Web界面获取用户输入,并将其作为“ user_input”发送到模型。然后,我需要获取响应“ answer”,并将user_input和answer作为POST发送到新呈现的index.html中。由于答案是在while循环内生成的,因此我仍然无法在运行while循环的同时将其作为POST请求发送。在此while循环内使用user_input生成答案。

def chatbot(net, sess, chars, vocab, max_length, beam_width, relevance, temperature, topn):
    states = initial_state_with_relevance_masking(net, sess, relevance)

    user_input = ''
    answer = ''

    app = Flask(__name__)

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

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

    while True:

        @app.route('/process',methods=['POST'])
        def process():
            user_input=request.form['user_input']
            return user_input, render_template('index.html', user_input=user_input)
            #return render_template('index.html', user_input=user_input)

        if user_input == 'GoodBye':
            break
        user_command_entered, reset, states, relevance, temperature, topn, beam_width = process_user_command(
            user_input, states, relevance, temperature, topn, beam_width)
        if reset: states = initial_state_with_relevance_masking(net, sess, relevance)
        if not user_command_entered:
            states = forward_text(net, sess, states, relevance, vocab, sanitize_text(vocab, "> " + user_input + "\n>"))
            computer_response_generator = beam_search_generator(sess=sess, net=net,
                initial_state=copy.deepcopy(states), initial_sample=vocab[' '],
                early_term_token=vocab['\n'], beam_width=beam_width, forward_model_fn=forward_with_mask,
                forward_args={'relevance':relevance, 'mask_reset_token':vocab['\n'], 'forbidden_token':vocab['>'],
                                'temperature':temperature, 'topn':topn})
            out_chars = []
            for i, char_token in enumerate(computer_response_generator):
                out_chars.append(chars[char_token])
                #print(possibly_escaped_char(out_chars), end='', flush=True)
                states = forward_text(net, sess, states, relevance, vocab, chars[char_token])
                if i >= max_length: break
            answer = ''.join(out_chars)
            print('Bot:' + answer)
            states = forward_text(net, sess, states, relevance, vocab, sanitize_text(vocab, "\n> "))

下面是index.html的HTML代码

<!DOCTYPE html>
<html>
<head>
    <title>Friend Chatbot</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
    <div class="alert alert-primary" role="alert">
User: {{user_input}}
</div>
<div class="alert alert-dark" role="alert">
  Freind: {{answer}}
</div>


    <form  action="/process" method="POST">
  <div class="form-group">
    <label for="exampleInputEmail1">Friend Chatbot</label>
    <input type="text" name="user_input" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Talk to my friend"><br>
  <button type="submit" class="btn btn-primary">Send</button>
</form>
</div>
</body>
</html>

我希望在POST请求中同时获取user_input和index.html网页的答案,而while循环中的每一次重复。我试图将POST烧瓶方法放入while循环内,但是它不起作用。我该如何实现?

1 个答案:

答案 0 :(得分:0)

我可以在这里看到几个问题:

  1. 这里很多东西混合在一起,应该分开
  2. 您需要的循环是由用户向烧瓶发出请求而形成的,而不是一会儿
  3. 这并没有真正考虑到Web请求的异步性质(但这可能没关系)

首先,它可能比将生成响应的责任和处理Web请求的任务混合在一起的方法更令人困惑。因此,我们将拆分聊天机器人部分:

def get_chatbot(net, sess, chars, vocab, max_length, beam_width, relevance, temperature, topn):
    states = initial_state_with_relevance_masking(net, sess, relevance)

    def get_response(user_input):
        nonlocal states
        if user_input == 'GoodBye':
            # What do we expect to happen here?
            return

        user_command_entered, reset, states, relevance, temperature, topn, beam_width = process_user_command(
            user_input, states, relevance, temperature, topn, beam_width)

        if reset: 
            states = initial_state_with_relevance_masking(net, sess, relevance)

        if not user_command_entered:
            states = forward_text(net, sess, states, relevance, vocab, sanitize_text(vocab, "> " + user_input + "\n>"))
            computer_response_generator = beam_search_generator(sess=sess, net=net,
                initial_state=copy.deepcopy(states), initial_sample=vocab[' '],
                early_term_token=vocab['\n'], beam_width=beam_width, forward_model_fn=forward_with_mask,
                forward_args={'relevance':relevance, 'mask_reset_token':vocab['\n'], 'forbidden_token':vocab['>'],
                                'temperature':temperature, 'topn':topn})
            out_chars = []
            for i, char_token in enumerate(computer_response_generator):
                out_chars.append(chars[char_token])
                #print(possibly_escaped_char(out_chars), end='', flush=True)
                states = forward_text(net, sess, states, relevance, vocab, chars[char_token])
                if i >= max_length: break

            states = forward_text(net, sess, states, relevance, vocab, sanitize_text(vocab, "\n> "))
            return ''.join(out_chars)

    return get_response

此函数返回一个函数,该函数将接受用户输入并提供答案。当它围绕状态和其他变量形成闭包时,它将记住所有的args和先前的状态。 (看起来确实如此,这似乎更像是class的候选人)。

现在,我们可以担心需要单独提供Web内容:

app = Flask(__name__)
chatbot = get_chatbot(... args here ...)


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


@app.route('/process', methods=['POST'])
def process():
    user_input = request.form['user_input']

    answer = chatbot(user_input)
    if answer is None:
        # Really do you want to bail out here?
        exit()

    return user_input, render_template(
        'index.html', user_input=user_input, answer=answer)


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

请注意,process()函数之外的所有代码现在都可以通过调用chatbot()在其内部执行。这是您看不到任何输出的主要原因。

那么循环在哪里去了?运行良好的烧瓶会形成事件循环。它总是在等待输入并提供输出。主要区别在于此循环是异步,这意味着许多事情可以一次发生,而且会发生混乱。

如果您自己慢慢地与机器人聊天,这可能没关系,但是如果您一个接一个地快速发出两个请求,或者两个人同时聊天,这将成为一个更大的问题。这种处理需要花更多的钱,例如,给每个用户一个唯一的“对话” ID或类似的东西,然后分别跟踪每个用户的状态。