From 4f782d83bc3fda504e500486b37d613c8c12ed64 Mon Sep 17 00:00:00 2001 From: Bogdan Abaev Date: Tue, 18 Aug 2026 17:25:27 -0700 Subject: [PATCH] temp: pref to select hybrid/semantic/lexical mode To make it easier to experiment --- .../preferences/preferences_advanced.xhtml | 17 ++++++++++ chrome/content/zotero/xpcom/bestMatch.js | 31 ++++++++++++++++--- chrome/locale/en-US/zotero/preferences.ftl | 7 +++++ defaults/preferences/zotero.js | 3 ++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/chrome/content/zotero/preferences/preferences_advanced.xhtml b/chrome/content/zotero/preferences/preferences_advanced.xhtml index cd4bb487a6..17e1afcdfd 100644 --- a/chrome/content/zotero/preferences/preferences_advanced.xhtml +++ b/chrome/content/zotero/preferences/preferences_advanced.xhtml @@ -311,6 +311,23 @@ + + + [itemID, Zotero.Embeddings.getScoreFraction(score)] + )); + } // A query the semantic engine can't embed ranks lexically alone - if (!_useSemantic() || !Zotero.Embeddings.normalizeQuery(queryText || '')) { + if (engine == 'lexical' || !_useSemantic() + || !Zotero.Embeddings.normalizeQuery(queryText || '')) { return await Zotero.Lexical.scoreItemIDs(queryText, itemIDs, options); } // Both engines score the same candidates concurrently. allSettled @@ -160,9 +172,16 @@ Zotero.BestMatch = new function () { * `strength`, plus chunk location fields or a lexical `source` */ this.getMatchingExcerpts = async function (queryText, itemID, options = {}) { + // Temporary, for testing: the bestMatchEngine pref keeps the pinned + // engine's excerpts alone -- no lexical excerpts or highlights when + // pinned semantic, no chunks when pinned lexical + let engine = Zotero.Prefs.get('search.bestMatchEngine'); let limit = options.limit ?? 5; - let excerpts = await Zotero.Lexical.getMatchingExcerpts(queryText, itemID, options); - if (!_useSemantic() || !Zotero.Embeddings.normalizeQuery(queryText || '')) { + let excerpts = engine == 'semantic' + ? [] + : await Zotero.Lexical.getMatchingExcerpts(queryText, itemID, options); + if (engine == 'lexical' || !_useSemantic() + || !Zotero.Embeddings.normalizeQuery(queryText || '')) { return excerpts; } let chunks = []; @@ -180,8 +199,10 @@ Zotero.BestMatch = new function () { if (!chunks.length) { return excerpts; } - let ranges = await Zotero.Lexical.findMatchRanges( - queryText, chunks.map(chunk => chunk.text)); + let ranges = engine == 'semantic' + ? chunks.map(() => []) + : await Zotero.Lexical.findMatchRanges( + queryText, chunks.map(chunk => chunk.text)); chunks = chunks.map((chunk, i) => ({ ...chunk, ranges: ranges[i], diff --git a/chrome/locale/en-US/zotero/preferences.ftl b/chrome/locale/en-US/zotero/preferences.ftl index dfdab9942d..db8a03d7a3 100644 --- a/chrome/locale/en-US/zotero/preferences.ftl +++ b/chrome/locale/en-US/zotero/preferences.ftl @@ -105,6 +105,13 @@ preferences-advanced-semantic-search-multilingual = preferences-advanced-semantic-search-model-description = “{ preferences-advanced-semantic-search-english.label }” and “{ preferences-advanced-semantic-search-chinese.label }” give the best results for libraries in those languages. “{ preferences-advanced-semantic-search-multilingual.label }” supports searching in and across many languages. preferences-advanced-semantic-search-index-fulltext = .label = Search full text of attachment files +preferences-advanced-best-match-engine = Engine (temporary, for testing): +preferences-advanced-best-match-engine-hybrid = + .label = Hybrid +preferences-advanced-best-match-engine-lexical = + .label = Lexical +preferences-advanced-best-match-engine-semantic = + .label = Semantic preferences-advanced-semantic-search-downloading = Downloading… preferences-advanced-semantic-search-downloading-progress = Downloading… { $percent }% preferences-advanced-semantic-search-indexing = Indexing… diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index 8d6f9f671e..6f3e78478e 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -108,6 +108,9 @@ pref("extensions.zotero.keys.toggleRead", "`"); pref("extensions.zotero.keys.showTabsMenu", ";"); pref("extensions.zotero.search.quicksearch-mode", "fields"); +// Temporary, for testing: which engine best-match search runs -- 'lexical', +// 'semantic', or 'hybrid' (both, fused) +pref("extensions.zotero.search.bestMatchEngine", "hybrid"); // Fulltext indexing pref("extensions.zotero.fulltext.textMaxLength", 500000);