0

I have a node js backend (app.js), which is connected to a html, css, and javascript (script.js) front end.

In my HTML I have a form that gets an image, which then calls a function in script.js.

Script.js then uploads the file using ajax and jquery, which works fine.

Once that's complete, I want it to automatically call a function I have in app.js that calls a python script.

This function works on its own, but I'm having problems connecting both the file upload and the python script. Right now I get an error when I upload the image that says that app is not defined. How can I call both of these in one function?

Relevant HTML:

<form id="form">
     Select your image: <input type="file"  name="myfile" id="myfile" accept="image/x-png,image/jpeg"><br/>
     <input type="submit" value="Submit" class="getCodeButton"/>
 </form>
<div id="status"></div>

Relevant node js (app.js):

const express = require('express')
    const bodyParser = require('body-parser')
    const multer  = require('multer')
    const sharp = require('sharp')
    
    const app = express()
    app.use(bodyParser.urlencoded({ extended: false })); 
    app.use(bodyParser.json());
    
    app.use(express.static('./public')) 
    app.use(express.static('./uploads/'))
    
    app.get('/', (req, res)=>{
        res.sendFile("index.html", { root: __dirname + "/public" })
    })
    
    const port = process.env.PORT || 8000
    app.listen(port, 
        ()=>console.log(`Server running on port ${port}`))
        
    const upload = multer().single('myfile')
    app.post('/upload', (req, res)=>{
        upload(req, res, async function(err){ 
         if( err|| req.file === undefined){
             console.log(err)
             res.send("error occured")
         }else{
            let fileName = "myfile.jpeg"
            var image = await sharp(req.file.buffer)
            .jpeg({
                quality: 40,
            }).toFile('./uploads/'+fileName)
            .catch( err => { console.log('error: ', err) })
            res.send(req.body)
         }
        })
    })
app.get('/runPython1', (req, res) => {
 
    var dataToSend;
    const python = spawn('python', ['qr_vision.py', 'uploads/myfile.jpeg']);
    python.stdout.on('data', function (data) {
    console.log('Pipe data from python script ...');
    dataToSend = data.toString();
    });
    python.on('close', (code) => {
    console.log(`child process close all stdio with code ${code}`);
    //console.log(dataToSend)
    res.send(dataToSend)
    });
 
})

Relevant javascript (script.js):

document.getElementById('form').onsubmit = function(event){
    event.preventDefault()
    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("status").innerHTML = 'sent'+this.responseText+ xhttp.status;
      }else{
        document.getElementById("status").innerHTML = xhttp.status ;
      }
    }

    xhttp.open("POST", "upload")
    var formData = new FormData()
    formData.append('myfile', document.getElementById('myfile').files[0])
    xhttp.send(formData)
    
    app.get('/runPython1', (req, res) => {
        console.log(res.result)
    });
}
4
  • What do you mean by "call both of these in one function"? And where does it say app is undefined? If you want to run the Python shell out after the file is uploaded why is it in a separate function? Unrelated, but if this is meant for more than one person to use at a time you'll have a problem with the file naming. Commented Mar 5, 2021 at 3:37
  • Client-side, you don't want app.get('/runPython1') - that's server-side code. Instead, you need to make an Ajax call to /runPython1 and get the result back from the server. You can use the fetch() interface in the browser for making that Ajax call. Commented Mar 5, 2021 at 3:46
  • I want to be able to be able to upload and then run the script one after another. It says that app is undefined in the browser console. My apologies for the vague wording. At the moment, I'm only running locally and have no plans for multiple users, but I will keep that in mind when I expand! Thank you! Commented Mar 5, 2021 at 3:58
  • The client knows nothing about the server-side code except for the endpoints; you'd make a request to the back end endpoint, just like you make the first request to the back end endpoint. Commented Mar 5, 2021 at 14:59

1 Answer 1

1

You can do it in several ways

  1. From frontend: Write an another XMLHttpRequest to call runPython1 endpoint and send the request once the upload one is completed.
  2. From nodejs backend: Instead of exposing runPython1 as api endpoint, you can have it as function and call it once the upload is completed.
app.post('/upload', (req, res)=>{
        upload(req, res, async function(err){ 
         if( err|| req.file === undefined){
             console.log(err)
             res.send("error occured")
         }else{
            let fileName = "myfile.jpeg"
            var image = await sharp(req.file.buffer)
            .jpeg({
                quality: 40,
            }).toFile('./uploads/'+fileName)
            .catch( err => { console.log('error: ', err) })
            runPython1(res);
         }
        })
    })

const runPython1 = (res) => {
 
    var dataToSend;
    const python = spawn('python', ['qr_vision.py', 'uploads/myfile.jpeg']);
    python.stdout.on('data', function (data) {
    console.log('Pipe data from python script ...');
    dataToSend = data.toString();
    });
    python.on('close', (code) => {
    console.log(`child process close all stdio with code ${code}`);
    //console.log(dataToSend)
    res.send(dataToSend)
    });
 
}
  1. You can also redirect to runPython1 endpoint once the upload finished. Refer This site for redirecting
Sign up to request clarification or add additional context in comments.

2 Comments

For your second way, how would I go about making it a function and calling it?
I can't post lengthy message in comment so i edit the answer itself

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.