Update useMessageOption hook and Playground component

This commit is contained in:
n4ze3m
2024-04-05 23:17:55 +05:30
parent b86332f9ec
commit aae2ddecbc
11 changed files with 262 additions and 57 deletions

View File

@@ -0,0 +1,18 @@
import { CSVIcon } from "@/components/Icons/CSVIcon"
import { PDFIcon } from "@/components/Icons/PDFIcon"
import { TXTIcon } from "@/components/Icons/TXTIcon"
type Props = {
type: string
className?: string
}
export const KnowledgeIcon = ({ type, className = "w-6 h-6" }: Props) => {
if (type === "pdf" || type === "application/pdf") {
return <PDFIcon className={className} />
} else if (type === "csv" || type === "text/csv") {
return <CSVIcon className={className} />
} else if (type === "txt" || type === "text/plain") {
return <TXTIcon className={className} />
}
}

View File

@@ -1,4 +1,5 @@
import { getAllKnowledge } from "@/db/knowledge"
import { useMessageOption } from "@/hooks/useMessageOption"
import { useQuery } from "@tanstack/react-query"
import { Dropdown, Tooltip } from "antd"
import { Blocks } from "lucide-react"
@@ -7,6 +8,7 @@ import { useTranslation } from "react-i18next"
export const KnowledgeSelect: React.FC = () => {
const { t } = useTranslation("playground")
const { setSelectedKnowledge, selectedKnowledge } = useMessageOption()
const { data } = useQuery({
queryKey: ["getAllKnowledge"],
queryFn: async () => {
@@ -30,14 +32,21 @@ export const KnowledgeSelect: React.FC = () => {
{d.title}
</div>
),
onClick: () => {}
onClick: () => {
const knowledge = data?.find((k) => k.id === d.id)
if (selectedKnowledge?.id === d.id) {
setSelectedKnowledge(null)
} else {
setSelectedKnowledge(knowledge)
}
}
})) || [],
style: {
maxHeight: 500,
overflowY: "scroll"
},
// hidescrollbars: true
className: "no-scrollbar"
className: "no-scrollbar",
activeKey: selectedKnowledge?.id
}}
placement={"topLeft"}
trigger={["click"]}>

View File

@@ -0,0 +1,39 @@
import { Knowledge } from "@/db/knowledge"
import { XIcon } from "lucide-react"
import { KnowledgeIcon } from "./KnowledgeIcon"
type Props = {
knowledge: Knowledge
onClose: () => void
}
export const SelectedKnowledge = ({ knowledge, onClose }: Props) => {
return (
<div className="mb-3 border flex justify-between items-center rounded-md p-2 dark:border-gray-600">
<div className="flex flex-col gap-2">
<div>
<h3 className="text-lg font-semibold dark:text-gray-100">
{knowledge.title}
</h3>
</div>
<div className="flex flex-row overflow-x-auto gap-2 w-full">
{knowledge.source.map((source, index) => (
<div
key={index}
className="inline-flex gap-2 border rounded-md p-1 dark:border-gray-600 dark:text-gray-100">
<KnowledgeIcon type={source.type} className="w-4 h-4" />
{source.filename}
</div>
))}
</div>
</div>
<div>
<button
onClick={onClose}
className="flex items-center justify-center bg-white dark:bg-[#262626] p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100">
<XIcon className="h-5 w-5" />
</button>
</div>
</div>
)
}

View File

