ai 추가

This commit is contained in:
익희 김 2024-12-06 21:56:30 +09:00
parent 1fa6f72233
commit b1f0627611
3 changed files with 116 additions and 21 deletions

View File

@ -7,7 +7,7 @@ import { Box, Container, Stack, Grid } from '@mui/material';
// components
import RelatedProductsCarousel from 'src/components/_main/product/relatedProducts';
import ProductDetailTabs from 'src/components/_main/product/tabs';
import ProductAdditionalInfo from 'src/components/_main/product/additionalInfo';
// import ProductAdditionalInfo from 'src/components/_main/product/additionalInfo';
import ProductDetailsCarousel from 'src/components/carousels/customPaginationSilder';
import ProductDetailsSumary from 'src/components/_main/product/summary';
import HeaderBreadcrumbs from 'src/components/headerBreadcrumbs';
@ -81,13 +81,13 @@ export default async function ProductDetail({ params: { slug } }) {
/>
</Grid>
</Grid>
<ProductAdditionalInfo />
{/* <ProductAdditionalInfo /> */}
<Suspense fallback={<></>}>
<ProductDetailTabs
{/* <ProductDetailTabs
product={{ description: data.description, _id: data._id }}
totalRating={totalRating}
totalReviews={totalReviews}
/>
/> */}
</Suspense>
<Suspense fallback={<></>}>
<RelatedProductsCarousel id={data._id} category={category?.slug} />

View File

@ -244,7 +244,7 @@ export default function ProductDetailsSumary({ ...props }) {
({totalRating?.toFixed(1)})
</Typography>
</Stack>
<Stack direction="row" alignItems="center" spacing={1} color="text.secondary">
{/* <Stack direction="row" alignItems="center" spacing={1} color="text.secondary">
<TbMessage size={18} />
<Typography variant="subtitle2" color="text.secondary">
{product?.reviews.length}{' '}
@ -256,7 +256,7 @@ export default function ProductDetailsSumary({ ...props }) {
<Typography variant="subtitle2" color="text.secondary">
{product?.sold} sold
</Typography>
</Stack>
</Stack> */}
</Stack>
<Stack direction="row" alignItems="center" spacing={1} mt={1.5}>
<Typography variant="subtitle1">Brand:</Typography>
@ -294,15 +294,15 @@ export default function ProductDetailsSumary({ ...props }) {
</Grid>
<Grid item xs={12} md={5}>
<Card sx={{ p: 2, position: 'sticky', top: 156 }}>
<Typography variant="h4" className="text-price">
{/* <Typography variant="h4" className="text-price">
{!isLoading && isLoaded && fCurrency(cCurrency(product?.priceSale))} &nbsp;
{product?.price <= product?.priceSale ? null : (
<Typography component="span" className="old-price" color="text.secondary">
{!isLoading && isLoaded && fCurrency(cCurrency(product?.price))}
</Typography>
)}
</Typography>
<Stack direction="row" alignItems="center" spacing={1} className="incrementer-wrapper" my={2}>
</Typography> */}
{/* <Stack direction="row" alignItems="center" spacing={1} className="incrementer-wrapper" my={2}>
{isLoading ? (
<Box sx={{ float: 'right' }}>
<Skeleton variant="rounded" width={120} height={40} />
@ -327,10 +327,10 @@ export default function ProductDetailsSumary({ ...props }) {
>
{product?.available > 0 ? `${product?.available} Items` : <span>Out of stock</span>}
</Typography>
</Stack>
</Stack> */}
<Stack spacing={1} className="contained-buttons" mb={2}>
<Button
{/* <Button
fullWidth
disabled={isMaxQuantity || isLoading || product?.available < 1}
// size={isMobile ? 'medium' : 'large'}
@ -383,9 +383,9 @@ export default function ProductDetailsSumary({ ...props }) {
>
Add to Wishlist
</LoadingButton>
)}
)} */}
{compareProducts?.filter((v) => v._id === product._id).length > 0 ? (
{/* {compareProducts?.filter((v) => v._id === product._id).length > 0 ? (
<Button
startIcon={<GoGitCompare />}
fullWidth
@ -407,7 +407,7 @@ export default function ProductDetailsSumary({ ...props }) {
>
Add to Compare
</Button>
)}
)} */}
<Stack direction="row" spacing={0.5} justifyContent={'center'}>
<Tooltip title="Copy Prooduct URL">
@ -423,14 +423,14 @@ export default function ProductDetailsSumary({ ...props }) {
</Tooltip>
{isClient && (
<>
<Tooltip title="Share on WhatsApp">
<Tooltip title="문의하기">
<WhatsappShareButton url={window?.location.href || ''}>
<IconButton sx={{ color: '#42BC50' }} aria-label="whatsapp">
<IoLogoWhatsapp size={24} />
</IconButton>
</WhatsappShareButton>
</Tooltip>
<Tooltip title="Share on Facebook">
{/* <Tooltip title="Share on Facebook">
<FacebookShareButton url={window?.location.href || ''}>
<IconButton sx={{ color: '#1373EC' }} aria-label="facebook">
<FaFacebook size={24} />
@ -450,13 +450,13 @@ export default function ProductDetailsSumary({ ...props }) {
<FaLinkedin size={24} />
</IconButton>
</LinkedinShareButton>
</Tooltip>
</Tooltip> */}
</>
)}
</Stack>
</Stack>
<Divider />
{/* <Divider />
{shippingData.map((item, index) => (
<Stack
key={index}
@ -473,7 +473,7 @@ export default function ProductDetailsSumary({ ...props }) {
{item.name}
</Typography>
</Stack>
))}
))} */}
</Card>
</Grid>
</Grid>

View File

@ -1,9 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useState, useRef } from 'react';
// mui
import { alpha, styled } from '@mui/material/styles';
import { Box, List, Stack, Paper, Button, ListItem, Typography, Skeleton, IconButton } from '@mui/material';
import { Box, List, Stack, Paper, Button, ListItem, Typography, Skeleton, IconButton, Modal } from '@mui/material';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
// components
@ -43,11 +43,79 @@ UploadMultiFile.propTypes = {
export default function UploadMultiFile({ ...props }) {
const { error, files, onRemove, blob, isEdit, onRemoveAll, loading, sx, ...other } = props;
const [modalOpen, setModalOpen] = useState(false);
const [image, setImage] = useState('');
const [predictions, setPredictions] = useState([]); // Roboflow
const canvasRef = useRef(null); //
const hasFile = files.length > 0;
const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
...other
});
// Roboflow API
const detectWithRoboflow = async () => {
if (!image) return;
const canvas = canvasRef.current;
const ctx = canvas?.getContext('2d');
const img = new Image();
img.src = image;
img.onload = async () => {
//
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Blob
const response = await fetch(image);
const blob = await response.blob();
// API
const formData = new FormData();
formData.append('file', blob);
const apiEndpoint = `https://detect.roboflow.com/picup/1?api_key=s9OJq0UPljSqkPsJY6xP`;
try {
const apiResponse = await fetch(apiEndpoint, {
method: 'POST',
body: formData
});
const result = await apiResponse.json();
console.log('Roboflow Predictions:', result);
if (result.predictions) {
setPredictions(result.predictions);
//
result.predictions.forEach((prediction) => {
const { x, y, width, height, class: label, confidence } = prediction;
//
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(x, y, width, height);
//
ctx.fillStyle = 'red';
ctx.font = '16px Arial';
ctx.fillText(`${label} (${(confidence * 100).toFixed(2)}%)`, x, y > 10 ? y - 5 : 10);
});
}
} catch (error) {
console.error('Error detecting objects:', error);
}
};
};
// AI
const objectDetect = () => {
detectWithRoboflow();
};
return (
<Box sx={{ width: '100%', ...sx }}>
<DropZoneStyle
@ -127,6 +195,10 @@ export default function UploadMultiFile({ ...props }) {
<Paper
variant="outlined"
component="img"
onClick={() => {
setModalOpen(true);
setImage(file.url);
}}
src={!file.blob ? file.url : file.blob}
sx={{
width: '100%',
@ -140,6 +212,29 @@ export default function UploadMultiFile({ ...props }) {
</React.Fragment>
))}
</List>
<Modal open={modalOpen} sx={{ position: 'relative' }}>
<Stack
direction="col"
sx={{ background: '#fff', position: 'fixed', left: '50%', top: '50%', transform: 'translate(-50%, -50%)' }}
>
<IconButton
sx={{ position: 'absolute;', right: 0, top: 0 }}
onClick={() => {
setModalOpen(false);
setImage('');
}}
>
<CloseRoundedIcon fontSize="small" />
</IconButton>
<Button
sx={{ position: 'absolute', bottom: 0, left: '50%', transform: 'translate(-50%, -30px)' }}
onClick={() => objectDetect()}
>
AI 상품 검출
</Button>
<canvas ref={canvasRef} style={{ width: '100%' }} />
</Stack>
</Modal>
{hasFile && (
<Stack direction="row" justifyContent="flex-end">