n8n-nodes-fasttext-language-detector 0.1.1 → 0.1.5
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.
|
@@ -195,9 +195,40 @@ class FastTextLanguageDetector {
|
|
|
195
195
|
}
|
|
196
196
|
// Динамически загружаем fasttext.js только когда он нужен
|
|
197
197
|
// Это предотвращает загрузку WASM при старте n8n
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
// Используем require для CommonJS модуля, обернутый в Promise
|
|
199
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
|
|
200
|
+
const fastTextModule = await new Promise((resolve, reject) => {
|
|
201
|
+
try {
|
|
202
|
+
// Используем require для загрузки CommonJS модуля
|
|
203
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
204
|
+
const FastText = require('fasttext.js');
|
|
205
|
+
resolve(FastText);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
reject(error);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
// fasttext.js экспортирует класс FastText напрямую
|
|
212
|
+
const FastTextClass = fastTextModule ||
|
|
213
|
+
fastTextModule.default ||
|
|
214
|
+
(fastTextModule.default && fastTextModule.default.default);
|
|
215
|
+
if (!FastTextClass || typeof FastTextClass !== 'function') {
|
|
216
|
+
const availableExports = Object.keys(fastTextModule).join(', ');
|
|
217
|
+
throw new n8n_workflow_1.ApplicationError(`Failed to load fastText module: FastText class not found. Available exports: ${availableExports}`, { level: 'error' });
|
|
218
|
+
}
|
|
219
|
+
// Создаем экземпляр FastText с путем к модели
|
|
220
|
+
const fastTextInstance = new FastTextClass({
|
|
221
|
+
loadModel: modelPath,
|
|
222
|
+
predict: {
|
|
223
|
+
mostlikely: topK,
|
|
224
|
+
verbosity: 0,
|
|
225
|
+
normalize: false
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
// Загружаем модель
|
|
229
|
+
await fastTextInstance.load();
|
|
230
|
+
model = fastTextInstance;
|
|
231
|
+
FastTextLanguageDetector.modelCache.set(modelPath, fastTextInstance);
|
|
201
232
|
}
|
|
202
233
|
}
|
|
203
234
|
catch (error) {
|
|
@@ -243,19 +274,48 @@ class FastTextLanguageDetector {
|
|
|
243
274
|
throw new n8n_workflow_1.ApplicationError('Model not initialized', { level: 'error' });
|
|
244
275
|
}
|
|
245
276
|
// Определяем язык
|
|
246
|
-
|
|
277
|
+
// fasttext.js возвращает массив массивов [label, probability] или массив объектов
|
|
278
|
+
const predictionsRaw = await model.predict(processedText);
|
|
279
|
+
if (!Array.isArray(predictionsRaw) || predictionsRaw.length === 0) {
|
|
280
|
+
throw new n8n_workflow_1.ApplicationError('No predictions returned from fastText model', { level: 'error' });
|
|
281
|
+
}
|
|
282
|
+
// Преобразуем формат ответа fasttext.js в наш формат
|
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
284
|
+
const predictions = predictionsRaw.map((pred) => {
|
|
285
|
+
// fasttext.js возвращает либо [label, value], либо объект
|
|
286
|
+
let label;
|
|
287
|
+
let probability;
|
|
288
|
+
if (Array.isArray(pred)) {
|
|
289
|
+
label = String(pred[0] || '');
|
|
290
|
+
probability = Number(pred[1] || 0);
|
|
291
|
+
}
|
|
292
|
+
else if (pred && typeof pred === 'object') {
|
|
293
|
+
label = String(pred.label || pred[0] || '');
|
|
294
|
+
probability = Number(pred.value || pred.probability || pred[1] || 0);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
label = String(pred || '');
|
|
298
|
+
probability = 0;
|
|
299
|
+
}
|
|
300
|
+
// Убираем префикс __label__ если есть
|
|
301
|
+
const cleanLabel = label.replace(/^__label__/, '');
|
|
302
|
+
return {
|
|
303
|
+
label: cleanLabel,
|
|
304
|
+
probability: probability
|
|
305
|
+
};
|
|
306
|
+
});
|
|
247
307
|
// Фильтруем по порогу уверенности
|
|
248
308
|
const filteredPredictions = predictions.filter((pred) => pred.probability >= confidenceThreshold);
|
|
249
309
|
if (filteredPredictions.length === 0) {
|
|
250
310
|
// Если нет предсказаний выше порога, возвращаем лучшее
|
|
251
311
|
const result = {
|
|
252
312
|
...json,
|
|
253
|
-
[outputField]: predictions[0]?.label
|
|
313
|
+
[outputField]: predictions[0]?.label || 'unknown',
|
|
254
314
|
};
|
|
255
315
|
if (includeConfidence) {
|
|
256
316
|
result[`${outputField}Confidence`] = predictions[0]?.probability || 0;
|
|
257
317
|
result[`${outputField}All`] = predictions.map((p) => ({
|
|
258
|
-
language: p.label
|
|
318
|
+
language: p.label || 'unknown',
|
|
259
319
|
confidence: p.probability || 0,
|
|
260
320
|
}));
|
|
261
321
|
}
|
|
@@ -266,7 +326,7 @@ class FastTextLanguageDetector {
|
|
|
266
326
|
const topPrediction = filteredPredictions[0];
|
|
267
327
|
const result = {
|
|
268
328
|
...json,
|
|
269
|
-
[outputField]: topPrediction.label
|
|
329
|
+
[outputField]: topPrediction.label || 'unknown',
|
|
270
330
|
};
|
|
271
331
|
if (includeConfidence) {
|
|
272
332
|
result[`${outputField}Confidence`] = topPrediction.probability || 0;
|