refactor: use timeout value specified in settings in query_coco_fusion() (#413)

* refactor: allow setting connection_timeout in query_coco_fusion()

* refactor: adding dynamic parameters to a request

* refactor: rename `connection_timeout` to `connectionTimeout`.

* refactor: simplifying object property assignment syntax

* feat: add query timeout function

* refactor: set min query_timeout to 1s

* refactor: rename connection_timeout to query_timeout

* fix: persist the setting entry

---------

Co-authored-by: ayang <473033518@qq.com>
This commit is contained in:
SteveLauC
2025-04-22 18:32:20 +08:00
committed by GitHub
parent 6d8fa81141
commit aee7df608f
9 changed files with 176 additions and 95 deletions

View File

@@ -16,6 +16,7 @@ pub async fn query_coco_fusion<R: Runtime>(
from: u64,
size: u64,
query_strings: HashMap<String, String>,
query_timeout: u64,
) -> Result<MultiSourceQueryResponse, SearchError> {
let data_source_to_search = query_strings.get("datasource");
@@ -28,7 +29,7 @@ pub async fn query_coco_fusion<R: Runtime>(
let sources_list = sources_future.await;
// Time limit for each query
let timeout_duration = Duration::from_millis(500); //TODO, settings
let timeout_duration = Duration::from_secs(query_timeout);
// Push all queries into futures
for query_source in sources_list {

View File

@@ -15,7 +15,7 @@ import {
TranscriptionResponse,
MultiSourceQueryResponse,
} from "@/types/commands";
import { useAppStore } from '@/stores/appStore';
import { useAppStore } from "@/stores/appStore";
async function invokeWithErrorHandler<T>(
command: string,
@@ -26,7 +26,7 @@ async function invokeWithErrorHandler<T>(
const result = await invoke<T>(command, args);
// console.log(command, result);
if (result && typeof result === 'object' && 'failed' in result) {
if (result && typeof result === "object" && "failed" in result) {
const failedResult = result as any;
if (failedResult.failed?.length > 0) {
failedResult.failed.forEach((error: any) => {
@@ -36,17 +36,17 @@ async function invokeWithErrorHandler<T>(
}
}
if (typeof result === 'string') {
if (typeof result === "string") {
const res = JSON.parse(result);
if (typeof res === 'string') {
if (typeof res === "string") {
throw new Error(result);
}
}
return result;
} catch (error: any) {
const errorMessage = error || 'Command execution failed';
addError(errorMessage, 'error');
const errorMessage = error || "Command execution failed";
addError(errorMessage, "error");
throw error;
}
}
@@ -234,7 +234,10 @@ export function send_message({
}
export const delete_session_chat = (serverId: string, sessionId: string) => {
return invokeWithErrorHandler<boolean>(`delete_session_chat`, { serverId, sessionId });
return invokeWithErrorHandler<boolean>(`delete_session_chat`, {
serverId,
sessionId,
});
};
export const update_session_chat = (payload: {
@@ -255,9 +258,12 @@ export const assistant_search = (payload: {
};
export const upload_attachment = async (payload: UploadAttachmentPayload) => {
const response = await invokeWithErrorHandler<UploadAttachmentResponse>("upload_attachment", {
...payload,
});
const response = await invokeWithErrorHandler<UploadAttachmentResponse>(
"upload_attachment",
{
...payload,
}
);
if (response?.acknowledged) {
return response.attachments;
@@ -265,7 +271,9 @@ export const upload_attachment = async (payload: UploadAttachmentPayload) => {
};
export const get_attachment = (payload: GetAttachmentPayload) => {
return invokeWithErrorHandler<GetAttachmentResponse>("get_attachment", { ...payload });
return invokeWithErrorHandler<GetAttachmentResponse>("get_attachment", {
...payload,
});
};
export const delete_attachment = (payload: DeleteAttachmentPayload) => {
@@ -273,13 +281,18 @@ export const delete_attachment = (payload: DeleteAttachmentPayload) => {
};
export const transcription = (payload: TranscriptionPayload) => {
return invokeWithErrorHandler<TranscriptionResponse>("transcription", { ...payload });
return invokeWithErrorHandler<TranscriptionResponse>("transcription", {
...payload,
});
};
export const query_coco_fusion = (payload: {
from: number;
size: number;
query_strings: Record<string, string>;
connection_timeout: number;
}) => {
return invokeWithErrorHandler<MultiSourceQueryResponse>("query_coco_fusion", { ...payload });
return invokeWithErrorHandler<MultiSourceQueryResponse>("query_coco_fusion", {
...payload,
});
};

View File

@@ -33,13 +33,26 @@ const Advanced = () => {
const setConnectionTimeout = useConnectStore((state) => {
return state.setConnectionTimeout;
});
const queryTimeout = useConnectStore((state) => {
return state.queryTimeout;
});
const setQueryTimeout = useConnectStore((state) => {
return state.setQueryTimeout;
});
useEffect(() => {
const unlisten = useStartupStore.subscribe((state) => {
const unsubscribeStartup = useStartupStore.subscribe((state) => {
emit("change-startup-store", state);
});
return unlisten;
const unsubscribeConnect = useConnectStore.subscribe((state) => {
emit("change-connect-store", state);
});
return () => {
unsubscribeStartup();
unsubscribeConnect();
};
}, []);
const startupList = [
@@ -162,6 +175,22 @@ const Advanced = () => {
}}
/>
</SettingsItem>
<SettingsItem
icon={Unplug}
title={t("settings.advanced.connect.queryTimeout.title")}
description={t("settings.advanced.connect.queryTimeout.description")}
>
<input
type="number"
min={1}
value={queryTimeout}
className="w-20 h-8 px-2 rounded-md border bg-transparent border-black/5 dark:border-white/10"
onChange={(event) => {
setQueryTimeout(Number(event.target.value) || 5);
}}
/>
</SettingsItem>
</div>
</div>
);

View File

@@ -1,3 +1,4 @@
import { useConnectStore } from "@/stores/connectStore";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import { useStartupStore } from "@/stores/startupStore";
import platformAdapter from "@/utils/platformAdapter";
@@ -61,6 +62,12 @@ export const useSyncStore = () => {
const setResetFixedWindow = useShortcutsStore((state) => {
return state.setResetFixedWindow;
});
const setConnectionTimeout = useConnectStore((state) => {
return state.setConnectionTimeout;
});
const setQueryTimeout = useConnectStore((state) => {
return state.setQueryTimeout;
});
useEffect(() => {
if (!resetFixedWindow) {
@@ -113,6 +120,12 @@ export const useSyncStore = () => {
setDefaultContentForSearchWindow(defaultContentForSearchWindow);
setDefaultContentForChatWindow(defaultContentForChatWindow);
}),
platformAdapter.listenEvent("change-connect-store", ({ payload }) => {
const { connectionTimeout, queryTimeout } = payload;
setConnectionTimeout(connectionTimeout);
setQueryTimeout(queryTimeout);
}),
]);
return () => {

View File

@@ -141,6 +141,10 @@
"connectionTimeout": {
"title": "Connection Timeout",
"description": "Retries the connection if no response is received within this time. Default: 120s."
},
"queryTimeout": {
"title": "Query Timeout",
"description": "Terminates the query if no search results are returned within this time. Default: 5s."
}
}
},

View File

@@ -141,6 +141,10 @@
"connectionTimeout": {
"title": "连接超时",
"description": "如果在此时间内未收到响应则重试连接。默认值120 秒。"
},
"queryTimeout": {
"title": "查询超时",
"description": "在此时间内未返回搜索结果则终止查询。默认值5 秒。"
}
}
},

View File

@@ -5,10 +5,14 @@ import platformAdapter from "@/utils/platformAdapter";
import { useAppStore } from "@/stores/appStore";
import { useSyncStore } from "@/hooks/useSyncStore";
import { useFeatureControl } from "@/hooks/useFeatureControl";
import { useConnectStore } from "@/stores/connectStore";
function MainApp() {
const setIsTauri = useAppStore((state) => state.setIsTauri);
setIsTauri(true);
const queryTimeout = useConnectStore((state) => {
return state.queryTimeout;
});
const querySearch = useCallback(async (input: string) => {
try {
@@ -18,6 +22,7 @@ function MainApp() {
from: 0,
size: 10,
queryStrings: { query: input },
queryTimeout: queryTimeout,
}
);
if (!response || typeof response !== "object") {
@@ -39,6 +44,7 @@ function MainApp() {
from,
size,
queryStrings,
queryTimeout: queryTimeout,
}
);
return response;
@@ -59,7 +65,7 @@ function MainApp() {
const hasFeature = useFeatureControl({
initialFeatures: ["think", "search"],
featureToToggle: "think",
condition: (item) => item?._source?.type === "simple"
condition: (item) => item?._source?.type === "simple",
});
return (

View File

@@ -1,5 +1,5 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { persist, subscribeWithSelector } from "zustand/middleware";
import { produce } from "immer";
import platformAdapter from "@/utils/platformAdapter";
@@ -26,86 +26,95 @@ export type IConnectStore = {
setCurrentSessionId: (currentSessionId?: string) => void;
currentAssistant: any;
setCurrentAssistant: (assistant: any) => void;
queryTimeout: number;
setQueryTimeout: (queryTimeout: number) => void;
};
export const useConnectStore = create<IConnectStore>()(
persist(
(set) => ({
serverList: [],
setServerList: (serverList: []) => {
console.log("set serverList:", serverList);
set(
produce((draft) => {
draft.serverList = serverList;
})
);
},
currentService: "default_coco_server",
setCurrentService: (server: any) => {
console.log("set default server:", server);
set(
produce((draft) => {
draft.currentService = server;
})
);
},
connector_data: {},
setConnectorData: async (connector_data: any[], key: string) => {
set(
produce((draft) => {
draft.connector_data[key] = connector_data;
})
);
await platformAdapter.emitEvent(CONNECTOR_CHANGE_EVENT, {
connector_data,
});
},
datasourceData: {},
setDatasourceData: async (datasourceData: any[], key: string) => {
set(
produce((draft) => {
draft.datasourceData[key] = datasourceData;
})
);
await platformAdapter.emitEvent(DATASOURCE_CHANGE_EVENT, {
datasourceData,
});
},
initializeListeners: () => {
platformAdapter.listenEvent(CONNECTOR_CHANGE_EVENT, (event: any) => {
const { connector_data } = event.payload;
set({ connector_data });
});
platformAdapter.listenEvent(DATASOURCE_CHANGE_EVENT, (event: any) => {
const { datasourceData } = event.payload;
set({ datasourceData });
});
},
connectionTimeout: 120,
setConnectionTimeout: (connectionTimeout: number) => {
return set(() => ({ connectionTimeout }));
},
setCurrentSessionId(currentSessionId) {
return set(() => ({ currentSessionId }));
},
currentAssistant: null,
setCurrentAssistant: (assistant: any) => {
set(
produce((draft) => {
draft.currentAssistant = assistant;
})
);
},
}),
{
name: "connect-store",
partialize: (state) => ({
currentService: state.currentService,
connector_data: state.connector_data,
datasourceData: state.datasourceData,
connectionTimeout: state.connectionTimeout,
currentAssistant: state.currentAssistant,
subscribeWithSelector(
persist(
(set) => ({
serverList: [],
setServerList: (serverList: []) => {
console.log("set serverList:", serverList);
set(
produce((draft) => {
draft.serverList = serverList;
})
);
},
currentService: "default_coco_server",
setCurrentService: (server: any) => {
console.log("set default server:", server);
set(
produce((draft) => {
draft.currentService = server;
})
);
},
connector_data: {},
setConnectorData: async (connector_data: any[], key: string) => {
set(
produce((draft) => {
draft.connector_data[key] = connector_data;
})
);
await platformAdapter.emitEvent(CONNECTOR_CHANGE_EVENT, {
connector_data,
});
},
datasourceData: {},
setDatasourceData: async (datasourceData: any[], key: string) => {
set(
produce((draft) => {
draft.datasourceData[key] = datasourceData;
})
);
await platformAdapter.emitEvent(DATASOURCE_CHANGE_EVENT, {
datasourceData,
});
},
initializeListeners: () => {
platformAdapter.listenEvent(CONNECTOR_CHANGE_EVENT, (event: any) => {
const { connector_data } = event.payload;
set({ connector_data });
});
platformAdapter.listenEvent(DATASOURCE_CHANGE_EVENT, (event: any) => {
const { datasourceData } = event.payload;
set({ datasourceData });
});
},
connectionTimeout: 120,
setConnectionTimeout: (connectionTimeout: number) => {
return set(() => ({ connectionTimeout }));
},
setCurrentSessionId(currentSessionId) {
return set(() => ({ currentSessionId }));
},
currentAssistant: null,
setCurrentAssistant: (assistant: any) => {
set(
produce((draft) => {
draft.currentAssistant = assistant;
})
);
},
queryTimeout: 5,
setQueryTimeout: (queryTimeout: number) => {
return set(() => ({ queryTimeout }));
},
}),
}
{
name: "connect-store",
partialize: (state) => ({
currentService: state.currentService,
connector_data: state.connector_data,
datasourceData: state.datasourceData,
connectionTimeout: state.connectionTimeout,
currentAssistant: state.currentAssistant,
queryTimeout: state.queryTimeout,
}),
}
)
)
);

View File

@@ -1,3 +1,4 @@
import { IConnectStore } from "@/stores/connectStore";
import { IShortcutsStore } from "@/stores/shortcutsStore";
import { IStartupStore } from "@/stores/startupStore";
import { AppTheme } from "@/types/index";
@@ -36,6 +37,7 @@ export interface EventPayloads {
[key: `ws-message-${string}`]: string;
"change-startup-store": IStartupStore;
"change-shortcuts-store": IShortcutsStore;
"change-connect-store": IConnectStore;
}
// Window operation interface