File size: 5,072 Bytes
d007ed6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12b037e
 
d007ed6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// 导入experss模块
const express=require("express");
let fs = require('fs');
// 创建服务器对象
let app = express();
// 导入body-parser插件
const bodyparser = require("body-parser");;
 // 配置body-parser模块
 app.use(bodyparser.urlencoded({extended:false}));
 app.use(bodyparser.json());
// 导入系统模块path
const path = require("path");
const afs = require('fs-extra');

let multiparty = require('multiparty');
let imgJS = require("image-js");
const nsfw = require('nsfwjs');
const tf = require('@tensorflow/tfjs-node');
const safeContent = ['Drawing', 'Neutral']; // 设置图片内容安全的类型

// https://github.com/alex000kim/nsfw_data_scraper

let imgTypeoObj = {
    Drawing: '艺术性的',
    Neutral: '中性的',
    Sexy: '性感的',
    Porn: '色情的',
    Hentai: '变态的',
};

//转换图片格式
const convert = async file => {
  const image = await imgJS.Image.load(file.path);
  const numChannels = 3;
  const numPixels = image.width * image.height;
  const values = new Int32Array(numPixels * numChannels);

  for (let i = 0; i < numPixels; i++) {
    for (let c = 0; c < numChannels; ++c) {
      values[i * numChannels + c] = image.data[i * 4 + c];
    }
  }

  return tf.tensor3d(values, [image.height, image.width, numChannels], 'int32');
};

// 初始化模型
let model;
(async function() {
    model = await nsfw.load('file://./web_model/', {
        type: 'graph'
    });
})();


const isSafeContent = predictions => {
  let safeProbability = 0;
  let imgTypeValArr = [];
  for (let index = 0; index < predictions.length; index++) {
    const item = predictions[index];
    const className = item.className;
    const probability = item.probability;
    if (safeContent.includes(className)) {
      safeProbability += probability;
    };
  }
  imgTypeValArr = predictions.sort((a, b) => b.probability - a.probability);
//   console.log('imgTypeValArr:', imgTypeValArr);
  let myimgType = '';
  if (imgTypeValArr.length && imgTypeValArr[0]) {
    myimgType = imgTypeoObj[imgTypeValArr[0].className];
  }
  return {
    isSafe: safeProbability > 0.5,
    imgType: myimgType
  };
};

app.post('/checkImg',async (req, res) => {
	try {
        // 删除指定文件夹下面的所有文件或文件夹
        try {
          await afs.emptyDirSync('./tempImgs');
          console.log('清空tempImgs成功');
        } catch (error) {
          console.log('清空tempImgs失败');
        }
        let form = new multiparty.Form();
        // 设置文件存储路径,以当前编辑的文件为相对路径
        form.uploadDir = './tempImgs';
        form.parse(req, async (err, fields, files) => {
            if (!files || !files.file[0]) {
                return res.send({
                    code: -1,
                    msg: '请上传file图片资源(form-data格式)',
                    data: {}
                })
            }
            // console.log('files.file[0]:', files.file[0]);
            // 图片最大尺寸
            if (files.file[0].size > 1024 * 1024 * 3) {
                return res.send({
                    code: -2,
                    msg: '被检测图片最大3M',
                    data: {}
                })
            };
            // 支持的图片类型
            let imgReg = /\S+\.(png|jpeg|jpg)$/g;
            let originImgName = files.file[0].originalFilename || files.file[0].path;
            if (!imgReg.test(originImgName)) {
                return res.send({
                    code: -3,
                    msg: '仅仅支持(png、jpeg、jpg)类型图片检测',
                    data: {}
                })
            }
            let img = await convert(files.file[0]);
            let predictions = await model.classify(img);
            const {isSafe, imgType} = isSafeContent(predictions);
            // console.log('是否安全:', predictions, isSafe);
            res.send({
                code: 0,
                msg: isSafe ? '图片合规' : '图片可能存在不合规的风险,请核查',
                data: {
                    isSafe,
                    imgType,
                    predictions,
                }
            })
        });
	} catch (error) {
        res.send({
            code: -9,
            msg: '图片核查失败,请重试',
            data: {}
        })
	}
});

// {
// 	"code": 0,
// 	"msg": "图片合规",
// 	"data": {
// 		"isSafe": true,
// 		"imgType": "艺术性的",
// 		"predictions": [
// 			{
// 				"className": "Drawing",
// 				"probability": 0.9533441662788391
// 			},
// 			{
// 				"className": "Neutral",
// 				"probability": 0.015517046675086021
// 			},
// 			{
// 				"className": "Sexy",
// 				"probability": 0.013940851204097271
// 			},
// 			{
// 				"className": "Porn",
// 				"probability": 0.012532410211861134
// 			},
// 			{
// 				"className": "Hentai",
// 				"probability": 0.004665587563067675
// 			}
// 		]
// 	}
// }

// 监听端口
app.listen(7860,()=>{
	console.log("图片鉴黄服务器启动成功!port:7860");
});