Search code examples
javascriptnode.jsreactjsexpresslazy-loading

Run Loading Component in React JS until a specific python file is executed in the express js


I am new to React JS and I am working on a project, in which user uploads a noisy audio file in react js (client side), then user clicks on a denoise button which executes a python file using spawn library. This python file then takes the noisy input file from user, denoise that file and save the file in server, which is currently my system's directory. And then I am able to return the denoised file to the user. Everything is working well up till now.

Now what I was trying to do is, when user clicks on the denoise button, a loading component should appear and this component should be visible to the user until that python file has been executed or there is another possibility which is that, show the loading component until there are changes in a specific directory. Changes means the denoised file has been uploaded in the server and is ready for the user.

I have researched a lot and could not find the solution to my problem.

This is my React JS file:

import React from "react";
import Navbar from "../navbar/Navbar";
import { useState } from "react";
import axios from "axios";
import CustomModal from "../../containers/modal/Modal";
import UploadedAudios from "../uploadedAudios/UploadedAudios";
import NoisySpectogram from "../../spectograms_for_uploaded_audio/spec_noisy.png";
import DenoisedSpectogram from "../../spectograms_for_uploaded_audio/spec_denoised.png";
import logo from "../../assets/sound.png";
import DenoiseModal from "../denoiseModal/DenoiseModal";

const AudioUpload = () => {
  const [modal, setModal] = useState(false);
  const [audioSource, setAudioSource] = useState(null);
  const [showDenoisedModal, setShowDenoisedModal] = useState(false);
  const rawUrl = "http://localhost:8000/denoise-uploaded-audio-raw";

  const showDenoiseModal = () => {
    setShowDenoisedModal(!showDenoisedModal);
  };

const handleAudioChange = (event) => {
    const file = event.target.files[0];
    setAudioSource(file);
  };

  //file uplaod in a folder
  const onAudioSubmit = (e) => {
    e.preventDefault();
    const url = "http://localhost:8000/upload-audio";
    const data = new FormData();
    data.append("file", audioSource);
    data.append("fileName", audioSource.name);

    axios.post(url, data).then((e) => {
      console.log("success");
    });

    alert("Audio Uploaded Successfully");
  };

  const selectModal = () => {
    setModal(!modal);
  };
  return (
    <>
      <div className="audio_upload">
        <CustomModal
          displayModal={modal}
          closeModal={selectModal}
          spectogram1={NoisySpectogram}
          spectogram2={DenoisedSpectogram}
        />
        <DenoiseModal
          displayModal={showDenoisedModal}
          closeModal={showDenoiseModal}
          denoiseByRawUrl={rawUrl}
        />
        <Navbar />
        <div className="audio_upload-container section__padding ">
          <div className="audio_upload-container-title">
            <div />
            <h1>Select your audio file:</h1>
          </div>
          <div className="audio_upload-container-text">
            <form
              method="post"
              action="#"
              id="#"
              onSubmit={onAudioSubmit}
              className="form-group"
            >
              <input
                type="file"
                className="form-control"
                id="media-URL"
                accept="audio/wav,audio/mp3,audio/*;capture=microphone"
                onChange={(event) => {
                  handleAudioChange(event);
                }}
              />
              <button className="submitbtn" style={{}}>
                {" "}
                Submit{" "}
              </button>
            </form>
          </div>
          <div className="audio_upload_buttons_section ">
            <div className="audio_upload_denoise_button">
              <button
                onClick={() => showDenoiseModal()}
                type="submit"
                style={{ color: "white" }}
              >
                Denoise
              </button>
            </div>

            <div className="audio_upload_denoise_button">
              <button
                style={{
                  backgroundColor: "#1a068a",
                  border: "2px solid #0c0572",
                }}
                onClick={() => selectModal()}
                id="show-spec-btn"
              >
                Show Spectograms
              </button>
            </div>
          </div>
          <br />
        </div>
      </div>
      <UploadedAudios />
      <div>
    </>
      );
};

export default AudioUpload;


