| | 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, |
| | }, |
| | 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.')); |
| | } |
| | } |
| | }); |
| |
|
| | |
| | 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, |
| | 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; |