api / src /server /plugins /ai /ai_image_editor.js
OhMyDitzzy
disabled image ai editor
f437910
import { sendSuccess, ErrorResponses } from "../../lib/response-helper.js";
import { AIEnhancer } from "./ai_image_utils.js";
import multer from "multer";
import axios from "axios";
import path from "path";
const ModelMap = {
nano_banana: 2,
seed_dream: 5,
flux: 8,
qwen_image: 9
};
const storage = multer.memoryStorage();
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Invalid file type. Only JPEG, PNG, GIF, and WebP are allowed.'));
}
}
});
/** @type {import("../../types/plugin.ts").ApiPluginHandler}*/
const handler = {
name: "AI Image Editor",
description: "Edit your images using AI",
method: "POST",
version: "1.0.0",
category: ["ai"],
alias: ["aiImageEditor"],
tags: ["ai", "image"],
disabled: true,
disabledReason: "The API Server is restricting access to their API with IP Tracking, We are making some efforts to find a way at the moment, Please wait until it is fixed",
parameters: {
body: [
{
name: "image",
type: "file",
required: true,
description: "Image file to edit (or URL)",
fileConstraints: {
maxSize: 5 * 1024 * 1024, // 5MB
acceptedTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
acceptedExtensions: [".jpg", ".jpeg", ".png", ".gif", ".webp"]
},
acceptUrl: true
},
{
name: "model",
type: "string",
required: true,
description: "Select an AI model to edit your image.",
example: "nano_banana",
enum: ["nano_banana", "seed_dream", "flux", "qwen_image"],
default: "nano_banana"
},
{
name: "prompt",
type: "string",
required: true,
description: "Tell AI how your image will look edited",
example: "Put Cristiano Ronaldo next to that person"
},
{
name: "output_size",
type: "string",
required: true,
description: "Output size",
example: "2K",
enum: ["2K", "4K", "8K"],
default: "2K"
},
{
name: "disable_safety_checker",
type: "boolean",
required: false,
description: "If you want to disable safety checker for indecent images, set to true (default false)",
example: false,
default: false
}
]
},
responses: {
200: {
status: 200,
description: "Successfully retrieved data",
example: {
status: 200,
author: "Ditzzy",
note: "Thank you for using this API!",
results: {
image_url: "https://example.com/edited-image.jpg",
filename: "edited-image.jpg",
size: "2K"
}
}
},
404: {
status: 404,
description: "Missing required parameter",
example: {
status: 404,
message: "Missing required parameter"
}
},
400: {
status: 400,
description: "Invalid file or URL",
example: {
success: false,
message: "Invalid image file or URL"
}
},
413: {
status: 413,
description: "File too large",
example: {
success: false,
message: "File size exceeds 5MB limit"
}
},
500: {
status: 500,
description: "Server error or unavailable",
example: {
status: 500,
message: "An error occurred, please try again later."
}
}
},
exec: async (req, res) => {
upload.single('image')(req, res, async (err) => {
if (err) {
if (err instanceof multer.MulterError) {
if (err.code === 'LIMIT_FILE_SIZE') {
return res.status(413).json({
success: false,
message: "File size exceeds 5MB limit"
});
}
}
return res.status(400).json({
success: false,
message: err.message || "File upload error"
});
}
try {
const { prompt, output_size, disable_safety_checker, model } = req.body;
if (!prompt) {
return ErrorResponses.missingParameter(res, "prompt");
}
if (!output_size) {
return ErrorResponses.missingParameter(res, "output_size");
}
if (!model) {
return ErrorResponses.missingParameter(res, "model");
}
if (!ModelMap[model]) {
return res.status(400).json({
success: false,
message: `Invalid model. Must be one of: ${Object.keys(ModelMap).join(', ')}`
});
}
const ai = new AIEnhancer();
let imageBuffer;
let filename;
if (req.file) {
imageBuffer = req.file.buffer;
filename = req.file.originalname;
}
else if (req.body.image && typeof req.body.image === 'string') {
const imageUrl = req.body.image;
try {
new URL(imageUrl);
} catch {
return ErrorResponses.invalidUrl(res, "Invalid image URL");
}
const response = await axios.get(imageUrl, {
responseType: 'arraybuffer',
maxContentLength: 5 * 1024 * 1024,
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; AIImageEditor/1.0)'
}
});
imageBuffer = Buffer.from(response.data);
filename = path.basename(new URL(imageUrl).pathname) || 'image';
} else {
return ErrorResponses.missingParameter(res, "image (file or URL)");
}
const edit = await ai.ImageAIEditor(imageBuffer, model, {
size: output_size,
aspect_ratio: "match_input_image",
go_fast: true,
prompt: prompt,
output_quality: 100,
disable_safety_checker: disable_safety_checker === 'true' || disable_safety_checker === true,
});
return sendSuccess(res, edit.results);
} catch (e) {
console.error("Exception caught:", e);
return ErrorResponses.serverError(res, "An error occurred, try again later.");
}
});
}
}
export default handler;