{ "version": 3, "sources": ["../../../../server/artemis/local.ts"], "sourcesContent": ["/**\n * Typescript wrapper around the Python Artemis model.\n * By Mia.\n * @author mia-pi-git\n */\n\nimport * as child_process from 'child_process';\nimport {ProcessManager, Streams, Utils, Repl, FS} from '../../lib';\nimport {Config} from '../config-loader';\nimport {toID} from '../../sim/dex-data';\n\nclass ArtemisStream extends Streams.ObjectReadWriteStream {\n\ttasks = new Set();\n\tprivate process: child_process.ChildProcessWithoutNullStreams;\n\tconstructor() {\n\t\tsuper();\n\t\tthis.process = child_process.spawn('python3', [\n\t\t\t'-u', FS('server/artemis/model.py').path, Config.debugartemisprocesses ? \"debug\" : \"\",\n\t\t].filter(Boolean));\n\t\tthis.listen();\n\t}\n\tlisten() {\n\t\tthis.process.stdout.setEncoding('utf8');\n\t\tthis.process.stderr.setEncoding('utf8');\n\t\tthis.process.stdout.on('data', (data) => {\n\t\t\t// so many bugs were created by \\nready\\n\n\t\t\tdata = data.trim();\n\t\t\tconst [taskId, dataStr] = data.split(\"|\");\n\t\t\tif (this.tasks.has(taskId)) {\n\t\t\t\tthis.tasks.delete(taskId);\n\t\t\t\treturn this.push(`${taskId}\\n${dataStr}`);\n\t\t\t}\n\t\t\tif (taskId === 'error') { // there was a major crash and the script is no longer running\n\t\t\t\tconst info = JSON.parse(dataStr);\n\t\t\t\tMonitor.crashlog(new Error(info.error), \"An Artemis script\", info);\n\t\t\t\ttry {\n\t\t\t\t\tthis.pushEnd(); // push end first so the stream always closes\n\t\t\t\t\tthis.process.disconnect();\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t});\n\t\tthis.process.stderr.on('data', data => {\n\t\t\tif (/Downloading: ([0-9]+)%/i.test(data)) {\n\t\t\t\t// this prints to stderr fsr and it should not be throwing\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tMonitor.crashlog(new Error(data), \"An Artemis process\");\n\t\t});\n\t\tthis.process.on('error', err => {\n\t\t\tMonitor.crashlog(err, \"An Artemis process\");\n\t\t\tthis.pushEnd();\n\t\t});\n\t\tthis.process.on('close', () => {\n\t\t\tthis.pushEnd();\n\t\t});\n\t}\n\t_write(chunk: string) {\n\t\tconst [taskId, message] = Utils.splitFirst(chunk, '\\n');\n\t\tthis.tasks.add(taskId);\n\t\tthis.process.stdin.write(`${taskId}|${message}\\n`);\n\t}\n\tdestroy() {\n\t\ttry {\n\t\t\tthis.process.kill();\n\t\t} catch {}\n\t\tthis.pushEnd();\n\t}\n}\n\nexport const PM = new ProcessManager.StreamProcessManager(module, () => new ArtemisStream(), message => {\n\tif (message.startsWith('SLOW\\n')) {\n\t\tMonitor.slow(message.slice(5));\n\t}\n});\n\nexport class LocalClassifier {\n\tstatic readonly PM = PM;\n\tstatic readonly ATTRIBUTES: Record = {\n\t\tsexual_explicit: {},\n\t\tsevere_toxicity: {},\n\t\ttoxicity: {},\n\t\tobscene: {},\n\t\tidentity_attack: {},\n\t\tinsult: {},\n\t\tthreat: {},\n\t};\n\tstatic classifiers: LocalClassifier[] = [];\n\tstatic destroy() {\n\t\tfor (const classifier of this.classifiers) void classifier.destroy();\n\t\treturn this.PM.destroy();\n\t}\n\t/** If stream exists, model is usable */\n\tstream?: Streams.ObjectReadWriteStream;\n\tenabled = false;\n\trequests = new Map void>();\n\tlastTask = 0;\n\treadyPromise: Promise | null = null;\n\tconstructor() {\n\t\tLocalClassifier.classifiers.push(this);\n\t\tvoid this.setupProcesses();\n\t}\n\tasync setupProcesses() {\n\t\tthis.readyPromise = new Promise(resolve => {\n\t\t\tchild_process.exec('python3 -c \"import detoxify\"', (err, out, stderr) => {\n\t\t\t\tif (err || stderr) {\n\t\t\t\t\tresolve(false);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(true);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tconst res = await this.readyPromise;\n\t\tthis.enabled = res;\n\t\tthis.readyPromise = null;\n\t\tif (res) {\n\t\t\tthis.stream = PM.createStream();\n\t\t\tvoid this.listen();\n\t\t}\n\t}\n\tasync listen() {\n\t\tif (!this.stream) return null;\n\t\tfor await (const chunk of this.stream) {\n\t\t\tconst [rawTaskId, data] = Utils.splitFirst(chunk, '\\n');\n\t\t\tconst task = parseInt(rawTaskId);\n\t\t\tconst resolver = this.requests.get(task);\n\t\t\tif (resolver) {\n\t\t\t\tresolver(JSON.parse(data));\n\t\t\t\tthis.requests.delete(task);\n\t\t\t}\n\t\t}\n\t}\n\tdestroy() {\n\t\tLocalClassifier.classifiers.splice(LocalClassifier.classifiers.indexOf(this), 1);\n\t\treturn this.stream?.destroy();\n\t}\n\tasync classify(text: string) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!this.stream) return null;\n\t\tconst taskId = this.lastTask++;\n\t\tconst data = await new Promise(resolve => {\n\t\t\tthis.requests.set(taskId, resolve);\n\t\t\tvoid this.stream?.write(`${taskId}\\n${text}`);\n\t\t});\n\t\tfor (const k in data) {\n\t\t\t// floats have to be made into strings because python's json.dumps\n\t\t\t// doesn't like float32s\n\t\t\tdata[k] = parseFloat(data[k]);\n\t\t}\n\t\treturn data as Record;\n\t}\n}\n\n// main module check necessary since this gets required in other non-parent processes sometimes\n// when that happens we do not want to take over or set up or anything\nif (require.main === module) {\n\t// This is a child process!\n\tglobal.Config = Config;\n\tglobal.Monitor = {\n\t\tcrashlog(error: Error, source = 'A local Artemis child process', details: AnyObject | null = null) {\n\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\n\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\n\t\t},\n\t\tslow(text: string) {\n\t\t\tprocess.send!(`CALLBACK\\nSLOW\\n${text}`);\n\t\t},\n\t};\n\tglobal.toID = toID;\n\tprocess.on('uncaughtException', err => {\n\t\tif (Config.crashguard) {\n\t\t\tMonitor.crashlog(err, 'A local Artemis child process');\n\t\t}\n\t});\n\t// eslint-disable-next-line no-eval\n\tRepl.start(`abusemonitor-local-${process.pid}`, cmd => eval(cmd));\n} else if (!process.send) {\n\tPM.spawn(Config.localartemisprocesses || 1);\n}\n"], "mappings": "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", "names": [] }