fr-spell 1.0.2 → 1.0.4
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/README.cn.md +17 -63
- package/README.fr.md +17 -63
- package/README.md +17 -63
- package/{src/module → module}/Predictor.js +9 -1
- package/package.json +17 -16
- package/benchmark/checklist_adje_100.json +0 -702
- package/benchmark/checklist_lemma_verb_100.json +0 -402
- package/benchmark/checklist_noun_100.json +0 -702
- package/benchmark/checklist_verb_100.json +0 -702
- package/benchmark/generate-checklists.js +0 -192
- package/benchmark/run-benchmark.js +0 -123
- package/dist/models/community/derive_form_model.int8.onnx +0 -0
- package/dist/models/community/derive_form_vocab.json +0 -74
- package/dist/models/community/lemma_type_labels.json +0 -47
- package/dist/models/community/lemma_type_model.int8.onnx +0 -0
- package/dist/models/community/lemma_type_vocab.json +0 -244
- package/scripts/build.js +0 -53
- package/src/frspell.browser.global.js +0 -9
- package/src/module/Predictor.browser.js +0 -428
- package/test/test.js +0 -21
- /package/{dist/frspell.browser.js → frspell.browser.js} +0 -0
- /package/{src/frspell.js → index.js} +0 -0
package/scripts/build.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { build } from 'esbuild';
|
|
4
|
-
|
|
5
|
-
const rootDir = path.resolve(process.cwd());
|
|
6
|
-
const distDir = path.join(rootDir, 'dist');
|
|
7
|
-
const distModelsDir = path.join(distDir, 'models', 'community');
|
|
8
|
-
const sourceModelsDir = path.join(rootDir, 'models', 'community');
|
|
9
|
-
|
|
10
|
-
async function cleanDist() {
|
|
11
|
-
await fs.rm(distDir, { recursive: true, force: true });
|
|
12
|
-
await fs.mkdir(distModelsDir, { recursive: true });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function bundleBrowserBuild() {
|
|
16
|
-
await build({
|
|
17
|
-
entryPoints: [path.join(rootDir, 'src', 'frspell.browser.global.js')],
|
|
18
|
-
bundle: true,
|
|
19
|
-
outfile: path.join(distDir, 'frspell.browser.js'),
|
|
20
|
-
format: 'iife',
|
|
21
|
-
platform: 'browser',
|
|
22
|
-
target: ['es2020'],
|
|
23
|
-
minify: false,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function copyModelAssets() {
|
|
28
|
-
const assetFiles = [
|
|
29
|
-
'lemma_type_model.int8.onnx',
|
|
30
|
-
'derive_form_model.int8.onnx',
|
|
31
|
-
'lemma_type_vocab.json',
|
|
32
|
-
'lemma_type_labels.json',
|
|
33
|
-
'derive_form_vocab.json',
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
await Promise.all(
|
|
37
|
-
assetFiles.map((name) =>
|
|
38
|
-
fs.copyFile(path.join(sourceModelsDir, name), path.join(distModelsDir, name)),
|
|
39
|
-
),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function main() {
|
|
44
|
-
await cleanDist();
|
|
45
|
-
await bundleBrowserBuild();
|
|
46
|
-
await copyModelAssets();
|
|
47
|
-
console.log('Build completed: dist/frspell.browser.js and model assets are ready.');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
main().catch((error) => {
|
|
51
|
-
console.error(error);
|
|
52
|
-
process.exitCode = 1;
|
|
53
|
-
});
|
|
@@ -1,428 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FR-SPELL browser predictor implementation
|
|
3
|
-
* Author: Davy Chen <davy.chen@163.com>
|
|
4
|
-
* Profile: https://www.linkedin.com/in/davychxn/
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import * as ort from 'onnxruntime-web';
|
|
8
|
-
|
|
9
|
-
function argmax(arr) {
|
|
10
|
-
let bestIdx = 0;
|
|
11
|
-
let bestVal = arr[0];
|
|
12
|
-
for (let i = 1; i < arr.length; i += 1) {
|
|
13
|
-
if (arr[i] > bestVal) {
|
|
14
|
-
bestVal = arr[i];
|
|
15
|
-
bestIdx = i;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return { index: bestIdx, value: bestVal };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function softmaxAt(logits, idx) {
|
|
22
|
-
let maxVal = -Infinity;
|
|
23
|
-
for (let i = 0; i < logits.length; i += 1) {
|
|
24
|
-
if (logits[i] > maxVal) maxVal = logits[i];
|
|
25
|
-
}
|
|
26
|
-
let sum = 0;
|
|
27
|
-
for (let i = 0; i < logits.length; i += 1) {
|
|
28
|
-
sum += Math.exp(logits[i] - maxVal);
|
|
29
|
-
}
|
|
30
|
-
return Math.exp(logits[idx] - maxVal) / sum;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function makeInt64Tensor2D(rows) {
|
|
34
|
-
const batch = rows.length;
|
|
35
|
-
const seq = rows[0].length;
|
|
36
|
-
const data = new BigInt64Array(batch * seq);
|
|
37
|
-
let k = 0;
|
|
38
|
-
for (let i = 0; i < batch; i += 1) {
|
|
39
|
-
for (let j = 0; j < seq; j += 1) {
|
|
40
|
-
data[k] = BigInt(rows[i][j]);
|
|
41
|
-
k += 1;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return new ort.Tensor('int64', data, [batch, seq]);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function makeInt64Tensor1D(values) {
|
|
48
|
-
const data = new BigInt64Array(values.length);
|
|
49
|
-
for (let i = 0; i < values.length; i += 1) {
|
|
50
|
-
data[i] = BigInt(values[i]);
|
|
51
|
-
}
|
|
52
|
-
return new ort.Tensor('int64', data, [values.length]);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function toStoi(itos) {
|
|
56
|
-
const stoi = {};
|
|
57
|
-
for (let i = 0; i < itos.length; i += 1) stoi[itos[i]] = i;
|
|
58
|
-
return stoi;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function decodeTextFromIds(ids, itos, specials) {
|
|
62
|
-
let out = '';
|
|
63
|
-
for (const id of ids) {
|
|
64
|
-
const tok = itos[id];
|
|
65
|
-
if (tok === specials.eos) break;
|
|
66
|
-
if (tok === specials.pad || tok === specials.bos || tok === specials.unk) continue;
|
|
67
|
-
out += tok;
|
|
68
|
-
}
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function normalizeEnumToken(value, fallback) {
|
|
73
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
74
|
-
return value.trim().toUpperCase();
|
|
75
|
-
}
|
|
76
|
-
return fallback;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function trimTrailingSlash(v) {
|
|
80
|
-
return String(v || '').replace(/\/+$/, '');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function resolveAssetPath(basePath, assetName) {
|
|
84
|
-
return `${trimTrailingSlash(basePath)}/${assetName}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function readJsonFromUrl(url) {
|
|
88
|
-
const response = await fetch(url);
|
|
89
|
-
if (!response.ok) {
|
|
90
|
-
throw new Error(`Failed to fetch JSON asset: ${url} (status ${response.status})`);
|
|
91
|
-
}
|
|
92
|
-
return response.json();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const DEFAULT_MODEL_BASE_PATH = './models/community';
|
|
96
|
-
|
|
97
|
-
function getDefaultModelPaths(modelBasePath = DEFAULT_MODEL_BASE_PATH) {
|
|
98
|
-
return {
|
|
99
|
-
lemmaModelPath: resolveAssetPath(modelBasePath, 'lemma_type_model.int8.onnx'),
|
|
100
|
-
lemmaVocabPath: resolveAssetPath(modelBasePath, 'lemma_type_vocab.json'),
|
|
101
|
-
lemmaLabelsPath: resolveAssetPath(modelBasePath, 'lemma_type_labels.json'),
|
|
102
|
-
derivativeModelPath: resolveAssetPath(modelBasePath, 'derive_form_model.int8.onnx'),
|
|
103
|
-
derivativeVocabPath: resolveAssetPath(modelBasePath, 'derive_form_vocab.json'),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export async function createLemmaTypePredictor({
|
|
108
|
-
modelPath,
|
|
109
|
-
vocabPath,
|
|
110
|
-
labelsPath,
|
|
111
|
-
maxDecodeLen,
|
|
112
|
-
executionProviders,
|
|
113
|
-
}) {
|
|
114
|
-
const [vocab, labels] = await Promise.all([
|
|
115
|
-
readJsonFromUrl(vocabPath),
|
|
116
|
-
readJsonFromUrl(labelsPath),
|
|
117
|
-
]);
|
|
118
|
-
|
|
119
|
-
const itos = vocab.itos;
|
|
120
|
-
const stoi = toStoi(itos);
|
|
121
|
-
|
|
122
|
-
const idToCode = {};
|
|
123
|
-
for (const [k, v] of Object.entries(vocab.id_to_code)) {
|
|
124
|
-
idToCode[Number(k)] = v;
|
|
125
|
-
}
|
|
126
|
-
const codeCharToName = labels.code_char_to_name || {};
|
|
127
|
-
|
|
128
|
-
const PAD = '<pad>';
|
|
129
|
-
const BOS = '<bos>';
|
|
130
|
-
const EOS = '<eos>';
|
|
131
|
-
const UNK = '<unk>';
|
|
132
|
-
|
|
133
|
-
const padId = stoi[PAD];
|
|
134
|
-
const bosId = stoi[BOS];
|
|
135
|
-
const eosId = stoi[EOS];
|
|
136
|
-
const unkId = stoi[UNK];
|
|
137
|
-
|
|
138
|
-
const session = await ort.InferenceSession.create(modelPath, {
|
|
139
|
-
executionProviders: executionProviders || ['wasm'],
|
|
140
|
-
graphOptimizationLevel: 'all',
|
|
141
|
-
});
|
|
142
|
-
const inputNameSet = new Set(session.inputNames);
|
|
143
|
-
|
|
144
|
-
const decodeLimit = maxDecodeLen || labels.max_decode_len || 32;
|
|
145
|
-
|
|
146
|
-
function encodeWord(word) {
|
|
147
|
-
const ids = [];
|
|
148
|
-
for (const ch of word) {
|
|
149
|
-
ids.push(stoi[ch] ?? unkId);
|
|
150
|
-
}
|
|
151
|
-
ids.push(eosId);
|
|
152
|
-
return ids;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const specials = {
|
|
156
|
-
pad: PAD,
|
|
157
|
-
bos: BOS,
|
|
158
|
-
eos: EOS,
|
|
159
|
-
unk: UNK,
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
async function predict(word) {
|
|
163
|
-
const t0 = performance.now();
|
|
164
|
-
const srcIds = encodeWord(word);
|
|
165
|
-
const srcTensor = makeInt64Tensor2D([srcIds]);
|
|
166
|
-
const srcLenTensor = makeInt64Tensor1D([srcIds.length]);
|
|
167
|
-
|
|
168
|
-
let tgt = [bosId];
|
|
169
|
-
let codeLogits = null;
|
|
170
|
-
const lemmaTokenIds = [];
|
|
171
|
-
|
|
172
|
-
for (let step = 0; step < decodeLimit; step += 1) {
|
|
173
|
-
const tgtTensor = makeInt64Tensor2D([tgt]);
|
|
174
|
-
const outputs = await session.run({
|
|
175
|
-
...(inputNameSet.has('src') ? { src: srcTensor } : {}),
|
|
176
|
-
...(inputNameSet.has('src_len') ? { src_len: srcLenTensor } : {}),
|
|
177
|
-
...(inputNameSet.has('tgt_in') ? { tgt_in: tgtTensor } : {}),
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
const token = outputs.token_logits;
|
|
181
|
-
const code = outputs.code_logits;
|
|
182
|
-
codeLogits = code.data;
|
|
183
|
-
|
|
184
|
-
// token_logits shape: [1, tgt_len, vocab_size]
|
|
185
|
-
const vocabSize = token.dims[2];
|
|
186
|
-
const tgtLen = tgt.length;
|
|
187
|
-
const lastOffset = (tgtLen - 1) * vocabSize;
|
|
188
|
-
const lastStep = token.data.slice(lastOffset, lastOffset + vocabSize);
|
|
189
|
-
const { index: nextId } = argmax(lastStep);
|
|
190
|
-
|
|
191
|
-
lemmaTokenIds.push(nextId);
|
|
192
|
-
if (nextId === eosId) break;
|
|
193
|
-
tgt.push(nextId);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const predLemma = decodeTextFromIds(lemmaTokenIds, itos, specials);
|
|
197
|
-
const codeBest = argmax(codeLogits);
|
|
198
|
-
const predCode = idToCode[codeBest.index] || 'A';
|
|
199
|
-
const codeConf = softmaxAt(codeLogits, codeBest.index);
|
|
200
|
-
const predType = codeCharToName[predCode] || 'UNKNOWN';
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
input: word,
|
|
204
|
-
lemma: predLemma,
|
|
205
|
-
wordType: predType,
|
|
206
|
-
confidence: codeConf,
|
|
207
|
-
timeMs: performance.now() - t0,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async function lemma(word) {
|
|
212
|
-
return predict(word);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async function predictBatch(words) {
|
|
216
|
-
const out = [];
|
|
217
|
-
for (const w of words) {
|
|
218
|
-
// Keep sequential to keep implementation simple and deterministic.
|
|
219
|
-
out.push(await predict(w));
|
|
220
|
-
}
|
|
221
|
-
return out;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return {
|
|
225
|
-
predict,
|
|
226
|
-
lemma,
|
|
227
|
-
predictBatch,
|
|
228
|
-
metadata: {
|
|
229
|
-
modelPath,
|
|
230
|
-
vocabSize: itos.length,
|
|
231
|
-
decodeLimit,
|
|
232
|
-
},
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export async function createDerivativeTypePredictor({
|
|
237
|
-
modelPath,
|
|
238
|
-
vocabPath,
|
|
239
|
-
maxDecodeLen,
|
|
240
|
-
executionProviders,
|
|
241
|
-
}) {
|
|
242
|
-
const vocab = await readJsonFromUrl(vocabPath);
|
|
243
|
-
const itos = vocab.itos;
|
|
244
|
-
const stoi = toStoi(itos);
|
|
245
|
-
|
|
246
|
-
const PAD = '<pad>';
|
|
247
|
-
const BOS = '<bos>';
|
|
248
|
-
const EOS = '<eos>';
|
|
249
|
-
const UNK = '<unk>';
|
|
250
|
-
|
|
251
|
-
const padId = stoi[PAD];
|
|
252
|
-
const bosId = stoi[BOS];
|
|
253
|
-
const eosId = stoi[EOS];
|
|
254
|
-
const unkId = stoi[UNK];
|
|
255
|
-
|
|
256
|
-
if (padId === undefined || bosId === undefined || eosId === undefined || unkId === undefined) {
|
|
257
|
-
throw new Error('Invalid derive vocab: missing special tokens <pad>/<bos>/<eos>/<unk>.');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const session = await ort.InferenceSession.create(modelPath, {
|
|
261
|
-
executionProviders: executionProviders || ['wasm'],
|
|
262
|
-
graphOptimizationLevel: 'all',
|
|
263
|
-
});
|
|
264
|
-
const inputNameSet = new Set(session.inputNames);
|
|
265
|
-
const outputTokenName = session.outputNames.includes('token_logits')
|
|
266
|
-
? 'token_logits'
|
|
267
|
-
: session.outputNames[0];
|
|
268
|
-
|
|
269
|
-
const decodeLimit = maxDecodeLen || 48;
|
|
270
|
-
const specials = {
|
|
271
|
-
pad: PAD,
|
|
272
|
-
bos: BOS,
|
|
273
|
-
eos: EOS,
|
|
274
|
-
unk: UNK,
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
function encodeText(text, addBos = false, addEos = false) {
|
|
278
|
-
const ids = [];
|
|
279
|
-
if (addBos) ids.push(bosId);
|
|
280
|
-
for (const ch of text) ids.push(stoi[ch] ?? unkId);
|
|
281
|
-
if (addEos) ids.push(eosId);
|
|
282
|
-
return ids;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function buildSourceText(lemma, wordType, person, mode, tense) {
|
|
286
|
-
return `L:${lemma}|W:${wordType}|P:${person}|M:${mode}|T:${tense}`;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async function predict(lemma, wordType, sentencePerson, sentenceMode, sentenceTense) {
|
|
290
|
-
const t0 = performance.now();
|
|
291
|
-
const normalizedLemma = String(lemma || '').trim();
|
|
292
|
-
const normalizedWordType = normalizeEnumToken(wordType, 'NONE');
|
|
293
|
-
const normalizedPerson = normalizeEnumToken(sentencePerson, 'ALL');
|
|
294
|
-
const isNounOrAdje = normalizedWordType === 'NOUN' || normalizedWordType === 'ADJE';
|
|
295
|
-
const normalizedMode = isNounOrAdje
|
|
296
|
-
? normalizeEnumToken(sentenceMode, 'ALL')
|
|
297
|
-
: normalizeEnumToken(sentenceMode, 'NONE');
|
|
298
|
-
const normalizedTense = isNounOrAdje
|
|
299
|
-
? normalizeEnumToken(sentenceTense, 'ALL')
|
|
300
|
-
: normalizeEnumToken(sentenceTense, 'NONE');
|
|
301
|
-
|
|
302
|
-
const source = buildSourceText(
|
|
303
|
-
normalizedLemma,
|
|
304
|
-
normalizedWordType,
|
|
305
|
-
normalizedPerson,
|
|
306
|
-
normalizedMode,
|
|
307
|
-
normalizedTense,
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
const srcIds = encodeText(source, false, true);
|
|
311
|
-
const srcTensor = makeInt64Tensor2D([srcIds]);
|
|
312
|
-
const srcLenTensor = makeInt64Tensor1D([srcIds.length]);
|
|
313
|
-
|
|
314
|
-
const tokenIds = [];
|
|
315
|
-
let lastStepLogits = null;
|
|
316
|
-
let tgt = [bosId];
|
|
317
|
-
|
|
318
|
-
for (let step = 0; step < decodeLimit; step += 1) {
|
|
319
|
-
const tgtTensor = makeInt64Tensor2D([tgt]);
|
|
320
|
-
const outputs = await session.run({
|
|
321
|
-
...(inputNameSet.has('src') ? { src: srcTensor } : {}),
|
|
322
|
-
...(inputNameSet.has('src_len') ? { src_len: srcLenTensor } : {}),
|
|
323
|
-
...(inputNameSet.has('tgt_in') ? { tgt_in: tgtTensor } : {}),
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
const token = outputs[outputTokenName];
|
|
327
|
-
const vocabSize = token.dims[2];
|
|
328
|
-
const tgtLen = tgt.length;
|
|
329
|
-
const lastOffset = (tgtLen - 1) * vocabSize;
|
|
330
|
-
lastStepLogits = token.data.slice(lastOffset, lastOffset + vocabSize);
|
|
331
|
-
const { index: nextId } = argmax(lastStepLogits);
|
|
332
|
-
|
|
333
|
-
tokenIds.push(nextId);
|
|
334
|
-
if (nextId === eosId) break;
|
|
335
|
-
tgt.push(nextId);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const form = decodeTextFromIds(tokenIds, itos, specials);
|
|
339
|
-
const bestId = argmax(lastStepLogits).index;
|
|
340
|
-
const confidence = softmaxAt(lastStepLogits, bestId);
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
lemma: normalizedLemma,
|
|
344
|
-
wordType: normalizedWordType,
|
|
345
|
-
person: normalizedPerson,
|
|
346
|
-
mode: normalizedMode,
|
|
347
|
-
tense: normalizedTense,
|
|
348
|
-
output: form,
|
|
349
|
-
confidence,
|
|
350
|
-
timeMs: performance.now() - t0,
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async function nounDerive(lemma, sentencePerson, sentenceMode, sentenceTense) {
|
|
355
|
-
return predict(lemma, 'NOUN', sentencePerson, sentenceMode, sentenceTense);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
async function adjeDerive(lemma, sentencePerson, sentenceMode, sentenceTense) {
|
|
359
|
-
return predict(lemma, 'ADJE', sentencePerson, sentenceMode, sentenceTense);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async function verbDerive(lemma, sentencePerson, sentenceMode, sentenceTense) {
|
|
363
|
-
return predict(lemma, 'VERB', sentencePerson, sentenceMode, sentenceTense);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
predict,
|
|
368
|
-
derive: predict,
|
|
369
|
-
nounDerive,
|
|
370
|
-
adjeDerive,
|
|
371
|
-
verbDerive,
|
|
372
|
-
metadata: {
|
|
373
|
-
modelPath,
|
|
374
|
-
vocabSize: itos.length,
|
|
375
|
-
decodeLimit,
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
export async function FrSpell(options = {}) {
|
|
381
|
-
const {
|
|
382
|
-
modelBasePath = DEFAULT_MODEL_BASE_PATH,
|
|
383
|
-
lemmaMaxDecodeLen,
|
|
384
|
-
derivativeMaxDecodeLen,
|
|
385
|
-
executionProviders,
|
|
386
|
-
wasmPaths = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/',
|
|
387
|
-
} = options;
|
|
388
|
-
|
|
389
|
-
const defaultPaths = getDefaultModelPaths(modelBasePath);
|
|
390
|
-
|
|
391
|
-
const lemmaModelPath = options.lemmaModelPath || defaultPaths.lemmaModelPath;
|
|
392
|
-
const lemmaVocabPath = options.lemmaVocabPath || defaultPaths.lemmaVocabPath;
|
|
393
|
-
const lemmaLabelsPath = options.lemmaLabelsPath || defaultPaths.lemmaLabelsPath;
|
|
394
|
-
const derivativeModelPath = options.derivativeModelPath || defaultPaths.derivativeModelPath;
|
|
395
|
-
const derivativeVocabPath = options.derivativeVocabPath || defaultPaths.derivativeVocabPath;
|
|
396
|
-
|
|
397
|
-
if (wasmPaths && ort.env && ort.env.wasm) {
|
|
398
|
-
ort.env.wasm.wasmPaths = wasmPaths;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const [lemmaPredictor, derivativePredictor] = await Promise.all([
|
|
402
|
-
createLemmaTypePredictor({
|
|
403
|
-
modelPath: lemmaModelPath,
|
|
404
|
-
vocabPath: lemmaVocabPath,
|
|
405
|
-
labelsPath: lemmaLabelsPath,
|
|
406
|
-
maxDecodeLen: lemmaMaxDecodeLen,
|
|
407
|
-
executionProviders,
|
|
408
|
-
}),
|
|
409
|
-
createDerivativeTypePredictor({
|
|
410
|
-
modelPath: derivativeModelPath,
|
|
411
|
-
vocabPath: derivativeVocabPath,
|
|
412
|
-
maxDecodeLen: derivativeMaxDecodeLen,
|
|
413
|
-
executionProviders,
|
|
414
|
-
}),
|
|
415
|
-
]);
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
lemma: lemmaPredictor.lemma,
|
|
419
|
-
derive: derivativePredictor.derive,
|
|
420
|
-
nounDerive: derivativePredictor.nounDerive,
|
|
421
|
-
adjeDerive: derivativePredictor.adjeDerive,
|
|
422
|
-
verbDerive: derivativePredictor.verbDerive,
|
|
423
|
-
metadata: {
|
|
424
|
-
lemma: lemmaPredictor.metadata,
|
|
425
|
-
derivative: derivativePredictor.metadata,
|
|
426
|
-
},
|
|
427
|
-
};
|
|
428
|
-
}
|
package/test/test.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { FrSpell } from '../src/frspell.js';
|
|
2
|
-
|
|
3
|
-
const predictor = await FrSpell();
|
|
4
|
-
|
|
5
|
-
const lemmaResult = await predictor.lemma('mangeons');
|
|
6
|
-
const nounResult = await predictor.nounDerive('chat', 'THD_PLF');
|
|
7
|
-
const adjeResult = await predictor.adjeDerive('beau', 'THD_F');
|
|
8
|
-
const verbResult1 = await predictor.verbDerive('manger', 'FST_PL', 'INDI', 'PRES');
|
|
9
|
-
const verbResult2 = await predictor.verbDerive('manger', 'SND_PL', 'INDI', 'FUTU');
|
|
10
|
-
const verbResult3 = await predictor.verbDerive('manger', 'FST_PL', 'INDI', 'PASS');
|
|
11
|
-
const verbResult4 = await predictor.verbDerive('manger', 'SND', 'SUBJ', 'PRES');
|
|
12
|
-
const verbResult5 = await predictor.verbDerive('manger', 'THD_PLF', 'PART', 'PASS');
|
|
13
|
-
|
|
14
|
-
console.log(lemmaResult);
|
|
15
|
-
console.log(nounResult);
|
|
16
|
-
console.log(adjeResult);
|
|
17
|
-
console.log(verbResult1);
|
|
18
|
-
console.log(verbResult2);
|
|
19
|
-
console.log(verbResult3);
|
|
20
|
-
console.log(verbResult4);
|
|
21
|
-
console.log(verbResult5);
|
|
File without changes
|
|
File without changes
|