glin-profanity 3.2.0 → 3.2.2
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/dist/{types-Dj5vaoch.d.cts → Filter-BGcyIAvO.d.ts} +2 -162
- package/dist/{types-Dj5vaoch.d.ts → Filter-D34Wsmrj.d.cts} +2 -162
- package/dist/frameworks/index.cjs +5257 -0
- package/dist/frameworks/index.d.cts +2 -0
- package/dist/frameworks/index.d.ts +2 -0
- package/dist/frameworks/index.js +5252 -0
- package/dist/frameworks/nextjs.cjs +5257 -0
- package/dist/frameworks/nextjs.d.cts +173 -0
- package/dist/frameworks/nextjs.d.ts +173 -0
- package/dist/frameworks/nextjs.js +5252 -0
- package/dist/index.cjs +0 -28
- package/dist/index.d.cts +5 -29
- package/dist/index.d.ts +5 -29
- package/dist/index.js +1 -28
- package/dist/integrations/index.cjs +6110 -0
- package/dist/integrations/index.d.cts +5 -0
- package/dist/integrations/index.d.ts +5 -0
- package/dist/integrations/index.js +6082 -0
- package/dist/integrations/langchain.cjs +5252 -0
- package/dist/integrations/langchain.d.cts +231 -0
- package/dist/integrations/langchain.d.ts +231 -0
- package/dist/integrations/langchain.js +5239 -0
- package/dist/integrations/openai.cjs +5367 -0
- package/dist/integrations/openai.d.cts +167 -0
- package/dist/integrations/openai.d.ts +167 -0
- package/dist/integrations/openai.js +5362 -0
- package/dist/integrations/semantic.cjs +5314 -0
- package/dist/integrations/semantic.d.cts +268 -0
- package/dist/integrations/semantic.d.ts +268 -0
- package/dist/integrations/semantic.js +5309 -0
- package/dist/integrations/vercel-ai.cjs +5282 -0
- package/dist/integrations/vercel-ai.d.cts +224 -0
- package/dist/integrations/vercel-ai.d.ts +224 -0
- package/dist/integrations/vercel-ai.js +5273 -0
- package/dist/ml/index.cjs +207 -0
- package/dist/ml/index.d.cts +5 -2
- package/dist/ml/index.d.ts +5 -2
- package/dist/ml/index.js +203 -1
- package/dist/ml/transformers.cjs +5237 -0
- package/dist/ml/transformers.d.cts +232 -0
- package/dist/ml/transformers.d.ts +232 -0
- package/dist/ml/transformers.js +5231 -0
- package/dist/multimodal/audio.cjs +5269 -0
- package/dist/multimodal/audio.d.cts +255 -0
- package/dist/multimodal/audio.d.ts +255 -0
- package/dist/multimodal/audio.js +5264 -0
- package/dist/multimodal/index.cjs +5432 -0
- package/dist/multimodal/index.d.cts +4 -0
- package/dist/multimodal/index.d.ts +4 -0
- package/dist/multimodal/index.js +5422 -0
- package/dist/multimodal/ocr.cjs +5193 -0
- package/dist/multimodal/ocr.d.cts +157 -0
- package/dist/multimodal/ocr.d.ts +157 -0
- package/dist/multimodal/ocr.js +5187 -0
- package/dist/react.cjs +5133 -0
- package/dist/react.d.cts +13 -0
- package/dist/react.d.ts +13 -0
- package/dist/react.js +5131 -0
- package/dist/types-B9c_ik4k.d.cts +88 -0
- package/dist/types-B9c_ik4k.d.ts +88 -0
- package/dist/types-BuKh9tvV.d.ts +20 -0
- package/dist/types-Ct_ueYqw.d.cts +76 -0
- package/dist/types-Ct_ueYqw.d.ts +76 -0
- package/dist/types-DI8nzwWc.d.cts +20 -0
- package/package.json +170 -3
package/dist/ml/index.cjs
CHANGED
|
@@ -5578,5 +5578,212 @@ var HybridFilter = class {
|
|
|
5578
5578
|
}
|
|
5579
5579
|
};
|
|
5580
5580
|
|
|
5581
|
+
// src/ml/transformers.ts
|
|
5582
|
+
var RECOMMENDED_MODELS = {
|
|
5583
|
+
/** High accuracy English model (97.5%) - 67M params */
|
|
5584
|
+
pardonmyai: "tarekziade/pardonmyai",
|
|
5585
|
+
/** Smaller version for constrained environments */
|
|
5586
|
+
pardonmyaiTiny: "tarekziade/pardonmyai-tiny",
|
|
5587
|
+
/** Multilingual toxicity detection (7 languages) */
|
|
5588
|
+
toxicBert: "unitary/toxic-bert",
|
|
5589
|
+
/** Offensive speech detector (DeBERTa-based) */
|
|
5590
|
+
offensiveSpeech: "KoalaAI/OffensiveSpeechDetector"
|
|
5591
|
+
};
|
|
5592
|
+
var MODEL_PROFANE_LABELS = {
|
|
5593
|
+
"tarekziade/pardonmyai": "profane",
|
|
5594
|
+
"tarekziade/pardonmyai-tiny": "profane",
|
|
5595
|
+
"unitary/toxic-bert": "toxic",
|
|
5596
|
+
"KoalaAI/OffensiveSpeechDetector": "LABEL_1",
|
|
5597
|
+
// Offensive
|
|
5598
|
+
default: "LABEL_1"
|
|
5599
|
+
};
|
|
5600
|
+
async function getTransformers() {
|
|
5601
|
+
try {
|
|
5602
|
+
const transformers = await import('@xenova/transformers');
|
|
5603
|
+
return transformers;
|
|
5604
|
+
} catch {
|
|
5605
|
+
throw new Error(
|
|
5606
|
+
"Transformers.js is required for ML features. Install it with: npm install @xenova/transformers"
|
|
5607
|
+
);
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
async function createMLChecker(config = {}) {
|
|
5611
|
+
const {
|
|
5612
|
+
model = RECOMMENDED_MODELS.pardonmyai,
|
|
5613
|
+
threshold = 0.5,
|
|
5614
|
+
profaneLabel = MODEL_PROFANE_LABELS[model] || MODEL_PROFANE_LABELS.default,
|
|
5615
|
+
quantized = true,
|
|
5616
|
+
device = "cpu"
|
|
5617
|
+
} = config;
|
|
5618
|
+
const transformers = await getTransformers();
|
|
5619
|
+
const classifier = await transformers.pipeline("text-classification", model, {
|
|
5620
|
+
quantized,
|
|
5621
|
+
device
|
|
5622
|
+
});
|
|
5623
|
+
return {
|
|
5624
|
+
/**
|
|
5625
|
+
* Check a single text for profanity
|
|
5626
|
+
*/
|
|
5627
|
+
async check(text) {
|
|
5628
|
+
const startTime = Date.now();
|
|
5629
|
+
const output = await classifier(text);
|
|
5630
|
+
const processingTimeMs = Date.now() - startTime;
|
|
5631
|
+
const profaneScore = output.find((o) => o.label === profaneLabel)?.score || 0;
|
|
5632
|
+
const containsProfanity = profaneScore >= threshold;
|
|
5633
|
+
return {
|
|
5634
|
+
containsProfanity,
|
|
5635
|
+
confidence: profaneScore,
|
|
5636
|
+
rawOutput: output,
|
|
5637
|
+
processingTimeMs
|
|
5638
|
+
};
|
|
5639
|
+
},
|
|
5640
|
+
/**
|
|
5641
|
+
* Check multiple texts
|
|
5642
|
+
*/
|
|
5643
|
+
async checkBatch(texts) {
|
|
5644
|
+
return Promise.all(texts.map((text) => this.check(text)));
|
|
5645
|
+
},
|
|
5646
|
+
/**
|
|
5647
|
+
* Get the profanity score for text (0-1)
|
|
5648
|
+
*/
|
|
5649
|
+
async getScore(text) {
|
|
5650
|
+
const result = await this.check(text);
|
|
5651
|
+
return result.confidence;
|
|
5652
|
+
},
|
|
5653
|
+
/**
|
|
5654
|
+
* Get current configuration
|
|
5655
|
+
*/
|
|
5656
|
+
getConfig() {
|
|
5657
|
+
return { model, threshold, profaneLabel, quantized, device };
|
|
5658
|
+
},
|
|
5659
|
+
/**
|
|
5660
|
+
* Dispose of the model (free memory)
|
|
5661
|
+
*/
|
|
5662
|
+
dispose() {
|
|
5663
|
+
}
|
|
5664
|
+
};
|
|
5665
|
+
}
|
|
5666
|
+
async function createHybridChecker(config = {}) {
|
|
5667
|
+
const {
|
|
5668
|
+
model = RECOMMENDED_MODELS.pardonmyai,
|
|
5669
|
+
threshold = 0.5,
|
|
5670
|
+
profaneLabel,
|
|
5671
|
+
quantized = true,
|
|
5672
|
+
device = "cpu",
|
|
5673
|
+
filterConfig = {},
|
|
5674
|
+
mlThreshold = 0.3,
|
|
5675
|
+
dictionaryWeight = 0.6,
|
|
5676
|
+
mlWeight = 0.4
|
|
5677
|
+
} = config;
|
|
5678
|
+
const filter = new Filter({
|
|
5679
|
+
languages: filterConfig.languages || ["english"],
|
|
5680
|
+
detectLeetspeak: filterConfig.detectLeetspeak ?? true,
|
|
5681
|
+
normalizeUnicode: filterConfig.normalizeUnicode ?? true,
|
|
5682
|
+
severityLevels: true,
|
|
5683
|
+
cacheResults: true,
|
|
5684
|
+
...filterConfig
|
|
5685
|
+
});
|
|
5686
|
+
let mlChecker = null;
|
|
5687
|
+
async function getMLChecker() {
|
|
5688
|
+
if (!mlChecker) {
|
|
5689
|
+
mlChecker = await createMLChecker({
|
|
5690
|
+
model,
|
|
5691
|
+
threshold,
|
|
5692
|
+
profaneLabel,
|
|
5693
|
+
quantized,
|
|
5694
|
+
device
|
|
5695
|
+
});
|
|
5696
|
+
}
|
|
5697
|
+
return mlChecker;
|
|
5698
|
+
}
|
|
5699
|
+
return {
|
|
5700
|
+
/**
|
|
5701
|
+
* Check text using hybrid approach
|
|
5702
|
+
*/
|
|
5703
|
+
async check(text) {
|
|
5704
|
+
const startTime = Date.now();
|
|
5705
|
+
const dictionaryResult = filter.checkProfanity(text);
|
|
5706
|
+
if (dictionaryResult.containsProfanity) {
|
|
5707
|
+
return {
|
|
5708
|
+
containsProfanity: true,
|
|
5709
|
+
confidence: 1,
|
|
5710
|
+
dictionaryResult,
|
|
5711
|
+
usedML: false,
|
|
5712
|
+
profaneWords: dictionaryResult.profaneWords,
|
|
5713
|
+
processingTimeMs: Date.now() - startTime
|
|
5714
|
+
};
|
|
5715
|
+
}
|
|
5716
|
+
const ml = await getMLChecker();
|
|
5717
|
+
const mlResult = await ml.check(text);
|
|
5718
|
+
const dictionaryScore = dictionaryResult.containsProfanity ? 1 : 0;
|
|
5719
|
+
const combinedScore = dictionaryScore * dictionaryWeight + mlResult.confidence * mlWeight;
|
|
5720
|
+
const containsProfanity = combinedScore >= mlThreshold;
|
|
5721
|
+
return {
|
|
5722
|
+
containsProfanity,
|
|
5723
|
+
confidence: combinedScore,
|
|
5724
|
+
dictionaryResult,
|
|
5725
|
+
mlResult,
|
|
5726
|
+
usedML: true,
|
|
5727
|
+
profaneWords: dictionaryResult.profaneWords,
|
|
5728
|
+
processingTimeMs: Date.now() - startTime
|
|
5729
|
+
};
|
|
5730
|
+
},
|
|
5731
|
+
/**
|
|
5732
|
+
* Check multiple texts
|
|
5733
|
+
*/
|
|
5734
|
+
async checkBatch(texts) {
|
|
5735
|
+
return Promise.all(texts.map((text) => this.check(text)));
|
|
5736
|
+
},
|
|
5737
|
+
/**
|
|
5738
|
+
* Dictionary-only check (fast, no ML)
|
|
5739
|
+
*/
|
|
5740
|
+
checkFast(text) {
|
|
5741
|
+
return filter.checkProfanity(text);
|
|
5742
|
+
},
|
|
5743
|
+
/**
|
|
5744
|
+
* ML-only check (slower, more accurate)
|
|
5745
|
+
*/
|
|
5746
|
+
async checkML(text) {
|
|
5747
|
+
const ml = await getMLChecker();
|
|
5748
|
+
return ml.check(text);
|
|
5749
|
+
},
|
|
5750
|
+
/**
|
|
5751
|
+
* Get the underlying filter
|
|
5752
|
+
*/
|
|
5753
|
+
getFilter() {
|
|
5754
|
+
return filter;
|
|
5755
|
+
},
|
|
5756
|
+
/**
|
|
5757
|
+
* Dispose of resources
|
|
5758
|
+
*/
|
|
5759
|
+
async dispose() {
|
|
5760
|
+
if (mlChecker) {
|
|
5761
|
+
mlChecker.dispose();
|
|
5762
|
+
mlChecker = null;
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
};
|
|
5766
|
+
}
|
|
5767
|
+
async function isTransformersAvailable() {
|
|
5768
|
+
try {
|
|
5769
|
+
await getTransformers();
|
|
5770
|
+
return true;
|
|
5771
|
+
} catch {
|
|
5772
|
+
return false;
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5775
|
+
async function preloadModel(model = RECOMMENDED_MODELS.pardonmyai, options = {}) {
|
|
5776
|
+
const { quantized = true } = options;
|
|
5777
|
+
const transformers = await getTransformers();
|
|
5778
|
+
await transformers.pipeline("text-classification", model, {
|
|
5779
|
+
quantized
|
|
5780
|
+
});
|
|
5781
|
+
}
|
|
5782
|
+
|
|
5581
5783
|
exports.HybridFilter = HybridFilter;
|
|
5784
|
+
exports.RECOMMENDED_MODELS = RECOMMENDED_MODELS;
|
|
5582
5785
|
exports.ToxicityDetector = ToxicityDetector;
|
|
5786
|
+
exports.createHybridChecker = createHybridChecker;
|
|
5787
|
+
exports.createMLChecker = createMLChecker;
|
|
5788
|
+
exports.isTransformersAvailable = isTransformersAvailable;
|
|
5789
|
+
exports.preloadModel = preloadModel;
|
package/dist/ml/index.d.cts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { T as ToxicityLabel,
|
|
2
|
-
export {
|
|
1
|
+
import { T as ToxicityLabel, M as MLDetectorConfig, a as MLAnalysisResult, H as HybridAnalysisResult } from '../types-Ct_ueYqw.cjs';
|
|
2
|
+
export { b as ToxicityPrediction } from '../types-Ct_ueYqw.cjs';
|
|
3
|
+
import { F as Filter } from '../Filter-D34Wsmrj.cjs';
|
|
4
|
+
import { F as FilterConfig, C as CheckProfanityResult } from '../types-B9c_ik4k.cjs';
|
|
5
|
+
export { HybridCheckResult, HybridCheckerConfig, MLCheckResult, MLCheckerConfig, RECOMMENDED_MODELS, createHybridChecker, createMLChecker, isTransformersAvailable, preloadModel } from './transformers.cjs';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* ML-based toxicity detection using TensorFlow.js.
|
package/dist/ml/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { T as ToxicityLabel,
|
|
2
|
-
export {
|
|
1
|
+
import { T as ToxicityLabel, M as MLDetectorConfig, a as MLAnalysisResult, H as HybridAnalysisResult } from '../types-Ct_ueYqw.js';
|
|
2
|
+
export { b as ToxicityPrediction } from '../types-Ct_ueYqw.js';
|
|
3
|
+
import { F as Filter } from '../Filter-BGcyIAvO.js';
|
|
4
|
+
import { F as FilterConfig, C as CheckProfanityResult } from '../types-B9c_ik4k.js';
|
|
5
|
+
export { HybridCheckResult, HybridCheckerConfig, MLCheckResult, MLCheckerConfig, RECOMMENDED_MODELS, createHybridChecker, createMLChecker, isTransformersAvailable, preloadModel } from './transformers.js';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* ML-based toxicity detection using TensorFlow.js.
|
package/dist/ml/index.js
CHANGED
|
@@ -5576,4 +5576,206 @@ var HybridFilter = class {
|
|
|
5576
5576
|
}
|
|
5577
5577
|
};
|
|
5578
5578
|
|
|
5579
|
-
|
|
5579
|
+
// src/ml/transformers.ts
|
|
5580
|
+
var RECOMMENDED_MODELS = {
|
|
5581
|
+
/** High accuracy English model (97.5%) - 67M params */
|
|
5582
|
+
pardonmyai: "tarekziade/pardonmyai",
|
|
5583
|
+
/** Smaller version for constrained environments */
|
|
5584
|
+
pardonmyaiTiny: "tarekziade/pardonmyai-tiny",
|
|
5585
|
+
/** Multilingual toxicity detection (7 languages) */
|
|
5586
|
+
toxicBert: "unitary/toxic-bert",
|
|
5587
|
+
/** Offensive speech detector (DeBERTa-based) */
|
|
5588
|
+
offensiveSpeech: "KoalaAI/OffensiveSpeechDetector"
|
|
5589
|
+
};
|
|
5590
|
+
var MODEL_PROFANE_LABELS = {
|
|
5591
|
+
"tarekziade/pardonmyai": "profane",
|
|
5592
|
+
"tarekziade/pardonmyai-tiny": "profane",
|
|
5593
|
+
"unitary/toxic-bert": "toxic",
|
|
5594
|
+
"KoalaAI/OffensiveSpeechDetector": "LABEL_1",
|
|
5595
|
+
// Offensive
|
|
5596
|
+
default: "LABEL_1"
|
|
5597
|
+
};
|
|
5598
|
+
async function getTransformers() {
|
|
5599
|
+
try {
|
|
5600
|
+
const transformers = await import('@xenova/transformers');
|
|
5601
|
+
return transformers;
|
|
5602
|
+
} catch {
|
|
5603
|
+
throw new Error(
|
|
5604
|
+
"Transformers.js is required for ML features. Install it with: npm install @xenova/transformers"
|
|
5605
|
+
);
|
|
5606
|
+
}
|
|
5607
|
+
}
|
|
5608
|
+
async function createMLChecker(config = {}) {
|
|
5609
|
+
const {
|
|
5610
|
+
model = RECOMMENDED_MODELS.pardonmyai,
|
|
5611
|
+
threshold = 0.5,
|
|
5612
|
+
profaneLabel = MODEL_PROFANE_LABELS[model] || MODEL_PROFANE_LABELS.default,
|
|
5613
|
+
quantized = true,
|
|
5614
|
+
device = "cpu"
|
|
5615
|
+
} = config;
|
|
5616
|
+
const transformers = await getTransformers();
|
|
5617
|
+
const classifier = await transformers.pipeline("text-classification", model, {
|
|
5618
|
+
quantized,
|
|
5619
|
+
device
|
|
5620
|
+
});
|
|
5621
|
+
return {
|
|
5622
|
+
/**
|
|
5623
|
+
* Check a single text for profanity
|
|
5624
|
+
*/
|
|
5625
|
+
async check(text) {
|
|
5626
|
+
const startTime = Date.now();
|
|
5627
|
+
const output = await classifier(text);
|
|
5628
|
+
const processingTimeMs = Date.now() - startTime;
|
|
5629
|
+
const profaneScore = output.find((o) => o.label === profaneLabel)?.score || 0;
|
|
5630
|
+
const containsProfanity = profaneScore >= threshold;
|
|
5631
|
+
return {
|
|
5632
|
+
containsProfanity,
|
|
5633
|
+
confidence: profaneScore,
|
|
5634
|
+
rawOutput: output,
|
|
5635
|
+
processingTimeMs
|
|
5636
|
+
};
|
|
5637
|
+
},
|
|
5638
|
+
/**
|
|
5639
|
+
* Check multiple texts
|
|
5640
|
+
*/
|
|
5641
|
+
async checkBatch(texts) {
|
|
5642
|
+
return Promise.all(texts.map((text) => this.check(text)));
|
|
5643
|
+
},
|
|
5644
|
+
/**
|
|
5645
|
+
* Get the profanity score for text (0-1)
|
|
5646
|
+
*/
|
|
5647
|
+
async getScore(text) {
|
|
5648
|
+
const result = await this.check(text);
|
|
5649
|
+
return result.confidence;
|
|
5650
|
+
},
|
|
5651
|
+
/**
|
|
5652
|
+
* Get current configuration
|
|
5653
|
+
*/
|
|
5654
|
+
getConfig() {
|
|
5655
|
+
return { model, threshold, profaneLabel, quantized, device };
|
|
5656
|
+
},
|
|
5657
|
+
/**
|
|
5658
|
+
* Dispose of the model (free memory)
|
|
5659
|
+
*/
|
|
5660
|
+
dispose() {
|
|
5661
|
+
}
|
|
5662
|
+
};
|
|
5663
|
+
}
|
|
5664
|
+
async function createHybridChecker(config = {}) {
|
|
5665
|
+
const {
|
|
5666
|
+
model = RECOMMENDED_MODELS.pardonmyai,
|
|
5667
|
+
threshold = 0.5,
|
|
5668
|
+
profaneLabel,
|
|
5669
|
+
quantized = true,
|
|
5670
|
+
device = "cpu",
|
|
5671
|
+
filterConfig = {},
|
|
5672
|
+
mlThreshold = 0.3,
|
|
5673
|
+
dictionaryWeight = 0.6,
|
|
5674
|
+
mlWeight = 0.4
|
|
5675
|
+
} = config;
|
|
5676
|
+
const filter = new Filter({
|
|
5677
|
+
languages: filterConfig.languages || ["english"],
|
|
5678
|
+
detectLeetspeak: filterConfig.detectLeetspeak ?? true,
|
|
5679
|
+
normalizeUnicode: filterConfig.normalizeUnicode ?? true,
|
|
5680
|
+
severityLevels: true,
|
|
5681
|
+
cacheResults: true,
|
|
5682
|
+
...filterConfig
|
|
5683
|
+
});
|
|
5684
|
+
let mlChecker = null;
|
|
5685
|
+
async function getMLChecker() {
|
|
5686
|
+
if (!mlChecker) {
|
|
5687
|
+
mlChecker = await createMLChecker({
|
|
5688
|
+
model,
|
|
5689
|
+
threshold,
|
|
5690
|
+
profaneLabel,
|
|
5691
|
+
quantized,
|
|
5692
|
+
device
|
|
5693
|
+
});
|
|
5694
|
+
}
|
|
5695
|
+
return mlChecker;
|
|
5696
|
+
}
|
|
5697
|
+
return {
|
|
5698
|
+
/**
|
|
5699
|
+
* Check text using hybrid approach
|
|
5700
|
+
*/
|
|
5701
|
+
async check(text) {
|
|
5702
|
+
const startTime = Date.now();
|
|
5703
|
+
const dictionaryResult = filter.checkProfanity(text);
|
|
5704
|
+
if (dictionaryResult.containsProfanity) {
|
|
5705
|
+
return {
|
|
5706
|
+
containsProfanity: true,
|
|
5707
|
+
confidence: 1,
|
|
5708
|
+
dictionaryResult,
|
|
5709
|
+
usedML: false,
|
|
5710
|
+
profaneWords: dictionaryResult.profaneWords,
|
|
5711
|
+
processingTimeMs: Date.now() - startTime
|
|
5712
|
+
};
|
|
5713
|
+
}
|
|
5714
|
+
const ml = await getMLChecker();
|
|
5715
|
+
const mlResult = await ml.check(text);
|
|
5716
|
+
const dictionaryScore = dictionaryResult.containsProfanity ? 1 : 0;
|
|
5717
|
+
const combinedScore = dictionaryScore * dictionaryWeight + mlResult.confidence * mlWeight;
|
|
5718
|
+
const containsProfanity = combinedScore >= mlThreshold;
|
|
5719
|
+
return {
|
|
5720
|
+
containsProfanity,
|
|
5721
|
+
confidence: combinedScore,
|
|
5722
|
+
dictionaryResult,
|
|
5723
|
+
mlResult,
|
|
5724
|
+
usedML: true,
|
|
5725
|
+
profaneWords: dictionaryResult.profaneWords,
|
|
5726
|
+
processingTimeMs: Date.now() - startTime
|
|
5727
|
+
};
|
|
5728
|
+
},
|
|
5729
|
+
/**
|
|
5730
|
+
* Check multiple texts
|
|
5731
|
+
*/
|
|
5732
|
+
async checkBatch(texts) {
|
|
5733
|
+
return Promise.all(texts.map((text) => this.check(text)));
|
|
5734
|
+
},
|
|
5735
|
+
/**
|
|
5736
|
+
* Dictionary-only check (fast, no ML)
|
|
5737
|
+
*/
|
|
5738
|
+
checkFast(text) {
|
|
5739
|
+
return filter.checkProfanity(text);
|
|
5740
|
+
},
|
|
5741
|
+
/**
|
|
5742
|
+
* ML-only check (slower, more accurate)
|
|
5743
|
+
*/
|
|
5744
|
+
async checkML(text) {
|
|
5745
|
+
const ml = await getMLChecker();
|
|
5746
|
+
return ml.check(text);
|
|
5747
|
+
},
|
|
5748
|
+
/**
|
|
5749
|
+
* Get the underlying filter
|
|
5750
|
+
*/
|
|
5751
|
+
getFilter() {
|
|
5752
|
+
return filter;
|
|
5753
|
+
},
|
|
5754
|
+
/**
|
|
5755
|
+
* Dispose of resources
|
|
5756
|
+
*/
|
|
5757
|
+
async dispose() {
|
|
5758
|
+
if (mlChecker) {
|
|
5759
|
+
mlChecker.dispose();
|
|
5760
|
+
mlChecker = null;
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
};
|
|
5764
|
+
}
|
|
5765
|
+
async function isTransformersAvailable() {
|
|
5766
|
+
try {
|
|
5767
|
+
await getTransformers();
|
|
5768
|
+
return true;
|
|
5769
|
+
} catch {
|
|
5770
|
+
return false;
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
async function preloadModel(model = RECOMMENDED_MODELS.pardonmyai, options = {}) {
|
|
5774
|
+
const { quantized = true } = options;
|
|
5775
|
+
const transformers = await getTransformers();
|
|
5776
|
+
await transformers.pipeline("text-classification", model, {
|
|
5777
|
+
quantized
|
|
5778
|
+
});
|
|
5779
|
+
}
|
|
5780
|
+
|
|
5781
|
+
export { HybridFilter, RECOMMENDED_MODELS, ToxicityDetector, createHybridChecker, createMLChecker, isTransformersAvailable, preloadModel };
|