openreader/compute/core/src/whisper/alignment-map.ts

54 lines
1.4 KiB
TypeScript

import type { TTSSentenceAlignment, TTSSentenceWord } from '../types/tts';
function preprocessSentenceForAudio(text: string): string {
return text
.replace(/\S*(?:https?:\/\/|www\.)([^\/\s]+)(?:\/\S*)?/gi, '- (link to $1) -')
.replace(/(\w+)-\s+(\w+)/g, '$1$2')
.replace(/\*/g, '')
.replace(/\s+/g, ' ')
.trim();
}
export interface WhisperWord {
start: number;
end: number;
word: string;
}
export function mapWordsToSentenceOffsets(sentence: string, words: WhisperWord[]): TTSSentenceAlignment {
const normalizedSentence = preprocessSentenceForAudio(sentence);
const lowerSentence = normalizedSentence.toLowerCase();
let cursor = 0;
const alignedWords: TTSSentenceWord[] = words.map((w) => {
const token = w.word.trim();
if (!token) {
return {
text: '',
startSec: w.start,
endSec: w.end,
charStart: cursor,
charEnd: cursor,
};
}
const idx = lowerSentence.indexOf(token.toLowerCase(), cursor);
const start = idx >= 0 ? idx : cursor;
const end = Math.min(normalizedSentence.length, start + token.length);
cursor = Math.max(cursor, end);
return {
text: token,
startSec: w.start,
endSec: w.end,
charStart: start,
charEnd: end,
};
}).filter((word) => word.text.length > 0);
return {
sentence,
sentenceIndex: 0,
words: alignedWords,
};
}