✨ add nsfw
This commit is contained in:
@@ -80,7 +80,7 @@ export default {
|
||||
loginExpiredDesc: "this account has been logged in elsewhere, please login again",
|
||||
|
||||
},
|
||||
comment:{
|
||||
comment: {
|
||||
comment: 'Comment',
|
||||
sendComment: 'Send Comment',
|
||||
emoji: 'Emoji',
|
||||
@@ -100,5 +100,6 @@ export default {
|
||||
commentError: 'comment failed!',
|
||||
replySuccess: 'reply success!',
|
||||
replyError: 'reply failed!',
|
||||
illegalImage: 'illegal image!',
|
||||
}
|
||||
};
|
||||
|
@@ -99,6 +99,7 @@ export default {
|
||||
commentError: '评论失败!',
|
||||
replySuccess: '回复成功!',
|
||||
replyError: '回复失败!',
|
||||
illegalImage: ' 非法图片!',
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -7,6 +7,9 @@ import {getSlideCaptchaDataApi} from "@/api/captcha";
|
||||
import imageCompression from "browser-image-compression";
|
||||
import QQ_EMOJI from "@/constant/qq_emoji.ts";
|
||||
import QQ_LOTTIE_EMOJI from "@/constant/qq_lottie_emoji.ts";
|
||||
import {initNSFWJs, predictNSFW} from "@/utils/nsfw/nsfw.ts";
|
||||
import {NSFWJS} from "nsfwjs";
|
||||
import i18n from "@/locales";
|
||||
|
||||
export const useCommentStore = defineStore(
|
||||
'comment',
|
||||
@@ -180,6 +183,8 @@ export const useCommentStore = defineStore(
|
||||
maxWidthOrHeight: 750,
|
||||
maxIteration: 2
|
||||
};
|
||||
|
||||
|
||||
if (!window.FileReader) return false; // 判断是否支持FileReader
|
||||
const compressedFile = await imageCompression(file, options);
|
||||
const reader = new FileReader();
|
||||
@@ -188,7 +193,16 @@ export const useCommentStore = defineStore(
|
||||
if (fileList.value.length < 3) {
|
||||
const img: HTMLImageElement = document.createElement('img');
|
||||
img.src = reader.result as string;
|
||||
img.onload = () => {
|
||||
img.onload = async () => {
|
||||
// 图片 NSFW 检测
|
||||
const nsfw: NSFWJS = await initNSFWJs();
|
||||
const isNSFW: boolean = await predictNSFW(nsfw, img);
|
||||
if (isNSFW) {
|
||||
message.error(i18n.global.t('comment.illegalImage'));
|
||||
fileList.value.pop();
|
||||
uploadLoading.value = false;
|
||||
return false;
|
||||
}
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
@@ -215,12 +229,13 @@ export const useCommentStore = defineStore(
|
||||
|
||||
ctx.fillText(text, x, y);
|
||||
fileList.value.push(canvas.toDataURL());
|
||||
uploadLoading.value = false;
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
uploadLoading.value = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
51
src/utils/nsfw/nsfw.ts
Normal file
51
src/utils/nsfw/nsfw.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as nsfwjs from "nsfwjs";
|
||||
import {NSFWJS} from "nsfwjs";
|
||||
import * as tf from "@tensorflow/tfjs";
|
||||
|
||||
/**
|
||||
* Initializes the NSFWJS model and returns it.
|
||||
*/
|
||||
let isInit: boolean = false;
|
||||
const initNSFWJs = async (): Promise<NSFWJS> => {
|
||||
tf.enableProdMode();
|
||||
if (!isInit) {
|
||||
const initialLoad = await nsfwjs.load("/nsfw/model/mobilenet_v2_mid/model.json", {size: 224, type: "graph"});
|
||||
await initialLoad.model.save("indexeddb://nsfwjs-model");
|
||||
isInit = true;
|
||||
}
|
||||
return await nsfwjs.load("indexeddb://nsfwjs-model", {size: 224, type: "graph"});
|
||||
};
|
||||
/**
|
||||
* Predicts the NSFW score of an image using the NSFWJS model.
|
||||
* @param model
|
||||
* @param image
|
||||
*/
|
||||
const predictNSFW = async (model: NSFWJS, image: tf.Tensor3D | ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement): Promise<boolean> => {
|
||||
const predictions = await model.classify(image, 5);
|
||||
console.log(predictions);
|
||||
// 定义阈值与对应的类别
|
||||
const thresholds = {
|
||||
'Porn': 0.5,
|
||||
'Hentai': 0.3,
|
||||
'Sexy': 0.5
|
||||
};
|
||||
|
||||
// 使用一个变量来确定是否为色情内容
|
||||
let isNSFW: boolean = false;
|
||||
|
||||
// 遍历预测结果,并检查是否满足阈值
|
||||
for (const prediction of predictions) {
|
||||
const className = prediction.className;
|
||||
const probability = prediction.probability;
|
||||
|
||||
// 检查预测类别是否在阈值对象中
|
||||
if (thresholds[className] !== undefined && probability >= thresholds[className]) {
|
||||
isNSFW = true;
|
||||
break; // 早期退出,如果满足任一条件
|
||||
}
|
||||
}
|
||||
|
||||
return isNSFW; // 返回是否为色情图片
|
||||
};
|
||||
|
||||
export {initNSFWJs, predictNSFW};
|
Reference in New Issue
Block a user