mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 19:54:39 +00:00
feat: performance and visual improvements
This commit is contained in:
@@ -18,11 +18,9 @@
|
||||
|
||||
const {
|
||||
transparencyEffects,
|
||||
showRecentFirst,
|
||||
searchHotkey: initialSearchHotkey
|
||||
} = $props<{
|
||||
transparencyEffects: boolean,
|
||||
showRecentFirst: boolean,
|
||||
searchHotkey: string
|
||||
}>();
|
||||
|
||||
@@ -170,10 +168,7 @@
|
||||
combinedResults = await doSearch(
|
||||
term,
|
||||
commandsFuse,
|
||||
dynamicContentFuse,
|
||||
commandIdToItemMap,
|
||||
dynamicIdToItemMap,
|
||||
showRecentFirst
|
||||
);
|
||||
} else {
|
||||
combinedResults = [];
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
>
|
||||
<div class="flex items-center w-full">
|
||||
<div class="flex-none scale-90 w-8 h-8 text-xl font-IconFamily flex items-center justify-center text-white bg-gradient-to-br from-[#59aaf6] to-[#1b62c6] rounded-md">{item.metadata?.icon || '\uebe7'}</div>
|
||||
<span class="ml-4 text-lg truncate">
|
||||
<span class="ml-4 text-lg truncate {item.metadata?.closed ? 'line-through opacity-80' : ''}">
|
||||
<HighlightedText text={item.text} term={searchTerm} matches={matches} />
|
||||
</span>
|
||||
<span class="flex-none ml-auto text-xs text-zinc-500 dark:text-zinc-400">
|
||||
|
||||
@@ -80,4 +80,8 @@ export const actionMap: Record<string, ActionHandler<any>> = {
|
||||
subjectcourse: ((item: IndexItem) => {
|
||||
window.location.href = `/#?page=/courses/${item.metadata.programme}:${item.metadata.subjectId}`;
|
||||
}) as ActionHandler<any>,
|
||||
|
||||
forum: ((item: IndexItem) => {
|
||||
window.location.href = `/#?page=/forums/${item.metadata.forumId}`;
|
||||
}) as ActionHandler<any>,
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ export const forumsJob: Job = {
|
||||
forumId: forum.id,
|
||||
owner: forum.owner,
|
||||
title: forum.title,
|
||||
closed: forum.closed,
|
||||
},
|
||||
actionId: "forum",
|
||||
renderComponentId: "forum",
|
||||
@@ -60,9 +61,9 @@ export const forumsJob: Job = {
|
||||
return items;
|
||||
},
|
||||
|
||||
/** Keep only forums from the last 2 years. */
|
||||
/** Keep only forums from the last year. */
|
||||
purge: (items) => {
|
||||
const twoYearsAgo = Date.now() - 2 * 365 * 24 * 60 * 60 * 1000;
|
||||
return items.filter((i) => i.dateAdded >= twoYearsAgo);
|
||||
const oneYearAgo = Date.now() - 365 * 24 * 60 * 60 * 1000;
|
||||
return items.filter((i) => i.dateAdded >= oneYearAgo);
|
||||
},
|
||||
};
|
||||
@@ -27,7 +27,7 @@ export const subjectsJob: Job = {
|
||||
|
||||
let score = 0;
|
||||
if (item.metadata.isActive) {
|
||||
score += 1; // Boost for active subjects
|
||||
score += 0.01; // Boost for active subjects
|
||||
} else {
|
||||
score -= 50; // Penalty for inactive subjects
|
||||
}
|
||||
|
||||
@@ -130,10 +130,7 @@ export function searchDynamicItems(
|
||||
export async function performSearch(
|
||||
query: string,
|
||||
commandsFuse: Fuse<StaticCommandItem>,
|
||||
dynamicContentFuse: Fuse<IndexItem>,
|
||||
commandIdToItemMap: Map<string, StaticCommandItem>,
|
||||
dynamicIdToItemMap: Map<string, IndexItem>,
|
||||
showRecentFirst: boolean,
|
||||
): Promise<CombinedResult[]> {
|
||||
// Get all results first
|
||||
const commandResults = searchCommands(
|
||||
@@ -141,18 +138,11 @@ export async function performSearch(
|
||||
query,
|
||||
commandIdToItemMap,
|
||||
);
|
||||
const dynamicResults = searchDynamicItems(
|
||||
dynamicContentFuse,
|
||||
query,
|
||||
dynamicIdToItemMap,
|
||||
10,
|
||||
showRecentFirst,
|
||||
);
|
||||
|
||||
// Get vector results in parallel
|
||||
let vectorResults: VectorSearchResult[] = [];
|
||||
try {
|
||||
vectorResults = await searchVectors(query, 10);
|
||||
vectorResults = await searchVectors(query);
|
||||
} catch (e) {}
|
||||
|
||||
// Create a map to store our final results, using ID as key to avoid duplicates
|
||||
@@ -164,35 +154,6 @@ export async function performSearch(
|
||||
// Process dynamic results and vector results together
|
||||
const seenIds = new Set<string>();
|
||||
|
||||
// Add dynamic results first
|
||||
dynamicResults.forEach((r) => {
|
||||
seenIds.add(r.id);
|
||||
|
||||
if (r.type === "dynamic") {
|
||||
const dynamicItem = r.item as IndexItem;
|
||||
const job = jobs[dynamicItem.category];
|
||||
if (job && typeof job.boostCriteria === 'function') {
|
||||
const boost = job.boostCriteria(dynamicItem, query);
|
||||
if (boost) {
|
||||
r.score += boost; // Add the boost to the score
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const vectorMatch = vectorResults.find((v) => v.object.id === r.id);
|
||||
if (vectorMatch) {
|
||||
// If we found it in both searches, combine the scores
|
||||
resultMap.set(r.id, {
|
||||
...r,
|
||||
score: r.score + vectorMatch.similarity * 0.6, // Boost exact matches
|
||||
});
|
||||
} else {
|
||||
// If only in Fuse results, keep as is
|
||||
resultMap.set(r.id, r);
|
||||
}
|
||||
});
|
||||
|
||||
// Now add any vector results we haven't seen yet
|
||||
vectorResults.forEach((v) => {
|
||||
const id = v.object.id;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface VectorSearchResult extends SearchResult {
|
||||
|
||||
export async function searchVectors(
|
||||
query: string,
|
||||
topK: number = 10,
|
||||
topK: number = 20,
|
||||
): Promise<VectorSearchResult[]> {
|
||||
if (!vectorIndex) await initVectorSearch();
|
||||
|
||||
@@ -32,7 +32,11 @@ export async function searchVectors(
|
||||
dedupeEntries: true,
|
||||
});
|
||||
|
||||
return results as VectorSearchResult[];
|
||||
// filter results with a similarity below 0.81
|
||||
const filteredResults = results.filter((r) => r.similarity > 0.81);
|
||||
console.log("Vector search results", filteredResults);
|
||||
|
||||
return filteredResults as VectorSearchResult[];
|
||||
}
|
||||
|
||||
export async function refreshVectorCache() {
|
||||
|
||||
Reference in New Issue
Block a user