gpu-profanity-filter
v0.2.0
Published
Clasificador de toxicidad/groserías: preprocesamiento en CPU, inferencia en WebGPU, postprocesamiento en TS.
Readme
gpu-profanity-filter (core)
Clasificador de toxicidad/groserías por token: preprocesamiento en CPU, inferencia matemática en WebGPU, postprocesamiento en TypeScript. Cae automáticamente a CPU si el navegador no soporta WebGPU.
Uso
import { createProfanityFilter } from "gpu-profanity-filter";
const filter = await createProfanityFilter({
weightsUrl: "/weights.bin", // opcional — sin esto usa los pesos
// ENTRENADOS embebidos en el build
});
const result = await filter.check("eres un p3nd3jo");
console.log(result.censoredText); // "eres un ********"
console.log(result.isToxic); // true
console.log(result.backend); // "gpu" o "cpu"
console.log(result.perToken); // detalle rol + scores por palabra
filter.dispose();Cómo se construye
pnpm install
pnpm run prebuild # regenera generatedWordlists.ts, shaderSource.ts y embeddedWeights.ts
pnpm run build # tsc -> dist/
node scripts/sync-demo.js # actualiza la copia autocontenida que usa apps/demoOJO: si tu npm tiene ignore-scripts=true, prebuild no corre solo —
ejecuta los tres scripts de scripts/ a mano antes de build.
prebuild lee /wordlists/*.txt (compartido con packages/training),
src/shaders/filter.wgsl y apps/demo/weights.bin, y genera tres
archivos .ts embebidos (generatedWordlists.ts, shaderSource.ts,
embeddedWeights.ts) para que el bundle final no necesite hacer
fetch/leer archivos en runtime. Edita siempre las
fuentes (wordlists/*.txt, shaders/filter.wgsl, reentrena
weights.bin), nunca los generados.
Arquitectura de features (9 por token)
| # | Feature | De dónde sale |
|---|---------|---------------|
| 0 | hasNumbers | regex sobre el token crudo |
| 1 | hasRepeatedChars | regex sobre el token crudo |
| 2 | hasSymbols | regex sobre el token crudo |
| 3 | lengthRatio | len(token)/10 clamp a 1 |
| 4 | matchesProfanity | lookup en diccionario tras normalizar leet-speak |
| 5 | matchesHarassment | ídem |
| 6 | matchesDiscrimination | ídem |
| 7 | matchesSexual | ídem |
| 8 | bias | siempre 1.0 |
El diccionario (normalización + Set lookup) vive en CPU porque un
Set.has() es barato y no necesita GPU; la GPU aporta valor cuando hay
que clasificar miles de tokens en paralelo (streams de moderación,
timelines completos, etc.), no para un mensaje suelto.
Pesos
Sin weightsUrl, el paquete usa los pesos entrenados embebidos
(embeddedWeights.ts, generado desde apps/demo/weights.bin por
scripts/export-embedded-weights.js). Si el build se hizo sin
weights.bin disponible, cae a los escritos a mano en weights.ts
(solo demo). weightsUrl/loadWeightsFromBuffer() siguen disponibles
para sobreescribir pesos en runtime.
