POST method to upload file with json object in python flask app - python

I am stuck in a problem where I am trying to build single API which will upload file along with json object. I need this API to create webhook.
Using multi part, I am able to upload file and in option filed I am able to send json object.
In flask app when I am trying to retrieve json object its converting as blob type. I tried to convert it base64 then again converting into string but whole process is not working.
Let me know if anyone has good solution I can combine file and json object together and fetch it by flask python app.
zz is the variable in my code where I am trying to store my json object. name is the field where I am passing my json object with file.
Thanks in advance.
My current code
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route('/upload/',methods = ['POST'])
def upload():
customer_name='abc'
if request.method == 'POST':
zz=base64.b64encode(request.files['name'].read())
try:
file = request.files['file']
if file:
file.filename=customer_name+'_'+str(datetime.now())+'.'+file.filename.split('.')[-1]
filename = secure_filename(file.filename)
path=os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(path)
return jsonify({
'status':success,
'junk_data':[],
'message':error
})
except Exception as err:
logger.error(str(datetime.now())+' '+str(err))
return jsonify({
'status':False,
'junk_data':[],
'message':str(err)
})
if __name__ == '__main__':
app.run(host='localhost',debug=True, use_reloader=True,port=5000)

I have got the answer after lot R&D.
request format
//user any client-side
content-type:multipart/form-data
file: file need to upload
data: {"name":"abc","new_val":1}
python code to fetch from request object
data=json.loads(request.form.get('data'))
file = request.files['file']

Just send the file and json at once and let request handle the rest.
You can try the code below:
Server side:
import json
import os
from flask import Flask, request
from werkzeug import secure_filename
app = Flask(__name__)
#app.route('/test_api',methods=['GET','POST'])
def test_api():
uploaded_file = request.files['document']
data = json.load(request.files['data'])
filename = secure_filename(uploaded_file.filename)
uploaded_file.save(os.path.join('path/where/to/save', filename))
print(data)
return 'success'
if __name__ == '__main__':
app.run(host='localhost', port=8080)
Client Side:
import json
import requests
data = {'test1':1, 'test2':2}
filename = 'test.txt'
with open(filename, 'w') as f:
f.write('this is a test file\n')
url = "http://localhost:8080/test_api"
files = [
('document', (filename, open(filename, 'rb'), 'application/octet')),
('data', ('data', json.dumps(data), 'application/json')),
]
r = requests.post(url, files=files)
print(r)

Related

How to read blob data in Python

