From 6d914cc278627376151292bb11f2a603a6df02c8 Mon Sep 17 00:00:00 2001 From: JaberHPranto Date: Tue, 12 Oct 2021 20:51:19 +0600 Subject: [PATCH] plant identification complete --- client/package-lock.json | 138 ++++++++++++++++++ client/package.json | 2 + .../PlantIdentify/PIDetailsModal.js | 63 ++++++++ .../components/PlantIdentify/PlantIdentify.js | 102 +++++++++++++ .../components/PlantSearch/PlantDetails.js | 7 +- client/src/pages/MainPage.js | 4 + client/src/styles/index.css | 14 +- client/src/styles/plant-identify.css | 109 ++++++++++++++ server/controller/blogController.js | 46 ++++++ server/controller/plantIdentifyController.js | 39 +++++ server/index.js | 2 + server/package-lock.json | 13 ++ server/package.json | 1 + server/routes/blogRoute.js | 2 +- server/routes/plantIdentifyRoute.js | 8 + 15 files changed, 544 insertions(+), 6 deletions(-) create mode 100644 client/src/components/PlantIdentify/PIDetailsModal.js create mode 100644 client/src/components/PlantIdentify/PlantIdentify.js create mode 100644 client/src/styles/plant-identify.css create mode 100644 server/controller/plantIdentifyController.js create mode 100644 server/routes/plantIdentifyRoute.js diff --git a/client/package-lock.json b/client/package-lock.json index 0a2c6b0..f5f67aa 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -4725,6 +4725,15 @@ "sha.js": "^2.4.8" } }, + "create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -5591,6 +5600,24 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6603,6 +6630,35 @@ "bser": "2.1.1" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -7616,6 +7672,43 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" }, + "image-to-base64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/image-to-base64/-/image-to-base64-2.2.0.tgz", + "integrity": "sha512-Z+aMwm/91UOQqHhrz7Upre2ytKhWejZlWV/JxUTD1sT7GWWKFDJUEV5scVQKnkzSgPHFuQBUEWcanO+ma0PSVw==", + "requires": { + "node-fetch": "^2.6.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "immer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", @@ -8080,6 +8173,15 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -9707,6 +9809,15 @@ } } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -11905,6 +12016,28 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" }, + "react-file-base64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/react-file-base64/-/react-file-base64-1.0.3.tgz", + "integrity": "sha1-QXTvp5RFsTmQLswnMPxBfv55y4g=", + "requires": { + "react": "^15.6.1" + }, + "dependencies": { + "react": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-15.7.0.tgz", + "integrity": "sha512-5/MMRYmpmM0sMTHGLossnJCrmXQIiJilD6y3YN3TzAwGFj6zdnMtFv6xmi65PHKRV+pehIHpT7oy67Sr6s9AHA==", + "requires": { + "create-react-class": "^15.6.0", + "fbjs": "^0.8.9", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0", + "prop-types": "^15.5.10" + } + } + } + }, "react-google-login": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/react-google-login/-/react-google-login-5.2.2.tgz", @@ -14350,6 +14483,11 @@ "is-typedarray": "^1.0.0" } }, + "ua-parser-js": { + "version": "0.7.28", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz", + "integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==" + }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", diff --git a/client/package.json b/client/package.json index 7c2db69..6855ee9 100644 --- a/client/package.json +++ b/client/package.json @@ -13,9 +13,11 @@ "axios": "^0.21.1", "bootstrap": "^5.0.1", "concurrently": "^6.2.0", + "image-to-base64": "^2.2.0", "react": "^17.0.2", "react-bootstrap": "^1.6.1", "react-dom": "^17.0.2", + "react-file-base64": "^1.0.3", "react-google-login": "^5.2.2", "react-html-parser": "^2.0.2", "react-redux": "^7.2.4", diff --git a/client/src/components/PlantIdentify/PIDetailsModal.js b/client/src/components/PlantIdentify/PIDetailsModal.js new file mode 100644 index 0000000..c75ea45 --- /dev/null +++ b/client/src/components/PlantIdentify/PIDetailsModal.js @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import "../../styles/plant-identify.css"; + +function PIDetailsModal({ name, desc, synonyms, taxonomy, authority, common_names }) { + const [show, setShow] = useState(false); + + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + + return ( + <> + + + + + {name} + {authority} + + +
Common Names
+ {common_names.map(cn => ( +
{cn}
+ ))} +
+ + +
Description
+
{desc}
+
+ +
Taxonomy
+
+
Kingdom: {taxonomy.kingdom}
+
Phylum: {taxonomy.phylum}
+
Class: {taxonomy.class}
+
Order: {taxonomy.order}
+
Family: {taxonomy.family}
+
Genus: {taxonomy.genus}
+
+
+ + +
Synonyms
+ {synonyms.map(syn => ( +
{syn}
+ ))} +
+ + + + + +
+ + ); +} + +export default PIDetailsModal diff --git a/client/src/components/PlantIdentify/PlantIdentify.js b/client/src/components/PlantIdentify/PlantIdentify.js new file mode 100644 index 0000000..d0a8b22 --- /dev/null +++ b/client/src/components/PlantIdentify/PlantIdentify.js @@ -0,0 +1,102 @@ +import axios from 'axios'; +import React, { useState } from 'react'; +import { Button, Col, Form, Row } from 'react-bootstrap'; +import FileBase64 from 'react-file-base64'; +import "../../styles/plant-identify.css"; +import Loader from "../Ecommerce/Loader"; +import PIDetailsModal from './PIDetailsModal'; + +function PlantIdentify() { + const [file, setFile] = useState() + const [imageUrl, setImageUrl] = useState("") + const [plantSuggestion, setPlantSuggestion] = useState([]) + const [loading, setLoading] = useState(false) + + const handleFileInput = (e) => { + e.preventDefault() + getPlantInfo() + setLoading(true) + } + + const getPlantInfo = async () => { + try { + const {data} = await axios.post(`/api/identify-plant`, { file }) + setImageUrl(data.imageUrl) + setPlantSuggestion(data.plantSuggestions) + setLoading(false) + } catch (error) { + console.log('Error',error); + } + } + + // console.log(imageUrl); + console.log(plantSuggestion); + + + return ( +
+
+ setFile(base64)} /> + + + + + {loading ? : ( + <> + {imageUrl && +
+ pi-img +
+ } + + {plantSuggestion && +
+ {plantSuggestion.map(plant => ( + + +
+ {plant.similar_images.map(i => + ( + plant-img + ) + )} +
+ + +
+

{plant.plant_name}

+
Scientific Name:{plant.plant_details.scientific_name}
+
Genus:{plant.plant_details.structured_name.genus}
+
Species:{plant.plant_details.structured_name.species}
+ +
+ + +
+
+ + +
+

{`${((plant.probability).toFixed(2)) * 100} %`}

+
+ + +
+ ))} +
+ + } + + + + )} + + +
+ ) +} + +export default PlantIdentify diff --git a/client/src/components/PlantSearch/PlantDetails.js b/client/src/components/PlantSearch/PlantDetails.js index 2588f24..c273138 100644 --- a/client/src/components/PlantSearch/PlantDetails.js +++ b/client/src/components/PlantSearch/PlantDetails.js @@ -15,11 +15,10 @@ function PlantDetails({ match }) { fetchPlant() }, [match]) - console.log(plantData) return (
{plantData && ( - +
@@ -53,11 +52,11 @@ function PlantDetails({ match }) { - + - + diff --git a/client/src/pages/MainPage.js b/client/src/pages/MainPage.js index 7832dcc..aecb6c5 100644 --- a/client/src/pages/MainPage.js +++ b/client/src/pages/MainPage.js @@ -23,6 +23,7 @@ import ProfileScreen from '../components/Ecommerce/Screen/ProfileScreen'; import RegisterScreen from '../components/Ecommerce/Screen/RegisterScreen'; import ShippingScreen from "../components/Ecommerce/Screen/ShippingScreen"; import UserListScreen from "../components/Ecommerce/Screen/UserListScreen"; +import PlantIdentify from "../components/PlantIdentify/PlantIdentify"; import PlantDetails from "../components/PlantSearch/PlantDetails"; // Plant Search Page import PlantSearch from "../components/PlantSearch/PlantSearch"; @@ -65,6 +66,9 @@ function MainPage() { {/* Plant Search */} + {/* Plant Identify */} + +
diff --git a/client/src/styles/index.css b/client/src/styles/index.css index 66a3523..6f64e2a 100644 --- a/client/src/styles/index.css +++ b/client/src/styles/index.css @@ -31,7 +31,7 @@ code { background-color: var(--color-primary-1); } .bg-col-primary { - background-color: var(--color-primary-1); + background-color: var(--color-primary-1) !important; } .bg-col-primary:hover { background-color: #00c073 !important; @@ -176,3 +176,15 @@ dropdown { .ck-editor__editable_inline { min-height: 300px; } + +.close { + /* background-color: #fff !important; */ + display: none; + font-size: 1rem !important; + width: 3rem !important; + border: none !important; + outline: none !important; + background-color: transparent !important; +} +.pi-det-btn { +} diff --git a/client/src/styles/plant-identify.css b/client/src/styles/plant-identify.css new file mode 100644 index 0000000..bb1eaed --- /dev/null +++ b/client/src/styles/plant-identify.css @@ -0,0 +1,109 @@ +.pi-form { + display: flex; + justify-content: center; + margin-top: 2.5rem; + margin-bottom: 2rem; +} +.pi-mainImg img { + width: 20%; +} +.pi-mainImg { + margin: 2rem auto; + display: flex; + justify-content: center; + padding-bottom: 2rem; +} +.pi-col-2 { + margin-left: -2rem; + padding-top: 1.5rem !important; +} +.pi-col-2-info { + display: flex; + align-items: center; +} +.pi-col-2-info a i { + color: rgba(0, 158, 96, 0.9); + margin-left: 1rem; + cursor: pointer; + font-size: 1.2rem; + margin-top: 0.8rem !important; +} +.pi-plants { + width: 80%; + margin: 0 auto !important; +} +.pi-plants > * { + background-color: #f3f4f6; + margin-bottom: 1.5rem; + padding: 1.2rem; +} + +.pi-plants-img { + display: flex; + width: 80%; + margin-left: -4.2rem; +} +.pi-plants-info { + display: flex; + justify-content: center; +} +.pi-plants-img img:not(:last-child) { + margin-right: 1.5rem !important; +} +.pi-plants-img img { + width: 50%; +} +.pi-probability { + height: 6rem; + width: 6rem; + display: flex; + align-items: center; + justify-content: center; + margin-top: 2.2rem; + border-radius: 50%; + background-color: rgba(0, 158, 96, 0.9); + outline: 4px solid white; +} +.pi-probability p { + color: #f3f4f6; + font-size: 1.3rem; + font-family: "Open Sans" !important; + margin-top: 1rem; +} +.pi-name { + font-size: 1.9rem; + font-family: "Nunito"; + font-weight: bold; +} +.pi-card-info div span { + font-weight: bold; + font-size: 1.1rem; + margin-right: 0.3rem; + font-family: "Nunito"; +} +.pi-card-info div { + font-size: 1.25rem; + font-family: "Nunito"; +} +.pi-modal-btn { + font-size: 0.9rem !important; + margin-top: 0.6rem; +} +.pi-mt { + font-size: 1.6rem !important; +} +.pi-mb h5 { + font-family: "Poppins"; +} +.pi-mb-tax div, +.pi-mb-syn, +.pi-mb-cn, +.pi-mb-desc { + font-family: "Poppins"; +} +.pi-mb-tax div span { + font-style: italic; + font-weight: bold; + font-family: "Nunito" !important; + margin-right: 0.3rem; +} diff --git a/server/controller/blogController.js b/server/controller/blogController.js index 2fc7e93..e89d6f8 100644 --- a/server/controller/blogController.js +++ b/server/controller/blogController.js @@ -1,3 +1,4 @@ +// import fs from 'fs'; import BlogPost from '../models/blogModel.js'; import User from '../models/userModel.js'; // Get all blog posts @@ -40,3 +41,48 @@ export const getBlogById = async (req, res) => { res.status(404).json({ message: "No blog found" }) } } + + +// test +// export const test = (req, res) => { +// const {file } = req.body +// // const files = ['photo1.jpg', 'photo2.jpg']; +// // const base64files = fs.readFileSync(file, "base64") +// console.log(file); +// const arr = [] +// // const k = Object.keys(file) +// // const v = Object.values(file) +// // console.log(typeof(k)); +// // console.log(v); +// // const fst = String(file) + +// // const t = k[0].replace("data:image/jpeg;base64,","") +// // console.log(typeof(arr)); +// arr.push(file) +// // arr.push(k[0]) +// // console.log(typeof(file)); +// const data = { +// api_key: "Bxj3gYFWqAJpIqan2CenvlqFUr3XepY4nBW0z2lKhX3kKVpnfY", +// images:arr, +// modifiers: ["crops_fast", "similar_images"], +// plant_language: "en", +// plant_details: ["common_names", +// "url", +// "name_authority", +// "wiki_description", +// "taxonomy", +// "synonyms"] +// }; +// const config = { +// headers: { +// 'Content-Type': 'application/json', + +// // api_key: "Bxj3gYFWqAJpIqan2CenvlqFUr3XepY4nBW0z2lKhX3kKVpnfY", +// } +// } +// axios.post('https://api.plant.id/v2/identify', data,config).then(res => { +// console.log('Success:',res.data); +// }).catch(error => { +// console.error('Error: ') +// }) +// } \ No newline at end of file diff --git a/server/controller/plantIdentifyController.js b/server/controller/plantIdentifyController.js new file mode 100644 index 0000000..a6080e1 --- /dev/null +++ b/server/controller/plantIdentifyController.js @@ -0,0 +1,39 @@ +import axios from 'axios'; +export const IdentifyPlant = (req, res) => { + const {file } = req.body; + const arr = [] + arr.push(file) + + const data = { + api_key: process.env.PI_API_KEY, + images:arr, + modifiers: ["crops_fast", "similar_images"], + plant_language: "en", + plant_details: ["common_names", + "url", + "name_authority", + "wiki_description", + "taxonomy", + "synonyms"] +}; + const config = { + headers: { + 'Content-Type': 'application/json', + } + } + axios.post('https://api.plant.id/v2/identify', data, config).then(result => { + console.log('Success'); + const plantSuggestions = result.data.suggestions + const imageUrl = result.data.images[0].url + const isPlantProbability = result.data.is_plant_probability + // console.log(plantSuggestions); + // console.log(imageUrl); + // console.log(isPlantProbability); + + return res.status(200).json({ imageUrl, plantSuggestions, isPlantProbability }) + + }).catch(error => { + console.error('Error: ', error) + return res.status(500).json({error:"Server Error"}) + }) +} diff --git a/server/index.js b/server/index.js index 51709eb..f67d865 100644 --- a/server/index.js +++ b/server/index.js @@ -7,6 +7,7 @@ import connectDB from "./config/db.js"; import { errorHandler, notFound } from "./middlewares/errorMiddleware.js"; import blogRoutes from "./routes/blogRoute.js"; import orderRoutes from "./routes/orderRoutes.js"; +import plantIdentifyRoutes from "./routes/plantIdentifyRoute.js"; import productRoutes from "./routes/productRoutes.js"; import uploadRoutes from "./routes/uploadRoutes.js"; import userRoutes from "./routes/userRoutes.js"; @@ -33,6 +34,7 @@ app.use("/api/users", userRoutes); app.use("/api/orders", orderRoutes); app.use("/api/uploads", uploadRoutes); app.use("/api/blogs", blogRoutes); +app.use("/api/identify-plant",plantIdentifyRoutes) // static folder const __dirname = path.resolve() diff --git a/server/package-lock.json b/server/package-lock.json index 7c14cf6..b5bac3f 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -222,6 +222,14 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "axios": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.22.0.tgz", + "integrity": "sha512-Z0U3uhqQeg1oNcihswf4ZD57O3NrR1+ZXhxaROaWpDmsDTx7T2HNBV2ulBtie2hwJptu8UvgnJoK+BIqdzh/1w==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1003,6 +1011,11 @@ } } }, + "follow-redirects": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", diff --git a/server/package.json b/server/package.json index 4999011..91dd1a0 100644 --- a/server/package.json +++ b/server/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "axios": "^0.22.0", "bcrypt": "^5.0.1", "cloudinary": "^1.26.2", "concurrently": "^6.2.0", diff --git a/server/routes/blogRoute.js b/server/routes/blogRoute.js index 3c26d24..2b3c664 100644 --- a/server/routes/blogRoute.js +++ b/server/routes/blogRoute.js @@ -5,7 +5,7 @@ const router = express.Router() router.get("/", getBlogs) router.post("/", isLoggedIn, postBlogs) -router.get("/:id",getBlogById) +router.get("/:id", getBlogById) export default router \ No newline at end of file diff --git a/server/routes/plantIdentifyRoute.js b/server/routes/plantIdentifyRoute.js new file mode 100644 index 0000000..786f797 --- /dev/null +++ b/server/routes/plantIdentifyRoute.js @@ -0,0 +1,8 @@ +import express from 'express' +import { IdentifyPlant } from '../controller/plantIdentifyController.js' +const router = express.Router() + +router.post("/",IdentifyPlant) + + +export default router \ No newline at end of file
Row Spacing{plantData.attributes.row_spacing}{plantData.attributes.row_spacing} cm
Height{plantData.attributes.height}{plantData.attributes.height} cm