Spaces:
Sleeping
Sleeping
feat: revalidate path / remove create chat api (use server action) / code block style (#53)
71679ee
unverified
'use client'; | |
import React, { useCallback, useState } from 'react'; | |
import useImageUpload from '../../lib/hooks/useImageUpload'; | |
import { cn, fetcher } from '@/lib/utils'; | |
import { SignedPayload, MessageBase } from '@/lib/types'; | |
import { useRouter } from 'next/navigation'; | |
import Loading from '../ui/Loading'; | |
import toast from 'react-hot-toast'; | |
import { | |
generateVideoThumbnails, | |
getVideoCover, | |
} from '@rajesh896/video-thumbnails-generator'; | |
import { ChatWithMessages } from '@/lib/db/types'; | |
import { dbPostCreateChat } from '@/lib/db/functions'; | |
export interface ImageSelectorProps {} | |
type Example = { | |
url: string; | |
initMessages: MessageBase[]; | |
}; | |
const ImageSelector: React.FC<ImageSelectorProps> = () => { | |
const router = useRouter(); | |
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 } = useImageUpload( | |
undefined, | |
async files => { | |
const formData = new FormData(); | |
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]; | |
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); | |
}); | |
} | |
await dbPostCreateChat({ | |
id: resp.id, | |
mediaUrl: resp.publicUrl, | |
}); | |
setUploading(false); | |
router.push(`/chat/${resp.id}`); | |
}; | |
}, | |
); | |
return ( | |
<div | |
{...getRootProps()} | |
className={cn( | |
'dropzone border-2 border-dashed border-gray-400 w-full h-64 flex items-center justify-center rounded-lg mt-4 cursor-pointer', | |
isDragActive && 'bg-gray-500/50 border-solid', | |
)} | |
> | |
<input {...getInputProps()} /> | |
<div className="text-gray-400 text-md"> | |
{isUploading ? ( | |
<Loading /> | |
) : ( | |
'Start using Vision Agent by selecting an image' | |
)} | |
</div> | |
</div> | |
); | |
}; | |
export default ImageSelector; | |