Upload 4 files
Browse files- src/NsfwImageClassifier.ts +46 -0
- src/config/model.ts +5 -0
- src/controllers/NsfwController.ts +42 -0
- src/index.ts +17 -0
src/NsfwImageClassifier.ts
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as tf from '@tensorflow/tfjs-node';
|
2 |
+
import * as nsfwjs from 'nsfwjs';
|
3 |
+
import {NSFWJS} from 'nsfwjs';
|
4 |
+
import {Tensor3D} from '@tensorflow/tfjs';
|
5 |
+
import {model as config} from 'app/config/model';
|
6 |
+
|
7 |
+
tf.enableProdMode();
|
8 |
+
|
9 |
+
export class NsfwImageClassifier {
|
10 |
+
#model?: NSFWJS;
|
11 |
+
|
12 |
+
async classify(imageBuffer: Buffer) {
|
13 |
+
const [model, image] = await Promise.all([
|
14 |
+
this.#getModel(),
|
15 |
+
tf.node.decodeImage(imageBuffer, 3),
|
16 |
+
]);
|
17 |
+
|
18 |
+
const predictions = await model.classify(image as Tensor3D);
|
19 |
+
|
20 |
+
image.dispose();
|
21 |
+
|
22 |
+
return this.#transformData(predictions);
|
23 |
+
}
|
24 |
+
|
25 |
+
async classifyMany(imagesBuffers: Buffer[]) {
|
26 |
+
return await Promise.all(imagesBuffers.map(buffer => this.classify(buffer)));
|
27 |
+
}
|
28 |
+
|
29 |
+
async #getModel(): Promise<NSFWJS> {
|
30 |
+
if (!this.#model) {
|
31 |
+
this.#model = await nsfwjs.load('file://model/', {size: config.size});
|
32 |
+
}
|
33 |
+
|
34 |
+
return this.#model;
|
35 |
+
}
|
36 |
+
|
37 |
+
#transformData(data: { className: string; probability: number }[]): Record<string, number> {
|
38 |
+
const result: Record<string, number> = {};
|
39 |
+
|
40 |
+
for (const item of data) {
|
41 |
+
result[item.className.toLowerCase()] = item.probability;
|
42 |
+
}
|
43 |
+
|
44 |
+
return result;
|
45 |
+
}
|
46 |
+
}
|
src/config/model.ts
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const DEFAULT_MODEL_SIZE = 299;
|
2 |
+
|
3 |
+
export const model = {
|
4 |
+
size: Number(process.env.MODEL_SIZE) || DEFAULT_MODEL_SIZE,
|
5 |
+
};
|
src/controllers/NsfwController.ts
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Controller, Post} from 'simple-ts-express-decorators';
|
2 |
+
import multer, {memoryStorage} from 'multer';
|
3 |
+
import {Request, Response} from 'express';
|
4 |
+
import {NsfwImageClassifier} from 'app/NsfwImageClassifier';
|
5 |
+
|
6 |
+
const upload = multer({storage: memoryStorage()});
|
7 |
+
|
8 |
+
@Controller()
|
9 |
+
export class NsfwController {
|
10 |
+
classifier: NsfwImageClassifier;
|
11 |
+
|
12 |
+
constructor() {
|
13 |
+
this.classifier = new NsfwImageClassifier();
|
14 |
+
}
|
15 |
+
|
16 |
+
@Post('/classify', upload.single('image'))
|
17 |
+
async classify(request: Request, response: Response) {
|
18 |
+
if (!request.file) {
|
19 |
+
return response
|
20 |
+
.status(410)
|
21 |
+
.json({error: 'Specify image'});
|
22 |
+
}
|
23 |
+
|
24 |
+
const data = await this.classifier.classify(request.file.buffer);
|
25 |
+
|
26 |
+
return response.json(data);
|
27 |
+
}
|
28 |
+
|
29 |
+
@Post('/classify-many', upload.array('images', 10))
|
30 |
+
async classifyMany(request: Request, response: Response) {
|
31 |
+
if (!request.files || !request.files.length) {
|
32 |
+
return response
|
33 |
+
.status(410)
|
34 |
+
.json({error: 'Specify images'});
|
35 |
+
}
|
36 |
+
|
37 |
+
const buffers = (request.files as Express.Multer.File[]).map(file => file.buffer);
|
38 |
+
const data = await this.classifier.classifyMany(buffers);
|
39 |
+
|
40 |
+
return response.json(data);
|
41 |
+
}
|
42 |
+
}
|
src/index.ts
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import 'reflect-metadata';
|
2 |
+
import 'module-alias/register';
|
3 |
+
|
4 |
+
import express from 'express';
|
5 |
+
import bodyParser from 'body-parser';
|
6 |
+
import {ControllersLoader} from 'simple-ts-express-decorators';
|
7 |
+
import {NsfwController} from 'app/controllers/NsfwController';
|
8 |
+
|
9 |
+
const app = express();
|
10 |
+
|
11 |
+
app.use(bodyParser.json());
|
12 |
+
|
13 |
+
new ControllersLoader({
|
14 |
+
controllers: [NsfwController]
|
15 |
+
}).load(app);
|
16 |
+
|
17 |
+
app.listen(3000);
|