-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
1,516 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,17 @@ | ||
import React from "react"; | ||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; | ||
import Homepage from "./pages/homepage"; | ||
import Upload from "./pages/upload"; | ||
|
||
const App = () => { | ||
return <div className="font-bold">Hello World</div>; | ||
const App: React.FC = () => { | ||
return ( | ||
<Router> | ||
<Routes> | ||
<Route path="/" element={<Homepage />} /> | ||
<Route path="/upload" element={<Upload />} /> | ||
</Routes> | ||
</Router> | ||
); | ||
}; | ||
|
||
export default App; | ||
export default App; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React from "react"; | ||
import { Link } from "react-router-dom"; | ||
|
||
interface ButtonProps { | ||
children: React.ReactNode; | ||
className?: string; | ||
href?: string; | ||
onClick?: () => void; | ||
disabled?: boolean; | ||
} | ||
|
||
const Button: React.FC<ButtonProps> = ({ | ||
children, | ||
className, | ||
href, | ||
onClick, | ||
disabled | ||
}) => { | ||
return ( | ||
<> | ||
{href ? ( | ||
<Link to={href}> | ||
<button | ||
className={`${className} bg-white cursor-pointer rounded-lg px-6 py-2 text-[#083708] hover:bg-white-400`} | ||
disabled={disabled} | ||
> | ||
{children} | ||
</button> | ||
</Link> | ||
) : ( | ||
<button | ||
onClick={onClick} | ||
disabled={disabled} | ||
className={`${className} bg-white cursor-pointer rounded-lg px-6 py-2 text-[#083708] hover:bg-white-400`} | ||
> | ||
{children} | ||
</button> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default Button; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
import { StrictMode } from 'react' | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; | ||
import { createRoot } from 'react-dom/client' | ||
import App from './App.tsx' | ||
import './index.css' | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
createRoot(document.getElementById('root')!).render( | ||
<StrictMode> | ||
<QueryClientProvider client={queryClient}> | ||
<App /> | ||
</QueryClientProvider> | ||
</StrictMode>, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from "react"; | ||
import Button from "../../components/button"; | ||
import bgImage from "../../assets/leaf-bg.png"; | ||
|
||
const Homepage = () => { | ||
return ( | ||
<div | ||
style={{ | ||
backgroundImage: `url(${bgImage})`, | ||
backgroundSize: "cover", | ||
backgroundPosition: "center", | ||
}} | ||
className="h-[100vh]" | ||
> | ||
<div className="overlay absolute top-0 left-0 w-full h-full bg-black opacity-50"></div> | ||
<div className="above-overlay absolute top-0 left-0 w-full h-full z-10"> | ||
<div className="flex flex-col justify-center items-center p-4 md:max-w-4xl m-auto h-[100%]"> | ||
<h1 className="text-4xl text-white my-8"> | ||
Leaf Identification System | ||
</h1> | ||
<p className="text-white text-2xl"> | ||
<strong className="text-4xl">Welcome</strong> to our leaf | ||
identification system. This tool is designed to help you easily | ||
identify plants based on their leaves. Simply upload an image of a | ||
leaf, and our advanced algorithms will analyze its unique features | ||
to provide accurate results | ||
</p> | ||
<div className="flex md:flex-row flex-col gap-3 justify-between items-center w-full mt-8"> | ||
<Button className="w-[100%]" href="/upload">Identify Leaf</Button> | ||
<Button>Learn More</Button> | ||
<Button>About Us</Button> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Homepage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import React, { useCallback, useState } from "react"; | ||
import axios from "axios"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import Button from "../../components/button"; | ||
import bgImage from "../../assets/leaf-bg.png"; | ||
import { LeafResponse } from "../../typings"; | ||
|
||
const uploadImage = async (file: File): Promise<LeafResponse> => { | ||
const formData = new FormData(); | ||
formData.append("image", file); | ||
|
||
const response = await axios.post( | ||
`http://localhost:5000/api/images/upload`, | ||
formData, | ||
{ | ||
headers: { | ||
"Content-Type": "multipart/form-data", | ||
}, | ||
} | ||
); | ||
|
||
return response.data; | ||
}; | ||
|
||
const ImageUpload: React.FC = () => { | ||
const [selectedFile, setSelectedFile] = useState<File | null>(null); | ||
const [modalVisible, setModalVisible] = useState(false); | ||
const [classificationResult, setClassificationResult] = | ||
useState<LeafResponse | null>(null); | ||
|
||
const mutation = useMutation<LeafResponse, Error, File>({ | ||
mutationFn: uploadImage, | ||
onSuccess: (data) => { | ||
console.log("Upload success:", data); | ||
setClassificationResult(data); | ||
setModalVisible(true); | ||
}, | ||
onError: (error) => { | ||
console.error("Upload error:", error); | ||
}, | ||
}); | ||
|
||
const handleFiles = useCallback((files: FileList | null) => { | ||
if (files && files.length > 0) { | ||
setSelectedFile(files[0]); | ||
} | ||
}, []); | ||
|
||
const handleUpload = () => { | ||
if (selectedFile) { | ||
mutation.mutate(selectedFile); | ||
} | ||
}; | ||
|
||
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => { | ||
e.preventDefault(); | ||
}; | ||
|
||
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => { | ||
e.preventDefault(); | ||
handleFiles(e.dataTransfer.files); | ||
}; | ||
|
||
return ( | ||
<div | ||
style={{ | ||
backgroundImage: `url(${bgImage})`, | ||
backgroundSize: "cover", | ||
backgroundPosition: "center", | ||
}} | ||
className="h-[100vh]" | ||
> | ||
<div className="overlay absolute top-0 left-0 w-full h-full bg-black opacity-50"></div> | ||
<div className="above-overlay absolute top-0 left-0 w-full h-full z-10"> | ||
<div className="flex flex-col justify-center items-center p-4 md:max-w-4xl m-auto h-[100%]"> | ||
<Button href="/" className="absolute top-3 left-3"> | ||
Go Back | ||
</Button> | ||
<div | ||
className="dropzone flex flex-col justify-center items-center border-4 border-dashed border-green-500 rounded-lg h-96 w-full md:w-[580px] bg-white shadow-md mt-16 md:mt-0" | ||
onDragOver={handleDragOver} | ||
onDrop={handleDrop} | ||
> | ||
<input | ||
type="file" | ||
id="fileElem" | ||
multiple | ||
accept="image/*" | ||
onChange={(e) => handleFiles(e.target.files)} | ||
className="hidden" | ||
/> | ||
<label | ||
htmlFor="fileElem" | ||
className="flex flex-col justify-center items-center h-full cursor-pointer" | ||
> | ||
<span className="text-gray-400 mb-2 text-center"> | ||
Drag and drop your image here or click to upload | ||
</span> | ||
<span className="text-gray-300">Only images are allowed</span> | ||
</label> | ||
{selectedFile && ( | ||
<div className="mt-2 text-gray-600">{`Selected file: ${selectedFile.name}`}</div> | ||
)} | ||
</div> | ||
<Button | ||
onClick={handleUpload} | ||
disabled={!selectedFile || mutation.isLoading} | ||
className="mt-4" | ||
> | ||
Upload Image | ||
</Button> | ||
{mutation.isLoading && ( | ||
<p className="mt-2 text-blue-500">Uploading...</p> | ||
)} | ||
{mutation.isError && ( | ||
<p className="mt-2 text-red-500">Error uploading image.</p> | ||
)} | ||
{mutation.isSuccess && ( | ||
<p className="mt-2 text-green-500">Upload successful!</p> | ||
)} | ||
<p className="mt-6 text-white text-center"> | ||
File must be JPEG, JPG or PNG and up to 40MB | ||
</p> | ||
</div> | ||
</div> | ||
|
||
{modalVisible && classificationResult && ( | ||
<div | ||
className="fixed inset-0 flex items-center justify-center z-20 bg-black bg-opacity-75" | ||
role="dialog" | ||
aria-labelledby="modal-title" | ||
aria-modal="true" | ||
onKeyDown={(e) => e.key === "Escape" && setModalVisible(false)} // Close on Esc key | ||
> | ||
<div className="bg-white rounded-lg shadow-lg p-6 max-w-md w-full max-h-[80vh] overflow-y-auto"> | ||
<h2 id="modal-title" className="text-lg font-bold mb-4"> | ||
Leaf Classification Result | ||
</h2> | ||
|
||
{/* <p className="mb-2"> | ||
<strong>Species:</strong> {classificationResult.leaf.species} | ||
</p> */} | ||
|
||
<img | ||
src={`${classificationResult.leaf.imageUrl}`} | ||
alt="Leaf" | ||
className="mb-2 w-full h-auto rounded" | ||
/> | ||
|
||
<p className="mb-2"> | ||
<strong>Features:</strong> | ||
</p> | ||
<ul className="list-disc list-inside mb-4"> | ||
<li>Length: {classificationResult.leaf.features.length}</li> | ||
<li>Width: {classificationResult.leaf.features.width}</li> | ||
<li>Color: {classificationResult.leaf.features.color}</li> | ||
</ul> | ||
|
||
<button | ||
onClick={() => setModalVisible(false)} | ||
className="bg-red-500 text-white px-8 py-2 rounded-md" | ||
> | ||
Close | ||
</button> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default ImageUpload; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
declare module "axios" { | ||
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; | ||
const axios: AxiosInstance; | ||
export default axios; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export interface ButtonProps { | ||
children: React.ReactNode; | ||
className?: string; | ||
} | ||
|
||
export interface LeafResponse { | ||
message: string; | ||
leaf: { | ||
_id: string; | ||
species: string; | ||
image: string; | ||
features: { | ||
length: number; | ||
width: number; | ||
color: string; | ||
}; | ||
[key: string]: any; | ||
}; | ||
} |
Oops, something went wrong.