From Salesforce File, I want to read the file and get the content between some text and store it in the Custom object record field.
For this, I have created an external API(python script deployed to heroku) where I am sending the file content as blob(basically the content of the file is Blob in Salesforce
).
Now I want to read the file and get the text. But I was not able to read the blob data.
If I convert the blob to string in SF while posting and decode it in python also doesn't work. Please give some inputs on this. I am new to python.
my python code :
from flask import Flask, request, jsonify
import base64
import blob
app = Flask(__name__)
#app.route('/get/record/', methods=['GET', 'POST','DELETE', 'PATCH'])
def index():
if request.method == 'POST':
print("===inside===")
payload_list = request.get_json(force=True)
print("====next line payload_list ===")
print(blob(payload_list["BlobData"])
# responseStr = str(payload_list["BlobData"])
# print("===decodedata===")
# print(base64.b64decode(responseStr))
return "sucesss"
Salesforce Rest Code:
List<ContentVersion> cv = [SELECT ContentDocumentId,VersionData from ContentVersion
where ContentDocumentId = 'xxxxxxxxxx' order by CreatedDate DESC];
String bodyEncoded = EncodingUtil.base64Encode(cv[0].versiondata);
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://realpyth.herokuapp.com/get/fileService/');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setBody('{"BlobData":"'+cv[0].versiondata+'"}'); // Send the data as Blob
//request.setBody('{"BlobData":"'+bodyEncoded+'"}'); // Convert the blob data and send as String
HttpResponse response = http.send(request);
if (response.getStatusCode() != 201) {
System.debug('=======' +response.getStatusCode() + ' ' + response.getBody());
} else {
System.debug('====response==='+response.getBody());
}

Trying to send an audio file and text to flask api but getting 400 bad request error

So, i am trying to send an audiofile and text as arguments to a flask api, it works fine when i send them through postman but i get a bad request error when i post it through python code.
Here is my python code:
import requests
import json
url= 'http://192.168.100.14:8000/v1/translate'
with open('/home/faizi/ai-chatbot-with-voice-driven-facial-animation/01_smalltalk_bot/game.wav', 'rb') as file:
files = {'input_file': file}
d = {"text":"hello, my name is faizan"}
req = requests.post(url, files=files, json=d)
print(req.status_code)
print(req.text)
And here is my flask api:
from flask import Flask
from flask_cors import cross_origin
from flask import Blueprint, request, Response
import json
from Voice_Cloning_Module import demo_cli
from flask import send_file
app = Flask("foo")
#app.route('/v1/translate', methods=['POST', 'OPTIONS'])
#cross_origin()
def translate_mbart():
data = request.get_json()
audio_file = request.files['input_file']
audio_file.save("./bufferaudiofile/"+audio_file.filename)
text = request.form['text']
returnedfile = demo_cli.clone(text,"./bufferaudiofile/"+audio_file.filename)
path_to_clonefile = returnedfile
return send_file(
path_to_clonefile,
mimetype="audio/wav",
as_attachment=True,
attachment_filename="test.wav")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
I am getting 400 bad request error and i dont understand what could be the issue, it works fine in postman
I was able to successfully send a wav file using the following code. I suggest stripping it back to bare bones and focussing on receiving the file to make sure nothing else is causing the issue.
For the API:
from flask import Flask
from flask import request
import json
app = Flask(__name__)
#app.route('/main', methods=['POST', 'OPTIONS'])
def main():
file = request.files['file']
print(file)
return { "ok": True }
if __name__ == '__main__':
app.run(host = 'localhost', port = 8000)
And for the request:
import requests
import json
url = 'http://localhost:8000/main'
with open('test_file.wav', 'rb') as wav:
files = { "file": wav }
d = { "body" : "Foo Bar" }
req = requests.post(url, files=files, json=d)
print(req.status_code)
print(req.text)

Can we include both JSON payload and CSV File using form-data in POSTMAN?

I am trying to send a POST request to my Python Flask Server. I tried to send a CSV file using the form-data option of POSTMAN. It was successfully received by the Flask server.
Now, I want to send a JSON payload along with the CSV file which will consist of the User credentials.
I tried the below method but it does not seem to be working. Although, I am receiving the CSV file but the JSON is still not received by the Flask server.
class Upload_File(Resource):
def post(self):
file_ = request.files['file']
Q_data = pd.read_csv(file_, header=None, names=['Questions'])
print(Q_data) # successfully displays file content
data = request.get_json(force=True) # gives None
EDIT
The issue was with the Flask code. The working code is -
class Upload_File(Resource):
def post(self):
file_ = request.files['file']
Q_data = pd.read_csv(file_, header=None, names=['Questions'])
print(Q_data) # successfully displays file content
username = request.form.get('username') # modified
password = request.form.get('password') # modified
The request is parsed as Form data. So, you need to check whether you can get it via request.post dictionary.
Example:
class Upload_File(Resource):
def post(self):
file_ = request.files['file']
Q_data = pd.read_csv(file_, header=None, names=['Questions'])
print(Q_data) # successfully displays file content
data = request.post['admin']

Send Presentation object as http response for download.

I am trying to develop a flask server which generates a presentation object based on json data and files from a HTTP Post request.
I am able to generate the file locally with same code but when I try to send it as an http response is fails.
Here is the code snippet for sending it as an http response -
prs_file_io = BytesIO()
prs.save(prs_file_io)
resp = Response()
resp.status_code = 200
resp.set_data(prs_file_io.getvalue())
return resp
And here is the python script sending the request and trying to save the file -
r = requests.post('http://localhost:8181/create-ppt',
#data=open('tile_resp.json', 'rb'),
files={'1': open('./0NtNFb0F9ch15fDrgYoECEpctPkjvayD.png', 'rb'),
'tile_data': open('tile_resp.json', 'rb')})
print(r.content)
And finally I pipe the output from request script to a pptx file.
But this is not working any idea what mistake I am making here?
How about the following:
response = make_response(prs_file_io.get_value())
response.headers['Content-Type'] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
response.headers['Content-Description'] = 'attachment; filename=example.pptx'
return response
make_response is a method from Flask see make_response()
Would that work if the response should be a pptx file?
I do this using
send_file
By doing:
from flask import send_file
from app import application
from pptx import Presentation
import os
prs=Presentation()
filename = os.path.join(application.root_path, 'test.pptx')
prs.save(filename)
return send_file(filename_or_fp=filename)
In my code, the application is defined in a python file in the app folder, hence the line:
from app import application
You'll have to change this for your application if you want to go this route.
This is an old question but none of the above worked for me, so I want to share my solution:
prs = Presentation(input)
file = io.BytesIO()
prs.save(file)
response = HttpResponse(content_type='application/vnd.ms-powerpoint')
response['Content-Disposition'] = 'attachment; filename="sample.pptx"'
response.write(file.getvalue())
file.close()
return response

"Object not callable" when echoing posted image

I'm trying to listen for a file being sent over post with the key 'image', then return it back to the caller.
from flask import Flask, request, make_response
app = Flask(__name__)
#app.route('/', methods = ['POST', 'GET'])
def img():
if request.method == 'GET':
return "yo, you forgot to post"
else:
img = request.files['image']
resp = make_response(img)
resp.status_code = 200
return resp
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
This fails with the message:
TypeError: 'FileStorage' object is not callable
I'm not massively familiar with Python, but I thought by doing the above that I was passing the byte[] straight through memory?
How do you achieve this without it failing? I want to take it the image blob from the request, manipulate it (not currently), and return it straight back out. In memory, without saving it to the file system.
You can serve out the image again with the Flask.send_image() function; it accepts a file-like object as well as filenames. You'll have to copy the file data over to an in-memory file object (the request.files file objects are closed too early to be suitable):
from io import BytesIO
return send_file(BytesIO(request.files['image'].read())
You may want to add additional headers, such as the mime-type, to the response as the send_file() function has less information to go on here than with 'regural' file objects. The sending browser probably included a content type for example:
import mimetypes
img = request.files['image']
mimetype = img.mimetype or mimetypes.guess_type(img.filename)[0]
return send_file(BytesIO(img.read()), mimetype=mimetype)
This does require you to hold the whole image in memory.

Categories