This commit is contained in:
louiscklaw
2025-01-31 22:32:41 +08:00
parent 8a673f6cfc
commit 2f92062c07
35 changed files with 5306 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
import Head from "next/head";
import theme from "@/config/theme";
import ThemeProvider from "@/config/StyledMaterialThemeProvider";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
</Head>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</>
);
}
export default MyApp;

View File

@@ -0,0 +1,100 @@
import Document, { Head, Html, Main, NextScript } from "next/document";
import { ServerStyleSheets } from "@mui/styles";
import { ServerStyleSheet } from "styled-components";
import theme from "@/config/theme";
export default class MyDocument extends Document {
componentDidMount() {}
render() {
return (
<Html lang="en">
<Head>
<meta charSet="utf-8" />
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
</Head>
<style jsx global>
{`
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Oxygen, Ubuntu, Cantarell, Fica Sans, Droid Sans, Helvetica Neue,
sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}
`}
</style>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(sheets.collect(<App {...props} />)),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: (
<>
{initialProps.styles}
{sheets.getStyleElement()}
{sheet.getStyleElement()}
{/* {flush() || null} */}
</>
),
};
} finally {
sheet.seal();
}
};

View File

@@ -0,0 +1,5 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function handler(req, res) {
res.status(200).json({ name: "John Doe" });
}

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe","age":30}' http://localhost:5000/api/data
# curl http://localhost:5000/api/data
# curl -F "file=@test.txt" http://localhost:3000/api/hello
curl -X POST -F "file=@test.txt" http://localhost:3000/api/testFileupload

View File

@@ -0,0 +1 @@
helloworld

View File

@@ -0,0 +1,21 @@
//
import formidable from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default function handler(req, res) {
try {
const form = new formidable.IncomingForm();
form.parse(req, async (err, fields, files) => {
console.log(files.zip.filepath, 222);
const lottieJSON = await zip2json(files.zip.filepath);
return res.status(200).json({ json: lottieJSON?.[0] });
});
} catch (error) {
res.status(400).json({ error: JSON.stringify(error, Object.getOwnPropertyNames(error)) });
}
}

View File

