Skip to content

Commit aef934e

Browse files
SteveLauCayangweb
andauthored
feat: advanced settings search debounce & local query source weight (#950)
* wip * wip * wip * feat: add search delay * refactor: update * refactor: update * refactor: update * refactor: update * docs: update changelog --------- Co-authored-by: ayang <473033518@qq.com> Co-authored-by: ayangweb <75017711+ayangweb@users.noreply.github.com>
1 parent 1fb927c commit aef934e

11 files changed

Lines changed: 226 additions & 61 deletions

File tree

docs/content.en/docs/release-notes/_index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ feat(View Extension): page field now accepts HTTP(s) links #925
2222
feat: return sub-exts when extension type exts themselves are matched #928
2323
feat: open quick ai with modifier key + enter #939
2424
feat: allow navigate back when cursor is at the beginning #940
25-
feat: add compact mode for window #947
2625
feat(extension compatibility): minimum_coco_version #946
26+
feat: add compact mode for window #947
27+
feat: advanced settings search debounce & local query source weight #950
2728
feat: add window opacity configuration option #963
2829

30+
2931
### 🐛 Bug fix
3032

3133
fix: automatic update of service list #913

src-tauri/src/common/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl SearchQuery {
100100
}
101101
}
102102

103-
#[derive(Debug, Clone, Serialize)]
103+
#[derive(Debug, Clone, Serialize, Hash, PartialEq, Eq)]
104104
pub struct QuerySource {
105105
pub r#type: String, //coco-server/local/ etc.
106106
pub id: String, //coco server's id

src-tauri/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ pub fn run() {
193193
extension::api::fs::read_dir,
194194
settings::set_allow_self_signature,
195195
settings::get_allow_self_signature,
196+
settings::set_local_query_source_weight,
197+
settings::get_local_query_source_weight,
196198
assistant::ask_ai,
197199
crate::common::document::open,
198200
extension::built_in::file_search::config::get_file_system_config,

src-tauri/src/search/mod.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ use crate::common::search::{
44
FailedRequest, MultiSourceQueryResponse, QueryHits, QuerySource, SearchQuery,
55
};
66
use crate::common::traits::SearchSource;
7+
use crate::extension::LOCAL_QUERY_SOURCE_TYPE;
78
use crate::server::servers::logout_coco_server;
89
use crate::server::servers::mark_server_as_offline;
10+
use crate::settings::get_local_query_source_weight;
911
use function_name::named;
1012
use futures::StreamExt;
1113
use futures::stream::FuturesUnordered;
@@ -205,7 +207,7 @@ async fn query_coco_fusion_multi_query_sources(
205207

206208
let mut total_hits = 0;
207209
let mut failed_requests = Vec::new();
208-
let mut all_hits_grouped_by_source_id: HashMap<String, Vec<QueryHits>> = HashMap::new();
210+
let mut all_hits_grouped_by_query_source: HashMap<QuerySource, Vec<QueryHits>> = HashMap::new();
209211

210212
while let Some((query_source, timeout_result)) = futures.next().await {
211213
match timeout_result {
@@ -219,7 +221,6 @@ async fn query_coco_fusion_multi_query_sources(
219221
Ok(query_result) => match query_result {
220222
Ok(response) => {
221223
total_hits += response.total_hits;
222-
let source_id = response.source.id.clone();
223224

224225
for (document, score) in response.hits {
225226
log::debug!(
@@ -236,8 +237,8 @@ async fn query_coco_fusion_multi_query_sources(
236237
document,
237238
};
238239

239-
all_hits_grouped_by_source_id
240-
.entry(source_id.clone())
240+
all_hits_grouped_by_query_source
241+
.entry(query_source.clone())
241242
.or_insert_with(Vec::new)
242243
.push(query_hit);
243244
}
@@ -255,7 +256,7 @@ async fn query_coco_fusion_multi_query_sources(
255256
}
256257
}
257258

258-
let n_sources = all_hits_grouped_by_source_id.len();
259+
let n_sources = all_hits_grouped_by_query_source.len();
259260

260261
if n_sources == 0 {
261262
return Ok(MultiSourceQueryResponse {
@@ -265,11 +266,25 @@ async fn query_coco_fusion_multi_query_sources(
265266
});
266267
}
267268

269+
/*
270+
* Apply settings: local query source weight
271+
*/
272+
let local_query_source_weight: f64 = get_local_query_source_weight(tauri_app_handle);
273+
// Scores remain unchanged if it is 1.0
274+
if local_query_source_weight != 1.0 {
275+
for (query_source, hits) in all_hits_grouped_by_query_source.iter_mut() {
276+
if query_source.r#type == LOCAL_QUERY_SOURCE_TYPE {
277+
hits.iter_mut()
278+
.for_each(|hit| hit.score = hit.score * local_query_source_weight);
279+
}
280+
}
281+
}
282+
268283
/*
269284
* Sort hits within each source by score (descending) in case data sources
270285
* do not sort them
271286
*/
272-
for hits in all_hits_grouped_by_source_id.values_mut() {
287+
for hits in all_hits_grouped_by_query_source.values_mut() {
273288
hits.sort_by(|a, b| {
274289
b.score
275290
.partial_cmp(&a.score)
@@ -288,15 +303,15 @@ async fn query_coco_fusion_multi_query_sources(
288303

289304
// Include at least 2 hits from each query source
290305
let max_hits_per_source = (size as usize / n_sources).max(2);
291-
for (source_id, hits) in all_hits_grouped_by_source_id.iter() {
306+
for (query_source, hits) in all_hits_grouped_by_query_source.iter() {
292307
let hits_taken = if hits.len() > max_hits_per_source {
293-
pruned.insert(&source_id, &hits[max_hits_per_source..]);
308+
pruned.insert(&query_source.id, &hits[max_hits_per_source..]);
294309
hits[0..max_hits_per_source].to_vec()
295310
} else {
296311
hits.clone()
297312
};
298313

299-
final_hits_grouped_by_source_id.insert(source_id.clone(), hits_taken);
314+
final_hits_grouped_by_source_id.insert(query_source.id.clone(), hits_taken);
300315
}
301316

302317
let final_hits_len = final_hits_grouped_by_source_id

src-tauri/src/settings.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use tauri::AppHandle;
44
use tauri_plugin_store::StoreExt;
55

66
const SETTINGS_ALLOW_SELF_SIGNATURE: &str = "settings_allow_self_signature";
7+
const LOCAL_QUERY_SOURCE_WEIGHT: &str = "local_query_source_weight";
78

89
#[tauri::command]
910
pub async fn set_allow_self_signature(tauri_app_handle: AppHandle, value: bool) {
@@ -70,3 +71,45 @@ pub fn _get_allow_self_signature(tauri_app_handle: AppHandle) -> bool {
7071
pub async fn get_allow_self_signature(tauri_app_handle: AppHandle) -> bool {
7172
_get_allow_self_signature(tauri_app_handle)
7273
}
74+
75+
#[tauri::command]
76+
pub async fn set_local_query_source_weight(tauri_app_handle: AppHandle, value: f64) {
77+
let store = tauri_app_handle
78+
.store(COCO_TAURI_STORE)
79+
.unwrap_or_else(|e| {
80+
panic!(
81+
"store [{}] not found/loaded, error [{}]",
82+
COCO_TAURI_STORE, e
83+
)
84+
});
85+
86+
store.set(LOCAL_QUERY_SOURCE_WEIGHT, value);
87+
}
88+
89+
#[tauri::command]
90+
pub fn get_local_query_source_weight(tauri_app_handle: AppHandle) -> f64 {
91+
// default to 1.0
92+
const DEFAULT: f64 = 1.0;
93+
94+
let store = tauri_app_handle
95+
.store(COCO_TAURI_STORE)
96+
.unwrap_or_else(|e| {
97+
panic!(
98+
"store [{}] not found/loaded, error [{}]",
99+
COCO_TAURI_STORE, e
100+
)
101+
});
102+
if !store.has(LOCAL_QUERY_SOURCE_WEIGHT) {
103+
store.set(LOCAL_QUERY_SOURCE_WEIGHT, DEFAULT);
104+
}
105+
106+
match store
107+
.get(LOCAL_QUERY_SOURCE_WEIGHT)
108+
.expect("should be Some")
109+
{
110+
Json::Number(n) => n
111+
.as_f64()
112+
.unwrap_or_else(|| panic!("setting [{}] should be a f64", LOCAL_QUERY_SOURCE_WEIGHT)),
113+
_ => unreachable!("{} should be stored as a number", LOCAL_QUERY_SOURCE_WEIGHT),
114+
}
115+
}

src/components/Settings/Advanced/index.tsx

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useEffect } from "react";
1+
import { useEffect, useState } from "react";
22
import { useTranslation } from "react-i18next";
33
import {
44
AppWindowMac,
5+
ArrowUpWideNarrow,
56
MessageSquareMore,
67
Search,
78
ShieldCheck,
@@ -18,6 +19,7 @@ import SettingsInput from "@/components//Settings/SettingsInput";
1819
import platformAdapter from "@/utils/platformAdapter";
1920
import UpdateSettings from "./components/UpdateSettings";
2021
import SettingsToggle from "../SettingsToggle";
22+
import { isNil } from "lodash-es";
2123

2224
const Advanced = () => {
2325
const { t } = useTranslation();
@@ -57,13 +59,22 @@ const Advanced = () => {
5759
const setAllowSelfSignature = useConnectStore((state) => {
5860
return state.setAllowSelfSignature;
5961
});
62+
const { searchDelay, setSearchDelay } = useConnectStore();
63+
64+
const [localSearchResultWeight, setLocalSearchResultWeight] = useState(1);
6065

6166
useMount(async () => {
6267
const allowSelfSignature = await platformAdapter.invokeBackend<boolean>(
6368
"get_allow_self_signature"
6469
);
6570

6671
setAllowSelfSignature(allowSelfSignature);
72+
73+
const weight = await platformAdapter.invokeBackend<number>(
74+
"get_local_query_source_weight"
75+
);
76+
77+
setLocalSearchResultWeight(weight);
6778
});
6879

6980
useEffect(() => {
@@ -174,16 +185,20 @@ const Advanced = () => {
174185

175186
<Shortcuts />
176187

188+
<Appearance />
189+
190+
<UpdateSettings />
191+
177192
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
178-
{t("settings.advanced.connect.title")}
193+
{t("settings.advanced.other.title")}
179194
</h2>
180195

181196
<div className="space-y-6">
182197
<SettingsItem
183198
icon={Unplug}
184-
title={t("settings.advanced.connect.connectionTimeout.title")}
199+
title={t("settings.advanced.other.connectionTimeout.title")}
185200
description={t(
186-
"settings.advanced.connect.connectionTimeout.description"
201+
"settings.advanced.other.connectionTimeout.description"
187202
)}
188203
>
189204
<SettingsInput
@@ -198,8 +213,8 @@ const Advanced = () => {
198213

199214
<SettingsItem
200215
icon={Unplug}
201-
title={t("settings.advanced.connect.queryTimeout.title")}
202-
description={t("settings.advanced.connect.queryTimeout.description")}
216+
title={t("settings.advanced.other.queryTimeout.title")}
217+
description={t("settings.advanced.other.queryTimeout.description")}
203218
>
204219
<SettingsInput
205220
type="number"
@@ -211,15 +226,30 @@ const Advanced = () => {
211226
/>
212227
</SettingsItem>
213228

229+
<SettingsItem
230+
icon={Unplug}
231+
title={t("settings.advanced.other.searchDelay.title")}
232+
description={t("settings.advanced.other.searchDelay.description")}
233+
>
234+
<SettingsInput
235+
type="number"
236+
min={0}
237+
value={searchDelay}
238+
onChange={(value) => {
239+
setSearchDelay(isNil(value) ? 0 : Number(value));
240+
}}
241+
/>
242+
</SettingsItem>
243+
214244
<SettingsItem
215245
icon={ShieldCheck}
216-
title={t("settings.advanced.connect.allowSelfSignature.title")}
246+
title={t("settings.advanced.other.allowSelfSignature.title")}
217247
description={t(
218-
"settings.advanced.connect.allowSelfSignature.description"
248+
"settings.advanced.other.allowSelfSignature.description"
219249
)}
220250
>
221251
<SettingsToggle
222-
label={t("settings.advanced.connect.allowSelfSignature.title")}
252+
label={t("settings.advanced.other.allowSelfSignature.title")}
223253
checked={allowSelfSignature}
224254
onChange={(value) => {
225255
setAllowSelfSignature(value);
@@ -230,11 +260,43 @@ const Advanced = () => {
230260
}}
231261
/>
232262
</SettingsItem>
233-
</div>
234263

235-
<Appearance />
264+
<SettingsItem
265+
icon={ArrowUpWideNarrow}
266+
title={t("settings.advanced.other.localSearchResultWeight.title")}
267+
description={t(
268+
"settings.advanced.other.localSearchResultWeight.description"
269+
)}
270+
>
271+
<select
272+
value={localSearchResultWeight}
273+
onChange={(event) => {
274+
const weight = Number(event.target.value);
236275

237-
<UpdateSettings />
276+
setLocalSearchResultWeight(weight);
277+
278+
platformAdapter.invokeBackend("set_local_query_source_weight", {
279+
value: weight,
280+
});
281+
}}
282+
className="px-3 py-1.5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
283+
>
284+
<option value="0.5">
285+
{t("settings.advanced.other.localSearchResultWeight.options.low")}
286+
</option>
287+
<option value="1">
288+
{t(
289+
"settings.advanced.other.localSearchResultWeight.options.medium"
290+
)}
291+
</option>
292+
<option value="2">
293+
{t(
294+
"settings.advanced.other.localSearchResultWeight.options.high"
295+
)}
296+
</option>
297+
</select>
298+
</SettingsItem>
299+
</div>
238300
</div>
239301
);
240302
};

src/hooks/useSearch.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function useSearch() {
5151
return state.aiOverviewMinQuantity;
5252
});
5353

54-
const { querySourceTimeout } = useConnectStore();
54+
const { querySourceTimeout, searchDelay } = useConnectStore();
5555

5656
const [searchState, setSearchState] = useState<SearchState>({
5757
isError: [],
@@ -159,6 +159,8 @@ export function useSearch() {
159159

160160
const performSearch = useCallback(
161161
async (searchInput: string) => {
162+
console.log(123);
163+
162164
if (!searchInput) {
163165
setSearchState((prev) => ({ ...prev, suggests: [] }));
164166
return;
@@ -219,10 +221,11 @@ export function useSearch() {
219221
]
220222
);
221223

222-
const debouncedSearch = useMemo(
223-
() => debounce(performSearch, 300),
224-
[performSearch]
225-
);
224+
const debouncedSearch = useMemo(() => {
225+
console.log("searchDelay", searchDelay);
226+
227+
return debounce(performSearch, searchDelay);
228+
}, [performSearch, searchDelay]);
226229

227230
return {
228231
...searchState,

0 commit comments

Comments
 (0)