@atlaskit/editor-plugin-autocomplete 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/afm-cc/tsconfig.json +5 -1
- package/afm-jira/tsconfig.json +5 -1
- package/afm-products/tsconfig.json +5 -1
- package/build/tsconfig.json +24 -0
- package/dist/cjs/autocompletePlugin.js +18 -5
- package/dist/cjs/autocompletePluginType.js +5 -1
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +361 -0
- package/dist/cjs/pm-plugins/ghost-text-decoration.js +39 -0
- package/dist/cjs/pm-plugins/scoring-pipeline.js +258 -0
- package/dist/cjs/pm-plugins/slow-lane-client.js +197 -0
- package/dist/cjs/pm-plugins/text-predictor.js +786 -0
- package/dist/es2019/autocompletePlugin.js +20 -6
- package/dist/es2019/autocompletePluginType.js +1 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +360 -0
- package/dist/es2019/pm-plugins/ghost-text-decoration.js +33 -0
- package/dist/es2019/pm-plugins/scoring-pipeline.js +224 -0
- package/dist/es2019/pm-plugins/slow-lane-client.js +154 -0
- package/dist/es2019/pm-plugins/text-predictor.js +624 -0
- package/dist/esm/autocompletePlugin.js +18 -5
- package/dist/esm/autocompletePluginType.js +1 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +354 -0
- package/dist/esm/pm-plugins/ghost-text-decoration.js +33 -0
- package/dist/esm/pm-plugins/scoring-pipeline.js +255 -0
- package/dist/esm/pm-plugins/slow-lane-client.js +190 -0
- package/dist/esm/pm-plugins/text-predictor.js +783 -0
- package/dist/types/autocompletePluginType.d.ts +6 -3
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +36 -0
- package/dist/types/pm-plugins/ghost-text-decoration.d.ts +7 -0
- package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -0
- package/dist/types/pm-plugins/slow-lane-client.d.ts +46 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +90 -0
- package/dist/types-ts4.5/autocompletePluginType.d.ts +6 -3
- package/dist/types-ts4.5/pm-plugins/autocomplete-plugin.d.ts +36 -0
- package/dist/types-ts4.5/pm-plugins/ghost-text-decoration.d.ts +7 -0
- package/dist/types-ts4.5/pm-plugins/scoring-pipeline.d.ts +33 -0
- package/dist/types-ts4.5/pm-plugins/slow-lane-client.d.ts +46 -0
- package/dist/types-ts4.5/pm-plugins/text-predictor.d.ts +90 -0
- package/package.json +2 -2
- package/src/autocompletePlugin.tsx +25 -5
- package/src/autocompletePluginType.ts +14 -3
- package/src/pm-plugins/autocomplete-plugin/package.json +15 -0
- package/src/pm-plugins/autocomplete-plugin.ts +429 -0
- package/src/pm-plugins/ghost-text-decoration.ts +44 -0
- package/src/pm-plugins/scoring-pipeline.ts +297 -0
- package/src/pm-plugins/slow-lane-client/package.json +15 -0
- package/src/pm-plugins/slow-lane-client.ts +220 -0
- package/src/pm-plugins/text-predictor/package.json +15 -0
- package/src/pm-plugins/text-predictor.ts +771 -0
- package/src/pm-plugins/typings.d.ts +12 -0
- package/tsconfig.app.json +10 -2
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
4
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
5
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
6
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
7
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
8
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
9
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
10
|
+
/**
|
|
11
|
+
* Fast Lane Predictor: Local autocomplete using weighted trie + frequency + semantic scoring.
|
|
12
|
+
*
|
|
13
|
+
* Two prediction modes:
|
|
14
|
+
* 1. Word boundary → bigram-based next-word suggestion (grammar-filtered)
|
|
15
|
+
* 2. Mid-word (≥3 chars) → trie prefix search → scoring pipeline → top result
|
|
16
|
+
*
|
|
17
|
+
* Scoring is delegated to scoring-pipeline.ts which handles:
|
|
18
|
+
* Stage 1 (semantic + frequency), grammar filter, Stage 2 (optional LM re-ranking).
|
|
19
|
+
*
|
|
20
|
+
* Context vector: average of word vectors from text before cursor (last N words).
|
|
21
|
+
* Falls back to cold mode (freq-only) when vectors not yet loaded.
|
|
22
|
+
*
|
|
23
|
+
* Session personalization (L1): words the user types are incrementally boosted
|
|
24
|
+
* via incrementSessionFreq(), called on word boundaries from the plugin.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
// import bigramsData from './data/bigrams.json';
|
|
28
|
+
import l3VocabularyData from './data/l3_vocabulary.json';
|
|
29
|
+
import vocabularyData from './data/vocabulary_10k.json';
|
|
30
|
+
import wordIndexData from './data/word_index_10k.json';
|
|
31
|
+
// import { rankCandidates, isGrammarAllowed } from './scoring-pipeline';
|
|
32
|
+
import { rankCandidates } from './scoring-pipeline';
|
|
33
|
+
import { getStoredContextVector, getStoredLmLogits } from './slow-lane-client';
|
|
34
|
+
|
|
35
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
var PUNCTUATION_BOUNDARY_REGEX = /^[!"'-\),\.:;\?\[\]`\{\}]+|[!"'-\),\.:;\?\[\]`\{\}]+$/g;
|
|
38
|
+
var MIN_PREFIX_LENGTH = 3;
|
|
39
|
+
var MAX_CANDIDATES = 200;
|
|
40
|
+
var CONTEXT_WORDS = 10;
|
|
41
|
+
var MIN_SCORE_THRESHOLD = 0.2;
|
|
42
|
+
var L3_BASELINE_FREQ = 0.001;
|
|
43
|
+
|
|
44
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
45
|
+
var TrieNode = /*#__PURE__*/_createClass(function TrieNode() {
|
|
46
|
+
_classCallCheck(this, TrieNode);
|
|
47
|
+
_defineProperty(this, "children", new Map());
|
|
48
|
+
_defineProperty(this, "word", null);
|
|
49
|
+
_defineProperty(this, "tenantFreq", 0);
|
|
50
|
+
_defineProperty(this, "docFreq", 0);
|
|
51
|
+
_defineProperty(this, "authorFreq", 0);
|
|
52
|
+
_defineProperty(this, "sessionFreq", 0);
|
|
53
|
+
});
|
|
54
|
+
var WeightedWordTrie = /*#__PURE__*/function () {
|
|
55
|
+
function WeightedWordTrie() {
|
|
56
|
+
_classCallCheck(this, WeightedWordTrie);
|
|
57
|
+
_defineProperty(this, "root", new TrieNode());
|
|
58
|
+
/** Highest tenantFreq seen — used to normalize freq scores at query time */
|
|
59
|
+
_defineProperty(this, "maxTenantFreq", 1);
|
|
60
|
+
}
|
|
61
|
+
return _createClass(WeightedWordTrie, [{
|
|
62
|
+
key: "insert",
|
|
63
|
+
value: function insert(word, tenantFreq, docFreq, authorFreq) {
|
|
64
|
+
var node = this.root;
|
|
65
|
+
var _iterator = _createForOfIteratorHelper(word.toLowerCase()),
|
|
66
|
+
_step;
|
|
67
|
+
try {
|
|
68
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
69
|
+
var char = _step.value;
|
|
70
|
+
var next = node.children.get(char);
|
|
71
|
+
if (!next) {
|
|
72
|
+
next = new TrieNode();
|
|
73
|
+
node.children.set(char, next);
|
|
74
|
+
}
|
|
75
|
+
node = next;
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
_iterator.e(err);
|
|
79
|
+
} finally {
|
|
80
|
+
_iterator.f();
|
|
81
|
+
}
|
|
82
|
+
node.word = word;
|
|
83
|
+
node.tenantFreq = tenantFreq;
|
|
84
|
+
node.docFreq = docFreq;
|
|
85
|
+
node.authorFreq = authorFreq;
|
|
86
|
+
if (tenantFreq > this.maxTenantFreq) {
|
|
87
|
+
this.maxTenantFreq = tenantFreq;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Return all words matching this prefix, up to maxResults.
|
|
93
|
+
* O(prefix_length + results) — traverses to the prefix node then collects subtree.
|
|
94
|
+
*/
|
|
95
|
+
}, {
|
|
96
|
+
key: "getCandidates",
|
|
97
|
+
value: function getCandidates(prefix) {
|
|
98
|
+
var maxResults = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : MAX_CANDIDATES;
|
|
99
|
+
var node = this.root;
|
|
100
|
+
var _iterator2 = _createForOfIteratorHelper(prefix.toLowerCase()),
|
|
101
|
+
_step2;
|
|
102
|
+
try {
|
|
103
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
104
|
+
var char = _step2.value;
|
|
105
|
+
var next = node.children.get(char);
|
|
106
|
+
if (!next) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
node = next;
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
_iterator2.e(err);
|
|
113
|
+
} finally {
|
|
114
|
+
_iterator2.f();
|
|
115
|
+
}
|
|
116
|
+
var candidates = [];
|
|
117
|
+
var stack = [node];
|
|
118
|
+
while (stack.length > 0 && candidates.length < maxResults) {
|
|
119
|
+
var current = stack.pop();
|
|
120
|
+
if (!current) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Only add candidates that are longer than the prefix
|
|
125
|
+
if (current.word && current.word.length > prefix.length) {
|
|
126
|
+
candidates.push({
|
|
127
|
+
word: current.word,
|
|
128
|
+
node: current
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
var _iterator3 = _createForOfIteratorHelper(current.children.values()),
|
|
132
|
+
_step3;
|
|
133
|
+
try {
|
|
134
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
135
|
+
var child = _step3.value;
|
|
136
|
+
stack.push(child);
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
_iterator3.e(err);
|
|
140
|
+
} finally {
|
|
141
|
+
_iterator3.f();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return candidates;
|
|
145
|
+
}
|
|
146
|
+
}, {
|
|
147
|
+
key: "findNode",
|
|
148
|
+
value: function findNode(word) {
|
|
149
|
+
var node = this.root;
|
|
150
|
+
var _iterator4 = _createForOfIteratorHelper(word.toLowerCase()),
|
|
151
|
+
_step4;
|
|
152
|
+
try {
|
|
153
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
154
|
+
var char = _step4.value;
|
|
155
|
+
var next = node.children.get(char);
|
|
156
|
+
if (!next) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
node = next;
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
_iterator4.e(err);
|
|
163
|
+
} finally {
|
|
164
|
+
_iterator4.f();
|
|
165
|
+
}
|
|
166
|
+
return node.word !== null ? node : null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Set the session frequency for a word.
|
|
171
|
+
* Returns true if the word exists in the trie.
|
|
172
|
+
*/
|
|
173
|
+
}, {
|
|
174
|
+
key: "updateSessionFreq",
|
|
175
|
+
value: function updateSessionFreq(word, count) {
|
|
176
|
+
var node = this.findNode(word);
|
|
177
|
+
if (!node) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
node.sessionFreq = count;
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Increment the session frequency for a word by 1.
|
|
186
|
+
* Returns true if the word exists in the trie.
|
|
187
|
+
*/
|
|
188
|
+
}, {
|
|
189
|
+
key: "incrementSessionFreq",
|
|
190
|
+
value: function incrementSessionFreq(word) {
|
|
191
|
+
var node = this.findNode(word);
|
|
192
|
+
if (!node) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
node.sessionFreq += 1;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
}]);
|
|
199
|
+
}(); // L1/L2 Trie (Session + Atlassian Domain)
|
|
200
|
+
var wordTrie = new WeightedWordTrie();
|
|
201
|
+
|
|
202
|
+
// L3 Trie (General English Fallback)
|
|
203
|
+
var l3Trie = new WeightedWordTrie();
|
|
204
|
+
|
|
205
|
+
// --- Initialization Function ---
|
|
206
|
+
/**
|
|
207
|
+
* Loads the General English vocabulary.
|
|
208
|
+
* expects a simple array of strings: ["about", "above", "actually", ...]
|
|
209
|
+
*/
|
|
210
|
+
export var initL3Vocabulary = function initL3Vocabulary(l3Words) {
|
|
211
|
+
var _iterator5 = _createForOfIteratorHelper(l3Words),
|
|
212
|
+
_step5;
|
|
213
|
+
try {
|
|
214
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
215
|
+
var word = _step5.value;
|
|
216
|
+
// Insert with a tiny baseline frequency so it mathematically
|
|
217
|
+
// loses to any domain word in Stage 1, but still scores above 0.
|
|
218
|
+
l3Trie.insert(word, L3_BASELINE_FREQ, 0, 0);
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
_iterator5.e(err);
|
|
222
|
+
} finally {
|
|
223
|
+
_iterator5.f();
|
|
224
|
+
}
|
|
225
|
+
if (debugMode) {
|
|
226
|
+
// eslint-disable-next-line no-console
|
|
227
|
+
console.log("[text-predictor] L3 General English loaded: ".concat(l3Words.length, " words"));
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// const bigramMap: Map<string, Record<string, number>> = new Map(
|
|
232
|
+
// Object.entries(bigramsData as Record<string, Record<string, number>>),
|
|
233
|
+
// );
|
|
234
|
+
|
|
235
|
+
var isInitialized = false;
|
|
236
|
+
var vectorStore = null;
|
|
237
|
+
var vectorsLoadStarted = false;
|
|
238
|
+
var debugMode = true;
|
|
239
|
+
var lastPredictionDebug = null;
|
|
240
|
+
var hasLoggedSemanticActive = false;
|
|
241
|
+
|
|
242
|
+
/** Get vector for a word from the store. */
|
|
243
|
+
var getWordVector = function getWordVector(word) {
|
|
244
|
+
if (!vectorStore) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
var idx = vectorStore.wordIndex[word.toLowerCase()];
|
|
248
|
+
if (idx === undefined) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
var start = idx * vectorStore.dim;
|
|
252
|
+
return vectorStore.float32.subarray(start, start + vectorStore.dim);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Compute context vector by averaging vectors of last N words in text.
|
|
257
|
+
* Falls back to null (cold mode) if no words have vectors.
|
|
258
|
+
*/
|
|
259
|
+
var computeContextVectorLocal = function computeContextVectorLocal(textBefore) {
|
|
260
|
+
if (!vectorStore) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
var tokens = tokenize(textBefore);
|
|
264
|
+
var words = tokens.slice(-CONTEXT_WORDS);
|
|
265
|
+
var vectors = [];
|
|
266
|
+
var _iterator6 = _createForOfIteratorHelper(words),
|
|
267
|
+
_step6;
|
|
268
|
+
try {
|
|
269
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
270
|
+
var word = _step6.value;
|
|
271
|
+
var _v = getWordVector(word);
|
|
272
|
+
if (_v) {
|
|
273
|
+
vectors.push(_v);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} catch (err) {
|
|
277
|
+
_iterator6.e(err);
|
|
278
|
+
} finally {
|
|
279
|
+
_iterator6.f();
|
|
280
|
+
}
|
|
281
|
+
if (vectors.length === 0) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
var dim = vectorStore.dim;
|
|
285
|
+
var avg = new Float32Array(dim);
|
|
286
|
+
for (var _i = 0, _vectors = vectors; _i < _vectors.length; _i++) {
|
|
287
|
+
var v = _vectors[_i];
|
|
288
|
+
for (var i = 0; i < dim; i++) {
|
|
289
|
+
avg[i] += v[i];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
for (var _i2 = 0; _i2 < dim; _i2++) {
|
|
293
|
+
avg[_i2] /= vectors.length;
|
|
294
|
+
}
|
|
295
|
+
return avg;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get context vector for scoring. Prefers Slow Lane (BE) context when available
|
|
300
|
+
* and dimension matches; otherwise falls back to local averaging.
|
|
301
|
+
*/
|
|
302
|
+
var getContextVectorForScoring = function getContextVectorForScoring(textBefore) {
|
|
303
|
+
var slowLaneVector = getStoredContextVector();
|
|
304
|
+
if (slowLaneVector && vectorStore && slowLaneVector.length === vectorStore.dim) {
|
|
305
|
+
return slowLaneVector;
|
|
306
|
+
}
|
|
307
|
+
return computeContextVectorLocal(textBefore);
|
|
308
|
+
};
|
|
309
|
+
var tokenize = function tokenize(text) {
|
|
310
|
+
var tokens = [];
|
|
311
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
312
|
+
var _iterator7 = _createForOfIteratorHelper(text.toLowerCase().split(/[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+/)),
|
|
313
|
+
_step7;
|
|
314
|
+
try {
|
|
315
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
316
|
+
var raw = _step7.value;
|
|
317
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
318
|
+
var clean = raw.replace(PUNCTUATION_BOUNDARY_REGEX, '');
|
|
319
|
+
if (clean.length >= 2) {
|
|
320
|
+
tokens.push(clean);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (err) {
|
|
324
|
+
_iterator7.e(err);
|
|
325
|
+
} finally {
|
|
326
|
+
_iterator7.f();
|
|
327
|
+
}
|
|
328
|
+
return tokens;
|
|
329
|
+
};
|
|
330
|
+
var extractPreviousWord = function extractPreviousWord(text) {
|
|
331
|
+
// 1. Split the text by newlines or punctuation (. ? !)
|
|
332
|
+
var sentences = text.split(/[\n!\.\?]+/);
|
|
333
|
+
|
|
334
|
+
// 2. Only look at the current sentence/line the user is typing in
|
|
335
|
+
var currentSentence = sentences[sentences.length - 1];
|
|
336
|
+
|
|
337
|
+
// 3. Extract the previous word as normal
|
|
338
|
+
var words = currentSentence.trimEnd().split(/[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+/);
|
|
339
|
+
return words.length >= 2 ? words[words.length - 2] : '';
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// ─── Debug Helpers ───────────────────────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
/** Enable or disable debug logging. Also checks localStorage key `autocomplete-debug`. */
|
|
345
|
+
export var setDebugMode = function setDebugMode(enabled) {
|
|
346
|
+
debugMode = enabled;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
/** Check localStorage for autocomplete-debug on first access. */
|
|
350
|
+
var ensureDebugModeFromStorage = function ensureDebugModeFromStorage() {
|
|
351
|
+
if (typeof localStorage !== 'undefined' && localStorage.getItem('autocomplete-debug') === '1') {
|
|
352
|
+
debugMode = true;
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get predictor status for debugging.
|
|
358
|
+
* vectorsLoaded: true when semantic scoring is active
|
|
359
|
+
* wordCount: number of words in vector store (0 if not loaded)
|
|
360
|
+
*/
|
|
361
|
+
export var getPredictorStatus = function getPredictorStatus() {
|
|
362
|
+
ensureDebugModeFromStorage();
|
|
363
|
+
return {
|
|
364
|
+
vectorsLoaded: vectorStore !== null,
|
|
365
|
+
wordCount: vectorStore ? Object.keys(vectorStore.wordIndex).length : 0,
|
|
366
|
+
vectorsLoadStarted: vectorsLoadStarted,
|
|
367
|
+
isInitialized: isInitialized
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get details of the last prediction (for debugging).
|
|
373
|
+
* Returns null if no prediction has run yet or debug was off.
|
|
374
|
+
*/
|
|
375
|
+
export var getLastPredictionDebug = function getLastPredictionDebug() {
|
|
376
|
+
ensureDebugModeFromStorage();
|
|
377
|
+
return lastPredictionDebug;
|
|
378
|
+
};
|
|
379
|
+
export var initVocabulary = function initVocabulary(vocabulary) {
|
|
380
|
+
var _iterator8 = _createForOfIteratorHelper(vocabulary.terms),
|
|
381
|
+
_step8;
|
|
382
|
+
try {
|
|
383
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
384
|
+
var term = _step8.value;
|
|
385
|
+
wordTrie.insert(term.word, term.freq, term.docFreq, term.authorFreq);
|
|
386
|
+
}
|
|
387
|
+
} catch (err) {
|
|
388
|
+
_iterator8.e(err);
|
|
389
|
+
} finally {
|
|
390
|
+
_iterator8.f();
|
|
391
|
+
}
|
|
392
|
+
isInitialized = true;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Increment L1 session frequency for a single word.
|
|
397
|
+
* Called from the plugin on word boundaries for efficient incremental boosting.
|
|
398
|
+
*/
|
|
399
|
+
export var incrementSessionFreq = function incrementSessionFreq(word) {
|
|
400
|
+
wordTrie.incrementSessionFreq(word);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Prime session frequencies from a document page string.
|
|
405
|
+
*
|
|
406
|
+
* Iterates through every token in `pageContent` and increments its session
|
|
407
|
+
* frequency so that words already present on the page receive an L1 boost
|
|
408
|
+
* before the user starts typing.
|
|
409
|
+
*
|
|
410
|
+
* Pass `undefined` (or omit the argument) to skip priming — useful when the
|
|
411
|
+
* calling context does not yet have a page value available.
|
|
412
|
+
*/
|
|
413
|
+
// NOTE: We ingest full page context here
|
|
414
|
+
export var ingestDocumentPage = function ingestDocumentPage(pageContent) {
|
|
415
|
+
if (!pageContent) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
var words = tokenize(pageContent);
|
|
419
|
+
var validBoostedWords = new Set();
|
|
420
|
+
var _iterator9 = _createForOfIteratorHelper(words),
|
|
421
|
+
_step9;
|
|
422
|
+
try {
|
|
423
|
+
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
|
424
|
+
var word = _step9.value;
|
|
425
|
+
var didBoost = wordTrie.incrementSessionFreq(word);
|
|
426
|
+
if (didBoost) {
|
|
427
|
+
validBoostedWords.add(word);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
} catch (err) {
|
|
431
|
+
_iterator9.e(err);
|
|
432
|
+
} finally {
|
|
433
|
+
_iterator9.f();
|
|
434
|
+
}
|
|
435
|
+
if (debugMode && validBoostedWords.size > 0) {
|
|
436
|
+
// eslint-disable-next-line no-console
|
|
437
|
+
console.groupCollapsed("%c[L1 Session] %cPrimed ".concat(validBoostedWords.size, " valid dictionary words from page"), 'color: #00b8d9; font-weight: bold;', 'color: inherit; font-style: italic;');
|
|
438
|
+
// eslint-disable-next-line no-console
|
|
439
|
+
console.dir(Array.from(validBoostedWords).sort());
|
|
440
|
+
// eslint-disable-next-line no-console
|
|
441
|
+
console.groupEnd();
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
export var predict = function predict(textBefore) {
|
|
445
|
+
ensureDebugModeFromStorage();
|
|
446
|
+
if (!isInitialized) {
|
|
447
|
+
loadDefaultVocabulary();
|
|
448
|
+
}
|
|
449
|
+
var t0 = performance.now();
|
|
450
|
+
|
|
451
|
+
// ── Step 1: Bigram-based next-word suggestion at word boundary ───────────
|
|
452
|
+
// if (textBefore.length > 0 && /\s$/u.test(textBefore)) {
|
|
453
|
+
// const words = textBefore.toLowerCase().trimEnd().split(/\s+/u);
|
|
454
|
+
// const prevWord = words[words.length - 1];
|
|
455
|
+
// const nextWords = bigramMap.get(prevWord);
|
|
456
|
+
// if (nextWords) {
|
|
457
|
+
// const sorted = Object.entries(nextWords).sort((a, b) => b[1] - a[1]);
|
|
458
|
+
// let bestWord = '';
|
|
459
|
+
// for (const [word] of sorted) {
|
|
460
|
+
// if (!isGrammarAllowed(prevWord, word)) {
|
|
461
|
+
// continue;
|
|
462
|
+
// }
|
|
463
|
+
// bestWord = word;
|
|
464
|
+
// break;
|
|
465
|
+
// }
|
|
466
|
+
// if (bestWord) {
|
|
467
|
+
// if (debugMode) {
|
|
468
|
+
// const latencyMs = performance.now() - t0;
|
|
469
|
+
// console.log(
|
|
470
|
+
// '%c[autocomplete] BIGRAM',
|
|
471
|
+
// 'color:cyan',
|
|
472
|
+
// '| "' + prevWord + '" -> "' + bestWord + '" | ' + latencyMs.toFixed(1) + 'ms',
|
|
473
|
+
// );
|
|
474
|
+
// }
|
|
475
|
+
// return bestWord;
|
|
476
|
+
// }
|
|
477
|
+
// }
|
|
478
|
+
// if (debugMode) {
|
|
479
|
+
// console.log(
|
|
480
|
+
// '%c[autocomplete] BIGRAM-MISS',
|
|
481
|
+
// 'color:gray',
|
|
482
|
+
// '| no bigram for "' + words[words.length - 1] + '", skipping prefix completion',
|
|
483
|
+
// );
|
|
484
|
+
// }
|
|
485
|
+
// return null;
|
|
486
|
+
// }
|
|
487
|
+
|
|
488
|
+
// ── Step 2: Prefix completion (≥3 chars typed) ──────────────────────────
|
|
489
|
+
if (textBefore.length > 0 && /[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]$/.test(textBefore)) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
var trimmed = textBefore.trimEnd();
|
|
493
|
+
var lastSpaceIdx = trimmed.lastIndexOf(' ');
|
|
494
|
+
var currentWord = lastSpaceIdx === -1 ? trimmed : trimmed.slice(lastSpaceIdx + 1);
|
|
495
|
+
if (currentWord.length < MIN_PREFIX_LENGTH) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// 1. Primary Query: Ask the L2 Domain Trie
|
|
500
|
+
var candidates = wordTrie.getCandidates(currentWord, MAX_CANDIDATES);
|
|
501
|
+
|
|
502
|
+
// 2. Fallback Query: Gap-fill with the L3 General English Trie
|
|
503
|
+
if (candidates.length < MAX_CANDIDATES) {
|
|
504
|
+
// Ask L3 for MAX_CANDIDATES to guarantee we have enough buffer
|
|
505
|
+
// to survive the deduplication process.
|
|
506
|
+
var l3Candidates = l3Trie.getCandidates(currentWord, MAX_CANDIDATES);
|
|
507
|
+
var existingWords = new Set(candidates.map(function (c) {
|
|
508
|
+
return c.word;
|
|
509
|
+
}));
|
|
510
|
+
var _iterator0 = _createForOfIteratorHelper(l3Candidates),
|
|
511
|
+
_step0;
|
|
512
|
+
try {
|
|
513
|
+
for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
|
|
514
|
+
var l3c = _step0.value;
|
|
515
|
+
if (candidates.length >= MAX_CANDIDATES) break; // Stop exactly at the limit
|
|
516
|
+
|
|
517
|
+
if (!existingWords.has(l3c.word)) {
|
|
518
|
+
candidates.push(l3c);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
} catch (err) {
|
|
522
|
+
_iterator0.e(err);
|
|
523
|
+
} finally {
|
|
524
|
+
_iterator0.f();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// If both Tries are completely empty for this prefix
|
|
529
|
+
if (candidates.length === 0) {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
var previousWord = extractPreviousWord(trimmed);
|
|
533
|
+
var contextVector = getContextVectorForScoring(trimmed);
|
|
534
|
+
var lmLogits = getStoredLmLogits();
|
|
535
|
+
|
|
536
|
+
// Raw LM Output Logger
|
|
537
|
+
if (debugMode && lmLogits && Object.keys(lmLogits).length > 0) {
|
|
538
|
+
var rawLmTop = Object.entries(lmLogits).sort(function (a, b) {
|
|
539
|
+
return b[1] - a[1];
|
|
540
|
+
}).slice(0, 5).map(function (_ref) {
|
|
541
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
542
|
+
word = _ref2[0],
|
|
543
|
+
score = _ref2[1];
|
|
544
|
+
return {
|
|
545
|
+
Word: word,
|
|
546
|
+
Prob: Number(score.toFixed(5))
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
// eslint-disable-next-line no-console
|
|
550
|
+
console.log('%c[Raw LM Prediction]🧠', 'color: #e83e8c; font-weight: bold;', rawLmTop);
|
|
551
|
+
}
|
|
552
|
+
var mode = contextVector ? 'warm' : 'cold';
|
|
553
|
+
if (debugMode && contextVector && !hasLoggedSemanticActive) {
|
|
554
|
+
hasLoggedSemanticActive = true;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Build ScoringCandidate array from TrieNodes
|
|
558
|
+
var scoringCandidates = candidates.map(function (_ref3) {
|
|
559
|
+
var word = _ref3.word,
|
|
560
|
+
node = _ref3.node;
|
|
561
|
+
return {
|
|
562
|
+
word: word,
|
|
563
|
+
tenantFreq: node.tenantFreq,
|
|
564
|
+
docFreq: node.docFreq,
|
|
565
|
+
authorFreq: node.authorFreq,
|
|
566
|
+
sessionFreq: node.sessionFreq
|
|
567
|
+
};
|
|
568
|
+
});
|
|
569
|
+
var _rankCandidates = rankCandidates(scoringCandidates, contextVector, function (w) {
|
|
570
|
+
return getWordVector(w);
|
|
571
|
+
}, lmLogits, wordTrie.maxTenantFreq, previousWord),
|
|
572
|
+
ranked = _rankCandidates.candidates,
|
|
573
|
+
grammarMeta = _rankCandidates.grammarMeta;
|
|
574
|
+
var best = ranked[0];
|
|
575
|
+
var suggestion = best && best.finalScore >= MIN_SCORE_THRESHOLD ? best.word.slice(currentWord.length) : null;
|
|
576
|
+
if (debugMode) {
|
|
577
|
+
var latencyMs = performance.now() - t0;
|
|
578
|
+
var tokens = tokenize(trimmed);
|
|
579
|
+
var contextWords = tokens.slice(-CONTEXT_WORDS);
|
|
580
|
+
var belowThreshold = best && best.finalScore < MIN_SCORE_THRESHOLD;
|
|
581
|
+
var suggestionLabel = belowThreshold ? '🚫 (below threshold)' : suggestion && suggestion.length > 0 ? "\u2728 \"".concat(suggestion, "\"") : '🚫 (no match)';
|
|
582
|
+
lastPredictionDebug = {
|
|
583
|
+
textBefore: trimmed,
|
|
584
|
+
currentWord: currentWord,
|
|
585
|
+
mode: mode,
|
|
586
|
+
contextWords: contextWords,
|
|
587
|
+
topCandidates: ranked.slice(0, 5).map(function (r) {
|
|
588
|
+
return {
|
|
589
|
+
word: r.word,
|
|
590
|
+
finalScore: r.finalScore,
|
|
591
|
+
semanticScore: r.semanticScore,
|
|
592
|
+
freqScore: r.freqScore,
|
|
593
|
+
lmScore: r.lmScore
|
|
594
|
+
};
|
|
595
|
+
}),
|
|
596
|
+
suggestion: suggestion && suggestion.length > 0 ? suggestion : null
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
// ── Mode label: COLD / WARM(local) / WARM(BE) ───────────────────────
|
|
600
|
+
var slowLaneVec = getStoredContextVector();
|
|
601
|
+
var isUsingSlowLaneVector = slowLaneVec !== null && vectorStore !== null && slowLaneVec.length === vectorStore.dim;
|
|
602
|
+
var modeLabel = !contextVector ? 'COLD' : isUsingSlowLaneVector ? 'WARM(BE)' : 'WARM(local)';
|
|
603
|
+
var modeColor = modeLabel === 'WARM(BE)' ? 'color: #ff9800; font-weight: bold;' : modeLabel === 'WARM(local)' ? 'color: #4caf50; font-weight: bold;' : 'color: #9e9e9e; font-weight: bold;';
|
|
604
|
+
|
|
605
|
+
// 1. Collapsible group header
|
|
606
|
+
// eslint-disable-next-line no-console
|
|
607
|
+
console.groupCollapsed("%c[Autocomplete] %c".concat(modeLabel, " %c| \"").concat(currentWord, "\" \u2794 ").concat(suggestionLabel, " | \u23F1 ").concat(latencyMs.toFixed(1), "ms"), 'color: #00b8d9; font-weight: bold;', modeColor, 'color: inherit; font-weight: normal;');
|
|
608
|
+
|
|
609
|
+
// 2. Context window (what local vector averaging sees)
|
|
610
|
+
// eslint-disable-next-line no-console
|
|
611
|
+
console.log('%cContext Window:', 'color: #888; font-style: italic;', contextWords.length ? contextWords.join(' ') : '(none)');
|
|
612
|
+
|
|
613
|
+
// 3. Slow-lane status
|
|
614
|
+
var vectorStatus = isUsingSlowLaneVector ? "\u2705 BE semantic vector (dim=".concat(slowLaneVec === null || slowLaneVec === void 0 ? void 0 : slowLaneVec.length, ")") : vectorStore ? '⚠️ Local vector average (slow-lane not yet returned)' : '❌ No vectors (cold)';
|
|
615
|
+
var logitsStatus = lmLogits && Object.keys(lmLogits).length > 0 ? "\u2705 LM logits active (".concat(Object.keys(lmLogits).length, " tokens)") : '⏳ No LM logits (slow-lane pending or failed)';
|
|
616
|
+
// eslint-disable-next-line no-console
|
|
617
|
+
console.log('%cSlow Lane:', 'color: #888; font-style: italic;', vectorStatus, '|', logitsStatus);
|
|
618
|
+
|
|
619
|
+
// 4. Scoring formula active this prediction
|
|
620
|
+
var formulaLabel = lmLogits && Object.keys(lmLogits).length > 0 ? 'Stage1(×0.6) + LM(×0.4)' : 'Stage1 only (no LM logits)';
|
|
621
|
+
// eslint-disable-next-line no-console
|
|
622
|
+
console.log('%cFormula:', 'color: #888; font-style: italic;', formulaLabel);
|
|
623
|
+
|
|
624
|
+
// 5. Grammar filter result (collected inside rankCandidates, logged here)
|
|
625
|
+
if (grammarMeta) {
|
|
626
|
+
// eslint-disable-next-line no-console
|
|
627
|
+
console.log("%c[Grammar] \"".concat(grammarMeta.prevWord, "\" [").concat(grammarMeta.prevTags.join('|'), "] \u2192 ").concat(grammarMeta.before, " candidates \u2192 ").concat(grammarMeta.after, " after filter"), 'color: #4caf50; font-weight: bold;');
|
|
628
|
+
if (grammarMeta.dropped.length > 0) {
|
|
629
|
+
// eslint-disable-next-line no-console
|
|
630
|
+
console.log("%c\uD83D\uDEAB Dropped: ".concat(grammarMeta.dropped.join(', ')), 'color: #f44336; font-style: italic;');
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// 6. Candidate table
|
|
635
|
+
if (ranked.length > 0) {
|
|
636
|
+
var lmCoverage = ranked.slice(0, 10).filter(function (r) {
|
|
637
|
+
return r.lmScore > 0.05;
|
|
638
|
+
}).length;
|
|
639
|
+
// eslint-disable-next-line no-console
|
|
640
|
+
console.log("%cLM coverage: ".concat(lmCoverage, "/").concat(Math.min(ranked.length, 10), " candidates had real logit scores"), 'color: #888; font-style: italic;');
|
|
641
|
+
var tableData = ranked.slice(0, 10).map(function (r) {
|
|
642
|
+
var rawLogit = 'Not in Payload';
|
|
643
|
+
if (lmLogits) {
|
|
644
|
+
var val = lmLogits[r.word.toLowerCase()];
|
|
645
|
+
if (val !== undefined) {
|
|
646
|
+
rawLogit = Number(val.toFixed(5));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
var original = scoringCandidates.find(function (sc) {
|
|
650
|
+
return sc.word === r.word;
|
|
651
|
+
});
|
|
652
|
+
var source = 'Unknown';
|
|
653
|
+
if (original) {
|
|
654
|
+
if (original.docFreq === 0 && original.tenantFreq === L3_BASELINE_FREQ) {
|
|
655
|
+
source = '🌍 L3 (Generic)';
|
|
656
|
+
} else if (original.sessionFreq > 0 && original.tenantFreq === 0) {
|
|
657
|
+
source = '👤 L1 (Session Only)';
|
|
658
|
+
} else {
|
|
659
|
+
source = '🏢 L2 (Domain)';
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return {
|
|
663
|
+
Candidate: r.word,
|
|
664
|
+
Source: source,
|
|
665
|
+
'Final Score': Number(r.finalScore.toFixed(4)),
|
|
666
|
+
Semantics: Number(r.semanticScore.toFixed(4)),
|
|
667
|
+
Freq: Number(r.freqScore.toFixed(4)),
|
|
668
|
+
'LM Score': Number(r.lmScore.toFixed(4)),
|
|
669
|
+
'Raw Logit': rawLogit,
|
|
670
|
+
'Session Freq': (original === null || original === void 0 ? void 0 : original.sessionFreq) || 0
|
|
671
|
+
};
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
// eslint-disable-next-line no-console
|
|
675
|
+
console.table(tableData);
|
|
676
|
+
} else {
|
|
677
|
+
// eslint-disable-next-line no-console
|
|
678
|
+
console.log('No candidates found.');
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// eslint-disable-next-line no-console
|
|
682
|
+
console.groupEnd();
|
|
683
|
+
}
|
|
684
|
+
return suggestion && suggestion.length > 0 ? suggestion : null;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
688
|
+
|
|
689
|
+
var DEFAULT_VECTORS_URL = '/data/word-vectors_10k.bin';
|
|
690
|
+
export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
691
|
+
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
|
|
692
|
+
var _options$vectorsUrl;
|
|
693
|
+
var url, res, buffer, float32, wordIndex, nWords, dim;
|
|
694
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
695
|
+
while (1) switch (_context.prev = _context.next) {
|
|
696
|
+
case 0:
|
|
697
|
+
if (!(vectorStore || vectorsLoadStarted)) {
|
|
698
|
+
_context.next = 2;
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
return _context.abrupt("return");
|
|
702
|
+
case 2:
|
|
703
|
+
vectorsLoadStarted = true;
|
|
704
|
+
url = (_options$vectorsUrl = options === null || options === void 0 ? void 0 : options.vectorsUrl) !== null && _options$vectorsUrl !== void 0 ? _options$vectorsUrl : DEFAULT_VECTORS_URL;
|
|
705
|
+
_context.prev = 4;
|
|
706
|
+
_context.next = 7;
|
|
707
|
+
return fetch(url);
|
|
708
|
+
case 7:
|
|
709
|
+
res = _context.sent;
|
|
710
|
+
if (res.ok) {
|
|
711
|
+
_context.next = 12;
|
|
712
|
+
break;
|
|
713
|
+
}
|
|
714
|
+
vectorsLoadStarted = false;
|
|
715
|
+
// eslint-disable-next-line no-console
|
|
716
|
+
console.warn("[text-predictor] Failed to load vectors: ".concat(res.status));
|
|
717
|
+
return _context.abrupt("return");
|
|
718
|
+
case 12:
|
|
719
|
+
_context.next = 14;
|
|
720
|
+
return res.arrayBuffer();
|
|
721
|
+
case 14:
|
|
722
|
+
buffer = _context.sent;
|
|
723
|
+
float32 = new Float32Array(buffer);
|
|
724
|
+
wordIndex = wordIndexData;
|
|
725
|
+
nWords = Object.keys(wordIndex).length;
|
|
726
|
+
dim = float32.length / nWords;
|
|
727
|
+
vectorStore = {
|
|
728
|
+
float32: float32,
|
|
729
|
+
wordIndex: wordIndex,
|
|
730
|
+
dim: dim
|
|
731
|
+
};
|
|
732
|
+
ensureDebugModeFromStorage();
|
|
733
|
+
if (debugMode) {
|
|
734
|
+
// eslint-disable-next-line no-console
|
|
735
|
+
console.log('[text-predictor] Vectors loaded:', {
|
|
736
|
+
wordCount: nWords,
|
|
737
|
+
dim: dim,
|
|
738
|
+
sizeBytes: float32.byteLength
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
_context.next = 28;
|
|
742
|
+
break;
|
|
743
|
+
case 24:
|
|
744
|
+
_context.prev = 24;
|
|
745
|
+
_context.t0 = _context["catch"](4);
|
|
746
|
+
vectorsLoadStarted = false;
|
|
747
|
+
// eslint-disable-next-line no-console
|
|
748
|
+
console.warn('[text-predictor] Failed to load vectors:', _context.t0);
|
|
749
|
+
case 28:
|
|
750
|
+
case "end":
|
|
751
|
+
return _context.stop();
|
|
752
|
+
}
|
|
753
|
+
}, _callee, null, [[4, 24]]);
|
|
754
|
+
}));
|
|
755
|
+
return function loadVectorsAsync(_x) {
|
|
756
|
+
return _ref4.apply(this, arguments);
|
|
757
|
+
};
|
|
758
|
+
}();
|
|
759
|
+
export var initVectors = function initVectors(store) {
|
|
760
|
+
vectorStore = store;
|
|
761
|
+
};
|
|
762
|
+
export var loadDefaultVocabulary = function loadDefaultVocabulary() {
|
|
763
|
+
// 1. Load the Atlassian Domain (L2)
|
|
764
|
+
var data = vocabularyData;
|
|
765
|
+
var terms = Object.entries(data.words).map(function (_ref5) {
|
|
766
|
+
var _ref6 = _slicedToArray(_ref5, 2),
|
|
767
|
+
word = _ref6[0],
|
|
768
|
+
stats = _ref6[1];
|
|
769
|
+
return {
|
|
770
|
+
word: word,
|
|
771
|
+
freq: stats.freq,
|
|
772
|
+
docFreq: stats.doc_freq,
|
|
773
|
+
authorFreq: stats.author_freq
|
|
774
|
+
};
|
|
775
|
+
});
|
|
776
|
+
initVocabulary({
|
|
777
|
+
terms: terms
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
// 2. Load General English (L3)
|
|
781
|
+
var l3Words = l3VocabularyData;
|
|
782
|
+
initL3Vocabulary(l3Words);
|
|
783
|
+
};
|