knownledge preview
This commit is contained in:
@@ -5,6 +5,7 @@ import { WebSearch } from "./WebSearch"
|
||||
import { CheckIcon, ClipboardIcon, Pen, RotateCcw } from "lucide-react"
|
||||
import { EditMessageForm } from "./EditMessageForm"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { MessageSource } from "./MessageSource"
|
||||
|
||||
type Props = {
|
||||
message: string
|
||||
@@ -23,6 +24,7 @@ type Props = {
|
||||
isSearchingInternet?: boolean
|
||||
sources?: any[]
|
||||
hideEditAndRegenerate?: boolean
|
||||
onSourceClick?: (source: any) => void
|
||||
}
|
||||
|
||||
export const PlaygroundMessage = (props: Props) => {
|
||||
@@ -95,13 +97,9 @@ export const PlaygroundMessage = (props: Props) => {
|
||||
{props.isBot && props?.sources && props?.sources.length > 0 && (
|
||||
<div className="mb-3 flex flex-wrap gap-2">
|
||||
{props?.sources?.map((source, index) => (
|
||||
<a
|
||||
key={index}
|
||||
href={source?.url}
|
||||
target="_blank"
|
||||
className="inline-flex cursor-pointer transition-shadow duration-300 ease-in-out hover:shadow-lg items-center rounded-md bg-gray-100 p-1 text-xs text-gray-800 border border-gray-300 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-100 opacity-80 hover:opacity-100">
|
||||
<span className="text-xs">{source.name}</span>
|
||||
</a>
|
||||
<MessageSource
|
||||
onSourceClick={props.onSourceClick}
|
||||
key={index} source={source} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
37
src/components/Common/Playground/MessageSource.tsx
Normal file
37
src/components/Common/Playground/MessageSource.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { KnowledgeIcon } from "@/components/Option/Knowledge/KnowledgeIcon"
|
||||
|
||||
type Props = {
|
||||
source: {
|
||||
name?: string
|
||||
url?: string
|
||||
mode?: string
|
||||
type?: string
|
||||
pageContent?: string
|
||||
content?: string
|
||||
}
|
||||
onSourceClick?: (source: any) => void
|
||||
}
|
||||
|
||||
export const MessageSource: React.FC<Props> = ({ source, onSourceClick }) => {
|
||||
if (source?.mode === "rag") {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
onSourceClick && onSourceClick(source)
|
||||
}}
|
||||
className="inline-flex gap-2 cursor-pointer transition-shadow duration-300 ease-in-out hover:shadow-lg items-center rounded-md bg-gray-100 p-1 text-xs text-gray-800 border border-gray-300 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-100 opacity-80 hover:opacity-100">
|
||||
<KnowledgeIcon type={source.type} className="h-4 w-5" />
|
||||
<span className="text-xs">{source.name}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href={source?.url}
|
||||
target="_blank"
|
||||
className="inline-flex cursor-pointer transition-shadow duration-300 ease-in-out hover:shadow-lg items-center rounded-md bg-gray-100 p-1 text-xs text-gray-800 border border-gray-300 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-100 opacity-80 hover:opacity-100">
|
||||
<span className="text-xs">{source.name}</span>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
52
src/components/Common/Playground/MessageSourcePopup.tsx
Normal file
52
src/components/Common/Playground/MessageSourcePopup.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { KnowledgeIcon } from "@/components/Option/Knowledge/KnowledgeIcon"
|
||||
import { Modal } from "antd"
|
||||
|
||||
type Props = {
|
||||
source: any
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
export const MessageSourcePopup: React.FC<Props> = ({
|
||||
source,
|
||||
open,
|
||||
setOpen
|
||||
}) => {
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
// mask={false}
|
||||
zIndex={10000}
|
||||
onCancel={() => setOpen(false)}
|
||||
footer={null}
|
||||
onOk={() => setOpen(false)}>
|
||||
<div className="flex flex-col gap-2 mt-6">
|
||||
<h4 className="bg-gray-100 text-md dark:bg-gray-800 inline-flex gap-2 items-center text-gray-800 dark:text-gray-100 font-semibold p-2">
|
||||
{source?.type && (
|
||||
<KnowledgeIcon type={source?.type} className="h-4 w-5" />
|
||||
)}
|
||||
{source?.name}
|
||||
</h4>
|
||||
{source?.type === "pdf" ? (
|
||||
<>
|
||||
<p className="text-gray-500 text-sm">{source?.pageContent}</p>
|
||||
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<span className="border border-gray-300 dark:border-gray-700 rounded-md p-1 text-gray-500 text-xs">
|
||||
{`Page ${source?.metadata?.page}`}
|
||||
</span>
|
||||
|
||||
<span className="border border-gray-300 dark:border-gray-700 rounded-md p-1 text-xs text-gray-500">
|
||||
{`Line ${source?.metadata?.loc?.lines?.from} - ${source?.metadata?.loc?.lines?.to}`}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-gray-500 text-sm">{source?.pageContent}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import React from "react"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { PlaygroundEmpty } from "./PlaygroundEmpty"
|
||||
import { PlaygroundMessage } from "~/components/Common/Playground/Message"
|
||||
import { MessageSourcePopup } from "@/components/Common/Playground/MessageSourcePopup"
|
||||
|
||||
export const PlaygroundChat = () => {
|
||||
const {
|
||||
@@ -12,41 +13,55 @@ export const PlaygroundChat = () => {
|
||||
editMessage
|
||||
} = useMessageOption()
|
||||
const divRef = React.useRef<HTMLDivElement>(null)
|
||||
const [isSourceOpen, setIsSourceOpen] = React.useState(false)
|
||||
const [source, setSource] = React.useState<any>(null)
|
||||
React.useEffect(() => {
|
||||
if (divRef.current) {
|
||||
divRef.current.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
})
|
||||
return (
|
||||
<div className="grow flex flex-col md:translate-x-0 transition-transform duration-300 ease-in-out">
|
||||
{messages.length === 0 && (
|
||||
<div className="mt-32">
|
||||
<PlaygroundEmpty />
|
||||
</div>
|
||||
)}
|
||||
{/* {messages.length > 0 && <div className="w-full h-16 flex-shrink-0"></div>} */}
|
||||
{messages.map((message, index) => (
|
||||
<PlaygroundMessage
|
||||
key={index}
|
||||
isBot={message.isBot}
|
||||
message={message.message}
|
||||
name={message.name}
|
||||
images={message.images || []}
|
||||
currentMessageIndex={index}
|
||||
totalMessages={messages.length}
|
||||
onRengerate={regenerateLastMessage}
|
||||
isProcessing={streaming}
|
||||
isSearchingInternet={isSearchingInternet}
|
||||
sources={message.sources}
|
||||
onEditFormSubmit={(value) => {
|
||||
editMessage(index, value, !message.isBot)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{messages.length > 0 && (
|
||||
<div className="w-full h-32 md:h-48 flex-shrink-0"></div>
|
||||
)}
|
||||
<div ref={divRef} />
|
||||
</div>
|
||||
<>
|
||||
{" "}
|
||||
<div className="grow flex flex-col md:translate-x-0 transition-transform duration-300 ease-in-out">
|
||||
{messages.length === 0 && (
|
||||
<div className="mt-32">
|
||||
<PlaygroundEmpty />
|
||||
</div>
|
||||
)}
|
||||
{/* {messages.length > 0 && <div className="w-full h-16 flex-shrink-0"></div>} */}
|
||||
{messages.map((message, index) => (
|
||||
<PlaygroundMessage
|
||||
key={index}
|
||||
isBot={message.isBot}
|
||||
message={message.message}
|
||||
name={message.name}
|
||||
images={message.images || []}
|
||||
currentMessageIndex={index}
|
||||
totalMessages={messages.length}
|
||||
onRengerate={regenerateLastMessage}
|
||||
isProcessing={streaming}
|
||||
isSearchingInternet={isSearchingInternet}
|
||||
sources={message.sources}
|
||||
onEditFormSubmit={(value) => {
|
||||
editMessage(index, value, !message.isBot)
|
||||
}}
|
||||
onSourceClick={(data) => {
|
||||
setSource(data)
|
||||
setIsSourceOpen(true)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{messages.length > 0 && (
|
||||
<div className="w-full h-32 md:h-48 flex-shrink-0"></div>
|
||||
)}
|
||||
<div ref={divRef} />
|
||||
</div>
|
||||
<MessageSourcePopup
|
||||
open={isSourceOpen}
|
||||
setOpen={setIsSourceOpen}
|
||||
source={source}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user