@@ -0,0 +1,19 @@
//
import formidable from "formidable";
import axios from "axios";
import fs from "fs";
// export const config = {
// api: { bodyParser: false },
// };
export default async function handler(req, res) {
try {
// console.log(req.body);
const response = await axios.post("http://localhost:5000/uploader", req.body);
console.log(response);
res.status(200).json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
}

View File

@@ -0,0 +1,256 @@
import { Box, Card, Grid, Typography, Button } from "@mui/material";
import Head from "next/head";
import Image from "next/image";
import styled from "styled-components";
import * as React from "react";
import { useEffect, useState } from "react";
import Paper from "@mui/material/Paper";
import styles from "./index.css";
const PLEASE_SELECT_IMAGE = "please select a photo and click submit button";
const RUNNING = "running";
const HomeWrapper = styled.div`
${styles}
`;
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: "center",
color: theme.palette.text.secondary,
}));
export default function Home() {
const [result, setResult] = useState({ similar: "", revalent: [] });
const [revalent_image_hit_pct, setRevalentImageHitPct] = useState(1);
const [loading, setLoading] = useState(false);
const [hide_result, setHideResult] = useState(true);
const [status_text, setStatusText] = useState(PLEASE_SELECT_IMAGE);
async function onSubmit(event) {
event.preventDefault();
setLoading(true);
setStatusText(RUNNING);
setHideResult(true);
const formData = new FormData(event.currentTarget);
await fetch("http://localhost:5000/uploader", {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((res_json) => {
setResult(res_json);
setLoading(false);
setHideResult(false);
});
}
useEffect(() => {
if (result != {}) {
let j = 0;
let len_revalent = result["revalent"].length;
for (let i = 0; i < len_revalent; i++) {
let first_char = result["revalent"][i].replace("public/", "")[0];
let expected_category = result["image_to_test"][0];
console.log(expected_category);
console.log(result["image_to_test"]);
if (first_char == expected_category) j += 1;
}
setRevalentImageHitPct(j);
}
}, [result]);
return (
<HomeWrapper>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="main" style={{ justifyContent: "flex-start" }}>
<Grid container spacing={2}>
<Grid item xs={4}>
<Item elevation={0}>
<form onSubmit={onSubmit}>
<Box>
<Button variant="contained" component="label">
Select file
<input type="file" name="file" hidden />
</Button>
</Box>
<Box>
{/* <button type="submit">Submit</button> */}
<Button type="submit" variant="contained">
Upload image
</Button>
</Box>
</form>
</Item>
</Grid>
<Grid item xs={4}>
<Item elevation={0}>
<div>
<Typography variant="h5">Most similar</Typography>
<Grid item xs={12}>
<Item
sx={{
backgroundImage:
"url(" +
"http://localhost:5000/" +
result["similar"] +
")",
backgroundPosition: "center",
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
width: "100%",
minHeight: "500px",
}}
></Item>
</Grid>
</div>
</Item>
</Grid>
<Grid item xs={4}>
<Item elevation={0}>
<Typography variant="h5">related {"99%"}</Typography>
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
{result["revalent"].map((item, idx) => (
<Grid item key={idx} xs={4}>
<Item
sx={{
backgroundImage:
"url(http://localhost:5000/public/695.jpg)",
backgroundPosition: "center",
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
//
width: "100%",
minHeight: "150px",
}}
></Item>
</Grid>
))}
</Grid>
</Box>
</Item>
</Grid>
</Grid>
</main>
<footer className="footer"></footer>
</HomeWrapper>
);
}
const test_json = {
similar: "public/654.jpg",
revalent: [
"public/695.jpg",
"public/640.jpg",
"public/648.jpg",
"public/641.jpg",
"public/693.jpg",
"public/644.jpg",
"public/698.jpg",
"public/670.jpg",
"public/639.jpg",
"public/703.jpg",
"public/72.jpg",
"public/657.jpg",
"public/650.jpg",
"public/652.jpg",
"public/687.jpg",
"public/20.jpg",
"public/674.jpg",
"public/666.jpg",
"public/697.jpg",
"public/67.jpg",
"public/643.jpg",
"public/672.jpg",
"public/683.jpg",
"public/25.jpg",
"public/653.jpg",
"public/663.jpg",
"public/719.jpg",
"public/655.jpg",
"public/710.jpg",
"public/660.jpg",
"public/673.jpg",
"public/190.jpg",
"public/700.jpg",
"public/671.jpg",
"public/691.jpg",
"public/677.jpg",
"public/676.jpg",
"public/679.jpg",
"public/665.jpg",
"public/229.jpg",
"public/26.jpg",
"public/696.jpg",
"public/668.jpg",
"public/237.jpg",
"public/662.jpg",
"public/238.jpg",
"public/221.jpg",
"public/195.jpg",
"public/688.jpg",
"public/267.jpg",
"public/266.jpg",
"public/255.jpg",
"public/716.jpg",
"public/704.jpg",
"public/680.jpg",
"public/204.jpg",
"public/659.jpg",
"public/259.jpg",
"public/70.jpg",
"public/711.jpg",
"public/206.jpg",
"public/7.jpg",
"public/230.jpg",
"public/271.jpg",
"public/720.jpg",
"public/701.jpg",
"public/707.jpg",
"public/219.jpg",
"public/202.jpg",
"public/193.jpg",
"public/248.jpg",
"public/239.jpg",
"public/705.jpg",
"public/233.jpg",
"public/708.jpg",
"public/241.jpg",
"public/21.jpg",
"public/272.jpg",
"public/198.jpg",
"public/251.jpg",
"public/243.jpg",
"public/249.jpg",
"public/192.jpg",
"public/270.jpg",
"public/277.jpg",
"public/22.jpg",
"public/242.jpg",
"public/727.jpg",
"public/725.jpg",
"public/678.jpg",
"public/709.jpg",
"public/19.jpg",
"public/232.jpg",
"public/236.jpg",
"public/658.jpg",
"public/694.jpg",
"public/261.jpg",
"public/205.jpg",
"public/263.jpg",
],
};

View File

@@ -0,0 +1,105 @@
export default () => `
padding: 0 2rem;
.main {
min-height: 100vh;
padding: 4rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
text-align: center;
a {
color: #0070f3;
text-decoration: none;
:hover,
:focus,
:active {
text-decoration: underline;
}
}
}
.description {
margin: 4rem 0;
line-height: 1.5;
font-size: 1.5rem;
text-align: center;
.code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
}
.card {
margin: 1rem;
padding: 1.5rem;
text-align: left;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 300px;
a {
text-decoration: none;
color: inherit;
}
:hover,
:focus,
:active {
color: #0070f3;
border-color: #0070f3;
}
h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
}
}
.footer {
display: flex;
flex: 1;
padding: 2rem 0;
border-top: 1px solid #eaeaea;
justify-content: center;
align-items: center;
a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
text-decoration: none;
color: inherit;
}
.logo {
height: 1em;
margin-left: 0.5rem;
}
}
`;

View File

@@ -0,0 +1,319 @@
import { Box, Card, Grid, Typography, Button } from "@mui/material";
import Head from "next/head";
import Image from "next/image";
import styled from "styled-components";
import * as React from "react";
import { useEffect, useState } from "react";
import Paper from "@mui/material/Paper";
import styles from "./index.css";
const PLEASE_SELECT_IMAGE = "please select a photo on the left";
const RUNNING = "running";
const HomeWrapper = styled.div`
${styles}
`;
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: "center",
color: theme.palette.text.secondary,
}));
export default function Home() {
const [result, setResult] = useState({ similar: "", revalent: [] });
const [revalent_image_hit_pct, setRevalentImageHitPct] = useState(1);
const [loading, setLoading] = useState(false);
const [hide_result, setHideResult] = useState(true);
const [status_text, setStatusText] = useState(PLEASE_SELECT_IMAGE);
const [disable_upload_button, setDisableUploadButton] = useState(true);
async function onSubmit(event) {
event.preventDefault();
setLoading(true);
setStatusText(RUNNING);
setHideResult(true);
setDisableUploadButton(true);
const formData = new FormData(event.currentTarget);
await fetch("http://localhost:5000/uploader", {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((res_json) => {
setResult(res_json);
setLoading(false);
setHideResult(false);
});
}
useEffect(() => {
if (result != {}) {
let j = 0;
let len_revalent = result["revalent"].length;
for (let i = 0; i < len_revalent; i++) {
let first_char = result["revalent"][i].replace("public/", "")[0];
let expected_category = result["image_to_test"][0];
console.log(expected_category);
console.log(result["image_to_test"]);
if (first_char == expected_category) j += 1;
}
setRevalentImageHitPct(j);
}
}, [result]);
return (
<HomeWrapper>
<Head>
<title>CS4185 Course Project</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="main" style={{ justifyContent: "flex-start" }}>
<Box sx={{ marginTop: "1rem", marginBottom: "1rem" }}>
<Typography variant={"h4"}>CS4185 Course Project</Typography>
</Box>
<Grid container spacing={2}>
<Grid item xs={12} md={4}>
<Item elevation={0}>
<form onSubmit={onSubmit}>
<Box>
<Typography variant={"h6"}>
1. please select image here
</Typography>
</Box>
<Box sx={{ marginTop: "1rem" }}>
<Button
variant="contained"
component="label"
disabled={loading}
>
Select image
<input
type="file"
name="file"
hidden
onChange={(e) => {
if (e.target.files[0]) {
setDisableUploadButton(false);
}
}}
/>
</Button>
</Box>
<Box sx={{ marginTop: "1rem" }}>
{/* <button type="submit">Submit</button> */}
<Button
type="submit"
variant="contained"
disabled={disable_upload_button}
>
Upload
</Button>
</Box>
</form>
</Item>
</Grid>
<Grid item xs={12} md={4}>
<Item elevation={0}>
<div>
<Typography variant="h5">2. Most similar</Typography>
<Box sx={{ marginTop: "1rem" }}>
{hide_result ? (
<Box
sx={{
width: "100%",
minHeight: "150px",
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
}}
>
<div>{status_text}</div>
</Box>
) : (
<Grid item xs={12}>
<Item
sx={{
backgroundImage:
"url(" +
"http://localhost:5000/" +
result["similar"] +
")",
backgroundPosition: "center",
backgroundSize: "contain",
backgroundRepeat: "no-repeat",
width: "100%",
minHeight: "500px",
}}
elevation={1}
></Item>
<Box>{result["similar"].replace("public/", "")}</Box>
</Grid>
)}
</Box>
</div>
</Item>
</Grid>
<Grid item xs={12} md={4}>
<Item elevation={0}>
<Typography variant="h5">
3. related {revalent_image_hit_pct}%
</Typography>
<Box sx={{ marginTop: "1rem" }}>
{hide_result ? (
<Box
sx={{
width: "100%",
minHeight: "150px",
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
}}
>
<div>{status_text}</div>
</Box>
) : (
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
{result["revalent"].map((item, idx) => (
<Grid item key={idx} xs={4}>
<Item
sx={{
backgroundImage: `url(http://localhost:5000/${item})`,
backgroundPosition: "center",
backgroundSize: "contain",
backgroundRepeat: "no-repeat",
//
width: "100%",
minHeight: "150px",
}}
elevation={1}
></Item>
<Box>{item.replace("public/", "")}</Box>
</Grid>
))}
</Grid>
</Box>
)}
</Box>
</Item>
</Grid>
</Grid>
</main>
<footer className="footer"></footer>
</HomeWrapper>
);
}
const test_json = {
similar: "public/654.jpg",
revalent: [
"public/695.jpg",
"public/640.jpg",
"public/648.jpg",
"public/641.jpg",
"public/693.jpg",
"public/644.jpg",
"public/698.jpg",
"public/670.jpg",
"public/639.jpg",
"public/703.jpg",
"public/72.jpg",
"public/657.jpg",
"public/650.jpg",
"public/652.jpg",
"public/687.jpg",
"public/20.jpg",
"public/674.jpg",
"public/666.jpg",
"public/697.jpg",
"public/67.jpg",
"public/643.jpg",
"public/672.jpg",
"public/683.jpg",
"public/25.jpg",
"public/653.jpg",
"public/663.jpg",
"public/719.jpg",
"public/655.jpg",
"public/710.jpg",
"public/660.jpg",
"public/673.jpg",
"public/190.jpg",
"public/700.jpg",
"public/671.jpg",
"public/691.jpg",
"public/677.jpg",
"public/676.jpg",
"public/679.jpg",
"public/665.jpg",
"public/229.jpg",
"public/26.jpg",
"public/696.jpg",
"public/668.jpg",
"public/237.jpg",
"public/662.jpg",
"public/238.jpg",
"public/221.jpg",
"public/195.jpg",
"public/688.jpg",
"public/267.jpg",
"public/266.jpg",
"public/255.jpg",
"public/716.jpg",
"public/704.jpg",
"public/680.jpg",
"public/204.jpg",
"public/659.jpg",
"public/259.jpg",
"public/70.jpg",
"public/711.jpg",
"public/206.jpg",
"public/7.jpg",
"public/230.jpg",
"public/271.jpg",
"public/720.jpg",
"public/701.jpg",
"public/707.jpg",
"public/219.jpg",
"public/202.jpg",
"public/193.jpg",
"public/248.jpg",
"public/239.jpg",
"public/705.jpg",
"public/233.jpg",
"public/708.jpg",
"public/241.jpg",
"public/21.jpg",
"public/272.jpg",
"public/198.jpg",
"public/251.jpg",
"public/243.jpg",
"public/249.jpg",
"public/192.jpg",
"public/270.jpg",
"public/277.jpg",
"public/22.jpg",
"public/242.jpg",
"public/727.jpg",
"public/725.jpg",
"public/678.jpg",
"public/709.jpg",
"public/19.jpg",
"public/232.jpg",
"public/236.jpg",
"public/658.jpg",
"public/694.jpg",
"public/261.jpg",
"public/205.jpg",
"public/263.jpg",
],
};