import { NextApiHandler } from "next"; import formidable, { File, Fields, Files } from "formidable"; import fs from "fs"; import path from "path"; import { translateExcel, getExcelColumns, ColumnSelection } from "@utils/document-processors/excel"; import { translateDocx } from "@utils/document-processors/docx"; import { translatePdf } from "@utils/document-processors/pdf"; import { readSettings } from "@utils/settings-store"; export const config = { api: { bodyParser: false, responseLimit: "50mb" } }; type ParsedForm = { fields: Fields; files: Files; }; function parseForm(req: Parameters[0]): Promise { const form = formidable({ maxFileSize: 50 * 1024 * 1024 }); // 50 MB return new Promise((resolve, reject) => { form.parse(req, (err, fields, files) => { if (err) reject(err); else resolve({ fields, files }); }); }); } function getFileBuffer(file: File): Buffer { return fs.readFileSync(file.filepath); } function getField(fields: Fields, key: string): string | undefined { const val = fields[key]; return Array.isArray(val) ? val[0] : (val as string | undefined); } const handler: NextApiHandler = async (req, res) => { if (req.method !== "POST") { res.setHeader("Allow", ["POST"]); return res.status(405).json({ error: "Method Not Allowed" }); } const settings = readSettings(); if (!settings.replicateEnabled) { return res.status(503).json({ error: "Replicate translation is not enabled. Configure it in the admin panel." }); } let parsed: ParsedForm; try { parsed = await parseForm(req); } catch (err) { return res.status(400).json({ error: "Failed to parse upload" }); } const { fields, files } = parsed; const fileEntry = files["file"]; const file = Array.isArray(fileEntry) ? fileEntry[0] : fileEntry; if (!file) { return res.status(400).json({ error: "No file uploaded" }); } const targetLanguage = getField(fields, "targetLanguage") ?? "en"; const sourceLanguage = getField(fields, "sourceLanguage"); const action = getField(fields, "action") ?? "translate"; const columnSelectionsRaw = getField(fields, "columnSelections"); const filename = file.originalFilename ?? file.newFilename ?? "file"; const ext = path.extname(filename).toLowerCase(); const buffer = getFileBuffer(file); try { // Action: getColumns - return column info for Excel files if (action === "getColumns") { if (![".xlsx", ".xls", ".csv"].includes(ext)) { return res.status(400).json({ error: "Column selection only supported for Excel/CSV files" }); } const columns = getExcelColumns(buffer, filename); return res.status(200).json({ columns }); } // Action: translate let outBuffer: Buffer; let outMime: string; let outFilename: string; if ([".xlsx", ".xls"].includes(ext)) { let columnSelections: ColumnSelection[] = []; if (columnSelectionsRaw) { try { columnSelections = JSON.parse(columnSelectionsRaw); } catch { /* use empty = translate all */ } } outBuffer = await translateExcel(buffer, targetLanguage, columnSelections); outMime = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; outFilename = filename.replace(ext, `_${targetLanguage}${ext}`); } else if (ext === ".csv") { // Treat CSV as Excel let columnSelections: ColumnSelection[] = []; if (columnSelectionsRaw) { try { columnSelections = JSON.parse(columnSelectionsRaw); } catch { /* use empty = translate all */ } } outBuffer = await translateExcel(buffer, targetLanguage, columnSelections); outMime = "text/csv"; outFilename = filename.replace(ext, `_${targetLanguage}${ext}`); } else if (ext === ".docx") { outBuffer = await translateDocx(buffer, targetLanguage); outMime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; outFilename = filename.replace(ext, `_${targetLanguage}${ext}`); } else if (ext === ".pdf") { outBuffer = await translatePdf(buffer, targetLanguage, sourceLanguage); outMime = "application/pdf"; outFilename = filename.replace(ext, `_${targetLanguage}${ext}`); } else { return res.status(400).json({ error: `Unsupported file type: ${ext}. Supported: .pdf, .docx, .xlsx, .xls, .csv` }); } res.setHeader("Content-Type", outMime); res.setHeader("Content-Disposition", `attachment; filename="${outFilename}"`); res.setHeader("Content-Length", outBuffer.length); return res.status(200).send(outBuffer); } catch (err) { const msg = err instanceof Error ? err.message : "Translation failed"; return res.status(500).json({ error: msg }); } }; export default handler;