mirror of
https://github.com/SrIzan10/vinci.git
synced 2026-06-06 01:07:00 +00:00
feat: image classification and cursivify
This commit is contained in:
10
bun.lock
10
bun.lock
@@ -7,8 +7,8 @@
|
||||
"@napi-rs/canvas": "^0.1.72",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@sern/handler": "^4.0.0",
|
||||
"@sern/publisher": "^1.1.1",
|
||||
"discord.js": "latest",
|
||||
"@sern/publisher": "1.1.2",
|
||||
"discord.js": "^14.21.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"mongodb": "^6.17.0",
|
||||
"sharp": "^0.34.2",
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
"@sern/ioc": ["@sern/ioc@1.1.2", "", {}, "sha512-n84w7n5hB1dl8N6dfSbeYIo0QYORMS1bpG/P7J7GoMNTu8c28EYVZ8uGs3Md9GB09UseOKn3mfv1QBDtRsbb1g=="],
|
||||
|
||||
"@sern/publisher": ["@sern/publisher@1.1.4", "", {}, "sha512-2O3GmKTzSdZr2cZhrVRFXg1iB0VwZT3vKfuubtJYLneu7F0j1oU6Db4QjGqloiZvOE4HBdQM1AhLx37ej22lgA=="],
|
||||
"@sern/publisher": ["@sern/publisher@1.1.2", "", {}, "sha512-1zh99JZykKUhqHhE75ZXfiLsBtf1WI+NnDCojv8UlpnGBEyzO8xyI1X7PNf6cPKRs4W9XqY3PqTJ+hrqzIsMkg=="],
|
||||
|
||||
"@types/luxon": ["@types/luxon@3.4.2", "", {}, "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA=="],
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
"discord.js": ["discord.js@14.21.0", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ=="],
|
||||
|
||||
"dotenv": ["dotenv@16.6.0", "", {}, "sha512-Omf1L8paOy2VJhILjyhrhqwLIdstqm1BvcDPKg4NGAlkwEu9ODyrFbvk8UymUOMCT+HXo31jg1lArIrVAAhuGA=="],
|
||||
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
|
||||
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"ws": ["ws@8.18.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="],
|
||||
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="],
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"@napi-rs/canvas": "^0.1.72",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@sern/handler": "^4.0.0",
|
||||
"@sern/publisher": "^1.1.1",
|
||||
"discord.js": "latest",
|
||||
"@sern/publisher": "1.1.2",
|
||||
"discord.js": "^14.21.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"mongodb": "^6.17.0",
|
||||
"sharp": "^0.34.2"
|
||||
|
||||
16
src/commands/contextMenu/cursivify.ts
Normal file
16
src/commands/contextMenu/cursivify.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
|
||||
export default commandModule({
|
||||
name: 'cursivify',
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply()
|
||||
const trimmedstring = ctx.targetMessage.content.replaceAll('*', '');
|
||||
if (trimmedstring.length === 0) {
|
||||
await ctx.editReply('No hay nada que cursivificar!');
|
||||
} else {
|
||||
await ctx.editReply(`*${trimmedstring}*`);
|
||||
}
|
||||
},
|
||||
});
|
||||
63
src/commands/contextMenu/image-classification.ts
Normal file
63
src/commands/contextMenu/image-classification.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { AttachmentBuilder, codeBlock } from 'discord.js';
|
||||
import { createCanvas, loadImage } from '@napi-rs/canvas';
|
||||
import sharp from 'sharp';
|
||||
|
||||
export default commandModule({
|
||||
name: 'Clasifica una imagen',
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply();
|
||||
|
||||
if (ctx.targetMessage.attachments.size === 0)
|
||||
return ctx.editReply('No hay ninguna imagen para clasificar!');
|
||||
const image = ctx.targetMessage.attachments.first()!;
|
||||
if (!image.contentType!.startsWith('image/') && image.contentType !== 'image/gif')
|
||||
return ctx.editReply('El archivo no es una imagen!');
|
||||
|
||||
const imageBuffer = await fetch(image.url).then(async (res) => await res.arrayBuffer());
|
||||
const compressed = sharp(imageBuffer)
|
||||
.png({ quality: 70 })
|
||||
.jpeg({ quality: 70 })
|
||||
.webp({ quality: 70 })
|
||||
.tiff({ quality: 70 });
|
||||
const imageUint8Array = new Uint8Array(await compressed.toBuffer());
|
||||
|
||||
const request = await fetch(
|
||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_AI_ACC}/ai/run/@cf/facebook/detr-resnet-50`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.CF_AI_TOKEN}`,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
body: imageUint8Array,
|
||||
}
|
||||
).then(async (res) => await res.json());
|
||||
if (request.errors.length > 0) {
|
||||
return ctx.editReply(`Hubo un error! ${codeBlock(JSON.stringify(request.errors))}`);
|
||||
}
|
||||
|
||||
// all canvas stuff, this was fun to make
|
||||
const imgMetadata = await compressed.metadata();
|
||||
const canvas = createCanvas(imgMetadata.width!, imgMetadata.height!);
|
||||
const ctxCanvas = canvas.getContext('2d');
|
||||
const img = await loadImage(image.url);
|
||||
ctxCanvas.drawImage(img, 0, 0, imgMetadata.width!, imgMetadata.height!);
|
||||
ctxCanvas.font = '30px sans-serif';
|
||||
ctxCanvas.fillStyle = 'red';
|
||||
ctxCanvas.strokeStyle = 'red';
|
||||
ctxCanvas.lineWidth = 3;
|
||||
for (const result of request.result) {
|
||||
if (result.score < 0.5) continue;
|
||||
const box = result.box;
|
||||
ctxCanvas.strokeRect(box.xmin, box.ymin, box.xmax - box.xmin, box.ymax - box.ymin);
|
||||
ctxCanvas.fillText(result.label, box.xmin, box.ymin - 5);
|
||||
}
|
||||
const canvasBuffer = canvas.toBuffer('image/png');
|
||||
const attachment = new AttachmentBuilder(canvasBuffer, { name: 'generatedImage.png' });
|
||||
|
||||
await ctx.editReply({ files: [attachment] });
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user