From 2568b5ccc41f77d020992bb71afcaac4f7c77612 Mon Sep 17 00:00:00 2001 From: Bogdan Abaev Date: Thu, 13 Aug 2026 12:49:00 -0700 Subject: [PATCH] Semantic search on fulltext of attachments Add optional pref to index and search fulltext of attachments. When enabled, attachment IDs are enqueue after regular items, notes, and annotations. Added helpers to extract outline and sections from structured text module. During indexing, the sections of the attachment are extracted, large sections are broken into chunks, and small sections are combined to fit into the context window of the model. Then, each chunk is embedded with its outline path as the prefix and added to embeddings table. Each row now contains full text of the chunk and it's path - a good amount of duplication needed to ensure that we can reliably connect the embedding of the chunk to its text for a preview. On search in Best Match mode, attachment rows get the score of the highest ranking chunk, so if there is a very relevant chunk in an attachment, the regular item with a non-relevant abstract will still rank highly. When the attachment row is selected, top 5 matching chunks appear in the new search results collapsible-section of the item pane, so one can examine matching chunks without opening the actual reader. --- .../content/zotero/collectionViewItemTree.jsx | 9 +- chrome/content/zotero/customElements.js | 2 + chrome/content/zotero/elements/itemDetails.js | 2 + .../zotero/elements/itemPaneSidenav.js | 2 +- .../zotero/elements/searchResultRow.js | 131 +++ .../zotero/elements/searchResultsBox.js | 192 ++++ .../preferences/preferences_advanced.js | 22 +- .../preferences/preferences_advanced.xhtml | 4 + chrome/content/zotero/xpcom/embeddings.js | 821 +++++++++++++++--- chrome/content/zotero/xpcom/sdt.js | 267 ++++++ chrome/locale/en-US/zotero/preferences.ftl | 2 + chrome/locale/en-US/zotero/zotero.ftl | 11 + defaults/preferences/zotero.js | 2 + scss/_zotero.scss | 1 + scss/abstracts/_variables.scss | 1 + scss/elements/_annotationRow.scss | 6 +- scss/elements/_searchResultsBox.scss | 75 ++ test/tests/embeddingsTest.js | 687 ++++++++++++++- test/tests/sdtTest.js | 275 ++++++ 19 files changed, 2397 insertions(+), 115 deletions(-) create mode 100644 chrome/content/zotero/elements/searchResultRow.js create mode 100644 chrome/content/zotero/elements/searchResultsBox.js create mode 100644 scss/elements/_searchResultsBox.scss diff --git a/chrome/content/zotero/collectionViewItemTree.jsx b/chrome/content/zotero/collectionViewItemTree.jsx index 1415859e66..b7432fe5cf 100644 --- a/chrome/content/zotero/collectionViewItemTree.jsx +++ b/chrome/content/zotero/collectionViewItemTree.jsx @@ -206,8 +206,13 @@ class CollectionViewItemTreeRowProvider extends ItemTreeRowProvider { ); let libraries = status.libraries .filter(lib => !libraryIDs.size || libraryIDs.has(lib.libraryID)); - let indexed = libraries.reduce((sum, lib) => sum + lib.indexed, 0); - let total = libraries.reduce((sum, lib) => sum + lib.eligible, 0); + // Coverage is coverage: attachment fulltext is reported separately + // in the preferences, but an incomplete index is incomplete + // whichever part of it is still filling in + let indexed = libraries.reduce( + (sum, lib) => sum + lib.indexed + lib.indexedAttachments, 0); + let total = libraries.reduce( + (sum, lib) => sum + lib.eligible + lib.eligibleAttachments, 0); if (indexed >= total) { return null; } diff --git a/chrome/content/zotero/customElements.js b/chrome/content/zotero/customElements.js index 59b5b319bc..03f2108a53 100644 --- a/chrome/content/zotero/customElements.js +++ b/chrome/content/zotero/customElements.js @@ -74,6 +74,8 @@ Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemTreeMe ['attachment-row', 'chrome://zotero/content/elements/attachmentRow.js'], ['attachment-annotations-box', 'chrome://zotero/content/elements/attachmentAnnotationsBox.js'], ['annotation-row', 'chrome://zotero/content/elements/annotationRow.js'], + ['search-results-box', 'chrome://zotero/content/elements/searchResultsBox.js'], + ['search-result-row', 'chrome://zotero/content/elements/searchResultRow.js'], ['annotation-items-pane', 'chrome://zotero/content/elements/annotationItemsPane.js'], ['context-notes-list', 'chrome://zotero/content/elements/contextNotesList.js'], ['note-row', 'chrome://zotero/content/elements/noteRow.js'], diff --git a/chrome/content/zotero/elements/itemDetails.js b/chrome/content/zotero/elements/itemDetails.js index 2e9a705f0a..4fbcd62137 100644 --- a/chrome/content/zotero/elements/itemDetails.js +++ b/chrome/content/zotero/elements/itemDetails.js @@ -55,6 +55,8 @@ + +