n8n-nodes-fasttext-language-detector 0.1.4 → 0.1.6

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,31 +195,50 @@ class FastTextLanguageDetector {
195
195
  }
196
196
  // Динамически загружаем fasttext.js только когда он нужен
197
197
  // Это предотвращает загрузку WASM при старте n8n
198
- // Используем require для CommonJS модуля, обернутый в Promise
198
+ // ВАЖНО: используем прямой путь к lib/index.js, чтобы избежать автоматической загрузки WASM
199
199
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
200
200
  const fastTextModule = await new Promise((resolve, reject) => {
201
201
  try {
202
- // Используем require для загрузки CommonJS модуля
202
+ // Используем прямой путь к index.js, минуя автоматическую загрузку WASM
203
203
  // eslint-disable-next-line @typescript-eslint/no-var-requires
204
- const fastText = require('fasttext.js');
205
- resolve(fastText);
204
+ const FastText = require('fasttext.js/lib/index');
205
+ resolve(FastText);
206
206
  }
207
207
  catch (error) {
208
- reject(error);
208
+ // Если прямой путь не работает, пробуем обычный require
209
+ try {
210
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
211
+ const FastText = require('fasttext.js');
212
+ resolve(FastText);
213
+ }
214
+ catch (fallbackError) {
215
+ reject(fallbackError);
216
+ }
209
217
  }
210
218
  });
211
- // Обрабатываем разные варианты экспорта (CommonJS/ESM)
212
- // fasttext.js может экспортировать через default или напрямую
213
- const FastTextClassifier = fastTextModule.Classifier ||
214
- (fastTextModule.default && fastTextModule.default.Classifier) ||
215
- fastTextModule.default;
216
- if (!FastTextClassifier || typeof FastTextClassifier !== 'function') {
219
+ // fasttext.js экспортирует класс FastText напрямую
220
+ const FastTextClass = fastTextModule ||
221
+ fastTextModule.default ||
222
+ (fastTextModule.default && fastTextModule.default.default);
223
+ if (!FastTextClass || typeof FastTextClass !== 'function') {
217
224
  const availableExports = Object.keys(fastTextModule).join(', ');
218
- throw new n8n_workflow_1.ApplicationError(`Failed to load fastText module: Classifier not found. Available exports: ${availableExports}`, { level: 'error' });
225
+ throw new n8n_workflow_1.ApplicationError(`Failed to load fastText module: FastText class not found. Available exports: ${availableExports}`, { level: 'error' });
219
226
  }
220
- const loadedModel = new FastTextClassifier(modelPath);
221
- model = loadedModel;
222
- FastTextLanguageDetector.modelCache.set(modelPath, loadedModel);
227
+ // Создаем экземпляр FastText с путем к модели
228
+ // ВАЖНО: явно отключаем WASM, используем бинарный режим
229
+ const fastTextInstance = new FastTextClass({
230
+ loadModel: modelPath,
231
+ predict: {
232
+ wasm: false, // КРИТИЧНО: отключаем WASM, используем бинарный файл
233
+ mostlikely: topK,
234
+ verbosity: 0,
235
+ normalize: false
236
+ }
237
+ });
238
+ // Загружаем модель
239
+ await fastTextInstance.load();
240
+ model = fastTextInstance;
241
+ FastTextLanguageDetector.modelCache.set(modelPath, fastTextInstance);
223
242
  }
224
243
  }
225
244
  catch (error) {
@@ -265,19 +284,48 @@ class FastTextLanguageDetector {
265
284
  throw new n8n_workflow_1.ApplicationError('Model not initialized', { level: 'error' });
266
285
  }
267
286
  // Определяем язык
268
- const predictions = await model.predict(processedText, topK);
287
+ // fasttext.js возвращает массив массивов [label, probability] или массив объектов
288
+ const predictionsRaw = await model.predict(processedText);
289
+ if (!Array.isArray(predictionsRaw) || predictionsRaw.length === 0) {
290
+ throw new n8n_workflow_1.ApplicationError('No predictions returned from fastText model', { level: 'error' });
291
+ }
292
+ // Преобразуем формат ответа fasttext.js в наш формат
293
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
294
+ const predictions = predictionsRaw.map((pred) => {
295
+ // fasttext.js возвращает либо [label, value], либо объект
296
+ let label;
297
+ let probability;
298
+ if (Array.isArray(pred)) {
299
+ label = String(pred[0] || '');
300
+ probability = Number(pred[1] || 0);
301
+ }
302
+ else if (pred && typeof pred === 'object') {
303
+ label = String(pred.label || pred[0] || '');
304
+ probability = Number(pred.value || pred.probability || pred[1] || 0);
305
+ }
306
+ else {
307
+ label = String(pred || '');
308
+ probability = 0;
309
+ }
310
+ // Убираем префикс __label__ если есть
311
+ const cleanLabel = label.replace(/^__label__/, '');
312
+ return {
313
+ label: cleanLabel,
314
+ probability: probability
315
+ };
316
+ });
269
317
  // Фильтруем по порогу уверенности
270
318
  const filteredPredictions = predictions.filter((pred) => pred.probability >= confidenceThreshold);
271
319
  if (filteredPredictions.length === 0) {
272
320
  // Если нет предсказаний выше порога, возвращаем лучшее
273
321
  const result = {
274
322
  ...json,
275
- [outputField]: predictions[0]?.label?.replace('__label__', '') || 'unknown',
323
+ [outputField]: predictions[0]?.label || 'unknown',
276
324
  };
277
325
  if (includeConfidence) {
278
326
  result[`${outputField}Confidence`] = predictions[0]?.probability || 0;
279
327
  result[`${outputField}All`] = predictions.map((p) => ({
280
- language: p.label?.replace('__label__', '') || 'unknown',
328
+ language: p.label || 'unknown',
281
329
  confidence: p.probability || 0,
282
330
  }));
283
331
  }
@@ -288,7 +336,7 @@ class FastTextLanguageDetector {
288
336
  const topPrediction = filteredPredictions[0];
289
337
  const result = {
290
338
  ...json,
291
- [outputField]: topPrediction.label?.replace('__label__', '') || 'unknown',
339
+ [outputField]: topPrediction.label || 'unknown',
292
340
  };
293
341
  if (includeConfidence) {
294
342
  result[`${outputField}Confidence`] = topPrediction.probability || 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-fasttext-language-detector",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "n8n node for language detection using fastText",
5
5
  "author": {
6
6
  "name": "Your Name",