54 lines
1.4 KiB
TypeScript
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,
|
|
};
|
|
}
|