mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-03-17 17:10:03 +01:00
[Missing change] Adapt local autocompleter to the new API
This commit is contained in:
parent
76f434b039
commit
caa2688c73
2 changed files with 78 additions and 36 deletions
|
@ -3,9 +3,8 @@ import { promises } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { TextDecoder } from 'util';
|
import { TextDecoder } from 'util';
|
||||||
|
|
||||||
describe('Local Autocompleter', () => {
|
describe('LocalAutocompleter', () => {
|
||||||
let mockData: ArrayBuffer;
|
let mockData: ArrayBuffer;
|
||||||
const defaultK = 5;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const mockDataPath = join(__dirname, 'autocomplete-compiled-v2.bin');
|
const mockDataPath = join(__dirname, 'autocomplete-compiled-v2.bin');
|
||||||
|
@ -44,59 +43,81 @@ describe('Local Autocompleter', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('topK', () => {
|
describe('matchPrefix', () => {
|
||||||
const termStem = ['f', 'o'].join('');
|
const termStem = ['f', 'o'].join('');
|
||||||
|
|
||||||
let localAutocomplete: LocalAutocompleter;
|
function expectLocalAutocomplete(term: string, topK = 5) {
|
||||||
|
const localAutocomplete = new LocalAutocompleter(mockData);
|
||||||
|
const results = localAutocomplete.matchPrefix(term, topK);
|
||||||
|
const actual = results.map(result => {
|
||||||
|
const canonical = `${result.canonical} (${result.images})`;
|
||||||
|
return result.alias ? `${result.alias} -> ${canonical}` : canonical;
|
||||||
|
});
|
||||||
|
|
||||||
beforeAll(() => {
|
return expect(actual);
|
||||||
localAutocomplete = new LocalAutocompleter(mockData);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
window.booru.hiddenTagList = [];
|
window.booru.hiddenTagList = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return suggestions for exact tag name match', () => {
|
it('should return suggestions for exact tag name match', () => {
|
||||||
const result = localAutocomplete.matchPrefix('safe', defaultK);
|
expectLocalAutocomplete('safe').toMatchInlineSnapshot(`
|
||||||
expect(result).toEqual([expect.objectContaining({ aliasName: 'safe', name: 'safe', imageCount: 6 })]);
|
[
|
||||||
|
"safe (6)",
|
||||||
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return suggestion for original tag when passed an alias', () => {
|
it('should return suggestion for an alias', () => {
|
||||||
const result = localAutocomplete.matchPrefix('flowers', defaultK);
|
expectLocalAutocomplete('flowers').toMatchInlineSnapshot(`
|
||||||
expect(result).toEqual([expect.objectContaining({ aliasName: 'flowers', name: 'flower', imageCount: 1 })]);
|
[
|
||||||
|
"flowers -> flower (1)",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prefer canonical tag over an alias when both match', () => {
|
||||||
|
expectLocalAutocomplete('flo').toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
"flower (1)",
|
||||||
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return suggestions sorted by image count', () => {
|
it('should return suggestions sorted by image count', () => {
|
||||||
const result = localAutocomplete.matchPrefix(termStem, defaultK);
|
expectLocalAutocomplete(termStem).toMatchInlineSnapshot(`
|
||||||
expect(result).toEqual([
|
[
|
||||||
expect.objectContaining({ aliasName: 'forest', name: 'forest', imageCount: 3 }),
|
"forest (3)",
|
||||||
expect.objectContaining({ aliasName: 'fog', name: 'fog', imageCount: 1 }),
|
"fog (1)",
|
||||||
expect.objectContaining({ aliasName: 'force field', name: 'force field', imageCount: 1 }),
|
"force field (1)",
|
||||||
]);
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return namespaced suggestions without including namespace', () => {
|
it('should return namespaced suggestions without including namespace', () => {
|
||||||
const result = localAutocomplete.matchPrefix('test', defaultK);
|
expectLocalAutocomplete('test').toMatchInlineSnapshot(`
|
||||||
expect(result).toEqual([
|
[
|
||||||
expect.objectContaining({ aliasName: 'artist:test', name: 'artist:test', imageCount: 1 }),
|
"artist:test (1)",
|
||||||
]);
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return only the required number of suggestions', () => {
|
it('should return only the required number of suggestions', () => {
|
||||||
const result = localAutocomplete.matchPrefix(termStem, 1);
|
expectLocalAutocomplete(termStem, 1).toMatchInlineSnapshot(`
|
||||||
expect(result).toEqual([expect.objectContaining({ aliasName: 'forest', name: 'forest', imageCount: 3 })]);
|
[
|
||||||
|
"forest (3)",
|
||||||
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT return suggestions associated with hidden tags', () => {
|
it('should NOT return suggestions associated with hidden tags', () => {
|
||||||
window.booru.hiddenTagList = [1];
|
window.booru.hiddenTagList = [1];
|
||||||
const result = localAutocomplete.matchPrefix(termStem, defaultK);
|
expectLocalAutocomplete(termStem).toMatchInlineSnapshot(`[]`);
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty array for empty prefix', () => {
|
it('should return empty array for empty prefix', () => {
|
||||||
const result = localAutocomplete.matchPrefix('', defaultK);
|
expectLocalAutocomplete('').toMatchInlineSnapshot(`[]`);
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,9 +3,21 @@ import { UniqueHeap } from './unique-heap';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
export interface Result {
|
export interface Result {
|
||||||
aliasName: string;
|
/**
|
||||||
name: string;
|
* If present, then this suggestion is for a tag alias.
|
||||||
imageCount: number;
|
* If absent, then this suggestion is for the `canonical` tag name.
|
||||||
|
*/
|
||||||
|
alias?: null | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The canonical name of the tag (non-alias).
|
||||||
|
*/
|
||||||
|
canonical: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of images tagged with this tag.
|
||||||
|
*/
|
||||||
|
images: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,10 +265,19 @@ export class LocalAutocompleter {
|
||||||
this.scanResults(referenceToAliasIndex, namespaceMatch, hasFilteredAssociation, isAlias, results);
|
this.scanResults(referenceToAliasIndex, namespaceMatch, hasFilteredAssociation, isAlias, results);
|
||||||
|
|
||||||
// Convert top K from heap into result array
|
// Convert top K from heap into result array
|
||||||
return results.topK(k).map((i: TagReferenceIndex) => ({
|
return results.topK(k).map((i: TagReferenceIndex) => {
|
||||||
aliasName: this.decoder.decode(this.referenceToName(i, false)),
|
const alias = this.decoder.decode(this.referenceToName(i, false));
|
||||||
name: this.decoder.decode(this.referenceToName(i)),
|
const canonical = this.decoder.decode(this.referenceToName(i));
|
||||||
imageCount: this.getImageCount(i),
|
const result: Result = {
|
||||||
}));
|
canonical,
|
||||||
|
images: this.getImageCount(i),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (alias !== canonical) {
|
||||||
|
result.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue