feat: add IoD search
This commit is contained in:
parent
691575e449
commit
e8471f1802
@ -109,7 +109,7 @@
|
|||||||
"translate": "ترجمة",
|
"translate": "ترجمة",
|
||||||
"custom": "مخصص"
|
"custom": "مخصص"
|
||||||
},
|
},
|
||||||
"citations": "الاقتباسات",
|
"webCitations": "الاقتباسات",
|
||||||
"segmented": {
|
"segmented": {
|
||||||
"ollama": "نماذج Ollama",
|
"ollama": "نماذج Ollama",
|
||||||
"custom": "نماذج مخصصة"
|
"custom": "نماذج مخصصة"
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"translate": "Oversæt",
|
"translate": "Oversæt",
|
||||||
"custom": "Brugerdefineret"
|
"custom": "Brugerdefineret"
|
||||||
},
|
},
|
||||||
"citations": "Citater",
|
"webCitations": "Citater",
|
||||||
"downloadCode": "Download Kode",
|
"downloadCode": "Download Kode",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Fastgjort",
|
"pinned": "Fastgjort",
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"translate": "Übersetzen",
|
"translate": "Übersetzen",
|
||||||
"custom": "Benutzerdefiniert"
|
"custom": "Benutzerdefiniert"
|
||||||
},
|
},
|
||||||
"citations": "Zitate",
|
"webCitations": "Zitate",
|
||||||
"downloadCode": "Code herunterladen",
|
"downloadCode": "Code herunterladen",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Angepinnt",
|
"pinned": "Angepinnt",
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
},
|
},
|
||||||
"copyToClipboard": "Copy to clipboard",
|
"copyToClipboard": "Copy to clipboard",
|
||||||
"webSearch": "Searching the web",
|
"webSearch": "Searching the web",
|
||||||
|
"iodSearch": "Searching the Internet of Data",
|
||||||
"regenerate": "Regenerate",
|
"regenerate": "Regenerate",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
@ -136,7 +137,8 @@
|
|||||||
"translate": "Translate",
|
"translate": "Translate",
|
||||||
"custom": "Custom"
|
"custom": "Custom"
|
||||||
},
|
},
|
||||||
"citations": "Citations",
|
"webCitations": "Web Citations",
|
||||||
|
"iodCitations": "Internet of Data Citations",
|
||||||
"segmented": {
|
"segmented": {
|
||||||
"ollama": "Ollama Models",
|
"ollama": "Ollama Models",
|
||||||
"custom": "Custom Models"
|
"custom": "Custom Models"
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"searchInternet": "Search Internet",
|
"searchInternet": "Search Internet",
|
||||||
|
"searchIod": "Search Internet of Data",
|
||||||
"speechToText": "Speech to Text",
|
"speechToText": "Speech to Text",
|
||||||
"uploadImage": "Upload Image",
|
"uploadImage": "Upload Image",
|
||||||
"stopStreaming": "Stop Streaming",
|
"stopStreaming": "Stop Streaming",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "Reformular",
|
"rephrase": "Reformular",
|
||||||
"translate": "Traducir"
|
"translate": "Traducir"
|
||||||
},
|
},
|
||||||
"citations": "Citas",
|
"webCitations": "Citas",
|
||||||
"downloadCode": "Descargar Código",
|
"downloadCode": "Descargar Código",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Fijado",
|
"pinned": "Fijado",
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
},
|
},
|
||||||
"advanced": "تنظیمات بیشتر مدل"
|
"advanced": "تنظیمات بیشتر مدل"
|
||||||
},
|
},
|
||||||
"citations": "منابع",
|
"webCitations": "منابع",
|
||||||
"downloadCode": "دانلود کد",
|
"downloadCode": "دانلود کد",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "پین شده",
|
"pinned": "پین شده",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "Reformuler",
|
"rephrase": "Reformuler",
|
||||||
"translate": "Traduire"
|
"translate": "Traduire"
|
||||||
},
|
},
|
||||||
"citations": "Citations",
|
"webCitations": "Citations",
|
||||||
"downloadCode": "Télécharger le code",
|
"downloadCode": "Télécharger le code",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Épinglé",
|
"pinned": "Épinglé",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "Riformulare",
|
"rephrase": "Riformulare",
|
||||||
"translate": "Tradurre"
|
"translate": "Tradurre"
|
||||||
},
|
},
|
||||||
"citations": "Citazioni",
|
"webCitations": "Citazioni",
|
||||||
"downloadCode": "Scarica Codice",
|
"downloadCode": "Scarica Codice",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Fissato",
|
"pinned": "Fissato",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "言い換え",
|
"rephrase": "言い換え",
|
||||||
"translate": "翻訳"
|
"translate": "翻訳"
|
||||||
},
|
},
|
||||||
"citations": "引用",
|
"webCitations": "引用",
|
||||||
"downloadCode": "コードをダウンロード",
|
"downloadCode": "コードをダウンロード",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "固定",
|
"pinned": "固定",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "다르게 표현",
|
"rephrase": "다르게 표현",
|
||||||
"translate": "번역"
|
"translate": "번역"
|
||||||
},
|
},
|
||||||
"citations": "인용",
|
"webCitations": "인용",
|
||||||
"downloadCode": "코드 다운로드",
|
"downloadCode": "코드 다운로드",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "고정됨",
|
"pinned": "고정됨",
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
"rephrase": "പുനഃരൂപീകരിക്കുക",
|
"rephrase": "പുനഃരൂപീകരിക്കുക",
|
||||||
"translate": "വിവർത്തനം ചെയ്യുക"
|
"translate": "വിവർത്തനം ചെയ്യുക"
|
||||||
},
|
},
|
||||||
"citations": "ഉദ്ധരണികൾ",
|
"webCitations": "ഉദ്ധരണികൾ",
|
||||||
"downloadCode": "കോഡ് ഡൗൺലോഡ് ചെയ്യുക",
|
"downloadCode": "കോഡ് ഡൗൺലോഡ് ചെയ്യുക",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "പിൻ ചെയ്തത്",
|
"pinned": "പിൻ ചെയ്തത്",
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"translate": "Oversett",
|
"translate": "Oversett",
|
||||||
"custom": "Egendefinert"
|
"custom": "Egendefinert"
|
||||||
},
|
},
|
||||||
"citations": "Sitater",
|
"webCitations": "Sitater",
|
||||||
"downloadCode": "Last ned kode",
|
"downloadCode": "Last ned kode",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Festet",
|
"pinned": "Festet",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "Reformular",
|
"rephrase": "Reformular",
|
||||||
"translate": "Traduzir"
|
"translate": "Traduzir"
|
||||||
},
|
},
|
||||||
"citations": "Citações",
|
"webCitations": "Citações",
|
||||||
"downloadCode": "Baixar Código",
|
"downloadCode": "Baixar Código",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Fixado",
|
"pinned": "Fixado",
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
"rephrase": "Перефразировать",
|
"rephrase": "Перефразировать",
|
||||||
"translate": "Перевести"
|
"translate": "Перевести"
|
||||||
},
|
},
|
||||||
"citations": "Цитаты",
|
"webCitations": "Цитаты",
|
||||||
"downloadCode": "Скачать код",
|
"downloadCode": "Скачать код",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "Закреплено",
|
"pinned": "Закреплено",
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"translate": "Översätt",
|
"translate": "Översätt",
|
||||||
"custom": "Custom"
|
"custom": "Custom"
|
||||||
},
|
},
|
||||||
"citations": "Citat",
|
"webCitations": "Citat",
|
||||||
"segmented": {
|
"segmented": {
|
||||||
"ollama": "Ollama-modeller",
|
"ollama": "Ollama-modeller",
|
||||||
"custom": "Custom modeller"
|
"custom": "Custom modeller"
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"translate": "Перекласти",
|
"translate": "Перекласти",
|
||||||
"custom": "Власне"
|
"custom": "Власне"
|
||||||
},
|
},
|
||||||
"citations": "Цитати",
|
"webCitations": "Цитати",
|
||||||
"segmented": {
|
"segmented": {
|
||||||
"ollama": "Моделі Ollama",
|
"ollama": "Моделі Ollama",
|
||||||
"custom": "Власні моделі"
|
"custom": "Власні моделі"
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"copyToClipboard": "复制到剪贴板",
|
"copyToClipboard": "复制到剪贴板",
|
||||||
"webSearch": "搜索网络",
|
"webSearch": "搜索万维网",
|
||||||
|
"iodSearch": "搜索数联网",
|
||||||
"regenerate": "重新生成",
|
"regenerate": "重新生成",
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
@ -105,7 +106,8 @@
|
|||||||
"rephrase": "重述",
|
"rephrase": "重述",
|
||||||
"translate": "翻译"
|
"translate": "翻译"
|
||||||
},
|
},
|
||||||
"citations": "引用",
|
"webCitations": "万维网引用",
|
||||||
|
"iodCitations": "数联网引用",
|
||||||
"downloadCode": "下载代码",
|
"downloadCode": "下载代码",
|
||||||
"date": {
|
"date": {
|
||||||
"pinned": "已置顶",
|
"pinned": "已置顶",
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"searchInternet": "搜索互联网",
|
"searchInternet": "搜索万维网",
|
||||||
|
"searchIod": "搜索数联网",
|
||||||
"speechToText": "语音到文本",
|
"speechToText": "语音到文本",
|
||||||
"uploadImage": "上传图片",
|
"uploadImage": "上传图片",
|
||||||
"stopStreaming": "停止流媒体",
|
"stopStreaming": "停止流媒体",
|
||||||
|
@ -18,7 +18,7 @@ import { useTTS } from "@/hooks/useTTS"
|
|||||||
import { tagColors } from "@/utils/color"
|
import { tagColors } from "@/utils/color"
|
||||||
import { removeModelSuffix } from "@/db/models"
|
import { removeModelSuffix } from "@/db/models"
|
||||||
import { GenerationInfo } from "./GenerationInfo"
|
import { GenerationInfo } from "./GenerationInfo"
|
||||||
import { parseReasoning, } from "@/libs/reasoning"
|
import { parseReasoning } from "@/libs/reasoning"
|
||||||
import { humanizeMilliseconds } from "@/utils/humanize-milliseconds"
|
import { humanizeMilliseconds } from "@/utils/humanize-milliseconds"
|
||||||
type Props = {
|
type Props = {
|
||||||
message: string
|
message: string
|
||||||
@ -36,7 +36,8 @@ type Props = {
|
|||||||
isProcessing: boolean
|
isProcessing: boolean
|
||||||
webSearch?: {}
|
webSearch?: {}
|
||||||
isSearchingInternet?: boolean
|
isSearchingInternet?: boolean
|
||||||
sources?: any[]
|
webSources?: any[]
|
||||||
|
iodSources?: any[]
|
||||||
hideEditAndRegenerate?: boolean
|
hideEditAndRegenerate?: boolean
|
||||||
onSourceClick?: (source: any) => void
|
onSourceClick?: (source: any) => void
|
||||||
isTTSEnabled?: boolean
|
isTTSEnabled?: boolean
|
||||||
@ -166,7 +167,7 @@ export const PlaygroundMessage = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{props.isBot && props?.sources && props?.sources.length > 0 && (
|
{props.isBot && props?.webSources && props?.webSources.length > 0 && (
|
||||||
<Collapse
|
<Collapse
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
ghost
|
ghost
|
||||||
@ -175,15 +176,44 @@ export const PlaygroundMessage = (props: Props) => {
|
|||||||
key: "1",
|
key: "1",
|
||||||
label: (
|
label: (
|
||||||
<div className="italic text-gray-500 dark:text-gray-400">
|
<div className="italic text-gray-500 dark:text-gray-400">
|
||||||
{t("citations")}
|
{t("webCitations")}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
children: (
|
children: (
|
||||||
<div className="mb-3 flex flex-wrap gap-2">
|
<div className="mb-3 flex flex-wrap gap-2">
|
||||||
{props?.sources?.map((source, index) => (
|
{props?.webSources?.map((source, index) => (
|
||||||
<MessageSource
|
<MessageSource
|
||||||
onSourceClick={props.onSourceClick}
|
onSourceClick={props.onSourceClick}
|
||||||
key={index}
|
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}
|
source={source}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import { useState } from "react"
|
||||||
|
import type React from "react"
|
||||||
import { KnowledgeIcon } from "@/components/Option/Knowledge/KnowledgeIcon"
|
import { KnowledgeIcon } from "@/components/Option/Knowledge/KnowledgeIcon"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
index: number
|
||||||
source: {
|
source: {
|
||||||
name?: string
|
name?: string
|
||||||
url?: string
|
url?: string
|
||||||
@ -8,11 +11,20 @@ type Props = {
|
|||||||
type?: string
|
type?: string
|
||||||
pageContent?: string
|
pageContent?: string
|
||||||
content?: string
|
content?: string
|
||||||
|
doId?: string
|
||||||
|
description?: string
|
||||||
}
|
}
|
||||||
onSourceClick?: (source: any) => void
|
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") {
|
if (source?.mode === "rag" || source?.mode === "chat") {
|
||||||
return (
|
return (
|
||||||
<button
|
<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 (
|
return (
|
||||||
<a
|
<div className="block items-center gap-1 text-xs text-gray-800 dark:text-gray-100 mb-1">
|
||||||
href={source?.url}
|
<span className="text-xs font-medium"></span>{" "}
|
||||||
target="_blank"
|
<a
|
||||||
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">
|
href={source?.url}
|
||||||
<span className="text-xs">{source.name}</span>
|
target="_blank"
|
||||||
</a>
|
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}
|
onRengerate={regenerateLastMessage}
|
||||||
isProcessing={streaming}
|
isProcessing={streaming}
|
||||||
isSearchingInternet={isSearchingInternet}
|
isSearchingInternet={isSearchingInternet}
|
||||||
sources={message.sources}
|
webSources={message.webSources}
|
||||||
|
iodSources={message.iodSources}
|
||||||
onEditFormSubmit={(value, isSend) => {
|
onEditFormSubmit={(value, isSend) => {
|
||||||
editMessage(index, value, !message.isBot, isSend)
|
editMessage(index, value, !message.isBot, isSend)
|
||||||
}}
|
}}
|
||||||
|
@ -13,7 +13,7 @@ import { getVariable } from "@/utils/select-variable"
|
|||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
|
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
|
||||||
import { useSpeechRecognition } from "@/hooks/useSpeechRecognition"
|
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 { handleChatInputKeyDown } from "@/utils/key-down"
|
||||||
import { getIsSimpleInternetSearch } from "@/services/search"
|
import { getIsSimpleInternetSearch } from "@/services/search"
|
||||||
|
|
||||||
@ -34,6 +34,8 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
|||||||
streaming: isSending,
|
streaming: isSending,
|
||||||
webSearch,
|
webSearch,
|
||||||
setWebSearch,
|
setWebSearch,
|
||||||
|
iodSearch,
|
||||||
|
setIodSearch,
|
||||||
selectedQuickPrompt,
|
selectedQuickPrompt,
|
||||||
textareaRef,
|
textareaRef,
|
||||||
setSelectedQuickPrompt,
|
setSelectedQuickPrompt,
|
||||||
@ -301,6 +303,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
|||||||
<div className="mt-2 flex justify-between items-center">
|
<div className="mt-2 flex justify-between items-center">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{!selectedKnowledge && (
|
{!selectedKnowledge && (
|
||||||
|
<div>
|
||||||
<Tooltip title={t("tooltip.searchInternet")}>
|
<Tooltip title={t("tooltip.searchInternet")}>
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
<PiGlobe
|
<PiGlobe
|
||||||
@ -314,6 +317,20 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</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>
|
||||||
<div className="flex !justify-end gap-3">
|
<div className="flex !justify-end gap-3">
|
||||||
|
@ -39,7 +39,8 @@ export const SidePanelBody = () => {
|
|||||||
message_type={message.messageType}
|
message_type={message.messageType}
|
||||||
isProcessing={streaming}
|
isProcessing={streaming}
|
||||||
isSearchingInternet={isSearchingInternet}
|
isSearchingInternet={isSearchingInternet}
|
||||||
sources={message.sources}
|
webSources={message.webSources}
|
||||||
|
iodSources={message.iodSources}
|
||||||
onEditFormSubmit={(value) => {
|
onEditFormSubmit={(value) => {
|
||||||
editMessage(index, value, !message.isBot)
|
editMessage(index, value, !message.isBot)
|
||||||
}}
|
}}
|
||||||
|
@ -29,7 +29,8 @@ type Message = {
|
|||||||
role: string
|
role: string
|
||||||
content: string
|
content: string
|
||||||
images?: string[]
|
images?: string[]
|
||||||
sources?: string[]
|
webSources?: string[]
|
||||||
|
iodSources?: string[]
|
||||||
search?: WebSearch
|
search?: WebSearch
|
||||||
createdAt: number
|
createdAt: number
|
||||||
reasoning_time_taken?: number
|
reasoning_time_taken?: number
|
||||||
@ -254,7 +255,8 @@ export const saveMessage = async (
|
|||||||
role: string,
|
role: string,
|
||||||
content: string,
|
content: string,
|
||||||
images: string[],
|
images: string[],
|
||||||
source?: any[],
|
webSources?: any[],
|
||||||
|
iodSources?: any[],
|
||||||
time?: number,
|
time?: number,
|
||||||
message_type?: string,
|
message_type?: string,
|
||||||
generationInfo?: any,
|
generationInfo?: any,
|
||||||
@ -273,7 +275,8 @@ export const saveMessage = async (
|
|||||||
content,
|
content,
|
||||||
images,
|
images,
|
||||||
createdAt,
|
createdAt,
|
||||||
sources: source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
messageType: message_type,
|
messageType: message_type,
|
||||||
generationInfo: generationInfo,
|
generationInfo: generationInfo,
|
||||||
reasoning_time_taken
|
reasoning_time_taken
|
||||||
@ -303,7 +306,8 @@ export const formatToMessage = (messages: MessageHistory): MessageType[] => {
|
|||||||
isBot: message.role === "assistant",
|
isBot: message.role === "assistant",
|
||||||
message: message.content,
|
message: message.content,
|
||||||
name: message.name,
|
name: message.name,
|
||||||
sources: message?.sources || [],
|
webSources: message?.webSources || [],
|
||||||
|
iodSources: message?.iodSources || [],
|
||||||
images: message.images || [],
|
images: message.images || [],
|
||||||
generationInfo: message?.generationInfo,
|
generationInfo: message?.generationInfo,
|
||||||
reasoning_time_taken: message?.reasoning_time_taken
|
reasoning_time_taken: message?.reasoning_time_taken
|
||||||
|
@ -62,6 +62,7 @@ export const saveMessageOnError = async ({
|
|||||||
userMessage,
|
userMessage,
|
||||||
[image],
|
[image],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
1,
|
1,
|
||||||
message_type
|
message_type
|
||||||
)
|
)
|
||||||
@ -73,6 +74,7 @@ export const saveMessageOnError = async ({
|
|||||||
botMessage,
|
botMessage,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
2,
|
2,
|
||||||
message_type
|
message_type
|
||||||
)
|
)
|
||||||
@ -91,6 +93,7 @@ export const saveMessageOnError = async ({
|
|||||||
userMessage,
|
userMessage,
|
||||||
[image],
|
[image],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
1,
|
1,
|
||||||
message_type
|
message_type
|
||||||
)
|
)
|
||||||
@ -102,6 +105,7 @@ export const saveMessageOnError = async ({
|
|||||||
botMessage,
|
botMessage,
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
2,
|
2,
|
||||||
message_type
|
message_type
|
||||||
)
|
)
|
||||||
@ -126,7 +130,8 @@ export const saveMessageOnSuccess = async ({
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
message_source = "web-ui",
|
message_source = "web-ui",
|
||||||
message_type, generationInfo,
|
message_type, generationInfo,
|
||||||
prompt_id,
|
prompt_id,
|
||||||
@ -140,7 +145,8 @@ export const saveMessageOnSuccess = async ({
|
|||||||
message: string
|
message: string
|
||||||
image: string
|
image: string
|
||||||
fullText: string
|
fullText: string
|
||||||
source: any[]
|
webSources: any[]
|
||||||
|
iodSources: any[]
|
||||||
message_source?: "copilot" | "web-ui",
|
message_source?: "copilot" | "web-ui",
|
||||||
message_type?: string
|
message_type?: string
|
||||||
generationInfo?: any
|
generationInfo?: any
|
||||||
@ -157,6 +163,7 @@ export const saveMessageOnSuccess = async ({
|
|||||||
message,
|
message,
|
||||||
[image],
|
[image],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
1,
|
1,
|
||||||
message_type,
|
message_type,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
@ -169,7 +176,8 @@ export const saveMessageOnSuccess = async ({
|
|||||||
"assistant",
|
"assistant",
|
||||||
fullText,
|
fullText,
|
||||||
[],
|
[],
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
2,
|
2,
|
||||||
message_type,
|
message_type,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
@ -189,6 +197,7 @@ export const saveMessageOnSuccess = async ({
|
|||||||
message,
|
message,
|
||||||
[image],
|
[image],
|
||||||
[],
|
[],
|
||||||
|
[],
|
||||||
1,
|
1,
|
||||||
message_type,
|
message_type,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
@ -200,7 +209,8 @@ export const saveMessageOnSuccess = async ({
|
|||||||
"assistant",
|
"assistant",
|
||||||
fullText,
|
fullText,
|
||||||
[],
|
[],
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
2,
|
2,
|
||||||
message_type,
|
message_type,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
|
@ -59,6 +59,8 @@ export const useMessage = () => {
|
|||||||
setIsSearchingInternet,
|
setIsSearchingInternet,
|
||||||
webSearch,
|
webSearch,
|
||||||
setWebSearch,
|
setWebSearch,
|
||||||
|
iodSearch,
|
||||||
|
setIodSearch,
|
||||||
isSearchingInternet
|
isSearchingInternet
|
||||||
} = useStoreMessageOption()
|
} = useStoreMessageOption()
|
||||||
const [defaultInternetSearchOn] = useStorage("defaultInternetSearchOn", false)
|
const [defaultInternetSearchOn] = useStorage("defaultInternetSearchOn", false)
|
||||||
@ -185,14 +187,16 @@ export const useMessage = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: []
|
images: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -203,7 +207,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -334,7 +339,16 @@ export const useMessage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let context: string = ""
|
let context: string = ""
|
||||||
let source: {
|
let webSources: {
|
||||||
|
name: any
|
||||||
|
type: any
|
||||||
|
mode: string
|
||||||
|
url: string
|
||||||
|
pageContent: string
|
||||||
|
metadata: Record<string, any>
|
||||||
|
}[] = []
|
||||||
|
// TODO: update type
|
||||||
|
let iodSources: {
|
||||||
name: any
|
name: any
|
||||||
type: any
|
type: any
|
||||||
mode: string
|
mode: string
|
||||||
@ -346,7 +360,7 @@ export const useMessage = () => {
|
|||||||
if (chatWithWebsiteEmbedding) {
|
if (chatWithWebsiteEmbedding) {
|
||||||
const docs = await vectorstore.similaritySearch(query, 4)
|
const docs = await vectorstore.similaritySearch(query, 4)
|
||||||
context = formatDocs(docs)
|
context = formatDocs(docs)
|
||||||
source = docs.map((doc) => {
|
webSources = docs.map((doc) => {
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
name: doc?.metadata?.source || "untitled",
|
name: doc?.metadata?.source || "untitled",
|
||||||
@ -365,7 +379,7 @@ export const useMessage = () => {
|
|||||||
.slice(0, maxWebsiteContext)
|
.slice(0, maxWebsiteContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
source = [
|
webSources = [
|
||||||
{
|
{
|
||||||
name: embedURL,
|
name: embedURL,
|
||||||
type: type,
|
type: type,
|
||||||
@ -476,7 +490,8 @@ export const useMessage = () => {
|
|||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText,
|
message: fullText,
|
||||||
sources: source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
}
|
}
|
||||||
@ -506,7 +521,8 @@ export const useMessage = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
message_source: "copilot",
|
message_source: "copilot",
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
@ -606,14 +622,16 @@ export const useMessage = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: []
|
images: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -624,7 +642,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -787,7 +806,8 @@ export const useMessage = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
message_source: "copilot",
|
message_source: "copilot",
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
@ -891,14 +911,16 @@ export const useMessage = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: [image]
|
images: [image]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -909,7 +931,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1077,7 +1100,8 @@ export const useMessage = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
message_source: "copilot",
|
message_source: "copilot",
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
@ -1114,12 +1138,14 @@ export const useMessage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const searchChatMode = async (
|
const searchChatMode = async (
|
||||||
|
webSearch: boolean,
|
||||||
|
iodSearch,
|
||||||
message: string,
|
message: string,
|
||||||
image: string,
|
image: string,
|
||||||
isRegenerate: boolean,
|
isRegenerate: boolean,
|
||||||
messages: Message[],
|
messages: Message[],
|
||||||
history: ChatHistory,
|
history: ChatHistory,
|
||||||
signal: AbortSignal
|
signal: AbortSignal,
|
||||||
) => {
|
) => {
|
||||||
const url = await getOllamaURL()
|
const url = await getOllamaURL()
|
||||||
setStreaming(true)
|
setStreaming(true)
|
||||||
@ -1176,14 +1202,16 @@ export const useMessage = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: [image]
|
images: [image]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1194,7 +1222,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1271,7 +1300,8 @@ export const useMessage = () => {
|
|||||||
query = removeReasoning(query)
|
query = removeReasoning(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { prompt, source } = await getSystemPromptForWeb(query)
|
const { prompt, webSources, iodSources } =
|
||||||
|
await getSystemPromptForWeb(query, [], webSearch, iodSearch)
|
||||||
setIsSearchingInternet(false)
|
setIsSearchingInternet(false)
|
||||||
|
|
||||||
// message = message.trim().replaceAll("\n", " ")
|
// message = message.trim().replaceAll("\n", " ")
|
||||||
@ -1394,7 +1424,8 @@ export const useMessage = () => {
|
|||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText,
|
message: fullText,
|
||||||
sources: source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
}
|
}
|
||||||
@ -1424,7 +1455,8 @@ export const useMessage = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
})
|
})
|
||||||
@ -1523,7 +1555,8 @@ export const useMessage = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: [image],
|
images: [image],
|
||||||
messageType: messageType
|
messageType: messageType
|
||||||
},
|
},
|
||||||
@ -1531,7 +1564,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1542,7 +1576,8 @@ export const useMessage = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1688,7 +1723,8 @@ export const useMessage = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
message_source: "copilot",
|
message_source: "copilot",
|
||||||
message_type: messageType,
|
message_type: messageType,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
@ -1766,14 +1802,16 @@ export const useMessage = () => {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (chatMode === "normal") {
|
if (chatMode === "normal") {
|
||||||
if (webSearch) {
|
if (webSearch || iodSearch) {
|
||||||
await searchChatMode(
|
await searchChatMode(
|
||||||
|
webSearch,
|
||||||
|
iodSearch,
|
||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
isRegenerate || false,
|
isRegenerate || false,
|
||||||
messages,
|
messages,
|
||||||
memory || history,
|
memory || history,
|
||||||
signal
|
signal,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
await normalChatMode(
|
await normalChatMode(
|
||||||
@ -1906,6 +1944,8 @@ export const useMessage = () => {
|
|||||||
regenerateLastMessage,
|
regenerateLastMessage,
|
||||||
webSearch,
|
webSearch,
|
||||||
setWebSearch,
|
setWebSearch,
|
||||||
|
iodSearch,
|
||||||
|
setIodSearch,
|
||||||
isSearchingInternet,
|
isSearchingInternet,
|
||||||
selectedQuickPrompt,
|
selectedQuickPrompt,
|
||||||
setSelectedQuickPrompt,
|
setSelectedQuickPrompt,
|
||||||
|
@ -3,6 +3,7 @@ import { cleanUrl } from "~/libs/clean-url"
|
|||||||
import {
|
import {
|
||||||
defaultEmbeddingModelForRag,
|
defaultEmbeddingModelForRag,
|
||||||
geWebSearchFollowUpPrompt,
|
geWebSearchFollowUpPrompt,
|
||||||
|
geWebSearchKeywordsPrompt,
|
||||||
getOllamaURL,
|
getOllamaURL,
|
||||||
promptForRag,
|
promptForRag,
|
||||||
systemPromptForNonRagOption
|
systemPromptForNonRagOption
|
||||||
@ -67,6 +68,8 @@ export const useMessageOption = () => {
|
|||||||
setChatMode,
|
setChatMode,
|
||||||
webSearch,
|
webSearch,
|
||||||
setWebSearch,
|
setWebSearch,
|
||||||
|
iodSearch,
|
||||||
|
setIodSearch,
|
||||||
isSearchingInternet,
|
isSearchingInternet,
|
||||||
setIsSearchingInternet,
|
setIsSearchingInternet,
|
||||||
selectedQuickPrompt,
|
selectedQuickPrompt,
|
||||||
@ -111,6 +114,8 @@ export const useMessageOption = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const searchChatMode = async (
|
const searchChatMode = async (
|
||||||
|
webSearch: boolean,
|
||||||
|
iodSearch: boolean,
|
||||||
message: string,
|
message: string,
|
||||||
image: string,
|
image: string,
|
||||||
isRegenerate: boolean,
|
isRegenerate: boolean,
|
||||||
@ -172,14 +177,16 @@ export const useMessageOption = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: [image]
|
images: [image]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -190,7 +197,8 @@ export const useMessageOption = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -204,6 +212,7 @@ export const useMessageOption = () => {
|
|||||||
setIsSearchingInternet(true)
|
setIsSearchingInternet(true)
|
||||||
|
|
||||||
let query = message
|
let query = message
|
||||||
|
let keywords: string[] = []
|
||||||
|
|
||||||
if (newMessage.length > 2) {
|
if (newMessage.length > 2) {
|
||||||
let questionPrompt = await geWebSearchFollowUpPrompt()
|
let questionPrompt = await geWebSearchFollowUpPrompt()
|
||||||
@ -268,7 +277,23 @@ export const useMessageOption = () => {
|
|||||||
query = removeReasoning(query)
|
query = removeReasoning(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { prompt, source } = await getSystemPromptForWeb(query)
|
// Currently only IoD search use keywords
|
||||||
|
if (iodSearch) {
|
||||||
|
// Extract keywords
|
||||||
|
const questionPrompt = await geWebSearchKeywordsPrompt()
|
||||||
|
const promptForQuestion = questionPrompt.replaceAll("{query}", query)
|
||||||
|
const response = await ollama.invoke(promptForQuestion)
|
||||||
|
let res = response.content.toString()
|
||||||
|
res = removeReasoning(res)
|
||||||
|
keywords = res.replace(/^Keywords:/i, '').split(', ').map(k => k.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
const { prompt, webSources, iodSources } = await getSystemPromptForWeb(
|
||||||
|
query,
|
||||||
|
keywords,
|
||||||
|
webSearch,
|
||||||
|
iodSearch,
|
||||||
|
)
|
||||||
setIsSearchingInternet(false)
|
setIsSearchingInternet(false)
|
||||||
|
|
||||||
// message = message.trim().replaceAll("\n", " ")
|
// message = message.trim().replaceAll("\n", " ")
|
||||||
@ -390,7 +415,8 @@ export const useMessageOption = () => {
|
|||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText,
|
message: fullText,
|
||||||
sources: source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
}
|
}
|
||||||
@ -420,7 +446,8 @@ export const useMessageOption = () => {
|
|||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
fullText,
|
fullText,
|
||||||
source,
|
webSources,
|
||||||
|
iodSources,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
})
|
})
|
||||||
@ -552,14 +579,16 @@ export const useMessageOption = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: [image]
|
images: [image]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -570,7 +599,8 @@ export const useMessageOption = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -855,14 +885,16 @@ export const useMessageOption = () => {
|
|||||||
isBot: false,
|
isBot: false,
|
||||||
name: "You",
|
name: "You",
|
||||||
message,
|
message,
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
images: []
|
images: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -873,7 +905,8 @@ export const useMessageOption = () => {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
name: selectedModel,
|
name: selectedModel,
|
||||||
message: "▋",
|
message: "▋",
|
||||||
sources: [],
|
webSources: [],
|
||||||
|
iodSources: [],
|
||||||
id: generateMessageId
|
id: generateMessageId
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1076,7 +1109,7 @@ export const useMessageOption = () => {
|
|||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
message: fullText,
|
message: fullText,
|
||||||
sources: source,
|
webSources: source,
|
||||||
generationInfo,
|
generationInfo,
|
||||||
reasoning_time_taken: timetaken
|
reasoning_time_taken: timetaken
|
||||||
}
|
}
|
||||||
@ -1175,8 +1208,10 @@ export const useMessageOption = () => {
|
|||||||
signal
|
signal
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (webSearch) {
|
if (webSearch || iodSearch) {
|
||||||
await searchChatMode(
|
await searchChatMode(
|
||||||
|
webSearch,
|
||||||
|
iodSearch,
|
||||||
message,
|
message,
|
||||||
image,
|
image,
|
||||||
isRegenerate,
|
isRegenerate,
|
||||||
@ -1311,6 +1346,8 @@ export const useMessageOption = () => {
|
|||||||
regenerateLastMessage,
|
regenerateLastMessage,
|
||||||
webSearch,
|
webSearch,
|
||||||
setWebSearch,
|
setWebSearch,
|
||||||
|
iodSearch,
|
||||||
|
setIodSearch,
|
||||||
isSearchingInternet,
|
isSearchingInternet,
|
||||||
setIsSearchingInternet,
|
setIsSearchingInternet,
|
||||||
selectedQuickPrompt,
|
selectedQuickPrompt,
|
||||||
|
@ -58,6 +58,30 @@ Follow-up question: {question}
|
|||||||
Rephrased question:
|
Rephrased question:
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const DEFAULT_WEBSEARCH_KEYWORDS_PROMPT = `Extract the most important keywords from the query (at most 3), and give me English and Chinese versions of the keywords.
|
||||||
|
|
||||||
|
The result format should be: keyword_1, keyword_2, ..., keyword_n
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
Query: What are the symptoms of a heart attack?
|
||||||
|
|
||||||
|
Keywords: symptoms, 症状, heart attack, 心臟病
|
||||||
|
|
||||||
|
Query: 什么是物联网?
|
||||||
|
|
||||||
|
Keywords: Internet of Things, IoT, 物联网
|
||||||
|
|
||||||
|
Query: 人工智能的发展趋势?
|
||||||
|
|
||||||
|
Keywords: Artificial Intelligence, AI, 人工智能, trend, 趋势
|
||||||
|
|
||||||
|
|
||||||
|
Query: {query}
|
||||||
|
|
||||||
|
Keywords:
|
||||||
|
`
|
||||||
|
|
||||||
export const getOllamaURL = async () => {
|
export const getOllamaURL = async () => {
|
||||||
const ollamaURL = await storage.get("ollamaURL")
|
const ollamaURL = await storage.get("ollamaURL")
|
||||||
if (!ollamaURL || ollamaURL.length === 0) {
|
if (!ollamaURL || ollamaURL.length === 0) {
|
||||||
@ -411,6 +435,18 @@ export const setWebPrompts = async (prompt: string, followUpPrompt: string) => {
|
|||||||
await setWebSearchFollowUpPrompt(followUpPrompt)
|
await setWebSearchFollowUpPrompt(followUpPrompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const geWebSearchKeywordsPrompt = async () => {
|
||||||
|
const prompt = await storage.get("webSearchKeywordsPrompt")
|
||||||
|
if (!prompt || prompt.length === 0) {
|
||||||
|
return DEFAULT_WEBSEARCH_KEYWORDS_PROMPT
|
||||||
|
}
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setWebSearchKeywordsPrompt = async (prompt: string) => {
|
||||||
|
await storage.set("webSearchKeywordsPrompt", prompt)
|
||||||
|
}
|
||||||
|
|
||||||
export const getPageShareUrl = async () => {
|
export const getPageShareUrl = async () => {
|
||||||
const pageShareUrl = await storage.get("pageShareUrl")
|
const pageShareUrl = await storage.get("pageShareUrl")
|
||||||
if (!pageShareUrl || pageShareUrl.length === 0) {
|
if (!pageShareUrl || pageShareUrl.length === 0) {
|
||||||
|
@ -14,7 +14,8 @@ export type Message = {
|
|||||||
isBot: boolean
|
isBot: boolean
|
||||||
name: string
|
name: string
|
||||||
message: string
|
message: string
|
||||||
sources: any[]
|
webSources: any[]
|
||||||
|
iodSources: any[]
|
||||||
images?: string[]
|
images?: string[]
|
||||||
search?: WebSearch
|
search?: WebSearch
|
||||||
reasoning_time_taken?: number
|
reasoning_time_taken?: number
|
||||||
@ -52,6 +53,8 @@ type State = {
|
|||||||
setIsEmbedding: (isEmbedding: boolean) => void
|
setIsEmbedding: (isEmbedding: boolean) => void
|
||||||
webSearch: boolean
|
webSearch: boolean
|
||||||
setWebSearch: (webSearch: boolean) => void
|
setWebSearch: (webSearch: boolean) => void
|
||||||
|
iodSearch: boolean
|
||||||
|
setIodSearch: (iodSearch: boolean) => void
|
||||||
isSearchingInternet: boolean
|
isSearchingInternet: boolean
|
||||||
setIsSearchingInternet: (isSearchingInternet: boolean) => void
|
setIsSearchingInternet: (isSearchingInternet: boolean) => void
|
||||||
|
|
||||||
@ -100,6 +103,8 @@ export const useStoreMessageOption = create<State>((set) => ({
|
|||||||
setIsEmbedding: (isEmbedding) => set({ isEmbedding }),
|
setIsEmbedding: (isEmbedding) => set({ isEmbedding }),
|
||||||
webSearch: false,
|
webSearch: false,
|
||||||
setWebSearch: (webSearch) => set({ webSearch }),
|
setWebSearch: (webSearch) => set({ webSearch }),
|
||||||
|
iodSearch: false,
|
||||||
|
setIodSearch: (iodSearch) => set({ iodSearch }),
|
||||||
isSearchingInternet: false,
|
isSearchingInternet: false,
|
||||||
setIsSearchingInternet: (isSearchingInternet) => set({ isSearchingInternet }),
|
setIsSearchingInternet: (isSearchingInternet) => set({ isSearchingInternet }),
|
||||||
selectedSystemPrompt: null,
|
selectedSystemPrompt: null,
|
||||||
|
@ -11,7 +11,8 @@ export type Message = {
|
|||||||
isBot: boolean
|
isBot: boolean
|
||||||
name: string
|
name: string
|
||||||
message: string
|
message: string
|
||||||
sources: any[]
|
webSources: any[]
|
||||||
|
iodSources: any[]
|
||||||
images?: string[]
|
images?: string[]
|
||||||
search?: WebSearch
|
search?: WebSearch
|
||||||
messageType?: string
|
messageType?: string
|
||||||
|
148
src/web/iod.ts
Normal file
148
src/web/iod.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { cleanUrl } from "@/libs/clean-url"
|
||||||
|
import { PageAssistHtmlLoader } from "@/loader/html"
|
||||||
|
import { pageAssistEmbeddingModel } from "@/models/embedding"
|
||||||
|
import { defaultEmbeddingModelForRag, getOllamaURL } from "@/services/ollama"
|
||||||
|
import {
|
||||||
|
getIsSimpleInternetSearch,
|
||||||
|
totalSearchResults
|
||||||
|
} from "@/services/search"
|
||||||
|
import { getPageAssistTextSplitter } from "@/utils/text-splitter"
|
||||||
|
import type { Document } from "@langchain/core/documents"
|
||||||
|
import { MemoryVectorStore } from "langchain/vectorstores/memory"
|
||||||
|
|
||||||
|
const makeRegSearchParams = (count: number, keyword: string) => ({
|
||||||
|
action: "executeContract",
|
||||||
|
contractID: "BDBrowser",
|
||||||
|
operation: "sendRequestDirectly",
|
||||||
|
arg: {
|
||||||
|
id: "670E241C9937B3537047C87053E3AA36",
|
||||||
|
doipUrl: "tcp://reg01.public.internetofdata.cn:21037",
|
||||||
|
op: "Search",
|
||||||
|
attributes: {
|
||||||
|
offset: 0,
|
||||||
|
count,
|
||||||
|
bodyBase64Encoded: false,
|
||||||
|
searchMode: [
|
||||||
|
{
|
||||||
|
key: "data_type",
|
||||||
|
type: "MUST",
|
||||||
|
value: "paper"
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: "title",
|
||||||
|
// type: "MUST",
|
||||||
|
// value: keyword,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
key: "description",
|
||||||
|
type: "MUST",
|
||||||
|
value: keyword
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
body: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const localIodSearch = async (query: string, keywords: string[]) => {
|
||||||
|
const TOTAL_SEARCH_RESULTS = await totalSearchResults()
|
||||||
|
|
||||||
|
const results = (
|
||||||
|
await Promise.all(
|
||||||
|
keywords.map(async (keyword) => {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
setTimeout(() => abortController.abort(), 10000)
|
||||||
|
|
||||||
|
const params = makeRegSearchParams(TOTAL_SEARCH_RESULTS, keyword)
|
||||||
|
|
||||||
|
return fetch("http://47.93.156.31:21033/SCIDE/SCManager", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(params),
|
||||||
|
signal: abortController.signal
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status !== "Success") {
|
||||||
|
console.log(res)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const body = JSON.parse(res.result.body)
|
||||||
|
if (body.code !== 0) {
|
||||||
|
console.log(body)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const results =
|
||||||
|
body.data?.results?.filter((r) => r.url || r.pdf_url) || []
|
||||||
|
results.forEach((r) => {
|
||||||
|
r.url = r.url || r.pdf_url
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).flat()
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
const ARXIV_URL = /^https:\/\/arxiv.org\//
|
||||||
|
|
||||||
|
export const searchIod = async (query: string, keywords: string[]) => {
|
||||||
|
const searchResults = await localIodSearch(query, keywords)
|
||||||
|
|
||||||
|
const isSimpleMode = await getIsSimpleInternetSearch()
|
||||||
|
|
||||||
|
if (isSimpleMode) {
|
||||||
|
await getOllamaURL()
|
||||||
|
return searchResults
|
||||||
|
}
|
||||||
|
|
||||||
|
const docs: Document<Record<string, any>>[] = []
|
||||||
|
for (const result of searchResults) {
|
||||||
|
let url = result.url
|
||||||
|
if (ARXIV_URL.test(result.url)) {
|
||||||
|
url = result.url.replace("/pdf/", "/abs/").replace(".pdf", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
const loader = new PageAssistHtmlLoader({
|
||||||
|
html: "",
|
||||||
|
url
|
||||||
|
})
|
||||||
|
|
||||||
|
const documents = await loader.loadByURL()
|
||||||
|
|
||||||
|
documents.forEach((doc) => {
|
||||||
|
docs.push(doc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const ollamaUrl = await getOllamaURL()
|
||||||
|
|
||||||
|
const embeddingModle = await defaultEmbeddingModelForRag()
|
||||||
|
const ollamaEmbedding = await pageAssistEmbeddingModel({
|
||||||
|
model: embeddingModle || "",
|
||||||
|
baseUrl: cleanUrl(ollamaUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
const textSplitter = await getPageAssistTextSplitter()
|
||||||
|
|
||||||
|
const chunks = await textSplitter.splitDocuments(docs)
|
||||||
|
|
||||||
|
const store = new MemoryVectorStore(ollamaEmbedding)
|
||||||
|
|
||||||
|
await store.addDocuments(chunks)
|
||||||
|
|
||||||
|
const resultsWithEmbeddings = await store.similaritySearch(query, 3)
|
||||||
|
|
||||||
|
const searchResult = resultsWithEmbeddings.map((result) => {
|
||||||
|
return {
|
||||||
|
url: result.metadata.url,
|
||||||
|
content: result.pageContent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return searchResult
|
||||||
|
}
|
@ -8,6 +8,7 @@ import { getWebsiteFromQuery, processSingleWebsite } from "./website"
|
|||||||
import { searxngSearch } from "./search-engines/searxng"
|
import { searxngSearch } from "./search-engines/searxng"
|
||||||
import { braveAPISearch } from "./search-engines/brave-api"
|
import { braveAPISearch } from "./search-engines/brave-api"
|
||||||
import { webBaiduSearch } from "./search-engines/baidu"
|
import { webBaiduSearch } from "./search-engines/baidu"
|
||||||
|
import { searchIod } from "./iod"
|
||||||
|
|
||||||
const getHostName = (url: string) => {
|
const getHostName = (url: string) => {
|
||||||
try {
|
try {
|
||||||
@ -37,30 +38,66 @@ const searchWeb = (provider: string, query: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSystemPromptForWeb = async (query: string) => {
|
export const getSystemPromptForWeb = async (
|
||||||
|
query: string,
|
||||||
|
keywords: string[] = [],
|
||||||
|
webSearch = true,
|
||||||
|
iodSearch = false
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const websiteVisit = getWebsiteFromQuery(query)
|
const websiteVisit = getWebsiteFromQuery(query)
|
||||||
let search: {
|
let webSearchResults: {
|
||||||
url: any;
|
url: any
|
||||||
content: string;
|
content: string
|
||||||
}[] = []
|
}[] = []
|
||||||
|
// let search_results_web = ""
|
||||||
|
|
||||||
const isVisitSpecificWebsite = await getIsVisitSpecificWebsite()
|
if (webSearch) {
|
||||||
|
const isVisitSpecificWebsite = await getIsVisitSpecificWebsite()
|
||||||
|
|
||||||
if (isVisitSpecificWebsite && websiteVisit.hasUrl) {
|
if (isVisitSpecificWebsite && websiteVisit.hasUrl) {
|
||||||
|
const url = websiteVisit.url
|
||||||
|
const queryWithoutUrl = websiteVisit.queryWithouUrls
|
||||||
|
webSearchResults = await processSingleWebsite(url, queryWithoutUrl)
|
||||||
|
} else {
|
||||||
|
const searchProvider = await getSearchProvider()
|
||||||
|
webSearchResults = await searchWeb(searchProvider, query)
|
||||||
|
}
|
||||||
|
|
||||||
const url = websiteVisit.url
|
// search_results_web = webSearchResults
|
||||||
const queryWithoutUrl = websiteVisit.queryWithouUrls
|
// .map(
|
||||||
search = await processSingleWebsite(url, queryWithoutUrl)
|
// (result, idx) =>
|
||||||
|
// `<result source="${result.url}" id="${idx}">${result.content}</result>`
|
||||||
} else {
|
// )
|
||||||
const searchProvider = await getSearchProvider()
|
// .join("\n")
|
||||||
search = await searchWeb(searchProvider, query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let iodSearchResults: {
|
||||||
|
doId: string
|
||||||
|
name: string
|
||||||
|
url?: string
|
||||||
|
// pdf_url?: string
|
||||||
|
description: string
|
||||||
|
}[] = []
|
||||||
|
// let search_results_iod = ""
|
||||||
|
|
||||||
const search_results = search
|
if (iodSearch) {
|
||||||
|
iodSearchResults = await searchIod(query, keywords)
|
||||||
|
// search_results_iod = iodSearchResults
|
||||||
|
// .map(
|
||||||
|
// (result, idx) =>
|
||||||
|
// `<result source="${result.url}" id="${idx}">${result.content}</result>`
|
||||||
|
// )
|
||||||
|
// .join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
const search_results = iodSearchResults.map((res) => ({
|
||||||
|
url: `${res.doId}: ${res.name}`,
|
||||||
|
content: res.description
|
||||||
|
}))
|
||||||
|
.concat(
|
||||||
|
webSearchResults
|
||||||
|
)
|
||||||
.map(
|
.map(
|
||||||
(result, idx) =>
|
(result, idx) =>
|
||||||
`<result source="${result.url}" id="${idx}">${result.content}</result>`
|
`<result source="${result.url}" id="${idx}">${result.content}</result>`
|
||||||
@ -77,13 +114,14 @@ export const getSystemPromptForWeb = async (query: string) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
prompt,
|
prompt,
|
||||||
source: search.map((result) => {
|
webSources: webSearchResults.map((result) => {
|
||||||
return {
|
return {
|
||||||
url: result.url,
|
url: result.url,
|
||||||
name: getHostName(result.url),
|
name: getHostName(result.url),
|
||||||
type: "url"
|
type: "url"
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
iodSources: iodSearchResults,
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user