fix: Übersetzungs-Retry + robuster Translate-Step + Nachhol-Endpoints
- callClaude: Retry mit Backoff bei Überlast/Rate-Limit/Netzfehler (429/500/503/529) — wahrscheinliche Ursache der fehlenden SV-Übersetzung - Translate-Step pro Pair gekapselt: ein Fehler reißt nicht mehr den ganzen Lauf ab, Fehlversuche werden gezählt (pipeline_progress.translateFailures) - translatePair als wiederverwendbarer Helfer extrahiert - POST /pipeline/picture/:id/translate-fill: fehlende Übersetzungen (Sätze + Antwort-Wörter) eines Bildes nachholen Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -139,33 +139,19 @@ async function runPicture(pictureId) {
|
||||
} catch (err) { await setFailed(pictureId, 'pairs', err); return; }
|
||||
|
||||
// ── Step 2: Übersetzen (pro Pair, füllt nur fehlende Sprachen) ──────────────
|
||||
// Pro Pair gekapselt: scheitert eine Übersetzung (z.B. transienter API-Fehler trotz
|
||||
// Retry), verliert das nicht den ganzen Lauf — der Rest läuft weiter, Fehlende werden
|
||||
// gezählt und können später über „Übersetzungen nachholen" ergänzt werden.
|
||||
const pairs = await loadPairs(pictureId);
|
||||
progress.pairsTotal = pairs.length;
|
||||
try {
|
||||
progress.translateFailures = 0;
|
||||
await setStep(pictureId, 'translate', progress);
|
||||
for (const p of pairs) {
|
||||
try { await translatePair(p); }
|
||||
catch (err) { progress.translateFailures++; console.error(`Translate-Fehler bei Pair ${p.id}:`, err.message); }
|
||||
progress.translatedPairs++;
|
||||
await setStep(pictureId, 'translate', progress);
|
||||
for (const p of pairs) {
|
||||
let questionRow = null;
|
||||
if (p.question_id) {
|
||||
questionRow = (await query(
|
||||
`SELECT sentence_de, sentence_en, sentence_sv FROM questions WHERE id = $1`,
|
||||
[p.question_id])).rows[0] || null;
|
||||
await fillMissingRow('questions', p.question_id, ['sentence']);
|
||||
}
|
||||
if (p.answer_type === 'word') {
|
||||
if (p.positive_statement_id)
|
||||
await translateWordGroup(p.positive_statement_id, 'statement_positive_words', questionRow, false);
|
||||
if (p.negative_statement_id)
|
||||
await translateWordGroup(p.negative_statement_id, 'statement_negative_words', questionRow, false);
|
||||
} else {
|
||||
if ((p.answer_type === 'text' || p.answer_type === 'question') && p.positive_statement_id)
|
||||
await fillMissingRow('statements', p.positive_statement_id, ['positive_sentence']);
|
||||
if (p.answer_type === 'question' && p.negative_statement_id)
|
||||
await fillMissingRow('statements', p.negative_statement_id, ['negative_sentence']);
|
||||
}
|
||||
progress.translatedPairs++;
|
||||
await setStep(pictureId, 'translate', progress);
|
||||
}
|
||||
} catch (err) { await setFailed(pictureId, 'translate', err); return; }
|
||||
}
|
||||
|
||||
// ── Step 3: Audio für alle Sätze + Wörter des Bildes in allen Sprachen ──────
|
||||
try {
|
||||
@@ -214,6 +200,29 @@ async function runPicture(pictureId) {
|
||||
} catch (err) { await setFailed(pictureId, 'finish', err); return; }
|
||||
}
|
||||
|
||||
// Übersetzt die fehlenden Sprachen EINES Pairs (Frage + Sätze bzw. Wort-Gruppen).
|
||||
// overwrite=true übersetzt auch bereits gefüllte Zielsprachen neu.
|
||||
async function translatePair(p, overwrite = false) {
|
||||
let questionRow = null;
|
||||
if (p.question_id) {
|
||||
questionRow = (await query(
|
||||
`SELECT sentence_de, sentence_en, sentence_sv FROM questions WHERE id = $1`,
|
||||
[p.question_id])).rows[0] || null;
|
||||
await fillMissingRow('questions', p.question_id, ['sentence'], { overwrite });
|
||||
}
|
||||
if (p.answer_type === 'word') {
|
||||
if (p.positive_statement_id)
|
||||
await translateWordGroup(p.positive_statement_id, 'statement_positive_words', questionRow, overwrite);
|
||||
if (p.negative_statement_id)
|
||||
await translateWordGroup(p.negative_statement_id, 'statement_negative_words', questionRow, overwrite);
|
||||
} else {
|
||||
if ((p.answer_type === 'text' || p.answer_type === 'question') && p.positive_statement_id)
|
||||
await fillMissingRow('statements', p.positive_statement_id, ['positive_sentence'], { overwrite });
|
||||
if (p.answer_type === 'question' && p.negative_statement_id)
|
||||
await fillMissingRow('statements', p.negative_statement_id, ['negative_sentence'], { overwrite });
|
||||
}
|
||||
}
|
||||
|
||||
// Alle 3 Sprachen in den genutzten Feldern des Pairs gefüllt? (Spiegel des Review-Checks)
|
||||
async function isPairComplete(p) {
|
||||
if (p.question_id) {
|
||||
@@ -334,4 +343,4 @@ async function generateWithBackoff(u) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { enqueue, resumePending, loadPairs, collectAudioUnits, generateWithBackoff };
|
||||
module.exports = { enqueue, resumePending, loadPairs, collectAudioUnits, generateWithBackoff, translatePair };
|
||||
|
||||
Reference in New Issue
Block a user