Browse Source

Implement face editing

denikson 5 năm trước cách đây
mục cha
commit
a99bdf4da8
4 tập tin đã thay đổi với 76 bổ sung4 xóa
  1. 1 0
      .gitignore
  2. 7 1
      db.js
  3. 66 3
      main.js
  4. 2 0
      package.json

+ 1 - 0
.gitignore

@@ -32,3 +32,4 @@ token.js
 package-lock.json
 db.json
 imagestats.csv
+clarifai_keys.js

+ 7 - 1
db.js

@@ -70,7 +70,13 @@ db.defaults({
     feedOutputs: [
         "422693157692637184"
     ],
-    messageReactions: {}
+    messageReactions: {},
+    faceEditChannels: {
+        "459622760839118848" : 1.0,
+        "297109482905796608": 0.25,
+        "297117726546198528": 0.1,
+        "401837400109875216": 0.1
+    }
 }).write();
 
 module.exports = db;

+ 66 - 3
main.js

@@ -6,6 +6,13 @@ const interval = require("interval-promise");
 const TurndownService = require("turndown");
 const fs = require("fs");
 const isImage = require("is-image");
+const Jimp = require("jimp");
+const Clarifai = require("clarifai");
+const ClarifaiTOKEN = require("./clarifai_keys.js");
+
+const clarifaiApp = new Clarifai.App({
+    apiKey: ClarifaiTOKEN
+});
 
 const turndown = new TurndownService();
 turndown.addRule("image", {
@@ -67,6 +74,61 @@ function isAuthorised(member) {
     return true;
 }
 
+async function processFaceSwap(message, attachmentUrl) {
+    let result = await clarifaiApp.models.predict(Clarifai.FACE_DETECT_MODEL, attachmentUrl);
+
+    if(result.outputs[0].data.regions === undefined || result.outputs[0].data.regions.length == 0)
+        return;
+    
+    let image = await Jimp.read(attachmentUrl);
+    let w = image.getWidth();
+    let h = image.getHeight();
+
+    let emojiKeys = [...client.emojis.filter(e => !e.animated).keys()];
+
+    for(let region of result.outputs[0].data.regions) {
+        let bb = region.region_info.bounding_box;
+        let bw = (bb.right_col - bb.left_col) * w;
+        let bh = (bb.bottom_row - bb.top_row) * h;
+        
+        let dx = (bb.right_col + bb.left_col) * w / 2;
+        let dy = (bb.bottom_row + bb.top_row) * h / 2;
+
+        let emojiKey = emojiKeys[Math.floor(Math.random() * emojiKeys.length)];
+        let emoji = client.emojis.get(emojiKey);
+        
+        let emojiImage = await Jimp.read(emoji.url);
+        let ew = emojiImage.getWidth();
+        let eh = emojiImage.getHeight();
+
+        let scaleFactor = Math.max(bw, bh) / Math.max(ew, eh);
+        ew *= scaleFactor;
+        eh *= scaleFactor;
+
+        emojiImage = emojiImage.scale(scaleFactor);
+        image = image.composite(emojiImage, dx - ew / 2, dy - eh / 2);
+    }
+
+    image.quality(90);
+    let buffer = await image.getBufferAsync(Jimp.MIME_JPEG);
+
+    message.channel.send(`I noticed a face in the image. I think this looks better ${client.emojis.get("505076258753740810").toString()}`, {
+        files: [ buffer ]
+    });
+}
+
+function faceMorph(message) {
+    let probValue = db.get("faceEditChannels").get(message.channel.id);
+    if(probValue.isUndefined().value() || probValue.isNull().value())
+        return;
+
+    if(Math.random() > probValue.value())
+        return;
+
+    let imageAttachment = message.attachments.find(v => isImage(v.filename));
+    processFaceSwap(message, imageAttachment.url).catch(err => console.log(`Failed to run faceapp because ${err}`));
+}
+
 const commands = {
     "make guide": msg => {
         if (!isAuthorised(msg.member)) return;
@@ -156,15 +218,16 @@ client.on("ready", () => {
 });
 
 client.on("message", m => {
+    if (m.author.id == client.user.id) return;
+
     let imagesCount = m.attachments.filter(v => isImage(v.filename)).size;
 
     if(imagesCount > 0) {
         let now = new Date();
         fs.writeSync(statsFile, `${now.getUTCFullYear()}-${now.getUTCMonth()+1}-${now.getUTCDate()} ${now.getUTCHours()}:${now.getUTCMinutes()};${imagesCount};${m.channel.name}\n`);
+        faceMorph(m);
     }
 
-    if (m.author.id == client.user.id) return;
-
     let content = m.cleanContent.trim();
     let lowerContent = content.toLowerCase();
     if(db.get("messageReactions").has(lowerContent).value()) {
@@ -241,4 +304,4 @@ client.on("messageReactionAdd", (r, u) => {
         r.message.react(r.emoji);
 });
 
-client.login(TOKEN);
+client.login(TOKEN);

+ 2 - 0
package.json

@@ -20,9 +20,11 @@
   "author": "Geoffrey Horsington <geoffrey.hoooooorse@gmail.com>",
   "license": "MIT",
   "dependencies": {
+    "clarifai": "^2.9.0",
     "discord.js": "^11.4.2",
     "interval-promise": "^1.2.0",
     "is-image": "^2.0.0",
+    "jimp": "^0.5.4",
     "lowdb": "^1.0.0",
     "rss-parser": "^3.4.3",
     "turndown": "^5.0.1",