Add @langchain/core dependency and update imports***
***Update SidepanelRouting to use dark mode*** ***Add image support to PlaygroundMessage component
This commit is contained in:
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
CheckIcon,
|
||||
ClipboardIcon,
|
||||
} from "@heroicons/react/24/outline"
|
||||
import { CheckIcon, ClipboardIcon } from "@heroicons/react/24/outline"
|
||||
import Markdown from "../../Common/Markdown"
|
||||
import React from "react"
|
||||
|
||||
@@ -12,6 +9,7 @@ type Props = {
|
||||
userAvatar?: JSX.Element
|
||||
isBot: boolean
|
||||
name: string
|
||||
images?: string[]
|
||||
}
|
||||
|
||||
export const PlaygroundMessage = (props: Props) => {
|
||||
@@ -48,13 +46,11 @@ export const PlaygroundMessage = (props: Props) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex w-[calc(100%-50px)] flex-col gap-1 md:gap-3 lg:w-[calc(100%-115px)]">
|
||||
{
|
||||
props.isBot && (
|
||||
{props.isBot && (
|
||||
<span className="absolute mb-8 -top-4 left-0 text-xs text-gray-400 dark:text-gray-500">
|
||||
{props.name}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
)}
|
||||
<div className="flex flex-grow flex-col gap-3">
|
||||
<Markdown message={props.message} />
|
||||
</div>
|
||||
@@ -81,6 +77,19 @@ export const PlaygroundMessage = (props: Props) => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{props.images && (
|
||||
<div className="flex md:max-w-2xl lg:max-w-xl xl:max-w-3xl p-3 m-auto w-full">
|
||||
{props.images.map((image, index) => (
|
||||
<div key={index} className="h-full rounded-md shadow relative">
|
||||
<img
|
||||
src={image}
|
||||
alt="Uploaded"
|
||||
className="h-full w-auto object-cover rounded-md min-w-[50px]"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export const SidePanelBody = () => {
|
||||
isBot={message.isBot}
|
||||
message={message.message}
|
||||
name={message.name}
|
||||
images={message.images || []}
|
||||
/>
|
||||
))}
|
||||
<div className="w-full h-32 md:h-48 flex-shrink-0"></div>
|
||||
|
||||
@@ -3,9 +3,17 @@ import { useMutation } from "@tanstack/react-query"
|
||||
import React from "react"
|
||||
import useDynamicTextareaSize from "~hooks/useDynamicTextareaSize"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import PhotoIcon from "@heroicons/react/24/outline/PhotoIcon"
|
||||
import XMarkIcon from "@heroicons/react/24/outline/XMarkIcon"
|
||||
import { toBase64 } from "~libs/to-base64"
|
||||
|
||||
export const SidepanelForm = () => {
|
||||
type Props = {
|
||||
dropedFile: File | undefined
|
||||
}
|
||||
|
||||
export const SidepanelForm = ({ dropedFile }: Props) => {
|
||||
const textareaRef = React.useRef<HTMLTextAreaElement>(null)
|
||||
const inputRef = React.useRef<HTMLInputElement>(null)
|
||||
|
||||
const resetHeight = () => {
|
||||
const textarea = textareaRef.current
|
||||
@@ -15,16 +23,34 @@ export const SidepanelForm = () => {
|
||||
}
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
message: ""
|
||||
message: "",
|
||||
image: ""
|
||||
}
|
||||
})
|
||||
|
||||
useDynamicTextareaSize(
|
||||
textareaRef,
|
||||
form.values.message,
|
||||
)
|
||||
const onInputChange = async (
|
||||
e: React.ChangeEvent<HTMLInputElement> | File
|
||||
) => {
|
||||
if (e instanceof File) {
|
||||
const base64 = await toBase64(e)
|
||||
form.setFieldValue("image", base64)
|
||||
} else {
|
||||
if (e.target.files) {
|
||||
const base64 = await toBase64(e.target.files[0])
|
||||
form.setFieldValue("image", base64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { onSubmit, selectedModel } = useMessage()
|
||||
React.useEffect(() => {
|
||||
if (dropedFile) {
|
||||
onInputChange(dropedFile)
|
||||
}
|
||||
}, [dropedFile])
|
||||
|
||||
useDynamicTextareaSize(textareaRef, form.values.message, 120)
|
||||
|
||||
const { onSubmit, selectedModel, chatMode } = useMessage()
|
||||
|
||||
const { mutateAsync: sendMessage, isPending: isSending } = useMutation({
|
||||
mutationFn: onSubmit
|
||||
@@ -33,6 +59,24 @@ export const SidepanelForm = () => {
|
||||
return (
|
||||
<div className="p-3 md:p-6 md:bg-white dark:bg-[#0a0a0a] border rounded-t-xl border-black/10 dark:border-gray-900/50">
|
||||
<div className="flex-grow space-y-6 ">
|
||||
{chatMode === "normal" && form.values.image && (
|
||||
<div className="h-full rounded-md shadow relative">
|
||||
<div>
|
||||
<img
|
||||
src={form.values.image}
|
||||
alt="Uploaded"
|
||||
className="h-full w-auto object-cover rounded-md min-w-[50px]"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
form.setFieldValue("image", "")
|
||||
}}
|
||||
className="absolute top-2 right-2 bg-white dark:bg-black p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 text-black dark:text-gray-100">
|
||||
<XMarkIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex">
|
||||
<form
|
||||
onSubmit={form.onSubmit(async (value) => {
|
||||
@@ -42,10 +86,34 @@ export const SidepanelForm = () => {
|
||||
}
|
||||
form.reset()
|
||||
resetHeight()
|
||||
await sendMessage(value.message)
|
||||
await sendMessage({
|
||||
image: value.image,
|
||||
message: value.message.trim()
|
||||
})
|
||||
})}
|
||||
className="shrink-0 flex-grow flex items-center ">
|
||||
<div className="flex items-center p-2 rounded-2xl border bg-gray-100 w-full dark:bg-black dark:border-gray-800">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
inputRef.current?.click()
|
||||
}}
|
||||
className={`flex ml-3 items-center justify-center dark:text-gray-100 ${
|
||||
chatMode === "rag" ? "hidden" : "block"
|
||||
}`}>
|
||||
<PhotoIcon className="h-5 w-5" />
|
||||
</button>
|
||||
<input
|
||||
id="file-upload"
|
||||
name="file-upload"
|
||||
type="file"
|
||||
className="sr-only"
|
||||
ref={inputRef}
|
||||
accept="image/*"
|
||||
multiple={false}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
|
||||
<textarea
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey && !isSending) {
|
||||
@@ -60,12 +128,15 @@ export const SidepanelForm = () => {
|
||||
}
|
||||
form.reset()
|
||||
resetHeight()
|
||||
await sendMessage(value.message)
|
||||
await sendMessage({
|
||||
image: value.image,
|
||||
message: value.message.trim()
|
||||
})
|
||||
})()
|
||||
}
|
||||
}}
|
||||
ref={textareaRef}
|
||||
className="rounded-full pl-4 pr-2 py-2 w-full resize-none bg-transparent focus-within:outline-none sm:text-sm focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100"
|
||||
className="pl-4 pr-2 py-2 w-full resize-none bg-transparent focus-within:outline-none sm:text-sm focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100"
|
||||
required
|
||||
rows={1}
|
||||
tabIndex={0}
|
||||
|
||||
Reference in New Issue
Block a user