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

BIN
vinniesniper-54816/task1/project/docs/W8FdNNrmGY.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
node_modules

View File

@@ -0,0 +1,68 @@
module.exports = {
env: {
browser: true,
es2021: true,
jest: true,
},
extends: ["plugin:react/recommended", "airbnb", "prettier"],
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["react", "prettier"],
rules: {
"react/react-in-jsx-scope": "off",
"import/no-duplicates": "error",
"import/no-unresolved": "error",
"import/named": "error",
"prettier/prettier": "error",
"react/jsx-filename-extension": [1, { extensions: [".js", ".jsx"] }],
"react/state-in-constructor": "off",
"react/prop-types": "off",
"react/no-access-state-in-setstate": "error",
"react/no-danger": "error",
"react/no-did-mount-set-state": "error",
"react/no-did-update-set-state": "error",
"react/no-will-update-set-state": "error",
"react/no-redundant-should-component-update": "error",
"react/no-this-in-sfc": "error",
"react/no-typos": "error",
"react/no-unused-state": "error",
"react/jsx-no-bind": "error",
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"react/jsx-props-no-spreading": "off",
// overriding recommended rules
"no-constant-condition": ["error", { checkLoops: false }],
"no-console": ["error", { allow: ["log", "warn", "error"] }],
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"no-underscore-dangle": ["error"],
},
settings: {
"import/resolver": {
node: {
paths: ["."],
},
alias: {
map: [
["@/public", "./public"],
["@/config", "./config"],
// Add more here
],
extensions: [".js", ".jsx"],
},
},
},
};

View File

@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

View File

@@ -0,0 +1,8 @@
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Yarn
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

View File

@@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
yarn lint-staged

View File

@@ -0,0 +1,18 @@
node_modules
.next
.DS_Store
static
.vercel
public/
.github/
.babelrc
README.md
# ignore deployment files
/.now
/.serverless
/.serverless_nextjs
/.vercel
.vercel
.now
.env

View File

