Spaces:
Running
Running
import * as React from 'react'; | |
import Textarea from 'react-textarea-autosize'; | |
import { UseChatHelpers } from 'ai/react'; | |
import { useEnterSubmit } from '@/lib/hooks/useEnterSubmit'; | |
import { Button, buttonVariants } from '@/components/ui/Button'; | |
import { | |
Tooltip, | |
TooltipContent, | |
TooltipTrigger, | |
} from '@/components/ui/Tooltip'; | |
import { | |
IconArrowElbow, | |
IconPlus, | |
IconRefresh, | |
IconStop, | |
} from '@/components/ui/Icons'; | |
import { useRouter } from 'next/navigation'; | |
import Img from '../ui/Img'; | |
import { MessageBase } from '@/lib/types'; | |
export interface PromptProps | |
extends Pick<UseChatHelpers, 'input' | 'setInput' | 'reload'> { | |
onSubmit: (value: string) => void; | |
isLoading: boolean; | |
url?: string; | |
messages: MessageBase[]; | |
} | |
export function PromptForm({ | |
onSubmit, | |
input, | |
setInput, | |
isLoading, | |
url, | |
messages, | |
reload, | |
}: PromptProps) { | |
const { formRef, onKeyDown } = useEnterSubmit(); | |
const inputRef = React.useRef<HTMLTextAreaElement>(null); | |
const router = useRouter(); | |
React.useEffect(() => { | |
if (inputRef.current) { | |
inputRef.current.focus(); | |
} | |
}, []); | |
return ( | |
<form | |
onSubmit={async e => { | |
e.preventDefault(); | |
if (!input?.trim()) { | |
return; | |
} | |
setInput(''); | |
await onSubmit(input); | |
}} | |
ref={formRef} | |
> | |
<div className="relative flex w-full px-8 pl-2 overflow-hidden max-h-60 grow bg-background sm:rounded-md sm:border sm:px-12 sm:pl-2"> | |
{url && ( | |
<Tooltip> | |
<TooltipTrigger asChild> | |
<Img | |
alt="prompt-image" | |
src={url} | |
className="w-1/5 my-4 mx-2 cursor-zoom-in" | |
/> | |
</TooltipTrigger> | |
<TooltipContent> | |
<Img alt="prompt-hovered-image" src={url} className="m-2" /> | |
</TooltipContent> | |
</Tooltip> | |
)} | |
<Textarea | |
ref={inputRef} | |
tabIndex={0} | |
onKeyDown={onKeyDown} | |
rows={1} | |
value={input} | |
onChange={e => setInput(e.target.value)} | |
placeholder="Ask questions about the images." | |
spellCheck={false} | |
className="min-h-[60px] w-4/5 resize-none bg-transparent px-4 py-[1.3rem] focus-within:outline-none sm:text-sm" | |
/> | |
<div className="absolute left-1/2 -translate-x-1/2 bottom-0 h-12 z-40"> | |
{isLoading ? ( | |
<Button | |
variant="outline" | |
onClick={() => stop()} | |
className="bg-background" | |
> | |
<IconStop className="mr-2" /> | |
Stop generating | |
</Button> | |
) : ( | |
messages?.length >= 2 && ( | |
<div className="flex space-x-2"> | |
<Button variant="outline" onClick={() => reload()}> | |
<IconRefresh className="mr-2" /> | |
Regenerate response | |
</Button> | |
</div> | |
) | |
)} | |
</div> | |
<div className="absolute top-1/2 -translate-y-1/2 right-4"> | |
<Tooltip> | |
<TooltipTrigger asChild> | |
<Button | |
type="submit" | |
size="icon" | |
disabled={isLoading || input === ''} | |
> | |
<IconArrowElbow /> | |
<span className="sr-only">Send message</span> | |
</Button> | |
</TooltipTrigger> | |
<TooltipContent>Send message</TooltipContent> | |
</Tooltip> | |
</div> | |
</div> | |
</form> | |
); | |
} | |