GoodWordsOnly / api /predict.js
Jathin Chetty
Vercel-ready API version without model artifacts
f7a8d72
const LABEL_NAMES = {
LABEL_0: "Appropriate",
LABEL_1: "Inappropriate",
LABEL_2: "Offensive",
LABEL_3: "Violent",
};
function normalizeScores(rawOutput) {
if (!Array.isArray(rawOutput) || rawOutput.length === 0) {
throw new Error("Unexpected model response format");
}
const scores = Array.isArray(rawOutput[0]) ? rawOutput[0] : rawOutput;
const normalized = scores
.filter((item) => item && typeof item === "object" && item.label)
.map((item) => ({
label: item.label,
display_label: LABEL_NAMES[item.label] || item.label,
score: Number(item.score || 0),
}))
.sort((a, b) => b.score - a.score);
if (normalized.length === 0) {
throw new Error("Model returned no class scores");
}
return normalized;
}
export default async function handler(req, res) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
try {
const body = typeof req.body === "string" ? JSON.parse(req.body) : req.body;
const text = (body?.text || "").trim();
if (!text) {
return res.status(400).json({ error: "Text cannot be empty" });
}
const model = process.env.HF_MODEL || "IMSyPP/hate_speech_multilingual";
const token = process.env.HF_TOKEN || "";
const endpoint = `https://router.huggingface.co/hf-inference/models/${model}`;
const headers = { "Content-Type": "application/json" };
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const hfResponse = await fetch(endpoint, {
method: "POST",
headers,
body: JSON.stringify({
inputs: text,
parameters: {
top_k: null,
function_to_apply: "softmax",
},
}),
});
if (!hfResponse.ok) {
const message = await hfResponse.text();
if (hfResponse.status === 401) {
return res.status(500).json({
error: "Hugging Face authentication failed. Set HF_TOKEN in Vercel env vars.",
});
}
return res.status(500).json({
error: `Hugging Face API error (${hfResponse.status}): ${message}`,
});
}
const responseData = await hfResponse.json();
const classes = normalizeScores(responseData);
const top = classes[0];
return res.status(200).json({
model,
label: top.label,
display_label: top.display_label,
probability: top.score,
classes,
});
} catch (error) {
return res.status(500).json({ error: error.message || "Internal server error" });
}
}