import type { NextApiRequest, NextApiResponse } from "next"; import { VALID_MODELS, validateModel, validateApiKey } from "../../lib/config"; import { getCachedGeneration, setCachedGeneration } from "../../lib/cache"; import type { GenerateRequestBody } from "../../lib/types"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { res.setHeader("Content-Type", "application/json"); if (req.method !== "POST") { return res.status(405).json({ error: "Method not allowed" }); } const hfApiKey = process.env.HF_API_KEY; if (!validateApiKey(hfApiKey)) { return res.status(500).json({ error: "Invalid or missing Hugging Face API key" }); } const model = VALID_MODELS.ACE_STEP; if (!validateModel(model)) { return res.status(500).json({ error: "Invalid model configuration" }); } let body: GenerateRequestBody; try { body = req.body as GenerateRequestBody; } catch { return res.status(400).json({ error: "Invalid JSON body" }); } const { stylePrompt, lyricPrompt = "", voice = "Random", durationSeconds, } = body; if (!stylePrompt || typeof stylePrompt !== "string") { return res.status(400).json({ error: "stylePrompt is required" }); } const duration = typeof durationSeconds === "number" ? Math.min(240, Math.max(30, durationSeconds)) : Math.floor(Math.random() * (240 - 30 + 1)) + 30; const cacheKey = JSON.stringify({ stylePrompt, lyricPrompt, voice, duration }); const cached = getCachedGeneration(cacheKey); if (cached) { return res.status(200).json({ cached: true, ...cached }); } try { const payload = { inputs: { text: `${stylePrompt}\n${lyricPrompt}`, voice, duration, }, }; const hfUrl = `https://api-inference.huggingface.co/models/${encodeURIComponent(model)}`; const response = await fetch(hfUrl, { method: "POST", headers: { Authorization: `Bearer ${hfApiKey}`, "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(payload), }); if (!response.ok) { const errText = await response.text().catch(() => ""); return res.status(response.status).json({ error: "Model request failed", details: errText || response.statusText, }); } const result = await response.json(); const data = { cached: false, model, duration, voice, result, }; setCachedGeneration(cacheKey, data); return res.status(200).json(data); } catch (e: any) { return res.status(500).json({ error: "Unexpected error during generation", details: e?.message ?? "Unknown error", }); } }