mirror of
https://github.com/zotero/zotero.git
synced 2026-10-08 03:08:19 +00:00
clear model pref if the model was removed
This commit is contained in:
parent
6ab8ba61b6
commit
faadeba624
4 changed files with 133 additions and 64 deletions
|
|
@ -144,6 +144,20 @@ Zotero.Embeddings = new function () {
|
|||
return Object.prototype.hasOwnProperty.call(MODELS, this.getModelName());
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable semantic search if the selected model isn't one this build has:
|
||||
* a model removed from MODELS after a user chose it leaves the pref naming
|
||||
* something nothing can run. Clearing the pref switches to Disabled, which
|
||||
* drops the stored index and the downloaded files with it.
|
||||
*/
|
||||
this.ensureModelAvailable = function () {
|
||||
let name = this.getModelName();
|
||||
if (name && !this.isEnabled()) {
|
||||
Zotero.debug(`Embeddings: model '${name}' is no longer available -- disabling semantic search`);
|
||||
Zotero.Prefs.clear('embeddings.model');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Available models, in display order, for the preferences UI.
|
||||
*
|
||||
|
|
@ -1792,6 +1806,9 @@ Zotero.Embeddings.Indexing = new function () {
|
|||
Zotero.Prefs.registerObserver('embeddings.model', () => {
|
||||
_switchModel();
|
||||
});
|
||||
// Through the observer above, a model this build no longer has is
|
||||
// switched off, and its index and files dropped
|
||||
Zotero.Embeddings.ensureModelAvailable();
|
||||
|
||||
// Toggling fulltext indexing changes what's eligible: on, the newly
|
||||
// eligible attachments get indexed; off, their stored chunks are
|
||||
|
|
|
|||
|
|
@ -219,37 +219,45 @@ describe("CollectionViewItemTree", function () {
|
|||
});
|
||||
|
||||
it("should rank items lexically", async function () {
|
||||
let col = await createDataObject('collection');
|
||||
// Unrelated items, so the query words the matches share still
|
||||
// separate documents in this corpus -- in a corpus of nothing
|
||||
// but matches, FTS5 floors their idf as separating nothing
|
||||
// and no match earns a score
|
||||
for (let i = 0; i < 6; i++) {
|
||||
await createDataObject('item', { title: `unrelated filler number ${i}` });
|
||||
// Ranking is under test, not membership: keep the two-word
|
||||
// match that the result margin would otherwise cut
|
||||
Zotero.Prefs.set('search.bestMatchMargin', 100);
|
||||
try {
|
||||
let col = await createDataObject('collection');
|
||||
// Unrelated items, so the query words the matches share still
|
||||
// separate documents in this corpus -- in a corpus of nothing
|
||||
// but matches, FTS5 floors their idf as separating nothing
|
||||
// and no match earns a score
|
||||
for (let i = 0; i < 6; i++) {
|
||||
await createDataObject('item', { title: `unrelated filler number ${i}` });
|
||||
}
|
||||
let full = await createDataObject('item',
|
||||
{ title: 'Lexint owl migration patterns', collections: [col.id] });
|
||||
// Three of the query's four terms, ranked below the full match
|
||||
let partial = await createDataObject('item',
|
||||
{ title: 'Lexint owl migration handbook', collections: [col.id] });
|
||||
// Two of four, ranked below both
|
||||
let sparse = await createDataObject('item',
|
||||
{ title: 'Lexint owl guidebook', collections: [col.id] });
|
||||
|
||||
await select(win, col);
|
||||
let itemsView = zp.itemsView;
|
||||
await itemsView.setFilter('search', 'lexint owl migration patterns');
|
||||
|
||||
// Scored items only, ranked by coverage, most relevant first
|
||||
assert.deepEqual(itemsView._rows.map(row => row.id),
|
||||
[full.id, partial.id, sparse.id]);
|
||||
assert.equal(itemsView.getSortField(), 'relevance');
|
||||
// The bars carry the lexical scores directly
|
||||
let fractions = itemsView.rowProvider.getBestMatchBarFractions();
|
||||
assert.isAbove(fractions.get(full.id), fractions.get(partial.id));
|
||||
assert.isAbove(fractions.get(partial.id), fractions.get(sparse.id));
|
||||
assert.isAtMost(fractions.get(full.id), 1);
|
||||
assert.isAbove(fractions.get(sparse.id), 0);
|
||||
}
|
||||
finally {
|
||||
Zotero.Prefs.clear('search.bestMatchMargin');
|
||||
}
|
||||
let full = await createDataObject('item',
|
||||
{ title: 'Lexint owl migration patterns', collections: [col.id] });
|
||||
// Three of the query's four terms, ranked below the full match
|
||||
let partial = await createDataObject('item',
|
||||
{ title: 'Lexint owl migration handbook', collections: [col.id] });
|
||||
// Two of four, ranked below both
|
||||
let sparse = await createDataObject('item',
|
||||
{ title: 'Lexint owl guidebook', collections: [col.id] });
|
||||
|
||||
await select(win, col);
|
||||
let itemsView = zp.itemsView;
|
||||
await itemsView.setFilter('search', 'lexint owl migration patterns');
|
||||
|
||||
// Scored items only, ranked by coverage, most relevant first
|
||||
assert.deepEqual(itemsView._rows.map(row => row.id),
|
||||
[full.id, partial.id, sparse.id]);
|
||||
assert.equal(itemsView.getSortField(), 'relevance');
|
||||
// The bars carry the lexical scores directly
|
||||
let fractions = itemsView.rowProvider.getBestMatchBarFractions();
|
||||
assert.isAbove(fractions.get(full.id), fractions.get(partial.id));
|
||||
assert.isAbove(fractions.get(partial.id), fractions.get(sparse.id));
|
||||
assert.isAtMost(fractions.get(full.id), 1);
|
||||
assert.isAbove(fractions.get(sparse.id), 0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -572,8 +572,9 @@ describe("Zotero.Embeddings", function () {
|
|||
(x, i) => `${tag} sentence number ${i} with several words in it.`).join(' ');
|
||||
var stubs = [];
|
||||
|
||||
// A model with a 512-token window, which the fixtures are sized to
|
||||
beforeEach(function () {
|
||||
stubs.push(sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'));
|
||||
stubs.push(sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-zh-v1.5'));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
|
@ -728,8 +729,9 @@ describe("Zotero.Embeddings", function () {
|
|||
describe("#chunkSections()", function () {
|
||||
var stubs = [];
|
||||
|
||||
// A model with a 512-token window, which the fixtures are sized to
|
||||
beforeEach(function () {
|
||||
stubs.push(sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'));
|
||||
stubs.push(sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-zh-v1.5'));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
|
@ -1007,7 +1009,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'pruneModels').resolves(),
|
||||
embedStub
|
||||
];
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
assert.ok(await getPromiseError(Zotero.Embeddings.embedQuery('retry query')));
|
||||
|
|
@ -1031,7 +1033,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'pruneModels').resolves(),
|
||||
embedStub
|
||||
];
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
// Whitespace around the quotes doesn't defeat the stripping
|
||||
|
|
@ -1058,7 +1060,7 @@ describe("Zotero.Embeddings", function () {
|
|||
];
|
||||
// Select a model so the query prefix and model version resolve; the
|
||||
// switch's indexing side effects are stubbed out above
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
let promise1 = Zotero.Embeddings.embedQuery('concurrent query');
|
||||
|
|
@ -1095,7 +1097,7 @@ describe("Zotero.Embeddings", function () {
|
|||
createEngine,
|
||||
sinon.stub(Zotero.ML, 'shutdown').resolves(),
|
||||
sinon.stub(Zotero.ML, 'getOptimalConcurrency').returns(2),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelVersion').returns('test-model/1')
|
||||
];
|
||||
}
|
||||
|
|
@ -1237,7 +1239,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'getModelVersion').returns('kept-model/1'),
|
||||
sinon.stub(Zotero.Embeddings.Indexing, 'startIndexing').resolves()
|
||||
];
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
await Zotero.Embeddings.pruneModels();
|
||||
|
|
@ -1264,6 +1266,48 @@ describe("Zotero.Embeddings", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#ensureModelAvailable()", function () {
|
||||
it("should disable semantic search and drop the index when the selected model no longer exists", async function () {
|
||||
let stubs = [
|
||||
sinon.stub(Zotero.ML, 'listModels').resolves([]),
|
||||
sinon.stub(Zotero.Embeddings.Indexing, 'startIndexing').resolves()
|
||||
];
|
||||
let item = await createDataObject('item');
|
||||
try {
|
||||
// As if a build removed the model a user had selected
|
||||
Zotero.Prefs.set('embeddings.model', 'removed-model');
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
await Zotero.Embeddings.initDB();
|
||||
await Zotero.DB.queryAsync(
|
||||
"REPLACE INTO embeddings.itemEmbeddings "
|
||||
+ "(itemID, chunkIndex, embedding, sourceHash) VALUES (?, 0, ?, ?)",
|
||||
[item.id, new Uint8Array([0, 0, 0, 0]), 'hash']
|
||||
);
|
||||
assert.isFalse(Zotero.Embeddings.isEnabled());
|
||||
|
||||
Zotero.Embeddings.ensureModelAvailable();
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
assert.equal(Zotero.Embeddings.getModelName(), '');
|
||||
assert.equal(
|
||||
await Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM embeddings.itemEmbeddings"),
|
||||
0
|
||||
);
|
||||
// Nothing to do for a model that exists, or none
|
||||
Zotero.Embeddings.ensureModelAvailable();
|
||||
assert.equal(Zotero.Embeddings.getModelName(), '');
|
||||
}
|
||||
finally {
|
||||
Zotero.Prefs.clear('embeddings.model');
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
stubs.forEach(stub => stub.restore());
|
||||
Zotero.Prefs.clear('embeddings.indexingPaused');
|
||||
// The disabled-model prune cleared the row the rest of the
|
||||
// file scores against
|
||||
testMean = await calibrateTestModel();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Diagnostics", function () {
|
||||
it("should estimate remaining time once the window spans long enough", function () {
|
||||
let diagnostics = Zotero.Embeddings.Diagnostics;
|
||||
|
|
@ -1610,7 +1654,7 @@ describe("Zotero.Embeddings", function () {
|
|||
[item.id, 'hash']
|
||||
);
|
||||
// The model switch clears the old vectors
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
await Zotero.Embeddings.Indexing.waitForPendingModelSwitch();
|
||||
assert.equal(
|
||||
await Zotero.DB.valueQueryAsync(
|
||||
|
|
@ -1678,7 +1722,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
];
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.startIndexing();
|
||||
|
|
@ -1722,7 +1766,7 @@ describe("Zotero.Embeddings", function () {
|
|||
// These fake an active model rather than selecting one (which
|
||||
// would kick off a model switch), so name one to keep the
|
||||
// window and passage prefix chunking reads consistent with it
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
];
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.startIndexing();
|
||||
|
|
@ -1776,7 +1820,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
];
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.startIndexing();
|
||||
|
|
@ -1831,7 +1875,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
];
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.startIndexing();
|
||||
|
|
@ -1883,7 +1927,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
];
|
||||
try {
|
||||
await Zotero.Embeddings.Indexing.startIndexing();
|
||||
|
|
@ -1925,7 +1969,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
// The extraction itself is sdt.js's concern (see sdtTest.js);
|
||||
// what's under test is what indexing does with the sections
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
|
|
@ -2044,7 +2088,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
|
|
@ -2112,7 +2156,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({ ok: true, sections })
|
||||
];
|
||||
|
|
@ -2212,7 +2256,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({ ok: true, sections })
|
||||
];
|
||||
|
|
@ -2269,7 +2313,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
|
|
@ -2340,7 +2384,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
|
|
@ -2401,7 +2445,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
|
|
@ -2454,7 +2498,7 @@ describe("Zotero.Embeddings", function () {
|
|||
let item = await createDataObject('item', { title: 'Parent of derived attachment' });
|
||||
let attachment = await importPDFAttachment(item);
|
||||
let stubs = [
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
sections: [
|
||||
|
|
@ -2525,7 +2569,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').callsFake(async (itemID) => {
|
||||
// Sections are read once to count chunks and again to
|
||||
|
|
@ -2586,7 +2630,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
ensureStub,
|
||||
getSectionsStub
|
||||
];
|
||||
|
|
@ -2637,7 +2681,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
ensureStub,
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({
|
||||
ok: true,
|
||||
|
|
@ -2679,7 +2723,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
sinon.stub(Zotero.SDT, 'getSections').resolves({ ok: false, reason: 'failed' })
|
||||
];
|
||||
|
|
@ -2747,7 +2791,7 @@ describe("Zotero.Embeddings", function () {
|
|||
sinon.stub(Zotero.Embeddings, 'isDownloaded').resolves(true),
|
||||
sinon.stub(Zotero.Embeddings, 'download').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'ensureCalibration').resolves(),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bge-small-en-v1.5'),
|
||||
sinon.stub(Zotero.Embeddings, 'getModelName').returns('bekko-embedding-v1-a8m'),
|
||||
sinon.stub(Zotero.Embeddings, 'embedQuery').resolves(Float32Array.from(testMean)),
|
||||
sinon.stub(Zotero.SDT, 'ensure').resolves(true),
|
||||
getSectionsStub
|
||||
|
|
@ -2844,7 +2888,7 @@ describe("Zotero.Embeddings", function () {
|
|||
// The runtime's model cache resolves navigator.storage via the most
|
||||
// recent browser window
|
||||
await loadZoteroPane();
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
await Zotero.Embeddings.preloadModel();
|
||||
|
||||
let [related, unrelated] = await Zotero.Embeddings.embedPassages([
|
||||
|
|
@ -2863,7 +2907,7 @@ describe("Zotero.Embeddings", function () {
|
|||
it("should report a cached model as downloaded and keep it when pruning", async function () {
|
||||
this.timeout(1800000);
|
||||
await loadZoteroPane();
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
await Zotero.Embeddings.preloadModel();
|
||||
|
||||
assert.isTrue(await Zotero.Embeddings.isDownloaded());
|
||||
|
|
@ -2875,7 +2919,7 @@ describe("Zotero.Embeddings", function () {
|
|||
it("should chunk within the model's real window", async function () {
|
||||
this.timeout(1800000);
|
||||
await loadZoteroPane();
|
||||
Zotero.Prefs.set('embeddings.model', 'bge-small-en-v1.5');
|
||||
Zotero.Prefs.set('embeddings.model', 'bekko-embedding-v1-a8m');
|
||||
await Zotero.Embeddings.download();
|
||||
|
||||
// The model's real tokenizer, built from the same files the
|
||||
|
|
|
|||
|
|
@ -166,17 +166,17 @@ describe("Advanced Preferences", function () {
|
|||
try {
|
||||
// Enabling from Disabled prompts nothing (the test would hang on
|
||||
// an unexpected modal prompt)
|
||||
menu.value = 'bge-small-en-v1.5';
|
||||
menu.value = 'bekko-embedding-v1-a8m';
|
||||
await win.Zotero_Preferences.Advanced.handleSemanticSearchModeChange();
|
||||
assert.equal(Zotero.Prefs.get('embeddings.model'), 'bge-small-en-v1.5');
|
||||
assert.equal(Zotero.Prefs.get('embeddings.model'), 'bekko-embedding-v1-a8m');
|
||||
|
||||
// Cancelling a switch restores the menu and leaves the pref alone
|
||||
var promise = waitForDialog(null, 'cancel');
|
||||
menu.value = 'multilingual-e5-small';
|
||||
menu.value = 'bekko-embedding-v1-a25m';
|
||||
await win.Zotero_Preferences.Advanced.handleSemanticSearchModeChange();
|
||||
await promise;
|
||||
assert.equal(Zotero.Prefs.get('embeddings.model'), 'bge-small-en-v1.5');
|
||||
assert.equal(menu.value, 'bge-small-en-v1.5');
|
||||
assert.equal(Zotero.Prefs.get('embeddings.model'), 'bekko-embedding-v1-a8m');
|
||||
assert.equal(menu.value, 'bekko-embedding-v1-a8m');
|
||||
|
||||
// Confirming applies the change
|
||||
promise = waitForDialog();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue