commit 2475931869c56ec9e700240f0d2e051fb8e88aad Author: William Date: Tue Mar 7 16:46:32 2023 +0100 Init diff --git a/README.md b/README.md new file mode 100644 index 0000000..8870820 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# tasbot + +You can do it! diff --git a/bot/index.ts b/bot/index.ts new file mode 100644 index 0000000..9c32636 --- /dev/null +++ b/bot/index.ts @@ -0,0 +1,181 @@ +import { + MatrixClient, + SimpleFsStorageProvider, + AutojoinRoomsMixin, +} from "matrix-bot-sdk"; + +const http = require("http"); + +// probably the worst code you have seen in your life + +const bannedKeywords = [ + ['Sus', 'thigh high'], + ['Amogus!!', 'amogus', 'among us'], + + ['LGBTQQIAAP++ propaganda', + + 'transgender', 'trans rights', + + [ + 'thigh', 'sock', 'computer' + ], + + 'transhumanist evolution', 'pride parade', 'pride flag', 'gay pride' + + ], + + ['Chinese cartoons', 'anime', 'manga', 'loli', 'azur lane', 'mihoyo', 'kancolle', 'neko', 'touhou', 'foxgirl', 'wolf girl', 'ayanamikodon', 'hatsune miku', 'vocaloid', 'mikudayo', 'kyoto animation'], + + ['Furries', 'fursona', 'fursuit', 'e621', 'furry fandom', 'furry art'], + + ['Gore', ' gore ', ' guro ', ' gory '], +]; + +// This will be the URL where clients can reach your homeserver. Note that this might be different +// from where the web/chat interface is hosted. The server must support password registration without +// captcha or terms of service (public servers typically won't work). +const homeserverUrl = "https://trygve.me"; + +// Use the access token you got from login or registration above. +const accessToken = "your token"; + +// In order to make sure the bot doesn't lose its state between restarts, we'll give it a place to cache +// any information it needs to. You can implement your own storage provider if you like, but a JSON file +// will work fine for this example. +const storage = new SimpleFsStorageProvider("hello-bot.json"); + +// Finally, let's create the client and set it to autojoin rooms. Autojoining is typical of bots to ensure +// they can be easily added to any room. +const client = new MatrixClient(homeserverUrl, accessToken, storage); +AutojoinRoomsMixin.setupOnClient(client); + +// Before we start the bot, register our command handler +client.on("room.event", handleCommand); + +// Now that everything is set up, start the bot. This will start the sync loop and run until killed. +client.start().then(() => console.log("Bot started!")); + +// This is the command handler we registered a few lines up +async function handleCommand(roomId: string, event: any) { + let expression = ''; + let image_url = ''; + if ( + event['content']?.['msgtype'] == 'm.image' + ) { + image_url = homeserverUrl + "/_matrix/media/r0/download/" + (event['content']?.['url']).slice(6); + expression = 'image'; + } + if ( + event["content"]["avatar_url"] + ) { + image_url = homeserverUrl + "/_matrix/media/r0/download/" + (event['content']?.['avatar_url']).slice(6); + expression = 'pfp'; + } + + if (event['sender'] === await client.getUserId()) return; + if (image_url == '') return; + + console.log('New image received, analyzing...'); + analyze_image(image_url, function(degenerate, degenerateKeywords, fullDegenerateKeywords, response) { + if (degenerate) { + console.log('====Degeneracy Detected!===='); + console.log('User: ' + event['sender'] + ' sent image with url: ' + image_url); + console.log("Full keywords: " + fullDegenerateKeywords); + console.log("Sent keywords: " + degenerateKeywords); + console.log(response); + console.log('https://matrix.to/#/' + roomId + '/' + event['event_id'] + '?via=willy.club&via=trygve.me&via=matrix.org'); + console.log('============================'); + // determine what type of event it was + if (expression == 'image') { + client.redactEvent(roomId, event['event_id']); + client.sendText(roomId, 'Woah! Please refrain from posting images containing: "' + degenerateKeywords + '".'); + } else { + client.kickUser(event['sender'], roomId, 'Please change your profile picture'); + } + + } else { + console.log('=======Nothing found========'); + console.log('User: ' + event['sender'] + ' sent image with url: ' + image_url); + console.log(response); + console.log('https://matrix.to/#/' + roomId + '/' + event['event_id'] + '?via=willy.club&via=trygve.me&via=matrix.org'); + console.log('============================'); + } + }); +} + +function analyze_image(image_url, callback) { + http.get(`http://localhost:5000/?image_url=` + image_url, resp => { + let data = ""; + + // A chunk of data has been recieved. + resp.on("data", chunk => { + data += chunk; + }); + + // The whole response has been received. Print out the result. + resp.on("end", () => { + let response = JSON.parse(data).message; + let responseWithoutComma = response.replace(',', ' '); + + let degenerate = false; + let degenerateKeywords = ''; + let fullDegenerateKeywords = ''; + bannedKeywords.forEach(keyword => { + if (Array.isArray(keyword)) { + let alreadyAddedKeywordForThisGroup = false; + let skippedFirstIterationBecauseItsTheTitle = false; + keyword.forEach(subKeyword => { + if (!skippedFirstIterationBecauseItsTheTitle) { + skippedFirstIterationBecauseItsTheTitle = true; + return; + } + if (Array.isArray(subKeyword)) { + let allOfThemMatch = true; + subKeyword.forEach(subsubKeyword => { + if(responseWithoutComma.includes(subsubKeyword)) { + fullDegenerateKeywords += subsubKeyword + ','; + } else { + allOfThemMatch = false; + } + }); + if (allOfThemMatch) { + degenerate = true; + if (!alreadyAddedKeywordForThisGroup) { + degenerateKeywords += keyword[0] + ','; + alreadyAddedKeywordForThisGroup = true; + } + } + } else if (responseWithoutComma.includes(subKeyword)) { + degenerate = true; + if (!alreadyAddedKeywordForThisGroup) { + degenerateKeywords += keyword[0] + ','; + fullDegenerateKeywords += subKeyword + ','; + alreadyAddedKeywordForThisGroup = true; + } + } + }); + } else if (responseWithoutComma.includes(keyword)) { + degenerate = true; + degenerateKeywords += keyword + ','; + fullDegenerateKeywords += keyword + ','; + } + }); + + degenerateKeywords = degenerateKeywords.substr(0, degenerateKeywords.length -1); + fullDegenerateKeywords = fullDegenerateKeywords.substr(0, fullDegenerateKeywords.length -1); + + if (degenerate) { + callback(true, degenerateKeywords, fullDegenerateKeywords, response); + } else { + callback(false, '', '', response); + } + }); + }); +} + +// sometimes we dont have permission to redact messages, lets just ignore that +process.on('uncaughtException', function (exception) { + console.log('An error occured but it was probably not that important'); + //console.log(exception); +}); + diff --git a/bot/package.json b/bot/package.json new file mode 100644 index 0000000..f8713aa --- /dev/null +++ b/bot/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "matrix-bot-sdk": "^0.6.3", + "typescript": "^4.9.4" + } +} diff --git a/interrogator/app.py b/interrogator/app.py new file mode 100644 index 0000000..a46cafe --- /dev/null +++ b/interrogator/app.py @@ -0,0 +1,26 @@ +from flask import Flask, request + +app = Flask(__name__) + +from PIL import Image +from clip_interrogator import Config, Interrogator + +ci = Interrogator(Config(clip_model_name="ViT-L-14/openai")) +#ci = Interrogator(Config(clip_model_name="ViT-H-14/laion2b_s32b_b79k")) + +image_path = "/dev/shm/image_data" + +import requests + +@app.route("/", methods=['GET']) +def hello_world(): + args = request.args + + img_data = requests.get(args['image_url']).content + with open(image_path, 'wb') as handler: + handler.write(img_data) + + image = Image.open(image_path).convert('RGB') + + #return {'message': ci.interrogate(image)} + return {'message': ci.interrogate_fast(image)}