From ee4a06b6de0c34c7225739f8ad2a8765d8782be6 Mon Sep 17 00:00:00 2001 From: BiggerRain <15911122312@163.COM> Date: Wed, 23 Apr 2025 18:23:40 +0800 Subject: [PATCH] feat: web components assistant (#422) * chore: web components assistant * chore: web components assistant * docs: update notes --- .env | 4 +- docs/content.en/docs/release-notes/_index.md | 1 + public/assets/fonts/icons/iconfont.js | 2 +- src/components/Assistant/AssistantList.tsx | 103 ++++++++++-------- src/components/Assistant/Chat.tsx | 3 + src/components/Assistant/ChatHeader.tsx | 11 +- src/components/Assistant/Greetings.tsx | 6 +- src/components/ChatMessage/PrevSuggestion.tsx | 34 ++---- src/components/Search/InputBox.tsx | 13 ++- src/components/Search/SearchListItem.tsx | 6 +- src/components/SearchChat/index.tsx | 26 +++-- src/pages/chat/index.tsx | 8 -- src/pages/main/index.tsx | 8 -- src/pages/web/README.md | 7 -- src/pages/web/index.tsx | 17 +-- src/utils/platformAdapter.ts | 8 +- tsup.config.ts | 2 +- vite.config.ts | 10 ++ 18 files changed, 132 insertions(+), 137 deletions(-) diff --git a/.env b/.env index f12d7e00..066376a4 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -COCO_SERVER_URL=https://coco.infini.cloud #http://localhost:9000 +COCO_SERVER_URL=http://localhost:9000 #https://coco.infini.cloud #http://localhost:9000 -COCO_WEBSOCKET_URL=wss://coco.infini.cloud/ws #ws://localhost:9000/ws \ No newline at end of file +COCO_WEBSOCKET_URL=ws://localhost:9000/ws #wss://coco.infini.cloud/ws #ws://localhost:9000/ws \ No newline at end of file diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index 1f9fbae7..ea6d842a 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -27,6 +27,7 @@ Information about release notes of Coco Server is provided here. - feat: add support for AI assistant #394 - feat: add support for calculator function #399 - feat: auto selects the first item after searching #411 +- feat: web components assistant #422 ### Bug fix diff --git a/public/assets/fonts/icons/iconfont.js b/public/assets/fonts/icons/iconfont.js index 8f82f3ac..e897c410 100644 --- a/public/assets/fonts/icons/iconfont.js +++ b/public/assets/fonts/icons/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4878526='',(h=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var a,t,o,F,i,p=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}a=function(){var l,c=document.createElement("div");c.innerHTML=h._iconfont_svg_string_4878526,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?p(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(o=a,F=h.document,i=!1,d(),F.onreadystatechange=function(){"complete"==F.readyState&&(F.onreadystatechange=null,v())})}function v(){i||(i=!0,o())}function d(){try{F.documentElement.doScroll("left")}catch(l){return void setTimeout(d,50)}v()}})(window); \ No newline at end of file +window._iconfont_svg_string_4878526='',(h=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var a,t,F,p,o,i=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}a=function(){var l,c=document.createElement("div");c.innerHTML=h._iconfont_svg_string_4878526,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?i(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(F=a,p=h.document,o=!1,v(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,d())})}function d(){o||(o=!0,F())}function v(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(v,50)}d()}})(window); \ No newline at end of file diff --git a/src/components/Assistant/AssistantList.tsx b/src/components/Assistant/AssistantList.tsx index 37479db3..550f6325 100644 --- a/src/components/Assistant/AssistantList.tsx +++ b/src/components/Assistant/AssistantList.tsx @@ -12,12 +12,13 @@ import FontIcon from "@/components/Common/Icons/FontIcon"; import { useChatStore } from "@/stores/chatStore"; import { AI_ASSISTANT_PANEL_ID } from "@/constants"; import { useShortcutsStore } from "@/stores/shortcutsStore"; +import { Get } from "@/api/axiosRequest"; interface AssistantListProps { - showChatHistory?: boolean; + assistantIDs?: string[]; } -export function AssistantList({ showChatHistory = true }: AssistantListProps) { +export function AssistantList({ assistantIDs = [] }: AssistantListProps) { const { t } = useTranslation(); const { connected } = useChatStore(); const isTauri = useAppStore((state) => state.isTauri); @@ -35,34 +36,49 @@ export function AssistantList({ showChatHistory = true }: AssistantListProps) { useClickAway(menuRef, () => setIsOpen(false)); const [assistants, setAssistants] = useState([]); - const fetchAssistant = useCallback(async (serverId: string) => { - if (!isTauri) return; - if (!serverId) return; - platformAdapter - .commands("assistant_search", { - serverId, - }) - .then((res: any) => { - res = res ? JSON.parse(res) : null; - console.log("assistant_search", res); - const assistantList = res?.hits?.hits || []; - setAssistants(assistantList); - if (assistantList.length > 0) { - const assistant = assistantList.find( - (item: any) => item._id === currentAssistant?._id - ); - if (assistant) { - setCurrentAssistant(assistant); - } else { - setCurrentAssistant(assistantList[0]); - } - } - }) - .catch((err: any) => { + const fetchAssistant = useCallback(async (serverId?: string) => { + let response: any; + if (isTauri) { + if (!serverId) return; + try { + response = await platformAdapter.commands("assistant_search", { + serverId, + }); + response = response ? JSON.parse(response) : null; + } catch (err) { setAssistants([]); setCurrentAssistant(null); - console.log("assistant_search", err); - }); + console.error("assistant_search", err); + } + } else { + const [error, res] = await Get(`/assistant/_search`); + if (error) { + setAssistants([]); + setCurrentAssistant(null); + console.error("assistant_search", error); + return; + } + console.log("/assistant/_search", res); + response = res; + } + console.log("assistant_search", response); + let assistantList = response?.hits?.hits || []; + + assistantList = assistantIDs.length > 0 + ? assistantList.filter((item: any) => assistantIDs.includes(item._id)) + : assistantList; + + setAssistants(assistantList); + if (assistantList.length > 0) { + const assistant = assistantList.find( + (item: any) => item._id === currentAssistant?._id + ); + if (assistant) { + setCurrentAssistant(assistant); + } else { + setCurrentAssistant(assistantList[0]); + } + } }, []); useEffect(() => { @@ -98,24 +114,22 @@ export function AssistantList({ showChatHistory = true }: AssistantListProps) {
{currentAssistant?._source?.name || "Coco AI"}
- {showChatHistory && isTauri && ( - { - setIsOpen(!isOpen); - }} - > - - - )} + { + setIsOpen(!isOpen); + }} + > + + - {showChatHistory && isTauri && isOpen && ( + {isOpen && (
{ + console.log("assistant", assistant); setCurrentAssistant(assistant); setIsOpen(false); }} diff --git a/src/components/Assistant/Chat.tsx b/src/components/Assistant/Chat.tsx index 86ac2d80..95765789 100644 --- a/src/components/Assistant/Chat.tsx +++ b/src/components/Assistant/Chat.tsx @@ -35,6 +35,7 @@ interface ChatAIProps { isChatPage?: boolean; getFileUrl: (path: string) => string; showChatHistory?: boolean; + assistantIDs?: string[]; } export interface ChatAIRef { @@ -58,6 +59,7 @@ const ChatAI = memo( isChatPage = false, getFileUrl, showChatHistory, + assistantIDs, }, ref ) => { @@ -376,6 +378,7 @@ const ChatAI = memo( isLogin={isLogin} setIsLogin={setIsLogin} showChatHistory={showChatHistory} + assistantIDs={assistantIDs} /> {isLogin ? ( void; isChatPage?: boolean; showChatHistory?: boolean; + assistantIDs?: string[]; } export function ChatHeader({ @@ -40,8 +39,8 @@ export function ChatHeader({ setIsLogin, isChatPage = false, showChatHistory = true, + assistantIDs, }: ChatHeaderProps) { - const isPinned = useAppStore((state) => state.isPinned); const setIsPinned = useAppStore((state) => state.setIsPinned); @@ -55,7 +54,7 @@ export function ChatHeader({ const fixedWindow = useShortcutsStore((state) => { return state.fixedWindow; }); - + const external = useShortcutsStore((state) => state.external); const togglePin = async () => { @@ -94,7 +93,7 @@ export function ChatHeader({ )} - + {showChatHistory ? (
diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 58ec8488..9ef3f20d 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -30,7 +30,6 @@ import { import { DataSource } from "@/types/commands"; import HistoryList from "@/components/Common/HistoryList"; import { useSyncStore } from "@/hooks/useSyncStore"; -import { useFeatureControl } from "@/hooks/useFeatureControl"; interface ChatProps {} @@ -262,12 +261,6 @@ export default function Chat({}: ChatProps) { await delete_session_chat(currentService.id, id); }; - const hasFeature = useFeatureControl({ - initialFeatures: ["think", "search"], - featureToToggle: "think", - condition: (item) => item?._source?.type === "simple" - }); - return (
@@ -337,7 +330,6 @@ export default function Chat({}: ChatProps) { openFileDialog={openFileDialog} getFileMetadata={getFileMetadata} getFileIcon={getFileIcon} - hasFeature={hasFeature} />
diff --git a/src/pages/main/index.tsx b/src/pages/main/index.tsx index 358b0228..b3603086 100644 --- a/src/pages/main/index.tsx +++ b/src/pages/main/index.tsx @@ -4,7 +4,6 @@ import SearchChat from "@/components/SearchChat"; import platformAdapter from "@/utils/platformAdapter"; import { useAppStore } from "@/stores/appStore"; import { useSyncStore } from "@/hooks/useSyncStore"; -import { useFeatureControl } from "@/hooks/useFeatureControl"; function MainApp() { const setIsTauri = useAppStore((state) => state.setIsTauri); @@ -16,18 +15,11 @@ function MainApp() { useSyncStore(); - const hasFeature = useFeatureControl({ - initialFeatures: ["think", "search"], - featureToToggle: "think", - condition: (item) => item?._source?.type === "simple", - }); - return ( ); } diff --git a/src/pages/web/README.md b/src/pages/web/README.md index 26763fa4..ad10b083 100644 --- a/src/pages/web/README.md +++ b/src/pages/web/README.md @@ -32,12 +32,6 @@ - **默认值**: `['search', 'chat']` - **描述**: 启用的功能模块列表,目前支持 'search' 和 'chat' 模块 -### `hasFeature` -- **类型**: `string[]` -- **可选**: 是 -- **默认值**: `['think', 'search', 'think_active', 'search_active']` -- **描述**: 启用的特性列表,支持 'think'、'search'、'think_active'、'search_active' 特性。其中 'think_active' 表示默认开启深度思考,'search_active' 表示默认开启搜索 - ### `hideCoco` - **类型**: `() => void` - **可选**: 是 @@ -87,7 +81,6 @@ function App() { width={680} height={590} hasModules={['search', 'chat']} - hasFeature={['think', 'search', 'think_active', 'search_active']} hideCoco={() => console.log('hide')} theme="dark" searchPlaceholder="" diff --git a/src/pages/web/index.tsx b/src/pages/web/index.tsx index 278f2577..a95f094d 100644 --- a/src/pages/web/index.tsx +++ b/src/pages/web/index.tsx @@ -5,7 +5,6 @@ import { useAppStore } from "@/stores/appStore"; import { useShortcutsStore } from "@/stores/shortcutsStore"; import { useIsMobile } from "@/hooks/useIsMobile"; import { useModifierKeyPress } from "@/hooks/useModifierKeyPress"; -import { useFeatureControl } from "@/hooks/useFeatureControl"; import "@/i18n"; import "@/web.css"; @@ -17,7 +16,7 @@ interface WebAppProps { height?: number; hasModules?: string[]; defaultModule?: "search" | "chat"; - hasFeature?: string[]; + assistantIDs?: string[]; hideCoco?: () => void; theme?: "auto" | "light" | "dark"; searchPlaceholder?: string; @@ -32,7 +31,7 @@ function WebApp({ height = 590, headers = { "X-API-TOKEN": - "cvvitp6hpceh0ip1q1706byts41c7213k4el22v3bp6f4ta2sar0u29jp4pg08h6xcyxn085x3lq1k7wojof", + "cvqt6r02sdb2v3bkgip0x3ixv01f3r2lhnxoz1efbn160wm9og58wtv8t6wrv1ebvnvypuc23dx9pb33aemh", "APP-INTEGRATION-ID": "cvkm9hmhpcemufsg3vug", }, // token = "cva1j5ehpcenic3ir7k0h8fb8qtv35iwtywze248oscrej8yoivhb5b1hyovp24xejjk27jy9ddt69ewfi3n", // https://coco.infini.cloud @@ -42,7 +41,7 @@ function WebApp({ hideCoco = () => {}, hasModules = ["search", "chat"], defaultModule = "search", - hasFeature = ["think_active", "search_active"], + assistantIDs = [], theme = "dark", searchPlaceholder = "", chatPlaceholder = "", @@ -71,12 +70,6 @@ function WebApp({ const [isChatMode, setIsChatMode] = useState(false); - const hasFeatureCopy = useFeatureControl({ - initialFeatures: hasFeature, - featureToToggle: "think", - condition: (item) => item?._source?.type === "simple", - }); - return (
@@ -110,7 +103,6 @@ function WebApp({ hideCoco={hideCoco} hasModules={hasModules} defaultModule={defaultModule} - hasFeature={hasFeatureCopy} theme={theme} searchPlaceholder={searchPlaceholder} chatPlaceholder={chatPlaceholder} @@ -118,6 +110,7 @@ function WebApp({ setIsPinned={setIsPinned} onModeChange={setIsChatMode} isMobile={isMobile} + assistantIDs={assistantIDs} />
); diff --git a/src/utils/platformAdapter.ts b/src/utils/platformAdapter.ts index 7afb9240..58b014cb 100644 --- a/src/utils/platformAdapter.ts +++ b/src/utils/platformAdapter.ts @@ -1,8 +1,8 @@ // manual modification -//import { createWebAdapter } from './webAdapter'; -import { createTauriAdapter } from "./tauriAdapter"; +import { createWebAdapter } from './webAdapter'; +//import { createTauriAdapter } from "./tauriAdapter"; -let platformAdapter = createTauriAdapter(); -//let platformAdapter = createWebAdapter(); +//let platformAdapter = createTauriAdapter(); +let platformAdapter = createWebAdapter(); export default platformAdapter; diff --git a/tsup.config.ts b/tsup.config.ts index 95c6bc4d..60090193 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -67,7 +67,7 @@ export default defineConfig({ const packageJson = { name: "@infinilabs/search-chat", - version: "1.1.4", + version: "1.1.5", main: "index.js", module: "index.js", type: "module", diff --git a/vite.config.ts b/vite.config.ts index deca7a97..07b648f6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -61,6 +61,16 @@ export default defineConfig(async () => ({ changeOrigin: true, secure: false, }, + "/assistant": { + target: process.env.COCO_SERVER_URL, + changeOrigin: true, + secure: false, + }, + "/datasource": { + target: process.env.COCO_SERVER_URL, + changeOrigin: true, + secure: false, + }, }, }, build: {