- Pair-Generierung markiert Nomen per [surface|lemma]-Markup und löst sie zu
{{label.o:objectId}} / {{label.w:wordId}} auf (Words werden auto-erstellt)
- Pipeline übersetzt + vertont Placeholder-Wörter aus den Sätzen mit
- translateText halluziniert keine ⟦PHn⟧-Tokens mehr (kein Token-Prompt ohne
Tokens, defensives Strippen); TTS/Review lösen geleakte Tokens auf
- POST /api/pipeline/repair-tokens repariert bestehende Sätze + Audios
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30 lines
1.3 KiB
JavaScript
30 lines
1.3 KiB
JavaScript
// Placeholder-Format in Satz-/Titel-Feldern: {{label.w:uuid}} (Wort) bzw. {{label.o:uuid}} (Objekt).
|
|
// Geteilt zwischen translate.js (Token-Schutz) und TTS (Auflösung in Sprechtext).
|
|
const PLACEHOLDER_RE = /\{\{([^.{}]+)\.(w|o):([0-9a-f-]{36})\}\}/g;
|
|
|
|
// Legacy-Form ohne Label: {{uuid}} — sollte migriert sein, defensiv trotzdem entfernen.
|
|
const LEGACY_PLACEHOLDER_RE = /\{\{\s*[0-9a-f-]{36}\s*\}\}/g;
|
|
|
|
// Schutz-Token während Übersetzung/Review: ⟦PHn:label⟧. Darf nie in der DB landen —
|
|
// falls doch (Claude-Halluzination), wird er überall defensiv zum Label aufgelöst.
|
|
const TOKEN_RE = /⟦(PH\d+):([^⟧]*)⟧/g;
|
|
|
|
// Entfernt geleakte ⟦PHn:label⟧-Tokens aus einem Text → nur das Label bleibt.
|
|
function stripLeakedTokens(text) {
|
|
if (!text) return text;
|
|
return String(text).replace(TOKEN_RE, (_, _key, label) => label.trim());
|
|
}
|
|
|
|
// Macht aus "Ist das ein {{Apfel.w:1234-…}}?" → "Ist das ein Apfel?" (für TTS/Anzeige).
|
|
function resolvePlaceholdersToLabels(text) {
|
|
if (!text) return '';
|
|
return String(text)
|
|
.replace(PLACEHOLDER_RE, (_, label) => label)
|
|
.replace(LEGACY_PLACEHOLDER_RE, '')
|
|
.replace(TOKEN_RE, (_, _key, label) => label.trim())
|
|
.replace(/\s{2,}/g, ' ')
|
|
.trim();
|
|
}
|
|
|
|
module.exports = { PLACEHOLDER_RE, TOKEN_RE, stripLeakedTokens, resolvePlaceholdersToLabels };
|