feat: add IoD search
This commit is contained in:
@@ -18,7 +18,7 @@ import { useTTS } from "@/hooks/useTTS"
|
||||
import { tagColors } from "@/utils/color"
|
||||
import { removeModelSuffix } from "@/db/models"
|
||||
import { GenerationInfo } from "./GenerationInfo"
|
||||
import { parseReasoning, } from "@/libs/reasoning"
|
||||
import { parseReasoning } from "@/libs/reasoning"
|
||||
import { humanizeMilliseconds } from "@/utils/humanize-milliseconds"
|
||||
type Props = {
|
||||
message: string
|
||||
@@ -36,7 +36,8 @@ type Props = {
|
||||
isProcessing: boolean
|
||||
webSearch?: {}
|
||||
isSearchingInternet?: boolean
|
||||
sources?: any[]
|
||||
webSources?: any[]
|
||||
iodSources?: any[]
|
||||
hideEditAndRegenerate?: boolean
|
||||
onSourceClick?: (source: any) => void
|
||||
isTTSEnabled?: boolean
|
||||
@@ -166,7 +167,7 @@ export const PlaygroundMessage = (props: Props) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.isBot && props?.sources && props?.sources.length > 0 && (
|
||||
{props.isBot && props?.webSources && props?.webSources.length > 0 && (
|
||||
<Collapse
|
||||
className="mt-6"
|
||||
ghost
|
||||
@@ -175,15 +176,44 @@ export const PlaygroundMessage = (props: Props) => {
|
||||
key: "1",
|
||||
label: (
|
||||
<div className="italic text-gray-500 dark:text-gray-400">
|
||||
{t("citations")}
|
||||
{t("webCitations")}
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div className="mb-3 flex flex-wrap gap-2">
|
||||
{props?.sources?.map((source, index) => (
|
||||
{props?.webSources?.map((source, index) => (
|
||||
<MessageSource
|
||||
onSourceClick={props.onSourceClick}
|
||||
key={index}
|
||||
index={index}
|
||||
source={source}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
{props.isBot && props?.iodSources && props?.iodSources.length > 0 && (
|
||||
<Collapse
|
||||
className="mt-6"
|
||||
ghost
|
||||
items={[
|
||||
{
|
||||
key: "1",
|
||||
label: (
|
||||
<div className="italic text-gray-500 dark:text-gray-400">
|
||||
{t("iodCitations")}
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div className="mb-3 flex flex-wrap gap-2">
|
||||
{props?.iodSources?.map((source, index) => (
|
||||
<MessageSource
|
||||
onSourceClick={props.onSourceClick}
|
||||
key={index}
|
||||
index={index}
|
||||
source={source}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useState } from "react"
|
||||
import type React from "react"
|
||||
import { KnowledgeIcon } from "@/components/Option/Knowledge/KnowledgeIcon"
|
||||
|
||||
type Props = {
|
||||
index: number
|
||||
source: {
|
||||
name?: string
|
||||
url?: string
|
||||
@@ -8,11 +11,20 @@ type Props = {
|
||||
type?: string
|
||||
pageContent?: string
|
||||
content?: string
|
||||
doId?: string
|
||||
description?: string
|
||||
}
|
||||
onSourceClick?: (source: any) => void
|
||||
}
|
||||
|
||||
export const MessageSource: React.FC<Props> = ({ source, onSourceClick }) => {
|
||||
export const MessageSource: React.FC<Props> = ({
|
||||
index,
|
||||
source,
|
||||
onSourceClick
|
||||
}) => {
|
||||
// Add state for tracking and content visibility
|
||||
const [showContent, setShowContent] = useState(false)
|
||||
|
||||
if (source?.mode === "rag" || source?.mode === "chat") {
|
||||
return (
|
||||
<button
|
||||
@@ -26,12 +38,46 @@ export const MessageSource: React.FC<Props> = ({ source, onSourceClick }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const onContextMenu = (e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation
|
||||
setShowContent(true)
|
||||
}
|
||||
|
||||
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>
|
||||
<div className="block items-center gap-1 text-xs text-gray-800 dark:text-gray-100 mb-1">
|
||||
<span className="text-xs font-medium"></span>{" "}
|
||||
<a
|
||||
href={source?.url}
|
||||
target="_blank"
|
||||
onContextMenu={onContextMenu}
|
||||
className="inline-block 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">
|
||||
{source.doId ? (
|
||||
<>
|
||||
<span className="text-xs">
|
||||
[{index + 1}] doid: {source.doId}
|
||||
</span>
|
||||
<br />
|
||||
<span className="text-xs">{source.name}</span>
|
||||
{showContent && (
|
||||
<div className="mt-2 p-2 border-t border-gray-200 dark:border-gray-700">
|
||||
{source.content || source.pageContent || source.description}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="text-xs">
|
||||
[{index + 1}] {source.name}
|
||||
</span>
|
||||
{showContent && (
|
||||
<div className="mt-2 p-2 border-t border-gray-200 dark:border-gray-700">
|
||||
{source.content || source.pageContent}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ export const PlaygroundChat = () => {
|
||||
onRengerate={regenerateLastMessage}
|
||||
isProcessing={streaming}
|
||||
isSearchingInternet={isSearchingInternet}
|
||||
sources={message.sources}
|
||||
webSources={message.webSources}
|
||||
iodSources={message.iodSources}
|
||||
onEditFormSubmit={(value, isSend) => {
|
||||
editMessage(index, value, !message.isBot, isSend)
|
||||
}}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { getVariable } from "@/utils/select-variable"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
|
||||
import { useSpeechRecognition } from "@/hooks/useSpeechRecognition"
|
||||
import { PiGlobe } from "react-icons/pi"
|
||||
import { PiGlobe, PiNetwork } from "react-icons/pi"
|
||||
import { handleChatInputKeyDown } from "@/utils/key-down"
|
||||
import { getIsSimpleInternetSearch } from "@/services/search"
|
||||
|
||||
@@ -34,6 +34,8 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
streaming: isSending,
|
||||
webSearch,
|
||||
setWebSearch,
|
||||
iodSearch,
|
||||
setIodSearch,
|
||||
selectedQuickPrompt,
|
||||
textareaRef,
|
||||
setSelectedQuickPrompt,
|
||||
@@ -301,6 +303,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
<div className="mt-2 flex justify-between items-center">
|
||||
<div className="flex">
|
||||
{!selectedKnowledge && (
|
||||
<div>
|
||||
<Tooltip title={t("tooltip.searchInternet")}>
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<PiGlobe
|
||||
@@ -314,6 +317,20 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip title={t("tooltip.searchIod")} className="ml-3">
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<PiNetwork
|
||||
className={`h-5 w-5 dark:text-gray-300 `}
|
||||
/>
|
||||
<Switch
|
||||
value={iodSearch}
|
||||
onChange={(e) => setIodSearch(e)}
|
||||
checkedChildren={t("form.webSearch.on")}
|
||||
unCheckedChildren={t("form.webSearch.off")}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex !justify-end gap-3">
|
||||
|
||||
@@ -39,7 +39,8 @@ export const SidePanelBody = () => {
|
||||
message_type={message.messageType}
|
||||
isProcessing={streaming}
|
||||
isSearchingInternet={isSearchingInternet}
|
||||
sources={message.sources}
|
||||
webSources={message.webSources}
|
||||
iodSources={message.iodSources}
|
||||
onEditFormSubmit={(value) => {
|
||||
editMessage(index, value, !message.isBot)
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user