mofeibai commited on
Commit
1d08e36
·
verified ·
1 Parent(s): 183a757

Upload 4 files

Browse files
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);