fix: traduccion con rotacion de modelos + filtro anti-basura + benchmark de modelos
This commit is contained in:
+40
-3
@@ -27,7 +27,26 @@ export async function translateTitle(title: string): Promise<string | null> {
|
||||
// Si ya parece estar en español, no traducir (heurística ligera).
|
||||
if (isProbablySpanish(clean)) return clean
|
||||
|
||||
const models = ["deepseek-v4-flash-free", "big-pickle"]
|
||||
// Modelos en orden de preferencia (benchmark real 2026-08):
|
||||
// nemotron-3-nano-omni y openrouter/free traducen bien.
|
||||
const models = [
|
||||
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
|
||||
"openrouter/free",
|
||||
"deepseek-v4-flash-free",
|
||||
"big-pickle",
|
||||
"tencent/hy3:free",
|
||||
"nvidia/nemotron-3-ultra-550b-a55b:free",
|
||||
"mimo-v2.5-free",
|
||||
"cohere/north-mini-code:free",
|
||||
"inclusionai/ling-3.0-flash:free",
|
||||
"nvidia/nemotron-3-super-120b-a12b:free",
|
||||
"nemotron-3-ultra-free",
|
||||
"north-mini-code-free",
|
||||
"poolside/laguna-s-2.1:free",
|
||||
"poolside/laguna-xs-2.1:free",
|
||||
"kilo-auto/free",
|
||||
"forever_free",
|
||||
]
|
||||
|
||||
for (const model of models) {
|
||||
try {
|
||||
@@ -51,8 +70,11 @@ export async function translateTitle(title: string): Promise<string | null> {
|
||||
if (!res.ok) continue
|
||||
const data = await res.json()
|
||||
const content: string | undefined = data?.choices?.[0]?.message?.content
|
||||
if (!content || !content.trim()) continue
|
||||
return content.trim().replace(/^["']|["']$/g, "")
|
||||
const text = (content || "").trim().replace(/^["']|["']$/g, "")
|
||||
if (!text) continue
|
||||
// Rechazar respuestas que NO son traducción (repiten el prompt).
|
||||
if (!isValidTranslation(text)) continue
|
||||
return text
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
@@ -60,6 +82,21 @@ export async function translateTitle(title: string): Promise<string | null> {
|
||||
return null
|
||||
}
|
||||
|
||||
// Filtra respuestas basura: si el modelo razona en voz alta ("The user
|
||||
// wants...") o entrega explicaciones, no es una traducción válida.
|
||||
function isValidTranslation(text: string): boolean {
|
||||
const t = text.toLowerCase()
|
||||
const junk = [
|
||||
"the user wants", "the task", "i need to", "i'll", "the manga title",
|
||||
"esta es una traducción", "aquí tienes", "la traducción es", "claro que",
|
||||
"por supuesto", "the translation", "here is", "the title", "sure",
|
||||
"voy a traducir", "the user asked", "the user is",
|
||||
]
|
||||
if (text.length > 120) return false
|
||||
for (const j of junk) if (t.includes(j)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
// Heurística: detecta si el título ya está mayormente en español (para no
|
||||
// re-traducir nombres propios o títulos ya en español).
|
||||
function isProbablySpanish(t: string): boolean {
|
||||
|
||||
Reference in New Issue
Block a user