@@ -0,0 +1,4 @@
{
"printWidth": 80,
"singleQuote": false
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Othneil Drew
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,58 @@
![Stargazers](https://img.shields.io/github/stars/miami78/nextjs-mui-boilerplate?style=for-the-badge)
![Forks](https://img.shields.io/github/forks/miami78/nextjs-mui-boilerplate?label=FORKS&style=for-the-badge)
![License](https://img.shields.io/github/license/miami78/nextjs-mui-boilerplate?style=for-the-badge)
![Issues](https://img.shields.io/github/issues/miami78/nextjs-mui-boilerplate?color=yellow&label=ISSUES&style=for-the-badge)
A JavaScript starter for Next.js that includes all you need to build your next 🦄 project.
## Technologies Used
- [Nextjs](https://nextjs.org/)
- [Material UI](https://mui.com/)
- [Eslint](https://eslint.org/)
- [Prettier](https://prettier.io/)
- [Husky](https://typicode.github.io/husky/#/)
Also includes:
- [Absolute imports](https://nextjs.org/docs/advanced-features/module-path-aliases)
- [AirBnB Style Guides for React](https://github.com/airbnb/javascript/tree/master/react)
# Getting started
```
1. git clone https://github.com/miami78/nextjs-mui-boilerplate
2. cd nextjs-mui-boilerplate
3. yarn && yarn dev or npm install && npm run dev if you prefer not to use yarn.
```
# Usage
### Development server
```bash
yarn start / npm start
```
You can view the development server at `localhost:3000`.
### Production build
```bash
yarn build / npm run build
```
## Contributing
1. Fork this repository;
2. Create your branch: ``git checkout -b my-new-feature``
3. Commit your changes: ``git commit -m 'Add some feature'``
4. Push to the branch: ``git push origin my-new-feature``
Made by [Larry Miami](https://github.com/miami78)

View File

@@ -0,0 +1,58 @@
![Stargazers](https://img.shields.io/github/stars/miami78/nextjs-mui-boilerplate?style=for-the-badge)
![Forks](https://img.shields.io/github/forks/miami78/nextjs-mui-boilerplate?label=FORKS&style=for-the-badge)
![License](https://img.shields.io/github/license/miami78/nextjs-mui-boilerplate?style=for-the-badge)
![Issues](https://img.shields.io/github/issues/miami78/nextjs-mui-boilerplate?color=yellow&label=ISSUES&style=for-the-badge)
A JavaScript starter for Next.js that includes all you need to build your next 🦄 project.
## Technologies Used
- [Nextjs](https://nextjs.org/)
- [Material UI](https://mui.com/)
- [Eslint](https://eslint.org/)
- [Prettier](https://prettier.io/)
- [Husky](https://typicode.github.io/husky/#/)
Also includes:
- [Absolute imports](https://nextjs.org/docs/advanced-features/module-path-aliases)
- [AirBnB Style Guides for React](https://github.com/airbnb/javascript/tree/master/react)
# Getting started
```
1. git clone https://github.com/miami78/nextjs-mui-boilerplate
2. cd nextjs-mui-boilerplate
3. yarn && yarn dev or npm install && npm run dev if you prefer not to use yarn.
```
# Usage
### Development server
```bash
yarn start / npm start
```
You can view the development server at `localhost:3000`.
### Production build
```bash
yarn build / npm run build
```
## Contributing
1. Fork this repository;
2. Create your branch: ``git checkout -b my-new-feature``
3. Commit your changes: ``git commit -m 'Add some feature'``
4. Push to the branch: ``git push origin my-new-feature``
Made by [Larry Miami](https://github.com/miami78)

View File

@@ -0,0 +1,15 @@
import { ThemeProvider as StyledThemeProvider } from "styled-components";
import { ThemeProvider as MuiThemeProvider } from "@mui/material/styles";
import { StylesProvider } from "@mui/styles";
import CssBaseline from "@mui/material/CssBaseline";
const MyThemeProvider = ({ theme, children }) => (
<StylesProvider injectFirst>
<CssBaseline />
<StyledThemeProvider theme={theme}>
<MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
</StyledThemeProvider>
</StylesProvider>
);
export default MyThemeProvider;

View File

@@ -0,0 +1,37 @@
import { createTheme } from "@mui/material/styles";
import { red } from "@mui/material/colors";
// Create a theme instance.
const theme = createTheme({
palette: {
primary: {
main: "#556cd6",
},
secondary: {
main: "#19857b",
},
error: {
main: red.A400,
},
},
components: {
MuiTypography: {
defaultProps: {
variantMapping: {
h1: "h2",
h2: "h2",
h3: "h2",
h4: "h2",
h5: "h2",
h6: "h2",
subtitle1: "h2",
subtitle2: "h2",
body1: "span",
body2: "span",
},
},
},
},
});
export default theme;

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es6",
"lib": ["dom", "dom.iterable", "esnext"],
"baseUrl": ".",
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"paths": {
"@/config/*": ["./config/*"],
"@/public/*": ["./public"]
},
"plugins": []
},
"include": ["**/*.js", "**/*.jsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,3 @@
module.exports = {
reactStrictMode: true,
};

View File

@@ -0,0 +1,53 @@
{
"name": "next-mui-boilerplate",
"private": true,
"description": "A JavaScript Nextjs boilerplate complete with material ui, eslint, airbnb react style guides and husky pre-commit hooks",
"keywords": [
"nextjs",
"mui",
"material-ui",
"airbnb-style-guides",
"husky",
"prettier",
"eslint"
],
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint **/*.js --report-unused-disable-directives",
"lint-fix": "eslint --fix --ext .js,.jsx .",
"format": "prettier --ignore-path .prettierignore --write .",
"prepare_disabled": "husky install"
},
"lint-staged": {
"*js": [
"yarn lint --fix",
"yarn format"
]
},
"dependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material": "^5.1.0",
"@mui/styles": "^5.1.0",
"next": "12.0.3",
"react": "17.0.2",
"react-dom": "17.0.2",
"styled-components": "^5.3.3"
},
"devDependencies": {
"eslint": "<8.0.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-config-next": "12.0.2",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react-hooks": "^4.2.0",
"husky": "^7.0.0",
"lint-staged": "^11.2.6",
"prettier": "^2.4.1"
}
}

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",
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -ex
rm -rf node_modules

File diff suppressed because it is too large Load Diff