업로드!

This commit is contained in:
익희 김 2025-01-20 04:08:17 +09:00
parent 4d92cc2b61
commit 2bf1c54e7a
2 changed files with 198 additions and 11 deletions

View File

@ -10,12 +10,13 @@ import Typography from '@mui/material/Typography';
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import Skeleton from '@mui/material/Skeleton'; import Skeleton from '@mui/material/Skeleton';
import { InputAdornment, Stack, Button } from '@mui/material'; import { InputAdornment, Stack, Button, Modal, IconButton } from '@mui/material';
import MenuList from '@mui/material/MenuList'; import MenuList from '@mui/material/MenuList';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemIcon from '@mui/material/ListItemIcon';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
// components // components
import NoDataFound from 'src/illustrations/dataNotFound'; import NoDataFound from 'src/illustrations/dataNotFound';
@ -28,6 +29,65 @@ import { useCurrencyFormatter } from 'src/hooks/formatCurrency';
// api // api
import * as api from 'src/services'; import * as api from 'src/services';
const axios = require('axios');
const getImageUrl = async (ids) => {
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
try {
const responses = await Promise.all(
ids.map(async (id) => {
const response = await fetch(
`https://api.roboflow.com/picup/picup/images/${id}?api_key=s9OJq0UPljSqkPsJY6xP`,
requestOptions
);
if (!response.ok) {
throw new Error(`Error fetching image for ID: ${id}, Status: ${response.status}`);
}
return response.json(); // JSON
})
);
return responses; //
} catch (error) {
console.error('Error fetching image URLs:', error);
return null; // null
}
};
const searchImages = async (imageBase64) => {
const myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/json');
const raw = JSON.stringify({
like_image: 'MV09CPgMSn9uhQ5D2nl5',
limit: 3,
in_dataset: true
});
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
try {
const response = await fetch(
'https://api.roboflow.com/picup/picup/search?api_key=s9OJq0UPljSqkPsJY6xP',
requestOptions
);
const result = await response.json();
return result; //
} catch (error) {
console.error('Error fetching images:', error);
throw error;
}
};
Search.propTypes = { Search.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
mobile: PropTypes.bool.isRequired mobile: PropTypes.bool.isRequired
@ -56,6 +116,9 @@ export default function Search({ ...props }) {
const router = useRouter(); const router = useRouter();
const [search, setSearch] = React.useState(''); const [search, setSearch] = React.useState('');
const [image, setImage] = React.useState(null);
const [imagesResultID, setImagesResultID] = React.useState(null);
const [roboFlowUrlLists, setRoboFlowUrlLists] = React.useState([]);
const { data: filters, isLoading: filtersLoading } = useQuery(['get-search-filters'], () => api.getSearchFilters()); const { data: filters, isLoading: filtersLoading } = useQuery(['get-search-filters'], () => api.getSearchFilters());
const { mutate, isLoading } = useMutation('search', api.search, { const { mutate, isLoading } = useMutation('search', api.search, {
@ -108,21 +171,48 @@ export default function Search({ ...props }) {
} }
}; };
// const handleFileChange = async (event) => {
const handleFileChange = (event) => {
const file = event.target.files?.[0]; const file = event.target.files?.[0];
if (file) { if (file) {
console.log('Selected File:', file);
// :
const reader = new FileReader(); const reader = new FileReader();
reader.onload = () => { reader.onloadend = async () => {
console.log('Image Preview URL:', reader.result); const base64Image = reader.result.split(',')[1]; // base64
setImage(reader.result);
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
}; };
const objectDetect = async (image) => {
try {
const result = await searchImages(image);
// id
const imageIds = result.results.map((r) => r.id);
//
setImagesResultID(imageIds);
console.log('Image IDs:', imageIds); //
} catch (error) {
console.error('Error in image search:', error);
}
};
React.useEffect(() => {
if (imagesResultID && imagesResultID.length > 0) {
getImageUrl(imagesResultID).then((url) => {
setRoboFlowUrlLists(url);
});
}
}, [imagesResultID]);
React.useEffect(() => {
if (roboFlowUrlLists) {
console.log(roboFlowUrlLists);
}
}, [roboFlowUrlLists]);
return ( return (
<> <>
<TextField <TextField
@ -167,7 +257,9 @@ export default function Search({ ...props }) {
} }
}} }}
/> />
<Button variant='contained' sx={{ width: '100%', borderRadius: 0 }} onClick={handleImageSearch}>이미지 검색</Button> <Button variant="contained" sx={{ width: '100%', borderRadius: 0 }} onClick={handleImageSearch}>
이미지 검색
</Button>
<input <input
type="file" type="file"
accept="image/*" accept="image/*"
@ -332,13 +424,13 @@ export default function Search({ ...props }) {
{isLoading ? <Skeleton variant="text" width="200px" /> : product.category} {isLoading ? <Skeleton variant="text" width="200px" /> : product.category}
</Typography> </Typography>
</div> </div>
<Typography variant="subtitle1" color="text.primary" noWrap> {/* <Typography variant="subtitle1" color="text.primary" noWrap>
{isLoading ? ( {isLoading ? (
<Skeleton variant="text" width="100px" /> <Skeleton variant="text" width="100px" />
) : ( ) : (
fCurrency(cCurrency(product.priceSale)) fCurrency(cCurrency(product.priceSale))
)} )}
</Typography> </Typography> */}
</Stack> </Stack>
</ListItemText> </ListItemText>
</MenuItem> </MenuItem>
@ -347,6 +439,63 @@ export default function Search({ ...props }) {
</> </>
)} )}
</Box>{' '} </Box>{' '}
{roboFlowUrlLists &&
roboFlowUrlLists.map((i, index) => (
<MenuList
key={`search-by-images-${i.image.annotation.key}-${index.toString()}`}
sx={{
pt: 0,
mt: 1,
overflow: 'auto',
px: 1,
li: {
borderRadius: '8px',
border: `1px solid transparent`,
'&:hover, &.Mui-focusVisible, &.Mui-selected ': {
border: (theme) => `1px solid ${theme.palette.primary.main}`,
bgcolor: (theme) => alpha(theme.palette.primary.main, 0.16),
h6: {
color: 'primary.main'
}
},
'&.active': {
border: (theme) => `1px solid ${theme.palette.primary.main}`,
bgcolor: (theme) => alpha(theme.palette.primary.main, 0.16),
h6: {
color: 'primary.main'
}
}
}
}}
autoFocusItem={!focus}
>
<MenuItem>
<ListItemIcon>
<img
alt="이미지"
src={i.image.urls.original}
style={{ width: '40px', height: '40px', borderRadius: '100%' }}
/>
</ListItemIcon>
<ListItemText>
<Stack direction="row" gap={1} alignItems={'center'} justifyContent={'space-between'}>
<div>
<Typography variant="subtitle1" color="text.primary" noWrap>
Object Data Set {index}
</Typography>
<Typography variant="body2" color="text.secondary" noWrap>
{i.image.tags.map((i) => {
return i;
})}
{` `}
<span>{i.image.r * 100}%</span>
</Typography>
</div>
</Stack>
</ListItemText>
</MenuItem>
</MenuList>
))}
{multiSelect && ( {multiSelect && (
<Stack gap={1} direction={'row'} p={1} justifyContent={'end'}> <Stack gap={1} direction={'row'} p={1} justifyContent={'end'}>
<Button variant="outlined" color="primary" onClick={() => handleSave(selectedProducts)}> <Button variant="outlined" color="primary" onClick={() => handleSave(selectedProducts)}>
@ -358,6 +507,42 @@ export default function Search({ ...props }) {
</Stack> </Stack>
)} )}
</Box> </Box>
{/* 이미지 미리보기 렌더링 */}
{image && (
<Modal
open={image}
sx={{ height: '100vh', width: '100vw', display: 'flex', justifyContent: 'center', alignItems: 'center' }}
>
<Box sx={{ position: 'relative' }}>
<Box mt={2} display="flex" justifyContent="center">
<IconButton
sx={{ position: 'absolute;', right: 0, top: 10, mixBlendMode: 'difference' }}
onClick={() => {
setImage(null);
}}
>
<CloseRoundedIcon fontSize="small" />
</IconButton>
<img
src={image}
style={{
maxWidth: '100%',
maxHeight: '300px',
borderRadius: '8px',
border: '1px solid #ddd'
}}
/>
<Button
sx={{ position: 'absolute', bottom: 0, left: '50%', transform: 'translate(-50%, 0px)' }}
onClick={() => objectDetect(image)}
>
이미지 상품 검색
</Button>
</Box>
</Box>
</Modal>
)}
</> </>
); );
} }

View File

@ -12,6 +12,8 @@ import { varFadeInRight } from '../animate';
// react dropzone // react dropzone
import { useDropzone } from 'react-dropzone'; import { useDropzone } from 'react-dropzone';
const DropZoneStyle = styled('div')(({ theme }) => ({ const DropZoneStyle = styled('div')(({ theme }) => ({
outline: 'none', outline: 'none',
display: 'flex', display: 'flex',