/[sudobot]/branches/8.x/src/services/ImageRecognitionService.ts
ViewVC logotype

Annotation of /branches/8.x/src/services/ImageRecognitionService.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (hide annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 3878 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 rakinar2 577 /**
2     * This file is part of SudoBot.
3     *
4     * Copyright (C) 2021-2024 OSN Developers.
5     *
6     * SudoBot is free software; you can redistribute it and/or modify it
7     * under the terms of the GNU Affero General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * SudoBot is distributed in the hope that it will be useful, but
12     * WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU Affero General Public License for more details.
15     *
16     * You should have received a copy of the GNU Affero General Public License
17     * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18     */
19    
20     import type { Tensor3D } from "@tensorflow/tfjs-node";
21     import type { NSFWJS } from "nsfwjs";
22     import Tesseract, { createWorker } from "tesseract.js";
23     import Service from "../core/Service";
24     import { log, logInfo } from "../utils/Logger";
25     import { developmentMode } from "../utils/utils";
26    
27     export const name = "imageRecognitionService";
28    
29     export default class ImageRecognitionService extends Service {
30     protected worker: Tesseract.Worker | null = null;
31     protected nsfwJsModel: NSFWJS | null = null;
32     protected timeout: Timer | null = null;
33     protected tensorFlow: typeof import("@tensorflow/tfjs-node") | null = null;
34     protected nsfwJs: typeof import("nsfwjs") | null = null;
35    
36     async boot() {
37     for (const guild in this.client.configManager.config) {
38     if (
39     this.client.configManager.config[guild]?.message_rules?.rules.some(
40     rule => rule.type === "EXPERIMENTAL_nsfw_filter"
41     )
42     ) {
43     logInfo("Loading NSFWJS model for NSFW image recognition");
44    
45     this.tensorFlow = await import("@tensorflow/tfjs-node");
46    
47     if (!developmentMode()) {
48     this.tensorFlow.enableProdMode();
49     }
50    
51     this.nsfwJs = await import("nsfwjs");
52     this.nsfwJsModel = await this.nsfwJs.load(
53     process.env.NSFWJS_MODEL_URL || undefined,
54     process.env.NSFWJS_MODEL_IMAGE_SIZE
55     ? {
56     size: parseInt(process.env.NSFWJS_MODEL_IMAGE_SIZE)
57     }
58     : undefined
59     );
60    
61     break;
62     }
63     }
64     }
65    
66     protected async createWorkerIfNeeded() {
67     if (!this.worker && !this.timeout) {
68     log("Spawning new tesseract worker for image recognition");
69     this.worker = await createWorker("eng");
70     this.setTimeout();
71     } else if (this.worker && this.timeout) {
72     log("Using existing tesseract worker for image recognition");
73     clearTimeout(this.timeout);
74     this.setTimeout();
75     }
76     }
77    
78     protected setTimeout() {
79     this.timeout = setTimeout(() => {
80     log("Terminating existing tesseract worker due to inactivity");
81     this.worker?.terminate();
82     this.timeout = null;
83     }, 60_000);
84     }
85    
86     async recognize(image: Tesseract.ImageLike) {
87     await this.createWorkerIfNeeded();
88     return this.worker!.recognize(image);
89     }
90    
91     async detectNSFW(image: Uint8Array | Buffer) {
92     if (!this.tensorFlow) {
93     throw new Error("Tensorflow is not loaded");
94     }
95    
96     const tensor = this.tensorFlow.node.decodeImage(image, 3, undefined, false);
97     const predictions = await this.nsfwJsModel!.classify(tensor as Tensor3D);
98     const result: Record<string, number> = {};
99    
100     for (const prediction of predictions) {
101     result[prediction.className.toLowerCase()] = prediction.probability;
102     }
103    
104     tensor.dispose();
105     return result;
106     }
107     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26