-1

My application takes user input (params.json and an image), uses machine learning to determine an output, and I want it to be able to show the output on the frontend. The output can either be in string, float, or json form — I can change its format as long as it's able to reach the frontend.

The only problem is, none of the methods I've tried so far have worked.

Here is my code:

index.html

<html>
  <head>
    <title>Dermagraph Upload Prototype</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Rubik:wght@400;500;600;700&display=swap"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="static/styles/style.css" />
  </head>

  <body>
    <div class="main-container">
      <h1>Dermagraph Upload Prototype</h1>
      <h1 id="demo">p</h1>

      <div id="app"></div>

      <form id="upload" onsubmit="return false">
        <input type="file" id="file" accept="image/*" />
        <div class="buttons">
          <button class="btn btn--full">Upload</button>
          <!-- <button class="btn btn--full">Next</button> -->
        </div>
      </form>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js"></script>
    <script src="static/script.js"></script>
  </body>
</html>

script.js Note: the params are just a placeholder for now, but later on I want them to be made from user input. Just sending the image to Flask isn't enough.

// Get the form and file field
let form = document.querySelector("#upload");
let file = document.querySelector("#file");
let app = document.querySelector("#app");

function logFile(event) {
  let str = event.target.result;
  let img = document.createElement("img");
  img.src = str;
  app.innerHTML = "";
  app.append(img);
  let req = new XMLHttpRequest();
  let formData = new FormData();
  let params = {
    image_name: ["ISIC_0251455"],
    patient_id: ["IP_3579794"],
    sex: ["male"],
    age_approx: [50.0],
    anatom_site_general_challenge: ["torso"],
    width: [6000],
    height: [4000],
  };
  formData.append("params", JSON.stringify(params));
  formData.append("photo", str);
  req.open("POST", "/");
  req.send(formData);
}

function handleSubmit(event) {
  event.preventDefault();
  // If there's no file, do nothing
  if (!file.value.length) return;

  // Create a new FileReader() object
  let reader = new FileReader();

  // Setup the callback event to run when the file is read
  reader.onload = logFile;

  // Read the file
  reader.readAsDataURL(file.files[0]);
  console.log("read");
}

// Listen for submit events
form.addEventListener("submit", handleSubmit);

server.py

app = Flask(__name__)
@app.route('/', methods=['POST', 'GET'])
def predict():
    if request.method == 'POST':
        file = request.form
        params = file['params']
        params = json.loads(params)
        photo = str(file['photo'])
        photo = urllib.request.urlopen(photo).read()
        photo = base64.b64encode(photo)
        embed = get_prediction(params, photo)
        print(embed)
        return render_template('index.html')
    else:
        return render_template('index.html')

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

I think there's something in my script.js file that prevents other solutions from working. For example:

Passing JSON data from Flask to JavaScript

I get the TypeError: Undefined is not JSON serializable

And when I try to set up redirects, they simply don't do anything.

Ideally, I would like if the output could be displayed on the same page as the input, so probably an element which's contents can be set to the output of the code.

Do you have any ideas about how I could do this? Thank you very much!

3
  • Right now, no matter what you're just returning HTML rendered from your template without any arguments. You can add something to your template which takes in either a string, float, or json (depending on what you want) to render it, but if you want that accessible by javascript I'm not sure how you would do that safely (perhaps there's a safe way to do it with flask, but I'm not familiar with it) Commented Oct 22, 2022 at 6:38
  • @Samathingamajig I know it does nothing, but any other method I try brings up an error or just doesn't work at all so that's why I'm keeping it like this for now. How do I add the element which takes a string, float or json? It doesn't necessarily have to be accessible by JavaScript. Edited my question to include this. Commented Oct 22, 2022 at 6:51
  • Just search how to make elements that can be given values from python to be rendered into the HTML template. here's one of the links geeksforgeeks.org/flask-rendering-templates Commented Oct 22, 2022 at 6:53

1 Answer 1

0

Solved by receiving the response in JS:

@app.route('/predict/input', methods=['POST', 'GET'])
def predict():
    if request.method == 'POST':
        file = request.form
        params = file['params']
        params = json.loads(params)
        photo = str(file['photo'])
        photo = urllib.request.urlopen(photo).read()
        photo = base64.b64encode(photo)
        embed = get_prediction(params, photo)
        url = 'http://127.0.0.1:5000/' + str(embed['prob'])
        return url

Javascript:

req.onreadystatechange = function () {
    if (req.readyState == XMLHttpRequest.DONE) {
      resp = req.responseText;
      window.location.href = resp;
    }
  };
  req.open("POST", "/predict/input");
  req.send(formData);
Sign up to request clarification or add additional context in comments.

Comments

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.