feat: add admin panel, Replicate AI translation, and document translation
- Admin panel (/admin) with JWT auth: configure Replicate API token,
JigsawStack API key, model version, enable/disable AI translation,
change admin password. Settings persisted in data/settings.json.
- Replicate AI translation: POST /api/translate/replicate uses
JigsawStack text-translate model via Replicate API. Main page
switches to client-side AI translation when enabled.
- Document translation tab: supports PDF, DOCX, XLSX, XLS, CSV.
Excel/Word formatting fully preserved (SheetJS + JSZip XML manipulation).
PDF uses pdf-parse extraction + pdf-lib reconstruction.
Column selector UI for tabular data (per-sheet, All/None toggles).
- Updated README with full implementation documentation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 07:43:54 +01:00
|
|
|
import { NextApiHandler } from "next";
|
|
|
|
|
import { requireAdmin } from "@utils/admin-auth";
|
|
|
|
|
import { readSettings, writeSettings } from "@utils/settings-store";
|
|
|
|
|
|
|
|
|
|
const handler: NextApiHandler = async (req, res) => {
|
|
|
|
|
if (!(await requireAdmin(req, res))) return;
|
|
|
|
|
|
|
|
|
|
if (req.method === "GET") {
|
|
|
|
|
const settings = readSettings();
|
|
|
|
|
// Never expose the adminPasswordHash
|
|
|
|
|
const { adminPasswordHash: _omit, ...safe } = settings;
|
|
|
|
|
return res.status(200).json(safe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (req.method === "POST") {
|
|
|
|
|
const {
|
|
|
|
|
replicateApiToken,
|
|
|
|
|
jigsawApiKey,
|
|
|
|
|
modelVersion,
|
|
|
|
|
replicateEnabled,
|
2026-03-10 08:50:40 +01:00
|
|
|
replicateMode,
|
|
|
|
|
localEndpoint,
|
feat: add admin panel, Replicate AI translation, and document translation
- Admin panel (/admin) with JWT auth: configure Replicate API token,
JigsawStack API key, model version, enable/disable AI translation,
change admin password. Settings persisted in data/settings.json.
- Replicate AI translation: POST /api/translate/replicate uses
JigsawStack text-translate model via Replicate API. Main page
switches to client-side AI translation when enabled.
- Document translation tab: supports PDF, DOCX, XLSX, XLS, CSV.
Excel/Word formatting fully preserved (SheetJS + JSZip XML manipulation).
PDF uses pdf-parse extraction + pdf-lib reconstruction.
Column selector UI for tabular data (per-sheet, All/None toggles).
- Updated README with full implementation documentation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 07:43:54 +01:00
|
|
|
newPassword
|
|
|
|
|
} = req.body ?? {};
|
|
|
|
|
|
|
|
|
|
const updates: Parameters<typeof writeSettings>[0] = {};
|
|
|
|
|
if (replicateApiToken !== undefined) updates.replicateApiToken = replicateApiToken;
|
|
|
|
|
if (jigsawApiKey !== undefined) updates.jigsawApiKey = jigsawApiKey;
|
|
|
|
|
if (modelVersion !== undefined) updates.modelVersion = modelVersion;
|
|
|
|
|
if (replicateEnabled !== undefined) updates.replicateEnabled = Boolean(replicateEnabled);
|
2026-03-10 08:50:40 +01:00
|
|
|
if (replicateMode === "cloud" || replicateMode === "local") updates.replicateMode = replicateMode;
|
|
|
|
|
if (localEndpoint !== undefined) updates.localEndpoint = localEndpoint;
|
feat: add admin panel, Replicate AI translation, and document translation
- Admin panel (/admin) with JWT auth: configure Replicate API token,
JigsawStack API key, model version, enable/disable AI translation,
change admin password. Settings persisted in data/settings.json.
- Replicate AI translation: POST /api/translate/replicate uses
JigsawStack text-translate model via Replicate API. Main page
switches to client-side AI translation when enabled.
- Document translation tab: supports PDF, DOCX, XLSX, XLS, CSV.
Excel/Word formatting fully preserved (SheetJS + JSZip XML manipulation).
PDF uses pdf-parse extraction + pdf-lib reconstruction.
Column selector UI for tabular data (per-sheet, All/None toggles).
- Updated README with full implementation documentation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 07:43:54 +01:00
|
|
|
if (newPassword && typeof newPassword === "string" && newPassword.length >= 6) {
|
|
|
|
|
updates.adminPasswordHash = newPassword;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const saved = writeSettings(updates);
|
|
|
|
|
const { adminPasswordHash: _omit, ...safe } = saved;
|
|
|
|
|
return res.status(200).json(safe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.setHeader("Allow", ["GET", "POST"]);
|
|
|
|
|
return res.status(405).json({ error: "Method Not Allowed" });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default handler;
|