diff --git a/cnn_website/Dockerfile b/cnn_website/Dockerfile new file mode 100644 index 0000000..ea1badc --- /dev/null +++ b/cnn_website/Dockerfile @@ -0,0 +1,19 @@ +FROM node:20-alpine AS build + +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . + +RUN npm run build + + +FROM nginx:alpine + +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/cnn_website/index.html b/cnn_website/index.html index 8c0e3ed..59046b6 100644 --- a/cnn_website/index.html +++ b/cnn_website/index.html @@ -1,13 +1,16 @@ - - - - - cnn_website - - -
- - - + + + + + + cnn_website + + + +
+ + + + \ No newline at end of file diff --git a/cnn_website/public/loading.gif b/cnn_website/public/loading.gif new file mode 100644 index 0000000..0e8f9ae Binary files /dev/null and b/cnn_website/public/loading.gif differ diff --git a/cnn_website/src/Bird_CNN.css b/cnn_website/src/Bird_CNN.css index 89ec9f0..b4fcaad 100644 --- a/cnn_website/src/Bird_CNN.css +++ b/cnn_website/src/Bird_CNN.css @@ -1,73 +1,77 @@ .custom-button { height: 40px; padding: 10px 20px; - background: #333; - color: rgb(225, 225, 225); + background: rgb(25, 100, 126); + color: rgb(255, 255, 255); cursor: pointer; - border-radius: 6px; - border: 1px solid black; + border-radius: 20px; + border: 1px solid rgb(25, 100, 126); + user-select: none; } .custom-button:hover { border-color: white; - color: white; } .custom-button.inactive { - background: #333; - color: rgb(117, 117, 117); + opacity: 0.3; cursor: default; } .custom-button.inactive:hover { - border-color: black; + border-color: rgb(25, 100, 126); } -.explanation-box a, -span, -p { - line-height: 1.7; - font-size: 17px; +#site-headline { + margin-left: 100px; + margin-bottom: 50px; + color: rgb(47, 168, 208); + font-weight: bold; + font-size: 4rem; + position: relative; + width: fit-content; +} + +#site-headline::before { + content: ""; + position: absolute; + bottom: 0; + right: 0; + height: 4px; + width: 100%; + border-radius: 20px; + background: rgb(47, 168, 208); } a { - color: rgb(0, 0, 0); text-decoration: none; - border-bottom: 1px solid black; + border-bottom: 1px solid rgb(255, 255, 255); padding-bottom: 2px; transition: border-color 0.15s; } a:hover { - border-color: white; + border-color: #c59eff; } .explanation-box { flex: 1; - min-width: 0; + min-width: 300px; display: flex; flex-direction: column; flex-wrap: wrap; overflow: hidden; - border: 3px solid rgb(48, 62, 74); - margin: 50px; - padding: 50px; border-radius: 12px; - background: rgb(97, 125, 151); + margin: 180px 50px 0px 50px; } .image-box { - border: 2px solid black; - background: rgb(69, 69, 69); height: 400px; - width: 600px; margin-top: 40px; display: flex; align-items: center; justify-content: center; - border-radius: 8px; - background: rgba(0, 0, 0, 0.5); cursor: pointer; } @@ -77,26 +81,55 @@ a:hover { .image-box img { border: 2px solid black; - border-Radius: 8px; + border-Radius: 10px; } -.image-box:hover p { - color: white; -} - .image-box img:hover { border-color: white; } -.image-box.active { - background: none; - border: none; -} - .content-block { display: flex; align-items: center; gap: 20px; height: 40px; +} + +/* HTML:
*/ +.loader { + width: 85px; + height: 25px; + --g1: conic-gradient(from 90deg at left 3px top 3px, #0000 90deg, #fff 0); + --g2: conic-gradient(from -90deg at bottom 3px right 3px, #0000 90deg, #fff 0); + background: var(--g1), var(--g1), var(--g1), var(--g2), var(--g2), var(--g2); + background-position: left, center, right; + background-repeat: no-repeat; + animation: l8 1s infinite; +} + +@keyframes l8 { + 0% { + background-size: 25px 100%, 25px 100%, 25px 100% + } + + 20% { + background-size: 25px 50%, 25px 100%, 25px 100% + } + + 40% { + background-size: 25px 50%, 25px 50%, 25px 100% + } + + 60% { + background-size: 25px 100%, 25px 50%, 25px 50% + } + + 80% { + background-size: 25px 100%, 25px 100%, 25px 50% + } + + 100% { + background-size: 25px 100%, 25px 100%, 25px 100% + } } \ No newline at end of file diff --git a/cnn_website/src/Bird_CNN.jsx b/cnn_website/src/Bird_CNN.jsx index 46825df..76a81c5 100644 --- a/cnn_website/src/Bird_CNN.jsx +++ b/cnn_website/src/Bird_CNN.jsx @@ -7,26 +7,24 @@ function Bird_CNN() { ? "http://134.60.154.7:8000" : "http://134.60.154.7:8000"; - const boxRef = useRef(null); - const [file, setFile] = useState(null); const [birdClass, setBirdClass] = useState(null); const [confidence, setConfidence] = useState(null); const [error, setError] = useState(false); - const [preview, setPreview] = useState(null); + const [preview, setPreview] = useState("\\cherry_bird.jpeg"); + const [loading, setLoading] = useState(false); const fileInputRef = useRef(null); const uploadButton = useRef(null); + const scrollRef = useRef(null); const handleImageDivClick = () => { fileInputRef.current.click(); } const handleImage = (e) => { - setFile(e.target.files[0]); - if (e.target.files[0]) { + setFile(e.target.files[0]); setPreview(URL.createObjectURL(e.target.files[0])); - boxRef.current.classList.add("active"); uploadButton.current.classList.remove("inactive"); } setConfidence(null); @@ -36,15 +34,20 @@ function Bird_CNN() { const sendImage = async (e) => { if (!file) return; + scrollRef.current.scrollIntoView({ behavior: "smooth" }); + const formData = new FormData(); formData.append("file", file); try { + setLoading(true); const response = await fetch(`${apiUrl}/predict`, { method: "POST", body: formData, }); + setLoading(false); + if (!response.ok) { setError(true); } @@ -65,23 +68,23 @@ function Bird_CNN() { return ( <>
-

Bird Species Expert

-
-
-

Explanation

+

Bird Species Expert

+
+
+

Explanation

Select an image and upload it to our bird expert. You will receive a classification and how certain the expert is with her opinion. Be aware that the expert may not be always right.
-
-
+
+
- +
-
-
- {!preview &&

Select Image

} - {preview && ( - preview - )} +
+ preview +
+ +
+ {loading &&
}
-
+

Bird Species:

{birdClass}

@@ -114,7 +118,7 @@ function Bird_CNN() {
-
+

Model Architecture

The model used for classification is a convolutional neural network (CNN) based on depthwise separable convolutions, as introduced in the @@ -123,7 +127,7 @@ function Bird_CNN() {
-
+
); } diff --git a/cnn_website/src/Menu.css b/cnn_website/src/Menu.css index a4fdcda..4aae397 100644 --- a/cnn_website/src/Menu.css +++ b/cnn_website/src/Menu.css @@ -5,8 +5,7 @@ gap: 20px; justify-content: center; align-items: center; - background-color: rgb(33, 122, 194); - border: 1px solid black; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; + background-color: rgb(25, 100, 126); + border-bottom-left-radius: 40px; + border-bottom-right-radius: 40px; } \ No newline at end of file diff --git a/cnn_website/src/index.css b/cnn_website/src/index.css index 8a472dc..6a509c1 100644 --- a/cnn_website/src/index.css +++ b/cnn_website/src/index.css @@ -1,3 +1,21 @@ +html { + font-family: system-ui, sans-serif; + color: rgb(255, 255, 255); + font-size: 1rem; + line-height: 1.7; +} + body { - background: rgb(130, 170, 205); + background: rgb(4, 0, 10); +} + +a { + color: rgb(255, 255, 255); +} + +h1, +h2, +h3, +h4 { + font-family: 'Times New Roman', serif; } \ No newline at end of file