vision-agent / lib /hooks /useMediaUpload.ts
MingruiZhang's picture
feat: Restruct Composer and Homepage (#64)
92f037b unverified
raw
history blame contribute delete
No virus
3.15 kB
import {
generateVideoThumbnails,
getVideoDurationFromVideoFile,
} from '@rajesh896/video-thumbnails-generator';
import { useCallback, useState } from 'react';
import { DropzoneOptions, useDropzone } from 'react-dropzone';
import { toast } from 'react-hot-toast';
import { fetcher } from '../utils';
import { SignedPayload } from '../types';
const useMediaUpload = (
onUpload: (uploadUrl: string) => void,
options?: Partial<DropzoneOptions>,
) => {
const [isUploading, setUploading] = useState(false);
const upload = useCallback(async (file: File, chatId?: string) => {
const { id, signedUrl, publicUrl, fields } = await fetcher<SignedPayload>(
'/api/sign',
{
method: 'POST',
body: JSON.stringify({
id: chatId,
fileType: file.type,
fileName: file.name,
}),
},
);
const formData = new FormData();
Object.entries(fields).forEach(([key, value]) => {
formData.append(key, value as string);
});
formData.append('file', file);
const uploadResponse = await fetch(signedUrl, {
method: 'POST',
body: formData,
});
if (!uploadResponse.ok) {
toast.error(uploadResponse.statusText);
return;
}
return {
id,
publicUrl,
};
}, []);
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
accept: {
'image/*': ['.jpeg', '.png'],
'video/mp4': ['.mp4', '.MP4'],
},
noClick: true,
noKeyboard: true,
multiple: false,
onDrop: async files => {
if (files.length !== 1) {
throw new Error('Only one image can be uploaded at a time');
}
setUploading(true);
const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = async () => {
const file = files[0];
if (file.type === 'video/mp4') {
const duration = await getVideoDurationFromVideoFile(file);
if (duration > 30) {
setUploading(false);
toast.error('Video duration must be less than 30 seconds');
return;
}
} else if (file.size > 2.5 * 1024 * 1024) {
setUploading(false);
toast.error('Image size must be less than 2.5MB');
return;
}
const resp = await upload(file);
if (!resp) {
return;
}
if (file.type === 'video/mp4') {
const thumbnails = await generateVideoThumbnails(file, 1, 'file');
fetch(thumbnails[0])
.then(res => res.blob())
.then(blob => {
const thumbnailFile = new File(
[blob],
file.name.replace('.mp4', '.png').replace('.MP4', '.png'),
{
type: 'image/png',
},
);
return upload(thumbnailFile, resp.id);
});
}
onUpload(resp.publicUrl);
setUploading(false);
};
},
...options,
});
return {
getRootProps,
getInputProps,
isDragActive,
isUploading,
openUpload: open,
};
};
export default useMediaUpload;