I am reviewing this repository https://github.com/ibrahim4529/flask-chatbot to get an inspiration and see how a model can be deployed in a chat UI. I am able to do this in Flask but ran across a quirky situation that I am not sure how to resolve. The UI accepts the first initial message that I type, but when I try returning the response, I get an 'undefined' appended to every line that is supposed to be the bot's response. On CMD though, my function is returning response. I've provided screenshots below:
Here is my routing:
#app.route('/')
def hello():
return render_template('index.html')
#app.route('/ask', methods={'POST', 'GET'})
def ask():
if request.method == 'POST':
message = (request.form['messageText'])
bresponse = response(message)
return render_template('Index.html', bresponse=bresponse)
'response' is a function that spits out the response of the model (this is the 'Rrraawwwwg!' response from the input).
Below is the js that I reviewed from the link that I am using:
$('#chatbot-form').submit(function(e) {
e.preventDefault();
var message = $('#messageText').val();
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "text-align:right; color : #2EFE2E" class="media-body">' + message + '<hr/></div></div></div></li>');
$.ajax({
type: "POST",
url: "/ask",
data: $(this).serialize(),
success: function(response) {
//console.log(response);
$('#messageText').val('');
var answers = response.answers;
const chatPanel = document.getElementById("chatPanel");
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "color : white" class="media-body">' + answers + '<hr/></div></div></div></li>');
$(".fixed-panel").stop().animate({ scrollTop: $(".fixed-panel")[0].scrollHeight}, 1000);
I am not sure what I am missing. I am seeing the response in the cli, but seeing an undefined in the UI.
Thanks in advance!
I finally was able to make this work. I've updated ajax to below:
var answers = response;
$('#messageText').val();
I was also printing the response function, instead of returning it; reason I am seeing the response in the console and not in the view. This was the main culprit.
Related
I'm a beginner.
What I used was flask and pymongo.
If you press the button, it's "Like". It should be +1, but there is a key error at the bottom.
My python route code:
#app.route('/api/like', methods=['POST'])
def like_movie():
title_receive = request.form['title_give']
movie = db.toytoy.find_one({'title': title_receive})
current_like = movie['like']
new_like = current_like + 1
db.toytoy.update_one({'title': title_receive}, {'$set': {'like': new_like}})
return jsonify({'msg': 'like!'})
This is how I POST from JS
function like_movie(title) {
$.ajax({
type: 'POST',
url: '/api/like',
data: {title_give: title},
success: function (response) {
console.log(response)
alert(response['msg']);
window.location.reload();
}
});
}
I get an exception as below:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'title_give'
What I want is if it's 'like_btn'. If you press the button, it becomes +1.
The base problem in what you did is not respecting Content-type. From front JS, you are making a POST with JSON object. Which makes the request to have a content type of application/json.
In backend code, you use request.form which expects the request to be in the form encoded types (like application/x-www-form-urlencoded, multipart/form-data) etc.
So, you need to read the JSON content in backend, instead of reading from a form which is not available. Like below:
ui_req = request.get_json()
title_receive = ui_req['title_give']
And then parse other structures accordingly.
UPDATE
For me the Problem got fixed as soon as I was putting "encoding: URLEncoding(destination: .queryString)" in my request. Maybe this helps somebody else. link
I struggled the whole day to find the problem in my Alamofire PUT Request or the Flask Restful API. Request like GET, DELETE and POST are working fine with Alamofire, except the PUT Request.
When I'm using PUT Requests in combination with Postman and Flask-Restful everything is also working fine. But as soon as I'm trying to achieve the same Result with Alamofire, I'm not getting any parameters in Flask. I tried to illustrate this in the code examples.
So in short my example illustrates the following:
DELETE Request(Same with GET and POST)
Postman: success
Alamofire: success
PUT Request
Postman: success
Alamofire: failure (parameter dictionary empty in Flask-Restful)
Here is my Python Code [API Server]:
from flask import Flask, request, jsonify
from flask_restful import Resource, Api, reqparse
app = Flask(__name__)
api = Api(app)
class Stackoverflow(Resource):
def delete(self):
print(request.args)
if request.args.get('test-key') is None:
return jsonify({"message": "failure"})
else:
return jsonify({"message": "success"})
def put(self):
print(request.args)
if request.args.get('test-key') is None:
return jsonify({"message": "failure"})
else:
return jsonify({"message": "success"})
api.add_resource(Stackoverflow, '/stackoverflow')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
If I'm using Postman, I get this result (like expected):
Result in Postman
But now I'm trying to do the same with Alamofire in Swift. Same Server, nothing changed.
SWIFT demo Code [IOS APP]:
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
simplePUTRequest()
simpleDELETERequest()
}
func simplePUTRequest(){
AF.request("http://localhost:5000/stackoverflow", method: .put, parameters: ["test-key":"testvalue"])
.validate(statusCode: 200..<300)
.responseJSON { response in
if let data = response.data {
print("Result PUT Request:")
print(String(data: data, encoding: .utf8)!)
//print(utf8Text)
}else{
}
}
}
func simpleDELETERequest(){
AF.request("http://localhost:5000/stackoverflow", method: .delete, parameters: ["test-key":"testvalue"])
.validate(statusCode: 200..<300)
.responseJSON { response in
if let data = response.data {
print("Result DELETE Request:")
print(String(data: data, encoding: .utf8)!)
//print(utf8Text)
}else{
}
}
}
Xcode Console:
Result PUT Request:
{
"message": "failure"
}
Result DELETE Request:
{
"message": "success"
}
python Console (both Alamofire Requests):
ImmutableMultiDict([])
127.0.0.1 - - [15/Jun/2019 21:17:31] "PUT /stackoverflow HTTP/1.1" 200 -
ImmutableMultiDict([('test-key', 'testvalue')])
127.0.0.1 - - [15/Jun/2019 21:17:31] "DELETE /stackoverflow?test-key=testvalue HTTP/1.1" 200 -
As you can see, I'm getting the success message only while using the DELETE method.
Till now I tried using different encodings like URLEncoding.httpbody and URLEncoding.default, but nothing really helped.
For me it seems like it's a Alamofire/Swift Problem, because in Postman the same request method is working fine.
I would really appreciate your help, because I'm stuck and don't know anything further to do. I hope I didn't misunderstood something essential.
Thank you in advance!
I am currently using the same version AlamoFire, and when I use the PUT method, I use it as follows:
let request = AF.request(url, method: .put, parameters: ["uid": uid],
encoding: JSONEncoding.default, headers: headers)
request.responseJSON(completionHandler: { response in
guard response.error == nil else {
//Handle error
}
if let json = response.value as? [String: Any]
// Handle result.
}
The only difference to your post is that I used the encoding option. You can try to put the option and see what happens.
It looks like your server is expecting your PUT parameters to be URL form encoded into the URL. You may be hitting the version of the request method that uses JSON encoding by default, so adding encoder: URLEncodedFormParameterEncoder.default at the end of your request call should fix that. A future release will make that the default, as it's safe across all request types.
If that's not the issue, I suggest you investigate more closely to see what the differences between the requests may be. Since you control the server you should have easy access to the traffic.
I currently have a button, that when clicked, it creates two variables. These hold the selected options from a list box. Then I am attempting to POST these into my database via the bottle script, however it doesnt work. Can someone explain to me why?
The HTML/JQuery code for the button is this:
$("#btnStartEvent").bind("click", function () {
var selectedStudents = $('#lstBox2 option:selected');
var selectedEvent = $('#event_options option:selected');
alert(selectedEvent);
$.post( "/send_data", { eventIDPost: selectedEvent},function(data ) {
alert( data );
});
And my bottle code that handles this POST is:
#post('/send_data')
def send_data():
postdata = request.body.read()
events_id = request.forms.get("eventIDPost")
sql = "INSERT INTO tblResults VALUES('{}')".format(events_id)
run_sql(sql)
I am not sure if bottle #post is broken, but referencing to
http://bottlepy.org/docs/dev/api.html#bottle.Bottle.route
and updating the api method to below:
#app.route('/send_data', method=['POST'])
def send_data():
started listening to the API calls.Otherwise it was 405 error
Also please refer https://api.jquery.com/jquery.post/
$.post("/send_data", { "eventIDPost": 1 })
.done( function (data) {console.log(data)});
Hope this helps.
I can assure you that the #post is not broken. I use it every single day.
from bottle import post, request
def merge_dicts(*args):
result = {}
for dictionary in args:
result.update(dictionary)
return result
#post('/send_data')
def send_data():
return merge_dicts(dict(request.forms), dict(request.query.decode()))
HTML: I have a 'sign-up' form in a modal (index.html)
JS: The form data is posted to a python flask function: /signup_user
$(function () {
$('#signupButton').click(function () {
$.ajax({
url: '/signup_user',
method: 'POST',
data: $('#signupForm').serialize()
})
.done(function (data) {
console.log('success callback 1', data)
})
.fail(function (xhr) {
console.log('error callback 1', xhr);
})
})
});
Python/Flask:
#app.route('/signup_user', methods=['POST'])
def signup_user():
#Request data from form and send to database
#Check that username isn't already taken
#if the username is not already taken
if new_user:
users.insert_one(new_user)
message = "Success"
return message
#else if ussername is taken, send message to user viewable in the modal
else:
message = "Failure"
return message
return redirect(url_for('index'))
I cannot figure out how to get the flask function to return the "Failure" message to the form in the modal so that the user can change the username.
Right now, as soon as I click the submit button the form/modal disappears and the 'Failure' message refreshes the entire page to a blank page with the word Failure.
How do I get the error message back to display in the form/modal?
I think that the problem is that you have a redirect function in your signup_user script at the end. That is why the page refreshes and shows the message that is returned by the script.
So remove this line:
return redirect(url_for('index'))
And update your Ajax code to this:
$(function () {
$('#signupButton').click(function () {
$.ajax({
type: "post",
url: "postride.php",
data:dataString,
success: function (data) {
$('#signupMessages').html(data);
}
});
});
Python/Flask:
#app.route('/signup_user', methods=['POST'])
def signup_user():
#Request data from form and send to database
#Check that username isn't already taken
#if the username is not already taken
if new_user:
users.insert_one(new_user)
message = "Success"
return message
#else if ussername is taken, send message to user viewable in the modal
else:
message = "Failure"
return message
Let me know if this works.
This seems to be the correct syntax for AJAX according to https://codehandbook.org/python-flask-jquery-ajax-post/
$.ajax({
url: '/signup_user',
data: $('#signupForm').serialize(),
type: 'POST',
success: function(response) {
console.log(response);
},
error: function(error) {
console.log(error);
}
});
You could also try getJSON for shorthand:
$.getJSON('/signup_user',
$('#signupForm').serialize(),
function(res) {
console.log(res)
});
UPDATED:
In my own use, I have found that methods=['POST'] isn't necessary for ajax calls in flask's #app.route. I could be wrong.
The thing i will do is to first check if we're reaching the function, with a breakpoint on the function, for this you can use the python debugger, just putting this line:
import pdb; pdb.set_trace()
(just at the beginning of the function)
so it will be like this:
#app.route('/signup_user', methods=['POST'])
def signup_user():
#Request data from form and send to database
#Check that username isn't already taken
#if the username is not already taken
import pdb; pdb.set_trace()
if new_user:
users.insert_one(new_user)
message = "Success"
return message
#else if ussername is taken, send message to user viewable in the modal
else:
message = "Failure"
return message
So when you finally run the code and send the request, you should see the console with the python server running that is stopped by a like with this -> (pdb)
(if you dont see that "(pdb)" in the console just press enter to see if it appears)
if not stopped then you're just not entering the function,
otherwise you're in the function, good.. now let's take a look and debug a little bit, the first thing you could check is if we can enter in the else statement.. you can pass line by line just entering the letter "n" and pressing enter, so keep going until you enter in the else part, if so then you're actually returning the text "Failure"
if not, then you've just discovered a part of the problem..
some other options that you should check:
.- try pass parameters to the ajax function like the dataType: 'json'
.- try to see if you need to enable CORS for the python app
.- keep debuggin line by line
Good luck on that buddy
I got this working after much testing;
my ajax call needed:
event.preventDefault();
Also, my python function needed to have the redirect changed to a return.
So Architect was correct.
I also noticed that my wasn't appearing in the source view of the page, so there may have been some caching issue.
All contributors were correct in some way. It was just that I had a couple of different things wrong.
I'm writing a very simple demo webapp, and I can't seem to pass a json object from js to python using ajax.
I've tried a number of suggestions from people on so with similar problems, such as using .get_json() instead of .json, passing the object without using JSON.stringify in the javascript, etc.
Any idea what piece I'm missing here?
Javascript
var run_method = function(){
var data1 = {"word":"hello"}
console.log("Before " + data1);
$.ajax({
url : "/examplemethod",
type : "POST",
data : data1//JSON.stringify(data1)
})
.done(function(data){
var data = JSON.parse(data);
console.log(data);
});
}
Python
#app.route("/examplemethod", methods=['POST', 'GET'])
def example_method():
global data
if request.method == 'POST':
print request
data = request.json
print "data", data
return "after "+ data["word"]
Every variation I have tried of this gives a 500 Error, and
TypeError: 'NoneType' object has no attribute 'getitem'
Obviously, that is because data is supposed to be an dictionary/json, not None. But how to I get it to return as a dictionary?
Because you are not sending JSON, to the flask app (see this and this). Your current code results in a standard urlencoded form post. Which in turn results in an entry being populated in request.form
request.form.get('word')
Switch to a json post as per the guidelines in the above Q&As to access the data through request.json.
the data is likely not flowing to json if you are getting None, so you should jsonify the data. It will be coming in in the form of form.
from flask import jsonify
#app.route("/examplemethod", methods=['POST'])
def example_method():
data = jsonify(request.form).json
print(data) #will be in the form a json dict
return data['foo-key'] #can retrieve specific items with their key-pairs