DenoiseModal.js file:

import React from "react";
import axios from "axios";

const DenoiseModal = (props) => {

  const denoiseAudioRaw = (e) => {
    e.preventDefault();
    const url = props.denoiseByRawUrl;
    axios.post(url).then((e) => {
      console.log("successfull");
    });
  };

  function closeModal(e) {
    e.stopPropagation();
    props.closeModal();
  }

  const divStyle = {
    display: props.displayModal ? "block" : "none",
  };

  return (
    <>
      <div className="denoise_modal" onClick={closeModal} style={divStyle}>
        <div
          className="denoise_modal-content"
          onClick={(e) => e.stopPropagation()}
        >
          <span className="denoise_modal_close" onClick={closeModal}>
            &times;
          </span>

          <div className="denoise_modal_row">
              <form method="POST" onSubmit={denoiseAudioRaw}>
                <button
                  type="submit"
                  onClick={closeModal}
                  sx={{
                    color: "white",
                    backgroundColor: "#042c54",
                    height: 30,
                    marginTop: 2,
                    marginLeft: 5,
                  }}
                >
                  Denoise using Raw
                </button>
              </form>
           </div>
        </>
  );
};

export default DenoiseModal;

And this is my server.js file:

const path = require("path");
const fs = require("fs");
const express = require("express");
const multer = require("multer");
const cors = require("cors");
const app = express();
const { spawn } = require("child_process");
const { request } = require("http");
const { response } = require("express");
const { stderr } = require("process");

app.use(cors());
app.use(express.static("uploads"));
app.use(express.json());
app.use(express.static("uploaded_audio"));

// uploading single audio file in different directories, 
// one to show at the client side as noisy input file and one as a input to the python file.

var uploadAudioStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "uploaded_audio/");
  },
  filename: (req, file, cb) => {
    cb(null, "audio.wav");
  },
});

var tempUploadAudioStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "../client/src/denoised_uploaded_audio/");
  },
  filename: function (req, file, cb) {
    // file name
    cb(null, `inputUploadAudio.wav`);
  },
});

const tempAudioUpload = multer({ storage: tempUploadAudioStorage }).single(
  "file"
);
const audioUpload = multer({ storage: uploadAudioStorage }).single("file");

function multipleAudioFilesUpload(req, res, next) {
  tempAudioUpload(req, res, next);
  audioUpload(req, res, next);
}

app.post("/upload-audio", multipleAudioFilesUpload, (req, res) => {
  res.json({ file: req.file });
});
function denoiseUploadedAudioRaw(req, res) {
  var spawn = require("child_process").spawn;
  var process = spawn("python", ["denoise_uploaded_audio_raw.py"]);

  process.stdout.on("data", function async(data) {
    console.log(data.toString());
  });
}
app.post("/denoise-uploaded-audio-raw", denoiseUploadedAudioRaw);

app.listen(8000, () => {
  console.log("server is running");
});

And then I have python file which takes input from uploaded_audio/ directory, then denoise the noisy file and save the the denoised(output) file at the client(react js) folder. I hope I am clear with my problem.


Solution

  • You can go with the second option which is that run the loading component until there is a file change in specific directory. You must have a loading state on which you are running loading component, so you can just set the loading state setLoading(false) in useEffect. Like below.

    import React, { useEffect, useState } from 'react';
    import imageFile from './image.jpg';
    
    const ImageComponent = () => {
      const [imageUrl, setImageUrl] = useState(imageFile);
    
      useEffect(() => {
        // Monitor the image file for changes
        const interval = setInterval(() => {
          if (imageFile !== imageUrl) {
            // Update the imageUrl state variable to trigger a re-render
            setImageUrl(imageFile);
            setLoading(false);
          }
        }, 1000);
    
        // Clear the interval when the component unmounts
        return () => clearInterval(interval);
      }, [imageUrl]);
    
      return <img src={imageUrl} alt="Image" />;
    };
    
    export default ImageComponent;
    

    This will render the component whenever the file changes and the loading state will be set to false.