100 lines
4.6 KiB
JavaScript
100 lines
4.6 KiB
JavaScript
import { z } from "zod";
|
|
import axios from "axios";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { withAuth } from "../../auth/index.js";
|
|
import { handleToolError } from "../helpers/errorHandler.js";
|
|
import { withAuthParams } from "../helpers/authSchema.js";
|
|
import { pythonPost } from "../helpers/pythonServerClient.js";
|
|
import { resolveCurrentProjectDir } from "../files/helpers.js";
|
|
|
|
// --- Verificacion de creditos ---
|
|
const WS_BASE = "https://ws.cocosolution.com/api/handler_acaicode.php";
|
|
|
|
function getAcaiToken() {
|
|
const projectDir = resolveCurrentProjectDir();
|
|
if (!projectDir) return null;
|
|
try {
|
|
const acaiFile = path.join(projectDir, ".acai");
|
|
const data = JSON.parse(fs.readFileSync(acaiFile, "utf-8"));
|
|
return data.token || null;
|
|
} catch { return null; }
|
|
}
|
|
|
|
async function checkCredits() {
|
|
const token = getAcaiToken();
|
|
if (!token) return false; // Si no hay token, no bloquear
|
|
const testParam = process.env.STRIPE_MODE === "test" ? "&test" : "";
|
|
try {
|
|
const resp = await axios.put(`${WS_BASE}?action=getUsageLimits${testParam}`, {}, {
|
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
timeout: 10000,
|
|
});
|
|
return resp.data?.data?.exceeded === true;
|
|
} catch { return false; }
|
|
}
|
|
|
|
export function registerGenerateImageTool(server) {
|
|
server.tool(
|
|
"generate_image",
|
|
`Generate an AI image and save it to the project's uploads folder. Returns preview URLs plus the recommended upload URL for upload_record_image. In Forge environments, prefer uploadUrl (or fullUrl if uploadUrl is absent) over dockerUrl when assigning the image to a record field.`,
|
|
withAuthParams({
|
|
prompt: z.string().describe("Description of the image to generate"),
|
|
width: z.number().optional().describe("Image width in pixels (default: 1024)"),
|
|
height: z.number().optional().describe("Image height in pixels (default: 1024)"),
|
|
style: z.string().optional().describe("Image style hint to add to prompt (e.g., 'photographic', 'digital-art', 'minimalist')"),
|
|
fileName: z.string().optional().describe("Custom filename (without extension). If not provided, auto-generated."),
|
|
}),
|
|
{ readOnlyHint: false, destructiveHint: false },
|
|
withAuth(async ({ prompt, width = 1024, height = 1024, style, fileName }, extra) => {
|
|
try {
|
|
// Verificar creditos antes de generar
|
|
const exceeded = await checkCredits();
|
|
if (exceeded) {
|
|
return {
|
|
content: [{ type: "text", text: "Error: No te quedan creditos. Mejora tu plan para seguir usando el asistente." }],
|
|
isError: true,
|
|
};
|
|
}
|
|
|
|
const projectSlug = path.basename(resolveCurrentProjectDir());
|
|
const safeFileName = fileName || `generated-${Date.now()}`;
|
|
const destRelativePath = `cms/uploads/generated/${safeFileName}.jpg`;
|
|
const fullPrompt = style ? `${style} style: ${prompt}` : prompt;
|
|
|
|
let result;
|
|
try {
|
|
result = await pythonPost("/api/generate-image", {
|
|
project: projectSlug,
|
|
prompt: fullPrompt,
|
|
destRelativePath,
|
|
}, 180000); // 3min timeout para generacion IA
|
|
} catch (pyErr) {
|
|
return handleToolError(new Error(`Python generate-image failed: ${pyErr.response?.data?.error || pyErr.message}`), 'generate_image', { prompt });
|
|
}
|
|
|
|
if (!result?.success) {
|
|
return { content: [{ type: "text", text: JSON.stringify({ error: result?.error || "Generation failed" }, null, 2) }], isError: true };
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify({
|
|
success: true,
|
|
message: `Image generated and saved to ${result.relativePath}`,
|
|
uploadUrl: result.fullUrl || result.dockerUrl,
|
|
fullUrl: result.fullUrl || result.dockerUrl,
|
|
relativePath: result.relativePath,
|
|
fileName: result.fileName,
|
|
size: result.size,
|
|
}, null, 2),
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return handleToolError(error, "generate_image", { prompt });
|
|
}
|
|
})
|
|
);
|
|
}
|