Update TTS providers and story markup
This commit is contained in:
@@ -161,6 +161,7 @@ export class InkEngine {
|
||||
const paragraphs: TurnResult['paragraphs'] = [];
|
||||
const globalTags: StoryTag[] = [];
|
||||
const turnTags: StoryTag[] = [];
|
||||
let pendingParagraphTags: StoryTag[] = [];
|
||||
|
||||
while (this.story.canContinue) {
|
||||
const rawText = this.story.Continue();
|
||||
@@ -173,11 +174,24 @@ export class InkEngine {
|
||||
.forEach((tag) => globalTags.push(tag));
|
||||
|
||||
if (text) {
|
||||
paragraphs.push({ text, tags });
|
||||
const paragraphTags = this.reassignTrailingGlossTags(text, [...pendingParagraphTags, ...tags], paragraphs);
|
||||
pendingParagraphTags = [];
|
||||
paragraphs.push({ text, tags: paragraphTags });
|
||||
} else {
|
||||
tags.forEach((tag) => globalTags.push(tag));
|
||||
const paragraphTags = this.reassignTrailingGlossTags('', tags, paragraphs);
|
||||
paragraphTags.forEach((tag) => {
|
||||
if (this.isParagraphScopedTag(tag)) {
|
||||
pendingParagraphTags.push(tag);
|
||||
} else {
|
||||
globalTags.push(tag);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (pendingParagraphTags.length > 0) {
|
||||
globalTags.push(...pendingParagraphTags);
|
||||
pendingParagraphTags = [];
|
||||
}
|
||||
|
||||
const choices = this.story.currentChoices.map((choice): ChoiceResult => {
|
||||
const tags = this.getChoiceTags(choice);
|
||||
@@ -234,6 +248,68 @@ export class InkEngine {
|
||||
};
|
||||
}
|
||||
|
||||
private isParagraphScopedTag(tag: StoryTag): boolean {
|
||||
const key = String(tag?.key || '').toLowerCase();
|
||||
return ['chapter', 'heading', 'section', 'textblock', 'image', 'music', 'sfx', 'sound', 'audio', 'gloss', 'tts']
|
||||
.includes(key) || key.startsWith('tts-');
|
||||
}
|
||||
|
||||
private reassignTrailingGlossTags(
|
||||
text: string,
|
||||
tags: StoryTag[],
|
||||
paragraphs: TurnResult['paragraphs'],
|
||||
): StoryTag[] {
|
||||
if (!Array.isArray(tags) || tags.length === 0) return [];
|
||||
|
||||
const previous = paragraphs.length > 0 ? paragraphs[paragraphs.length - 1] : null;
|
||||
if (!previous) return tags;
|
||||
|
||||
const currentText = this.normalizeGlossMatchText(text);
|
||||
const previousText = this.normalizeGlossMatchText(previous.text);
|
||||
const remainingTags: StoryTag[] = [];
|
||||
|
||||
tags.forEach((tag) => {
|
||||
if (tag.key === 'tts' || tag.key.startsWith('tts-')) {
|
||||
if (!currentText) {
|
||||
previous.tags.push(tag);
|
||||
} else {
|
||||
remainingTags.push(tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag.key !== 'gloss') {
|
||||
remainingTags.push(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
const term = this.normalizeGlossMatchText(tag.value || '');
|
||||
if (!term) {
|
||||
remainingTags.push(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
const matchesCurrent = currentText.includes(term);
|
||||
const matchesPrevious = previousText.includes(term);
|
||||
if (!matchesCurrent && matchesPrevious) {
|
||||
previous.tags.push(tag);
|
||||
} else {
|
||||
remainingTags.push(tag);
|
||||
}
|
||||
});
|
||||
|
||||
return remainingTags;
|
||||
}
|
||||
|
||||
private normalizeGlossMatchText(value: string): string {
|
||||
return String(value || '')
|
||||
.normalize('NFC')
|
||||
.toLocaleLowerCase('de-DE')
|
||||
.replace(/[.,;:!?()[\]{}"'„“”‚‘’»«]/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
private getChoiceTags(choice: any): StoryTag[] {
|
||||
const directTags = parseTags(choice?.tags || []);
|
||||
const previewTags = this.extractChoicePreviewTags(choice);
|
||||
|
||||
Reference in New Issue
Block a user