mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 19:47:43 +01:00
feat: web components assistant (#422)
* chore: web components assistant * chore: web components assistant * docs: update notes
This commit is contained in:
4
.env
4
.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
|
COCO_WEBSOCKET_URL=ws://localhost:9000/ws #wss://coco.infini.cloud/ws #ws://localhost:9000/ws
|
||||||
@@ -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 AI assistant #394
|
||||||
- feat: add support for calculator function #399
|
- feat: add support for calculator function #399
|
||||||
- feat: auto selects the first item after searching #411
|
- feat: auto selects the first item after searching #411
|
||||||
|
- feat: web components assistant #422
|
||||||
|
|
||||||
### Bug fix
|
### Bug fix
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -12,12 +12,13 @@ import FontIcon from "@/components/Common/Icons/FontIcon";
|
|||||||
import { useChatStore } from "@/stores/chatStore";
|
import { useChatStore } from "@/stores/chatStore";
|
||||||
import { AI_ASSISTANT_PANEL_ID } from "@/constants";
|
import { AI_ASSISTANT_PANEL_ID } from "@/constants";
|
||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
|
import { Get } from "@/api/axiosRequest";
|
||||||
|
|
||||||
interface AssistantListProps {
|
interface AssistantListProps {
|
||||||
showChatHistory?: boolean;
|
assistantIDs?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AssistantList({ showChatHistory = true }: AssistantListProps) {
|
export function AssistantList({ assistantIDs = [] }: AssistantListProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { connected } = useChatStore();
|
const { connected } = useChatStore();
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
const isTauri = useAppStore((state) => state.isTauri);
|
||||||
@@ -35,34 +36,49 @@ export function AssistantList({ showChatHistory = true }: AssistantListProps) {
|
|||||||
useClickAway(menuRef, () => setIsOpen(false));
|
useClickAway(menuRef, () => setIsOpen(false));
|
||||||
const [assistants, setAssistants] = useState<any[]>([]);
|
const [assistants, setAssistants] = useState<any[]>([]);
|
||||||
|
|
||||||
const fetchAssistant = useCallback(async (serverId: string) => {
|
const fetchAssistant = useCallback(async (serverId?: string) => {
|
||||||
if (!isTauri) return;
|
let response: any;
|
||||||
if (!serverId) return;
|
if (isTauri) {
|
||||||
platformAdapter
|
if (!serverId) return;
|
||||||
.commands("assistant_search", {
|
try {
|
||||||
serverId,
|
response = await platformAdapter.commands("assistant_search", {
|
||||||
})
|
serverId,
|
||||||
.then((res: any) => {
|
});
|
||||||
res = res ? JSON.parse(res) : null;
|
response = response ? JSON.parse(response) : null;
|
||||||
console.log("assistant_search", res);
|
} catch (err) {
|
||||||
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) => {
|
|
||||||
setAssistants([]);
|
setAssistants([]);
|
||||||
setCurrentAssistant(null);
|
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(() => {
|
useEffect(() => {
|
||||||
@@ -98,24 +114,22 @@ export function AssistantList({ showChatHistory = true }: AssistantListProps) {
|
|||||||
<div className="max-w-[100px] truncate">
|
<div className="max-w-[100px] truncate">
|
||||||
{currentAssistant?._source?.name || "Coco AI"}
|
{currentAssistant?._source?.name || "Coco AI"}
|
||||||
</div>
|
</div>
|
||||||
{showChatHistory && isTauri && (
|
<VisibleKey
|
||||||
<VisibleKey
|
aria-controls={isOpen ? AI_ASSISTANT_PANEL_ID : ""}
|
||||||
aria-controls={isOpen ? AI_ASSISTANT_PANEL_ID : ""}
|
shortcut={aiAssistant}
|
||||||
shortcut={aiAssistant}
|
onKeyPress={() => {
|
||||||
onKeyPress={() => {
|
setIsOpen(!isOpen);
|
||||||
setIsOpen(!isOpen);
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ChevronDownIcon
|
||||||
<ChevronDownIcon
|
className={`size-4 text-gray-500 dark:text-gray-400 transition-transform ${
|
||||||
className={`size-4 text-gray-500 dark:text-gray-400 transition-transform ${
|
isOpen ? "rotate-180" : ""
|
||||||
isOpen ? "rotate-180" : ""
|
}`}
|
||||||
}`}
|
/>
|
||||||
/>
|
</VisibleKey>
|
||||||
</VisibleKey>
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showChatHistory && isTauri && isOpen && (
|
{isOpen && (
|
||||||
<div
|
<div
|
||||||
id={isOpen ? AI_ASSISTANT_PANEL_ID : ""}
|
id={isOpen ? AI_ASSISTANT_PANEL_ID : ""}
|
||||||
className="absolute z-50 top-full mt-1 left-0 w-64 rounded-xl bg-white dark:bg-[#202126] p-2 text-sm/6 text-gray-800 dark:text-white shadow-lg border border-gray-200 dark:border-gray-700 focus:outline-none max-h-[calc(100vh-80px)] overflow-y-auto"
|
className="absolute z-50 top-full mt-1 left-0 w-64 rounded-xl bg-white dark:bg-[#202126] p-2 text-sm/6 text-gray-800 dark:text-white shadow-lg border border-gray-200 dark:border-gray-700 focus:outline-none max-h-[calc(100vh-80px)] overflow-y-auto"
|
||||||
@@ -140,6 +154,7 @@ export function AssistantList({ showChatHistory = true }: AssistantListProps) {
|
|||||||
<button
|
<button
|
||||||
key={assistant._id}
|
key={assistant._id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
console.log("assistant", assistant);
|
||||||
setCurrentAssistant(assistant);
|
setCurrentAssistant(assistant);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ interface ChatAIProps {
|
|||||||
isChatPage?: boolean;
|
isChatPage?: boolean;
|
||||||
getFileUrl: (path: string) => string;
|
getFileUrl: (path: string) => string;
|
||||||
showChatHistory?: boolean;
|
showChatHistory?: boolean;
|
||||||
|
assistantIDs?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatAIRef {
|
export interface ChatAIRef {
|
||||||
@@ -58,6 +59,7 @@ const ChatAI = memo(
|
|||||||
isChatPage = false,
|
isChatPage = false,
|
||||||
getFileUrl,
|
getFileUrl,
|
||||||
showChatHistory,
|
showChatHistory,
|
||||||
|
assistantIDs,
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
@@ -376,6 +378,7 @@ const ChatAI = memo(
|
|||||||
isLogin={isLogin}
|
isLogin={isLogin}
|
||||||
setIsLogin={setIsLogin}
|
setIsLogin={setIsLogin}
|
||||||
showChatHistory={showChatHistory}
|
showChatHistory={showChatHistory}
|
||||||
|
assistantIDs={assistantIDs}
|
||||||
/>
|
/>
|
||||||
{isLogin ? (
|
{isLogin ? (
|
||||||
<ChatContent
|
<ChatContent
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import {
|
import { MessageSquarePlus } from "lucide-react";
|
||||||
MessageSquarePlus,
|
|
||||||
} from "lucide-react";
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import HistoryIcon from "@/icons/History";
|
import HistoryIcon from "@/icons/History";
|
||||||
@@ -27,6 +25,7 @@ interface ChatHeaderProps {
|
|||||||
setIsLogin: (isLogin: boolean) => void;
|
setIsLogin: (isLogin: boolean) => void;
|
||||||
isChatPage?: boolean;
|
isChatPage?: boolean;
|
||||||
showChatHistory?: boolean;
|
showChatHistory?: boolean;
|
||||||
|
assistantIDs?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatHeader({
|
export function ChatHeader({
|
||||||
@@ -40,8 +39,8 @@ export function ChatHeader({
|
|||||||
setIsLogin,
|
setIsLogin,
|
||||||
isChatPage = false,
|
isChatPage = false,
|
||||||
showChatHistory = true,
|
showChatHistory = true,
|
||||||
|
assistantIDs,
|
||||||
}: ChatHeaderProps) {
|
}: ChatHeaderProps) {
|
||||||
|
|
||||||
const isPinned = useAppStore((state) => state.isPinned);
|
const isPinned = useAppStore((state) => state.isPinned);
|
||||||
const setIsPinned = useAppStore((state) => state.setIsPinned);
|
const setIsPinned = useAppStore((state) => state.setIsPinned);
|
||||||
|
|
||||||
@@ -94,7 +93,7 @@ export function ChatHeader({
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<AssistantList showChatHistory={showChatHistory} />
|
<AssistantList assistantIDs={assistantIDs} />
|
||||||
|
|
||||||
{showChatHistory ? (
|
{showChatHistory ? (
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { ChatMessage } from "@/components/ChatMessage";
|
import { ChatMessage } from "@/components/ChatMessage";
|
||||||
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
|
|
||||||
export const Greetings = () => {
|
export const Greetings = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const currentAssistant = useConnectStore((state) => state.currentAssistant);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChatMessage
|
<ChatMessage
|
||||||
@@ -12,7 +14,9 @@ export const Greetings = () => {
|
|||||||
_id: "greetings",
|
_id: "greetings",
|
||||||
_source: {
|
_source: {
|
||||||
type: "assistant",
|
type: "assistant",
|
||||||
message: t("assistant.chat.greetings"),
|
message:
|
||||||
|
currentAssistant?._source?.chat_settings?.greeting_message ||
|
||||||
|
t("assistant.chat.greetings"),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { MoveRight } from "lucide-react";
|
import { MoveRight } from "lucide-react";
|
||||||
import { FC, useEffect, useState } from "react";
|
import { FC, useEffect, useState } from "react";
|
||||||
|
|
||||||
import { Get } from "@/api/axiosRequest";
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
|
||||||
|
|
||||||
interface PrevSuggestionProps {
|
interface PrevSuggestionProps {
|
||||||
sendMessage: (message: string) => void;
|
sendMessage: (message: string) => void;
|
||||||
@@ -11,35 +10,18 @@ interface PrevSuggestionProps {
|
|||||||
const PrevSuggestion: FC<PrevSuggestionProps> = (props) => {
|
const PrevSuggestion: FC<PrevSuggestionProps> = (props) => {
|
||||||
const { sendMessage } = props;
|
const { sendMessage } = props;
|
||||||
|
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
const currentAssistant = useConnectStore((state) => state.currentAssistant);
|
||||||
|
|
||||||
const headersStr = localStorage.getItem("headers") || "{}";
|
|
||||||
const headers = JSON.parse(headersStr);
|
|
||||||
const id = headers["APP-INTEGRATION-ID"] || "cvkm9hmhpcemufsg3vug";
|
|
||||||
// console.log("id", id);
|
|
||||||
|
|
||||||
const [list, setList] = useState<string[]>([]);
|
const [list, setList] = useState<string[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isTauri) getList();
|
const suggested = currentAssistant?._source?.chat_settings?.suggested || {};
|
||||||
}, [id]);
|
if (suggested.enabled) {
|
||||||
|
setList(suggested.questions || []);
|
||||||
const getList = async () => {
|
} else {
|
||||||
if (!id) return;
|
setList([]);
|
||||||
|
|
||||||
const url = `/integration/${id}/chat/_suggest`;
|
|
||||||
|
|
||||||
const [error, res] = await Get(`/integration/${id}/chat/_suggest`);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error(url, error);
|
|
||||||
return setList([]);
|
|
||||||
}
|
}
|
||||||
|
}, [JSON.stringify(currentAssistant)]);
|
||||||
console.log("chat/_suggest", res);
|
|
||||||
|
|
||||||
setList(Array.isArray(res) ? res : []);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className="absolute left-2 bottom-2 flex flex-col gap-2">
|
<ul className="absolute left-2 bottom-2 flex flex-col gap-2">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import SearchPopover from "./SearchPopover";
|
|||||||
// import AudioRecording from "../AudioRecording";
|
// import AudioRecording from "../AudioRecording";
|
||||||
import { DataSource } from "@/types/commands";
|
import { DataSource } from "@/types/commands";
|
||||||
// import InputExtra from "./InputExtra";
|
// import InputExtra from "./InputExtra";
|
||||||
// import { useConnectStore } from "@/stores/connectStore";
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
import Copyright from "@/components/Common/Copyright";
|
import Copyright from "@/components/Common/Copyright";
|
||||||
import VisibleKey from "@/components/Common/VisibleKey";
|
import VisibleKey from "@/components/Common/VisibleKey";
|
||||||
@@ -55,7 +55,6 @@ interface ChatInputProps {
|
|||||||
getFileMetadata: (path: string) => Promise<any>;
|
getFileMetadata: (path: string) => Promise<any>;
|
||||||
getFileIcon: (path: string, size: number) => Promise<string>;
|
getFileIcon: (path: string, size: number) => Promise<string>;
|
||||||
hideCoco?: () => void;
|
hideCoco?: () => void;
|
||||||
hasFeature?: string[];
|
|
||||||
hasModules?: string[];
|
hasModules?: string[];
|
||||||
searchPlaceholder?: string;
|
searchPlaceholder?: string;
|
||||||
chatPlaceholder?: string;
|
chatPlaceholder?: string;
|
||||||
@@ -77,7 +76,6 @@ export default function ChatInput({
|
|||||||
isChatPage = false,
|
isChatPage = false,
|
||||||
getDataSourcesByServer,
|
getDataSourcesByServer,
|
||||||
setupWindowFocusListener,
|
setupWindowFocusListener,
|
||||||
hasFeature = ["think", "search", "think_active", "search_active"],
|
|
||||||
hideCoco,
|
hideCoco,
|
||||||
hasModules = [],
|
hasModules = [],
|
||||||
searchPlaceholder,
|
searchPlaceholder,
|
||||||
@@ -85,6 +83,9 @@ export default function ChatInput({
|
|||||||
}: ChatInputProps) {
|
}: ChatInputProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const currentAssistant = useConnectStore((state) => state.currentAssistant);
|
||||||
|
console.log("currentAssistant", currentAssistant);
|
||||||
|
|
||||||
const showTooltip = useAppStore((state) => state.showTooltip);
|
const showTooltip = useAppStore((state) => state.showTooltip);
|
||||||
const isPinned = useAppStore((state) => state.isPinned);
|
const isPinned = useAppStore((state) => state.isPinned);
|
||||||
|
|
||||||
@@ -437,7 +438,7 @@ export default function ChatInput({
|
|||||||
/>
|
/>
|
||||||
)} */}
|
)} */}
|
||||||
|
|
||||||
{hasFeature.includes("think") && (
|
{currentAssistant?._source?.config?.visible && (
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex items-center gap-1 py-[3px] pl-1 pr-1.5 rounded-md transition hover:bg-[#EDEDED] dark:hover:bg-[#202126]",
|
"flex items-center gap-1 py-[3px] pl-1 pr-1.5 rounded-md transition hover:bg-[#EDEDED] dark:hover:bg-[#202126]",
|
||||||
@@ -468,7 +469,7 @@ export default function ChatInput({
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hasFeature.includes("search") && (
|
{currentAssistant?._source?.datasource?.visible && (
|
||||||
<SearchPopover
|
<SearchPopover
|
||||||
isSearchActive={isSearchActive}
|
isSearchActive={isSearchActive}
|
||||||
setIsSearchActive={setIsSearchActive}
|
setIsSearchActive={setIsSearchActive}
|
||||||
@@ -476,7 +477,7 @@ export default function ChatInput({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!hasFeature.includes("search") && !hasFeature.includes("think") ? (
|
{!currentAssistant?._source?.datasource?.visible && !currentAssistant?._source?.config?.visible ? (
|
||||||
<div className="px-[9px]">
|
<div className="px-[9px]">
|
||||||
<Copyright />
|
<Copyright />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,14 +49,16 @@ const SearchListItem: React.FC<SearchListItemProps> = React.memo(
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
showListRight ? "max-w-[450px] mobile:w-full" : "flex-1"
|
showListRight ? "max-w-[450px] mobile:max-w-full mobile:w-full" : "flex-1"
|
||||||
} min-w-0 flex gap-2 items-center justify-start `}
|
} min-w-0 flex gap-2 items-center justify-start `}
|
||||||
>
|
>
|
||||||
<ItemIcon item={item} />
|
<ItemIcon item={item} />
|
||||||
<span className={`text-sm truncate text-left`}>{item?.title}</span>
|
<span className={`text-sm truncate text-left`}>{item?.title}</span>
|
||||||
</div>
|
</div>
|
||||||
{!isTauri && isMobile ? (
|
{!isTauri && isMobile ? (
|
||||||
<div className="w-full text-xs truncate">{item?.summary}</div>
|
<div className="w-full text-xs text-gray-500 dark:text-gray-400 truncate">
|
||||||
|
{item?.summary}
|
||||||
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{showListRight && (isTauri || !isMobile) ? (
|
{showListRight && (isTauri || !isMobile) ? (
|
||||||
<ListRight
|
<ListRight
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ import { useStartupStore } from "@/stores/startupStore";
|
|||||||
import { DataSource } from "@/types/commands";
|
import { DataSource } from "@/types/commands";
|
||||||
import { useThemeStore } from "@/stores/themeStore";
|
import { useThemeStore } from "@/stores/themeStore";
|
||||||
import { Get } from "@/api/axiosRequest";
|
import { Get } from "@/api/axiosRequest";
|
||||||
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
|
|
||||||
interface SearchChatProps {
|
interface SearchChatProps {
|
||||||
isTauri?: boolean;
|
isTauri?: boolean;
|
||||||
hasModules?: string[];
|
hasModules?: string[];
|
||||||
defaultModule?: "search" | "chat";
|
defaultModule?: "search" | "chat";
|
||||||
|
|
||||||
hasFeature?: string[];
|
|
||||||
showChatHistory?: boolean;
|
showChatHistory?: boolean;
|
||||||
|
|
||||||
theme?: "auto" | "light" | "dark";
|
theme?: "auto" | "light" | "dark";
|
||||||
@@ -41,13 +41,13 @@ interface SearchChatProps {
|
|||||||
setIsPinned?: (value: boolean) => void;
|
setIsPinned?: (value: boolean) => void;
|
||||||
onModeChange?: (isChatMode: boolean) => void;
|
onModeChange?: (isChatMode: boolean) => void;
|
||||||
isMobile?: boolean;
|
isMobile?: boolean;
|
||||||
|
assistantIDs?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchChat({
|
function SearchChat({
|
||||||
isTauri = true,
|
isTauri = true,
|
||||||
hasModules = ["search", "chat"],
|
hasModules = ["search", "chat"],
|
||||||
defaultModule = "search",
|
defaultModule = "search",
|
||||||
hasFeature = ["think", "search", "think_active", "search_active"],
|
|
||||||
theme,
|
theme,
|
||||||
hideCoco,
|
hideCoco,
|
||||||
searchPlaceholder,
|
searchPlaceholder,
|
||||||
@@ -56,11 +56,14 @@ function SearchChat({
|
|||||||
setIsPinned,
|
setIsPinned,
|
||||||
onModeChange,
|
onModeChange,
|
||||||
isMobile = false,
|
isMobile = false,
|
||||||
|
assistantIDs,
|
||||||
}: SearchChatProps) {
|
}: SearchChatProps) {
|
||||||
|
const currentAssistant = useConnectStore((state) => state.currentAssistant);
|
||||||
|
|
||||||
const customInitialState = {
|
const customInitialState = {
|
||||||
...initialAppState,
|
...initialAppState,
|
||||||
isDeepThinkActive: hasFeature.includes("think_active"),
|
isDeepThinkActive: currentAssistant?._source?.type === "deep_think",
|
||||||
isSearchActive: hasFeature.includes("search_active"),
|
isSearchActive: currentAssistant?._source?.datasource?.enabled === true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [state, dispatch] = useReducer(appReducer, customInitialState);
|
const [state, dispatch] = useReducer(appReducer, customInitialState);
|
||||||
@@ -172,26 +175,31 @@ function SearchChat({
|
|||||||
query?: string;
|
query?: string;
|
||||||
}
|
}
|
||||||
): Promise<DataSource[]> => {
|
): Promise<DataSource[]> => {
|
||||||
|
let response: any;
|
||||||
if (isTauri) {
|
if (isTauri) {
|
||||||
return platformAdapter.invokeBackend("get_datasources_by_server", {
|
response = platformAdapter.invokeBackend("get_datasources_by_server", {
|
||||||
id: serverId,
|
id: serverId,
|
||||||
options,
|
options,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const [error, response]: any = await Get("/datasource/_search");
|
const [error, res]: any = await Get("/datasource/_search");
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("_search", error);
|
console.error("_search", error);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const res = response?.hits?.hits?.map((item: any) => {
|
response = res?.hits?.hits?.map((item: any) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
id: item._source.id,
|
id: item._source.id,
|
||||||
name: item._source.name,
|
name: item._source.name,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return res || [];
|
|
||||||
}
|
}
|
||||||
|
let ids = currentAssistant?._source?.datasource?.ids;
|
||||||
|
if (Array.isArray(ids) && ids.length > 0 && !ids.includes("*")) {
|
||||||
|
response = response.filter((item: any) => ids.includes(item.id));
|
||||||
|
}
|
||||||
|
return response || [];
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
@@ -300,7 +308,6 @@ function SearchChat({
|
|||||||
setIsSearchActive={toggleSearchActive}
|
setIsSearchActive={toggleSearchActive}
|
||||||
isDeepThinkActive={isDeepThinkActive}
|
isDeepThinkActive={isDeepThinkActive}
|
||||||
setIsDeepThinkActive={toggleDeepThinkActive}
|
setIsDeepThinkActive={toggleDeepThinkActive}
|
||||||
hasFeature={hasFeature}
|
|
||||||
getDataSourcesByServer={getDataSourcesByServer}
|
getDataSourcesByServer={getDataSourcesByServer}
|
||||||
setupWindowFocusListener={setupWindowFocusListener}
|
setupWindowFocusListener={setupWindowFocusListener}
|
||||||
checkScreenPermission={checkScreenPermission}
|
checkScreenPermission={checkScreenPermission}
|
||||||
@@ -356,6 +363,7 @@ function SearchChat({
|
|||||||
isDeepThinkActive={isDeepThinkActive}
|
isDeepThinkActive={isDeepThinkActive}
|
||||||
getFileUrl={getFileUrl}
|
getFileUrl={getFileUrl}
|
||||||
showChatHistory={showChatHistory}
|
showChatHistory={showChatHistory}
|
||||||
|
assistantIDs={assistantIDs}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
import { DataSource } from "@/types/commands";
|
import { DataSource } from "@/types/commands";
|
||||||
import HistoryList from "@/components/Common/HistoryList";
|
import HistoryList from "@/components/Common/HistoryList";
|
||||||
import { useSyncStore } from "@/hooks/useSyncStore";
|
import { useSyncStore } from "@/hooks/useSyncStore";
|
||||||
import { useFeatureControl } from "@/hooks/useFeatureControl";
|
|
||||||
|
|
||||||
interface ChatProps {}
|
interface ChatProps {}
|
||||||
|
|
||||||
@@ -262,12 +261,6 @@ export default function Chat({}: ChatProps) {
|
|||||||
await delete_session_chat(currentService.id, id);
|
await delete_session_chat(currentService.id, id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasFeature = useFeatureControl({
|
|
||||||
initialFeatures: ["think", "search"],
|
|
||||||
featureToToggle: "think",
|
|
||||||
condition: (item) => item?._source?.type === "simple"
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen">
|
<div className="h-screen">
|
||||||
<div className="h-full flex">
|
<div className="h-full flex">
|
||||||
@@ -337,7 +330,6 @@ export default function Chat({}: ChatProps) {
|
|||||||
openFileDialog={openFileDialog}
|
openFileDialog={openFileDialog}
|
||||||
getFileMetadata={getFileMetadata}
|
getFileMetadata={getFileMetadata}
|
||||||
getFileIcon={getFileIcon}
|
getFileIcon={getFileIcon}
|
||||||
hasFeature={hasFeature}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import SearchChat from "@/components/SearchChat";
|
|||||||
import platformAdapter from "@/utils/platformAdapter";
|
import platformAdapter from "@/utils/platformAdapter";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
import { useAppStore } from "@/stores/appStore";
|
||||||
import { useSyncStore } from "@/hooks/useSyncStore";
|
import { useSyncStore } from "@/hooks/useSyncStore";
|
||||||
import { useFeatureControl } from "@/hooks/useFeatureControl";
|
|
||||||
|
|
||||||
function MainApp() {
|
function MainApp() {
|
||||||
const setIsTauri = useAppStore((state) => state.setIsTauri);
|
const setIsTauri = useAppStore((state) => state.setIsTauri);
|
||||||
@@ -16,18 +15,11 @@ function MainApp() {
|
|||||||
|
|
||||||
useSyncStore();
|
useSyncStore();
|
||||||
|
|
||||||
const hasFeature = useFeatureControl({
|
|
||||||
initialFeatures: ["think", "search"],
|
|
||||||
featureToToggle: "think",
|
|
||||||
condition: (item) => item?._source?.type === "simple",
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchChat
|
<SearchChat
|
||||||
isTauri={true}
|
isTauri={true}
|
||||||
hideCoco={hideCoco}
|
hideCoco={hideCoco}
|
||||||
hasModules={["search", "chat"]}
|
hasModules={["search", "chat"]}
|
||||||
hasFeature={hasFeature}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,6 @@
|
|||||||
- **默认值**: `['search', 'chat']`
|
- **默认值**: `['search', 'chat']`
|
||||||
- **描述**: 启用的功能模块列表,目前支持 'search' 和 'chat' 模块
|
- **描述**: 启用的功能模块列表,目前支持 'search' 和 'chat' 模块
|
||||||
|
|
||||||
### `hasFeature`
|
|
||||||
- **类型**: `string[]`
|
|
||||||
- **可选**: 是
|
|
||||||
- **默认值**: `['think', 'search', 'think_active', 'search_active']`
|
|
||||||
- **描述**: 启用的特性列表,支持 'think'、'search'、'think_active'、'search_active' 特性。其中 'think_active' 表示默认开启深度思考,'search_active' 表示默认开启搜索
|
|
||||||
|
|
||||||
### `hideCoco`
|
### `hideCoco`
|
||||||
- **类型**: `() => void`
|
- **类型**: `() => void`
|
||||||
- **可选**: 是
|
- **可选**: 是
|
||||||
@@ -87,7 +81,6 @@ function App() {
|
|||||||
width={680}
|
width={680}
|
||||||
height={590}
|
height={590}
|
||||||
hasModules={['search', 'chat']}
|
hasModules={['search', 'chat']}
|
||||||
hasFeature={['think', 'search', 'think_active', 'search_active']}
|
|
||||||
hideCoco={() => console.log('hide')}
|
hideCoco={() => console.log('hide')}
|
||||||
theme="dark"
|
theme="dark"
|
||||||
searchPlaceholder=""
|
searchPlaceholder=""
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useAppStore } from "@/stores/appStore";
|
|||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
import { useIsMobile } from "@/hooks/useIsMobile";
|
import { useIsMobile } from "@/hooks/useIsMobile";
|
||||||
import { useModifierKeyPress } from "@/hooks/useModifierKeyPress";
|
import { useModifierKeyPress } from "@/hooks/useModifierKeyPress";
|
||||||
import { useFeatureControl } from "@/hooks/useFeatureControl";
|
|
||||||
|
|
||||||
import "@/i18n";
|
import "@/i18n";
|
||||||
import "@/web.css";
|
import "@/web.css";
|
||||||
@@ -17,7 +16,7 @@ interface WebAppProps {
|
|||||||
height?: number;
|
height?: number;
|
||||||
hasModules?: string[];
|
hasModules?: string[];
|
||||||
defaultModule?: "search" | "chat";
|
defaultModule?: "search" | "chat";
|
||||||
hasFeature?: string[];
|
assistantIDs?: string[];
|
||||||
hideCoco?: () => void;
|
hideCoco?: () => void;
|
||||||
theme?: "auto" | "light" | "dark";
|
theme?: "auto" | "light" | "dark";
|
||||||
searchPlaceholder?: string;
|
searchPlaceholder?: string;
|
||||||
@@ -32,7 +31,7 @@ function WebApp({
|
|||||||
height = 590,
|
height = 590,
|
||||||
headers = {
|
headers = {
|
||||||
"X-API-TOKEN":
|
"X-API-TOKEN":
|
||||||
"cvvitp6hpceh0ip1q1706byts41c7213k4el22v3bp6f4ta2sar0u29jp4pg08h6xcyxn085x3lq1k7wojof",
|
"cvqt6r02sdb2v3bkgip0x3ixv01f3r2lhnxoz1efbn160wm9og58wtv8t6wrv1ebvnvypuc23dx9pb33aemh",
|
||||||
"APP-INTEGRATION-ID": "cvkm9hmhpcemufsg3vug",
|
"APP-INTEGRATION-ID": "cvkm9hmhpcemufsg3vug",
|
||||||
},
|
},
|
||||||
// token = "cva1j5ehpcenic3ir7k0h8fb8qtv35iwtywze248oscrej8yoivhb5b1hyovp24xejjk27jy9ddt69ewfi3n", // https://coco.infini.cloud
|
// token = "cva1j5ehpcenic3ir7k0h8fb8qtv35iwtywze248oscrej8yoivhb5b1hyovp24xejjk27jy9ddt69ewfi3n", // https://coco.infini.cloud
|
||||||
@@ -42,7 +41,7 @@ function WebApp({
|
|||||||
hideCoco = () => {},
|
hideCoco = () => {},
|
||||||
hasModules = ["search", "chat"],
|
hasModules = ["search", "chat"],
|
||||||
defaultModule = "search",
|
defaultModule = "search",
|
||||||
hasFeature = ["think_active", "search_active"],
|
assistantIDs = [],
|
||||||
theme = "dark",
|
theme = "dark",
|
||||||
searchPlaceholder = "",
|
searchPlaceholder = "",
|
||||||
chatPlaceholder = "",
|
chatPlaceholder = "",
|
||||||
@@ -71,12 +70,6 @@ function WebApp({
|
|||||||
|
|
||||||
const [isChatMode, setIsChatMode] = useState(false);
|
const [isChatMode, setIsChatMode] = useState(false);
|
||||||
|
|
||||||
const hasFeatureCopy = useFeatureControl({
|
|
||||||
initialFeatures: hasFeature,
|
|
||||||
featureToToggle: "think",
|
|
||||||
condition: (item) => item?._source?.type === "simple",
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="searchChat-container"
|
id="searchChat-container"
|
||||||
@@ -91,7 +84,7 @@ function WebApp({
|
|||||||
{isMobile && (
|
{isMobile && (
|
||||||
<div
|
<div
|
||||||
className={`fixed ${
|
className={`fixed ${
|
||||||
isChatMode ? "top-2" : "top-3"
|
isChatMode ? "top-1" : "top-3"
|
||||||
} right-2 flex items-center justify-center w-8 h-8 rounded-full bg-black/10 dark:bg-white/10 cursor-pointer z-50`}
|
} right-2 flex items-center justify-center w-8 h-8 rounded-full bg-black/10 dark:bg-white/10 cursor-pointer z-50`}
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
>
|
>
|
||||||
@@ -110,7 +103,6 @@ function WebApp({
|
|||||||
hideCoco={hideCoco}
|
hideCoco={hideCoco}
|
||||||
hasModules={hasModules}
|
hasModules={hasModules}
|
||||||
defaultModule={defaultModule}
|
defaultModule={defaultModule}
|
||||||
hasFeature={hasFeatureCopy}
|
|
||||||
theme={theme}
|
theme={theme}
|
||||||
searchPlaceholder={searchPlaceholder}
|
searchPlaceholder={searchPlaceholder}
|
||||||
chatPlaceholder={chatPlaceholder}
|
chatPlaceholder={chatPlaceholder}
|
||||||
@@ -118,6 +110,7 @@ function WebApp({
|
|||||||
setIsPinned={setIsPinned}
|
setIsPinned={setIsPinned}
|
||||||
onModeChange={setIsChatMode}
|
onModeChange={setIsChatMode}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
|
assistantIDs={assistantIDs}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// manual modification
|
// manual modification
|
||||||
//import { createWebAdapter } from './webAdapter';
|
import { createWebAdapter } from './webAdapter';
|
||||||
import { createTauriAdapter } from "./tauriAdapter";
|
//import { createTauriAdapter } from "./tauriAdapter";
|
||||||
|
|
||||||
let platformAdapter = createTauriAdapter();
|
//let platformAdapter = createTauriAdapter();
|
||||||
//let platformAdapter = createWebAdapter();
|
let platformAdapter = createWebAdapter();
|
||||||
|
|
||||||
export default platformAdapter;
|
export default platformAdapter;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export default defineConfig({
|
|||||||
|
|
||||||
const packageJson = {
|
const packageJson = {
|
||||||
name: "@infinilabs/search-chat",
|
name: "@infinilabs/search-chat",
|
||||||
version: "1.1.4",
|
version: "1.1.5",
|
||||||
main: "index.js",
|
main: "index.js",
|
||||||
module: "index.js",
|
module: "index.js",
|
||||||
type: "module",
|
type: "module",
|
||||||
|
|||||||
@@ -61,6 +61,16 @@ export default defineConfig(async () => ({
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
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: {
|
build: {
|
||||||
|
|||||||
Reference in New Issue
Block a user