diff --git a/chrome/content/zotero/preferences/embeddingsEndpoint.xhtml b/chrome/content/zotero/preferences/embeddingsEndpoint.xhtml new file mode 100644 index 0000000000..012a322794 --- /dev/null +++ b/chrome/content/zotero/preferences/embeddingsEndpoint.xhtml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + diff --git a/chrome/content/zotero/preferences/preferences_advanced.js b/chrome/content/zotero/preferences/preferences_advanced.js index a659c16f8d..2e0f74b54e 100644 --- a/chrome/content/zotero/preferences/preferences_advanced.js +++ b/chrome/content/zotero/preferences/preferences_advanced.js @@ -110,6 +110,15 @@ Zotero_Preferences.Advanced = { Zotero.Embeddings.Indexing.stopIndexing(); }); + document.getElementById('semantic-search-endpoint-configure').addEventListener('command', () => { + this.openSemanticSearchEndpointDialog(); + }); + // The endpoint's stored verdict is read lazily; have it in memory + // before the status line first renders + Zotero.Embeddings.Endpoint.load().then(() => { + this.updateSemanticSearchUI(Zotero.Embeddings.Indexing.getStatus()); + }); + // Render current state, then compute up-to-date per-library counts this.updateSemanticSearchUI(Zotero.Embeddings.Indexing.getStatus()); Zotero.Embeddings.Indexing.refreshStatus(); @@ -161,6 +170,8 @@ Zotero_Preferences.Advanced = { return; } + this.updateSemanticSearchEndpointUI(status.endpoint); + // Phase / status message let phaseLabel = document.getElementById('semantic-search-phase'); let hasRemaining = status.items.done < status.items.total @@ -235,6 +246,39 @@ Zotero_Preferences.Advanced = { }, + // Whether the active model can be served at all, and how the configured + // server stands (see Zotero.Embeddings.Endpoint.getStatus()) + updateSemanticSearchEndpointUI: function (endpoint) { + let row = document.getElementById('semantic-search-endpoint-row'); + row.hidden = !Zotero.Embeddings.Endpoint.isSupported(); + if (row.hidden) { + return; + } + let label = document.getElementById('semantic-search-endpoint-status'); + let id = { + off: 'off', + unknown: null, + unverified: 'unverified', + ok: 'valid', + unreachable: 'unreachable' + }[endpoint.state]; + if (id === null) { + label.removeAttribute('data-l10n-id'); + label.value = ''; + return; + } + document.l10n.setAttributes(label, `preferences-advanced-semantic-search-endpoint-${id || 'invalid'}`); + }, + + + openSemanticSearchEndpointDialog: function () { + let io = { ok: false }; + window.openDialog('chrome://zotero/content/preferences/embeddingsEndpoint.xhtml', + 'zotero-preferences-embeddingsEndpoint', 'chrome,modal,centerscreen', io); + this.updateSemanticSearchUI(Zotero.Embeddings.Indexing.getStatus()); + }, + + // Key/value rows of pipeline diagnostics for developers, so the labels // are plain English rather than localized _updateSemanticSearchDiagnostics: function (diagnostics, eta) { diff --git a/chrome/content/zotero/preferences/preferences_advanced.xhtml b/chrome/content/zotero/preferences/preferences_advanced.xhtml index fb2bc89d49..46104c9c1f 100644 --- a/chrome/content/zotero/preferences/preferences_advanced.xhtml +++ b/chrome/content/zotero/preferences/preferences_advanced.xhtml @@ -343,6 +343,11 @@ data-l10n-id="preferences-advanced-semantic-search-stop" hidden="true"/> +