I'm trying to create a portfolio where to display all of my ML projects that can be displayed with a simple API call and I decided to create a WebApp. I'm using React for the frontend and Django for the backend. The goal is to make a single page that doesn't need to refresh or change the page.
I've pretty much done everything, but on testing the API for the first project, I notice that after the API's function call, the page refreshes and I can't seem to figure out why it does.
App Component:
class App extends Component {
constructor(props) {
super(props);
this.state = {
menu: 1,
file: null
};
}
fileSelect = event =>{
this.state.file = event.target.files[0];
}
update_menu_item(new_item){
this.setState({menu: new_item});
}
// HERE PROBLEM
uploadSelfie(){
const fd = new FormData();
fd.append('image', this.state.file)
axios
.put("http://127.0.0.1:8000/api/obtainFaceEmotionPrediction", fd)
.then((response) => {
if (response.data){
// window.alert(response.data.file);
// Here even if I were to delete everything in this if statement, it would still refresh the page
document.getElementById("article").innerHTML +=
"<img src='../frontend/public/pictures_saved/face_emotion/" + response.data.file + "'/>";
}
})
.catch((err) => console.log(err));
}
uploadMilitary(){
// code not finalized yet. will be similar with uploadSelfie function but will handle multiple pictures
}
generate_segment(){
let uiItems = [];
if(this.state.menu === 1){
uiItems.push(
<article id="article">
<h2 id="title">My ML Projects</h2>
<div id="options">
<ul>
<li><button className="active" id="about" onClick={(e) => this.update_menu_item(1)}>About</button></li>
<li><button id="face_emotion_detection" onClick={(e) => this.update_menu_item(2)}>Face Emotion Detection</button></li>
<li><button id="military_detection" onClick={(e) => this.update_menu_item(3)}>Military Detection</button></li>
</ul>
</div>
<p>The scope of this application is to showcase all of the ML projects that I have finished. The application features a WebApp where the frontend is designed in React and the backend in Django.</p>
<p>Using REST API I'm able to make a call from the frontend to the backend. There, depending on the selected project, a pre-trained ML model will take your input and serve your request.</p>
<p>If you want to check the source code for each of these projects and more, you can do so by using this link.</p>
</article>
)
}
else if(this.state.menu === 2){
uiItems.push(
<article id="article">
<h2 id="title">My ML Projects</h2>
<div id="options">
<ul>
<li><button id="about" onClick={(e) => this.update_menu_item(1)}>About</button></li>
<li><button className="active" id="face_emotion_detection" onClick={(e) => this.update_menu_item(2)}>Face Emotion Detection</button></li>
<li><button id="military_detection" onClick={(e) => this.update_menu_item(3)}>Military Detection</button></li>
</ul>
</div>
<p>The aim of this project is to detect both the face and the emotion of a person. Upload a selfie with you and see how the model works:</p>
<input
type="file"
name="picture"
id="picture"
placeholder="Upload a Selfie"
onChange={this.fileSelect}
/>
<input
type="button"
value="Submit"
onClick={(e) => this.uploadSelfie()}
/>
</article>
)
}
else{
uiItems.push(
<article id="article">
<h2 id="title">My ML Projects</h2>
<div id="options">
<ul>
<li><button id="about" onClick={(e) => this.update_menu_item(1)}>About</button></li>
<li><button id="face_emotion_detection" onClick={(e) => this.update_menu_item(2)}>Face Emotion Detection</button></li>
<li><button className="active" id="military_detection" onClick={(e) => this.update_menu_item(3)}>Military Detection</button></li>
</ul>
</div>
<p>The aim of this project is to detect military personnel from an input data. The input can be a picture or a video, however for this WebApp, currently it is supported only images input. If you would like to test the video feature, check out the git repository. Upload a picture with military personnel and see how the model works:</p>
<input
type="file"
name="picture"
id="picture"
placeholder="Upload a Picture with Military"
onChange={this.fileSelect}
/>
<input
type="button"
value="submit"
onClick={(e) => this.uploadMilitary()}
/>
</article>
)
}
return uiItems;
}
render(){
return(
<main>
{this.generate_segment()}
</main>
);
}
}
export default App;
The API returns a simple strings and save a picture on the SSD:
API view:
#api_view(['PUT'])
def obtainFaceEmotionPrediction(request):
if request.method == 'PUT':
if request.FILES.get("image", None) is not None:
img = request.FILES["image"]
img = img.read()
model = FaceEmotionRecognition()
img = model.detect_emotion(img)
dir = '../frontend/public/pictures_saved/face_emotion/'
for f in os.listdir(dir):
os.remove(os.path.join(dir, f))
cv2.imwrite('../frontend/public/pictures_saved/face_emotion/face_emotion_1.png', img)
return Response({'file': 'face_emotion_1.png'})
There is 1 error and 1 warning that I have in the console but I can't seem to understand if they are related to the problem:
Also, the API call happens smoothly:
I've tried to write and rewrite the code in different ways. I've tried to use event.preventDefault() and other variants but nothing seems to work. Something that I would like to add is that the current code works, and does exactly what I want it to do, except it reloads the page.
I would very much appreciate your help.
I wound the solution. The problem was in the API, to be more specific here:
cv2.imwrite('../frontend/public/pictures_saved/face_emotion/face_emotion_1.png', img)
Basically, in the Django server, I was saving a picture into the React server files. React "saw" that there were changes in the files (new files added/modified. not necessarily to edit a .js or .css. just add a simple .png) and re-rendered the whole page. Why does it work like that? I have no clue. I changed the path where the image would be saved to be outside the React's server files and it worked like a charm.
Related
I am using Gatbyjs, and I would like to display multiple images in a card component. It seems that this solution shoud work, but it does not. I don't get any other specific error than:
GEThttp://localhost:8000/[object Module]
[HTTP/1.1 404 Not Found 13ms]
I tried to use an absolute path for the src attribute and it didn't work either. Neither did something nasty like importing every images in the file of the card component, and calling them this way:
<img src={`${Img}`} />.
Here is the component:
const ServiceCard = ({ title, subtitle, text, logos }) => {
const displayLogos = logos.split(",").map((logo) => (
<li key={logo} className="tech-logo">
<img
key={logo}
src={require(`../../images/tech-logos/${logo}.png`)}
alt={`${logo} logo`}
height="30px"
width="30px"
/>
</li>
));
return (
<div className="service-card">
<h1 className="service-card-title">{title}</h1>
<h2 className="service-card-subtitle">{subtitle}</h2>
<p className="service-card-text">{text}</p>
<ul className="tech-logo-list">{displayLogos}</ul>
</div>
);
};
Edit:
This is the way this component is used :
<ServiceCard
title="Text string"
subtitle="e-shop"
text="random text"
logos="React,Ror,Gatsby,Wordpress,Drupal,Js,Php,Mysql,Pgsql"
/>
So as we can expect, console.log("tech is " + logo); in displayLogos returns a new string for every string concatenated between comma.
Well, I managed to solve this by adding .default at the end of the require():
const displayLogos = logos.map((logo) => (
<li key={logo} className="tech-logo">
<img
key={logo}
src={require(`../../images/tech-logos/${logo}.png`).default}
alt={`${logo} logo`}
height="30px"
width="30px"
/>
</li>
));
Found the idea here.
I am trying to build out a component that can play audio files from my s3 bucket and have a button that will download the file locally if desired.
Here is what I have right now based on my research but it does not work. I think I may need to download a library?
Code:
import React from 'react';
<script src="https://unpkg.com/boxicons#latest/dist/boxicons.js"></script>
function AudioFilePlayer(props) {
var name = props.name;
var id = props.id;
var s3_url = props.s3_url;
const handleAudioPlay = (s3_url_link, state) => {
var audio = new Audio(s3_url_link)
if (state) {
audio.play()
}
else {
audio.pause()
}
}
//no clue how to download
return (
<div className="AudioFileListItem">
<div className="AudioFileListElements">
<a href="javascript:void(0);" onClick={handleAudioPlay(s3_url, true)}>
<span className="AudioFilePlayButton">
<box-icon name='play-circle' color='#ffffff' size="sm"></box-icon>
</span>
<span className="AudioFilePlayButtonTitle">
Play
</span>
</a>
<a ref="javascript:void(0);" onClick={handleDownloadPlay(s3_url, true)}>
<span className="AudioFileDownloadButton">
<box-icon name='download' type='solid' color='#ffffff' size="sm"></box-icon>
</span>
<span className="AudioFileDownloadButtonTitle">
Download
</span>
</a>
</div>
</div>
);
}
export default AudioFileListItem;
I tested the aws s3_url and it works great. It downloads the correct wav file in my browser when the link is opened.
Example link would be:
https://bobmarley.s3.amazonaws.com/music/34/reggae.wav
My desired outcome is to be ablet o click the play html (button for user), have it change to the pause look (I can do this easily), and then actually play the audio. When I want to stop the audio, I can press it and it should pause and show the play button again.
For the download button, I just want to download the file. I know I can do this simply by opening the url in a tab but I don't want to reveal the URL. I want to know if theres another way to do it without showing the user the url.
I've been at this for weeks so truly any help would mean the world to me.
Thank you and this community so much!
I change 2 things and it's works fine from my side
insted of using onClick={handleAudioPlay(s3_url, true) use onClick={()=>handleAudioPlay(s3_url, true)}
since I could not access https://bobmarley.s3.amazonaws.com/music/34/reggae.wav from my side i use this url https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3 to test.
ReactDOM.render(<AudioFilePlayer />, document.getElementById("root"));
function AudioFilePlayer(props) {
let name = props.name;
let id = props.id;
let s3_url = "https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3";
const handleAudioPlay = (s3_url_link, state) => {
var audio = new Audio(s3_url_link);
if (state) {
audio.play();
} else {
audio.pause();
}
};
//no clue how to download
return (
<div className="AudioFileListItem">
<div className="AudioFileListElements">
<a
href="javascript:void(0);"
onClick={()=>handleAudioPlay(s3_url, true)}
>
<span className="AudioFilePlayButton">
<box-icon
name="play-circle"
color="#ffffff"
size="sm"
></box-icon>
</span>
<span className="AudioFilePlayButtonTitle">Play</span>
</a>
<a
href="javascript:void(0);"
// onClick={handleDownloadPlay(s3_url, true)}
>
<span className="AudioFileDownloadButton">
<box-icon
name="download"
type="solid"
color="#ffffff"
size="sm"
></box-icon>
</span>
<span className="AudioFileDownloadButtonTitle">
Download
</span>
</a>
</div>
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I am making a React page which has a post and comments on the post. Now the onChange on being triggered re-renders the whole class which makes the typing in input slow.
Now, if the is declared in a separate class and the value entered in the input there can be sent to the main class for API call. But I am not able to do this. Can anyone help me?
Below is code for my comment section of the screen.
commentChange(html) {
this.setState({ post_comment: html})
}
<div className="post-comments">
<div className="post-comments-head">
<div>Comments ({this.state.comments.length})</div>
</div>
<div className="comments">
{this.createCommentList(this.state.comments2)}
</div>
</div>
<div className="post-commenting">
{this.state.reply == -1 ? <span>Comment as {this.state.name}</span>
: this.commentBy()}
<div className="write-comment-post">
<ReactQuill
data-gramm_editor="false"
onChange={this.commentChange}
value={this.state.post_comment}
className="post_comments_x"
placeholder="Write a comment"
ref={(ip) => this.myInp = ip}
autoFocus={true}
theme=""
/>
<div className="comments-submit">
<button className="submit-comment"
onClick={() => this.submitComment(this.state.reply)}
disabled={!enabledComment}>
Comment
</button>
</div>
</div>
</div>
The createCommentList function takes comments and returns a nested list of comments. Below is the section where new comment is added.
How to solve this because it is making typing a new comment very slow.
<div className="write-comment-post">
<ReactQuill
data-gramm_editor="false"
onChange={this.commentChange}
value={this.state.post_comment}
className="post_comments_x"
placeholder="Write a comment"
ref={(ip) => this.myInp = ip}
autoFocus={true}
theme=""
/>
create a seperate component for this
and only onn enter call parennt function else onchange it will trigger
I want to render images from my server ftp using props in React JS.
I have like:
render(){
console.log(this.props.product.image) //Which gives me the product image name properly
return(
<div className={this.props.openModal ? "modal-wrapper active" : "modal-wrapper"}>
<div className="modal" ref="modal">
<button type="button" className="close" onClick={this.handleClose.bind(this)}>×</button>
<div className="quick-view">
<div className="quick-view-image"><img src={`${this.props.product.image}`} alt={this.props.product.name +' image'}/></div>
<div className="quick-view-details">
<span className="product-name">{this.props.product.name}</span>
<span className="product-price">{this.props.product.price}</span>
</div>
</div>
</div>
</div>
)
}
In the log i am getting the image name, but why not the same in the img src attribute.
I tried to give the same line in src like i have given in console.
But just gave a try like:
Log data:
Ok i updated the full path, now image is rendering.
<img src={'http://localhost:5000/images/products/'+this.props.image}
I have a quiz form here and would like to add input fields for questions when a user clicks the "Add a question" button.
I've been playing around with the code and have been able to populate the state object with some text. Obviously, the goal is to have this be an input component and then somehow rendering this to the screen.
What I'm struggling with is how to render an actual element to the page. I know it's done in the render method of the component just not exactly sure how.
I think I'm getting close. Any help would be appreciated. The code is below.
Thanks!
var QuizForm = React.createClass({
getInitialState : function() {
return { questions : [] }
},
createQuestion : function() {
this.state.questions.push("Test");
// Adds "Test" to state object.
this.setState({
questions : this.state.questions
});
},
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul>
{/* Would like question inputs to show up here */}
</ul>
<button onClick={this.createQuestion} className="add-question-btn btn btn-primary" style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Just map your this.state.questions array to the HTML element you want.
For instance, if you want to render <li> elements:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li>{state}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
See an example.
If you want to render <input> tags, you can use the same technique above, but be mindful of the fact that React treats it as a controlled component.
A React best practice would be to map your state.questions array to a dynamically generated HTML component such as:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li key={state.someId}>{state.question}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Please keep in mind that when mapping and rendering dynamic objects in React it's always good to insert a key for each mapped object. So make sure to create that when you're creating the content.
Best Regards,