Skip to content

Improve the transcript alignment algorithm (timing interpolation, punctuation-aware matching, large-transcript performance) #425

Description

@maboa

The alignment algorithm in js/word-alignment.js (the "align previously transcribed content" feature, #259) uses Levenshtein edit-distance to map a human-corrected transcript onto the machine transcript's word timings. It works, but has several concrete weaknesses worth addressing:

1. Inserted-word timing is borrowed wholesale from one neighbour.
generateAlignedJSON gives every inserted word the next matched word's start/end verbatim (falling back to the previous). A run of several inserted words therefore collapses to identical timestamps — producing zero-duration and overlapping cues. Timing should be distributed/interpolated across the gap between the two surrounding anchored words, so inserted words get monotonic, non-overlapping spans.

2. Punctuation-aware matching is documented but not applied.
normalizeWord/stripPunctuation exist, but alignWords compares raw .toLowerCase() (lines 504 & 540). So "hello," vs "hello" scores as a substitution, not a match, inflating edit distance and worsening alignment. Numbers ("20" vs "twenty"), contractions, and hyphenation cause the same spurious substitutions. The DP comparison should normalise (and ideally handle number-word and contraction equivalence).

3. Full O(m×n) DP table over the whole transcript.
Memory/time grows with the product of both lengths — a long transcript (tens of thousands of words) builds an enormous table. Consider anchored / banded alignment (split on high-confidence match anchors and align segments) to bound cost.

4. Leftover debug output.
alignTranscripts has several console.log calls (lines 792–799) that should be removed.

Suggested acceptance criteria / tests:

  • Insert-run timings are strictly monotonic with no zero/negative durations or overlaps.
  • Normalised matches (trailing punctuation, case) count as matches, not substitutions.
  • A performance guard for large inputs.

The module is already self-contained, so this can be reworked and unit-tested in isolation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions