I'm trying to send a wav file from my HTML page to my flask back-end. I've looked at similar issues which say to add the name=file tag to the form attribute and also enctype=multipart/form-data but I still do not receive the file in the backend. Request.files contains an empty ImmutableMultiDict([]) I've also tried adding audio/wav
<html>
<form method="post" enctype="multipart/form-data">
<div>
<label>Select file to upload</label>
<input type="file" id="fileinput" name="file">
</div>
<button type="submit" value=Upload>Convert</button>
</form>
<script>
// Select your input type file and store it in a variable
const input = document.getElementById('fileinput');
// This will upload the file after having read it
const upload = (file) => {
var prod = 'https://elementa-backend-staging.herokuapp.com/wrapper/v1/file';
var debug = 'http://127.0.0.1:5000/wrapper/v1/file';
console.log("Sending file: " + file);
fetch(debug, { // Your POST endpoint
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: file // This is your file object
}).then(
response => console.log(response.json()) // if the response is a JSON object
).then(
success => console.log("Test succeeded: " + success) // Handle the success response object
).catch(
error => console.log("Test failed: " + error) // Handle the error response object
);
console.log(file[0]);
};
// Event handler executed when a file is selected
const onSelectFile = () => upload(input.files);
// Add a listener on your input
// It will be triggered when a file will be selected
input.addEventListener('change', onSelectFile, false);
</script>
</html>
Back-end:
from flask import Flask, request, abort, jsonify
import speech2new # this will be your file name; minus the `.py`
from flask_cors import CORS, cross_origin
wrapper = Flask(__name__)
cors = CORS(wrapper)
UPLOAD_FOLDER = '/uploads'
wrapper.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
ALLOWED_EXTENSIONS = {'wav', 'png', 'jpeg'}
#wrapper.route('/wrapper/v1/file', methods=['POST'])
def mozdhe():
#Pass the request parameters (containing the .WAV file) to the Speech-to-Text
return jsonify(speech2new.get_file(request))
if __name__ == '__main__':
wrapper.run(host='127.0.0.1', port='5000', debug=True)
#speech2new.py get_file function
def get_file(request):
#Outlier case: No file
print(request.files)
if 'file' not in request.files:
return json.dumps("You did not send a file ")
file = request.files['file']
#Outlier case: Invalid filename (not parse-able)
if file.filename == "":
return json.dumps("The application didn't assign a filename.")
#Ideal case: Audio file recieved in Byte Form, pass to Mozhde's Library
file.save('recievedAudio')
predict = dict({'result':get_large_audio_transcription(file)})
#data = json.dumps(predict)
return predict
To make a multipart/form-data file upload via fetch you have to use a FormData object as the data parameter you're using a file list
// This will upload the file after having read it
const upload = (file) => {
var prod = 'https://elementa-backend-staging.herokuapp.com/wrapper/v1/file';
var debug = 'http://127.0.0.1:5000/wrapper/v1/file';
var formData = new FormData();
// Add file to formdata object
formData.append("file", file); // Use "file" as thats what the server expects
console.log("Sending file: " + file);
fetch(debug, { // Your POST endpoint
method: 'POST',
body: formData// This is your form data object
}).then(
response => console.log(response.json()) // if the response is a JSON object
).then(
success => console.log("Test succeeded: " + success) // Handle the success response object
).catch(
error => console.log("Test failed: " + error) // Handle the error response object
);
console.log(file);
};
// Event handler executed when a file is selected
const onSelectFile = () => upload(input.files[0]); // send the file
Related
So i sent an image from react to flask using an axios post request , the image is in form of a formdata
const response = await axios({
method: "POST",
url: "http://127.0.0.1:5000/upload",
headers: { "content-type": "multipart/form-data" },
data: filou,
in the flask back , i recieve image , store it , then send as a responce another image
#app.route('/upload', methods=['POST'])
#cross_origin()
def fileUpload():
print("hello")
print(request.files)
# check if the post request has the file part
if 'file' not in request.files:
print("no file")
flash('No file part')
return "redirect(request.url)"
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
print("no selected file")
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
print("\n YYYYYYYYYYYYYYYYYYYEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEYYYY \n")
print(file.filename)
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# print(os.path.join(app.config['UPLOAD_FOLDER'], filename))
new_filename = app.config['UPLOAD_FOLDER']
print(new_filename)
return send_file(f"output/final_output/panda.jpg")
when i recieve the image , i get it like this
enter image description here
But i couldnt show it in react and i dunno how to do it (i tried many techniques , blob , createObjectURL ...etc)
.then((response) => {
const data = response.data;
console.log("-----------------------------------------------------");
console.log("I received");
console.log(data);
const img_bytes = new Uint8Array(Buffer.from(response.img, 'hex'));
const blob = new Blob([img_bytes], { type: 'image/jpeg' });
setoutImage(URL.createObjectURL(blob));
// setoutImage(response.data)
setDone(true);
});
{done == true && (
<img
src={outputUrl+outImage}
alt=""
width="400"
/>
)}
if someone can help .
Exactly what Unmitigated said...
axios
.get('your_url',{ responseType: 'blob' })
.then((response) => {
const img = URL.createObjectURL(response.data);
setoutImage(img);
...
});
I have an array of the object, each object contains some properties of type string and a file.
This is how my array looks like:
const args = [
{
name: 'presentation',
price: 9.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
},
{
name: 'presentation2',
price: 20.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
}
]
const headers = {
headers: {
Authorization: `Bearer ${token}`
}
};
My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3.
But Currently, I am unable to get the file stream on the server when I send this in a POST request,
even the whole req.body is an empty object when I console.log it
axios.post(`${slidesRoute}/createSlides`, args, headers);
Alternatively, I tried to put everything into FormData.
for example:
let formData = new FormData();
selectedFiles.forEach((selectedFile, i) => {
formData.append(`name_${i}`, selectedFile.name);
formData.append(`price_${i}`, selectedFile.price);
formData.append(`tags_${i}`, selectedFile.tags);
formData.append(`file_${i}`, selectedFile.file);
formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
});
axios.post(`${slidesRoute}/createSlides`, formData, headers);
Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like
file_1, file_2 file_3,...
But multer expects the exact filename to be passed
for example multer().array('file')
so in my second approach I am unable to catch files using Multer
You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.
As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side
FormData key values are array by default
in your code Just change
formData.append(`file_${i}`, selectedFile.file);
to
formData.append(`file`, selectedFile.file);
You should be able to receive the file array in server side using multer().array('file')
Sample below demonstrating FormData key values array behavior
const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');
formData.forEach(function(value, key){
console.log(key, value);
});
I use FormData to send a number of files - and then on the node.js server I use Formidable.
I've pasted some partial code below that may help - sorry it's not a smaller sample.
Hope it helps
On the browser side I have:
let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
url: '/file/upload' + remote_path + '/' + filename,
type: 'POST',
data: form_data,
processData: false,
contentType: false,
success: (res) => {
...
On the node.js side (apologies for the length..)I have:
const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IncomingForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
if (err) {
fail(res, 'failed to upload')
} else {
success(res)
}
})
form.on('fileBegin', (name, file) => {
const [fileName, fileExt] = file.name.split('.')
file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
if (!res.headersSent) { // Fix since first response is received
fail(res, 'an error has occured with form upload' + err)
}
})
})
form.on('error', (err) => {
fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
fail(res, 'Upload cancelled by browser')
})
})
The way I have found examples are:
const file = fs.readFileSync(filePath)
const formData = new FormData()
formData.append('userId', userId)
formData.append('file', file)
const options = {
method: 'post',
url: 'http://localhost:5000/uploadFile',
headers: {
'content-type': 'multipart/form-data'
},
data: formData
}
await axios(options).then(res => { console.log(res) }).catch(err => { console.log(err) })
But this doesn't attach the file in request.files which is required for python. Since it doesn't attach it as file, the information about file type is also lost.
I have also tried using the following. It does attach the file to request.files but the contents are not of the proper file and all I get is a text string which assumingely is a buffer string output.
const file = new File(fs.readFileSync(filePath), fileName, { type: 'text/csv' })
The aim is to preserve the file type information so that server can save the file properly. What am I missing?
Note that the requests are not sent from nodejs (which has file access) directly.
Server Side
I trying to send file from NodeJs
/**
* Exports data to PDF format route.
*/
app.post('/export/pdf', upload.single('imageBlob'), function (request, response) {
var PDF = require('./services/PdfService').PDF;
var fileUrl = PDF.generatePDFExport(request.body, request.file.buffer);
setTimeout(() => {
response.sendFile(fileUrl);
}, 200);
});
This piece of code creates a valid pdf file (I can open it browsers URL hit file)
But some browser hides the pop-up window and I wanted to download a file instead of opening it.
I check response in client and it is some BLOB looking response.
Client Side
I try to create a file from the response but there is only an empty pdf file.
return axios.post('http://172.18.0.2:8001/export/pdf', formData).then(response => {
let blob = new Blob([response.data]);
FileSaver.saveAs(blob, "st-seatmap-shop.pdf");
})
What is a mistake here? On the server side with a sending file or on the client with saving file?
The only problem was in sending a request to the server.
Server by default returns stream and for saving file on client response needs to be a BLOB so I just updated request.
let requestOptions = {
responseType: 'blob'
};
return axios.post('http://172.18.0.2:8001/export/pdf', formData, requestOptions).then(response => {
let blob = new Blob([response.data]);
FileSaver.saveAs(blob, "st-seatmap-shop.pdf");
}).catch(error => {
console.log("error.response is : ", error);
});
We have integrated the OnlyOffice editor in our application. I want to upload a .docx file from my PC to OnlyOffice server, so that we can use it later for editing. I am giving a POST request to the server using formdata, but it is not working. Following is my javascript code:
app.post('/topic/:id/upload', (req, res) => {
docManager.init(__dirname, req, res);
//docManager.storagePath(''); // mkdir if not exist
const userIp = docManager.curUserHostAddress();
const uploadDir = `./public/${configServer.get('storageFolder')}/${userIp}`;
const form = new formidable.IncomingForm();
form.uploadDir = uploadDir;
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
const file = files.uploadedFile;
file.name = docManager.getCorrectName(file.name);
if (configServer.get('maxFileSize') < file.size || file.size <= 0) {
fs.unlinkSync(file.path);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('{ "error": "File size is incorrect"}');
res.end();
return;
}
const exts = [].concat(
configServer.get('viewedDocs'),
configServer.get('editedDocs'),
configServer.get('convertedDocs')
);
const curExt = fileUtility.getFileExtension(file.name);
if (exts.indexOf(curExt) === -1) {
fs.unlinkSync(file.path);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('{ "error": "File type is not supported"}');
res.end();
return;
}
fs.rename(file.path, `${uploadDir}/${file.name}`, (err2) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
if (err2) {
res.write(`{ "error": "${err2}"}`);
} else {
res.write(`{ "filename": "${file.name}"}`);
const userid = req.query.userid ? req.query.userid : 'uid-1';
const firstname = req.query.firstname ? req.query.firstname : 'Jonn';
const lastname = req.query.lastname ? req.query.lastname : 'Smith';
docManager.saveFileData(file.name, userid, `${firstname} ${lastname}`);
docManager.getFileData(file.name, docManager.curUserHostAddress());
}
res.end();
});
});
});
At the beginning, in form.parse() call, there is a files array. This array is coming in as empty. And hence, I'm getting error as:
TypeError: Cannot read property 'name' of undefined
Following is my component code:
uploadFile(topicId: any, files: File[]) {
this.fileToUpload = files[0];
let apiUrl = "/topic/" + topicId + "/upload";
let headers = new Headers();
headers.append('authorization', 'Bearer ' + localStorage.getItem('id_token'));
headers.append('Access-Control-Allow-Origin', '*');
let data = new FormData();
data.append('file', this.fileToUpload);
this.ooApiService.postUrl(apiUrl, data, {headers})
.toPromise()
.catch(
(error: any) => this.handleError(error)
);
}
HTML code:
<form action="/upload" enctype="multipart/form-data" method="post">
<input class="chooseFile" id="uploadedFile" type="file" [disabled]="isChosen" #fileInput (change)="chooseImage(fileInput.files)"/>
<button *ngIf="userCanEditDetails" md-raised-button color="primary" (click)="uploadFile(topic.id, fileInput.files)">
{{ "Upload file" | translate }}
</button>
</form>
I am invoking this POST request from my client application which is in angular2, from there I am selecting and passing a file as a formdata.
Can someone please help me to resolve this issue?
Thanks in advance.
I would like to pay your attention to the fact that you are using an integration example.
This application is used to demonstrate document editors functions and it is not recommended for using in a production environment.
According to the information provided by you the document just wasn't sent to ONLYOFFICE server
Please note that the default version of the test example is totally functional, to understand why it doesn't work after your changes we also need to analyze the client part. Please send us the code how you upload the file into the document manager.
You probably do not sent the content with file details when sending a POST request.