@@ -1,19 +1,21 @@
import { useState } from "react"
import { useTranslation } from "react-i18next"
import { AddKnowledge } from "./AddKnowledge"
import {
useMutation,
useQuery,
useQueryClient
} from "@tanstack/react-query"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { deleteKnowledge, getAllKnowledge } from "@/db/knowledge"
import { Skeleton, Table, Tag, Tooltip, message } from "antd"
import { Trash2 } from "lucide-react"
import { KnowledgeIcon } from "./KnowledgeIcon"
import { useMessageOption } from "@/hooks/useMessageOption"
export const KnowledgeSettings = () => {
const { t } = useTranslation(["knownledge", "common"])
const [open, setOpen] = useState(false)
const queryClient = useQueryClient()
const {
selectedKnowledge,
setSelectedKnowledge
} = useMessageOption()
const { data, status } = useQuery({
queryKey: ["fetchAllKnowledge"],
@@ -91,6 +93,9 @@ export const KnowledgeSettings = () => {
onClick={() => {
if (window.confirm(t("confirm.delete"))) {
deleteKnowledgeMutation(record.id)
if(selectedKnowledge.id === record.id) {
setSelectedKnowledge(null)
}
}
}}
className="text-red-500 dark:text-red-400">
@@ -110,11 +115,6 @@ export const KnowledgeSettings = () => {
title: t("expandedColumns.name"),
key: "filename",
dataIndex: "filename"
},
{
title: t("expandedColumns.type"),
key: "type",
dataIndex: "type"
}
]}
dataSource={record.source}

View File

@@ -1,15 +1,21 @@
import React from "react"
import { PlaygroundForm } from "./PlaygroundForm"
import { PlaygroundChat } from "./PlaygroundChat"
import { useMessageOption } from "@/hooks/useMessageOption"
export const Playground = () => {
const drop = React.useRef<HTMLDivElement>(null)
const [dropedFile, setDropedFile] = React.useState<File | undefined>()
const { selectedKnowledge } = useMessageOption()
const [dropState, setDropState] = React.useState<
"idle" | "dragging" | "error"
>("idle")
React.useEffect(() => {
if (selectedKnowledge) {
return
}
if (!drop.current) {
return
}
@@ -64,7 +70,7 @@ export const Playground = () => {
drop.current.removeEventListener("dragleave", handleDragLeave)
}
}
}, [])
}, [selectedKnowledge])
return (
<div
ref={drop}

View File

@@ -13,6 +13,7 @@ import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
import { getVariable } from "~/utils/select-varaible"
import { useTranslation } from "react-i18next"
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
import { SelectedKnowledge } from "../Knowledge/SelectedKnwledge"
type Props = {
dropedFile: File | undefined
@@ -33,7 +34,9 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
setWebSearch,
selectedQuickPrompt,
textareaRef,
setSelectedQuickPrompt
setSelectedQuickPrompt,
selectedKnowledge,
setSelectedKnowledge
} = useMessageOption()
const textAreaFocus = () => {
@@ -155,6 +158,14 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
}
return (
<div className="px-3 pt-3 md:px-6 md:pt-6 bg-gray-50 dark:bg-[#262626] border rounded-t-xl dark:border-gray-600">
{selectedKnowledge && (
<SelectedKnowledge
onClose={() => {
setSelectedKnowledge(null)
}}
knowledge={selectedKnowledge}
/>
)}
<div
className={`h-full rounded-md shadow relative ${
form.values.image.length === 0 ? "hidden" : "block"
@@ -225,29 +236,31 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
/>
<div className="mt-4 flex justify-between items-center">
<div className="flex">
<Tooltip title={t("tooltip.searchInternet")}>
<div className="inline-flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-5 h-5 dark:text-gray-300">
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418"
{!selectedKnowledge && (
<Tooltip title={t("tooltip.searchInternet")}>
<div className="inline-flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-5 h-5 dark:text-gray-300">
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418"
/>
</svg>
<Switch
value={webSearch}
onChange={(e) => setWebSearch(e)}
checkedChildren={t("form.webSearch.on")}
unCheckedChildren={t("form.webSearch.off")}
/>
</svg>
<Switch
value={webSearch}
onChange={(e) => setWebSearch(e)}
checkedChildren={t("form.webSearch.on")}
unCheckedChildren={t("form.webSearch.off")}
/>
</div>
</Tooltip>
</div>
</Tooltip>
)}
</div>
<div className="flex !justify-end gap-3">
<KnowledgeSelect />
@@ -276,18 +289,20 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
</button>
</Tooltip>
<Tooltip title={t("tooltip.uploadImage")}>
<button
type="button"
onClick={() => {
inputRef.current?.click()
}}
className={`flex items-center justify-center dark:text-gray-300 ${
chatMode === "rag" ? "hidden" : "block"
}`}>
<ImageIcon className="h-5 w-5" />
</button>
</Tooltip>
{!selectedKnowledge && (
<Tooltip title={t("tooltip.uploadImage")}>
<button
type="button"
onClick={() => {
inputRef.current?.click()
}}
className={`flex items-center justify-center dark:text-gray-300 ${
chatMode === "rag" ? "hidden" : "block"
}`}>
<ImageIcon className="h-5 w-5" />
</button>
</Tooltip>
)}
{!isSending ? (
<Dropdown.Button
htmlType="submit"