Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
62c93e5
feat: implement caption word deletion, filler detection, and timeline…
ganganimaulik Jun 1, 2026
751dfdf
fix: add auxiliary metadata fields to CaptionWord type and update str…
ganganimaulik Jun 1, 2026
88b85a7
fix: restore video with word restore
ganganimaulik Jun 1, 2026
eab4d9e
feat(desktop): implement transcript editing buffers and ripple deletion
ganganimaulik Jun 1, 2026
15f4340
feat(desktop): support deleting pauses and cap word duration during t…
ganganimaulik Jun 1, 2026
b194ea5
improve(desktop): refine word duration capping, buffer popover intera…
ganganimaulik Jun 1, 2026
cc6857c
fix(desktop): prevent timeline word stretching during ripple insert
ganganimaulik Jun 1, 2026
510cebe
fix(desktop): map isFiller with fallback to isFillerWord
ganganimaulik Jun 1, 2026
ad0f51a
fix(desktop): force array update in autoClean to guarantee reactivity…
ganganimaulik Jun 1, 2026
c412566
fix(desktop): correctly fallback to isFillerWord evaluation for old p…
ganganimaulik Jun 1, 2026
91f6523
fix: resolve undo/redo break when adjusting buffer for deleted words
ganganimaulik Jun 1, 2026
11676f7
fix(desktop): detect pauses after removing filler words to accurately…
ganganimaulik Jun 1, 2026
fd7ba58
fix(desktop): import detectPauses in TranscriptPage.tsx
ganganimaulik Jun 1, 2026
0fc0ea0
feat(desktop): implement auto-clean undo and refine transcript editin…
ganganimaulik Jun 1, 2026
79a951b
improve(desktop): refine auto-clean logic and remove redundant undo h…
ganganimaulik Jun 1, 2026
f8d3428
feat(desktop): refine transcript pause and filler auto-clean index tr…
ganganimaulik Jun 1, 2026
6d31241
feat: improve transcript editor buffers, pause deletion, and playhead…
ganganimaulik Jun 1, 2026
90d5c39
fix: resolve timeline buffer logic and deleted words coordinate tracking
ganganimaulik Jun 1, 2026
f2e7792
fix: manual timeline shift logic to prevent crushing words, and pause…
ganganimaulik Jun 1, 2026
fa46d35
chore: add timeline shifting tests and filler updates
ganganimaulik Jun 1, 2026
387ea11
Merge branch 'main' into feat/transcript-editing-buffers
ganganimaulik Jun 1, 2026
918853d
fix: subtract deleted word durations from pause detection gaps in Tra…
ganganimaulik Jun 1, 2026
500ccb6
fix: prevent destructive positive buffers to avoid timeline corruption
ganganimaulik Jun 1, 2026
56fad70
fix: revert to manual loop in handleBufferChange to prevent shifting …
ganganimaulik Jun 1, 2026
dfa8dfe
fix: reset buffer manually inside restoreWords to perfectly reconstru…
ganganimaulik Jun 1, 2026
cadf82f
Revert "fix: reset buffer manually inside restoreWords to perfectly r…
ganganimaulik Jun 1, 2026
10c891a
fix: use manual shifting without clamping to flawlessly restore posit…
ganganimaulik Jun 1, 2026
a49f706
fix: change w.storedEnd to w.end in restoreWords because CaptionWordE…
ganganimaulik Jun 1, 2026
6f62b68
fix: remove timeline clamping in handleBufferChange and replace binar…
ganganimaulik Jun 1, 2026
9680424
fix: update gap duration calculation logic and reformat active word i…
ganganimaulik Jun 2, 2026
a15d657
feat: close auto-clean dropdown when clicking outside its container
ganganimaulik Jun 2, 2026
9b8c4f1
fix: disable auto clean button when pauses do not exceed silence thre…
ganganimaulik Jun 2, 2026
4ac5eb4
refactor: process restoration words chronologically to ensure correct…
ganganimaulik Jun 2, 2026
b23da7b
refactor: extract word duration capping logic into a helper function …
ganganimaulik Jun 2, 2026
8aa43da
Merge remote-tracking branch 'upstream/main' into feat/transcript-edi…
ganganimaulik Jun 2, 2026
e4738fb
fix: transcript backspace deletion and scroll container focus
ganganimaulik Jun 2, 2026
63a61fe
fix: restrict negative buffer to 50% of word duration
ganganimaulik Jun 2, 2026
5859681
feat: treat pauses as first-class word entities
ganganimaulik Jun 9, 2026
0e15333
Merge remote-tracking branch 'upstream/main' into feat/transcript-edi…
ganganimaulik Jun 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions apps/desktop/src-tauri/src/captions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,15 @@ fn process_with_whisper(

log::info!(" Segment {i} has {num_tokens} tokens");

let cap_word_end = |text: &str, start: f32, end: f32| -> f32 {
let max_duration = (text.len() as f32 * 0.1).clamp(0.5, 1.5);
if end - start > max_duration + 0.3 {
start + max_duration
} else {
end
}
};

let mut current_word = String::new();
let mut word_start: Option<f32> = None;
let mut word_end: f32 = start_time;
Expand Down Expand Up @@ -812,16 +821,17 @@ fn process_with_whisper(
if !current_word.is_empty()
&& let Some(ws) = word_start
{
let text = current_word.trim().to_string();
word_end = cap_word_end(&text, ws, word_end);

log::info!(
" -> Completing word: '{}' ({:.2}s - {:.2}s)",
current_word.trim(),
ws,
word_end
" -> Completing word: '{text}' ({ws:.2}s - {word_end:.2}s)"
);
words.push(CaptionWord {
text: current_word.trim().to_string(),
text,
start: ws,
end: word_end,
..Default::default()
});
}
current_word = token_text.trim().to_string();
Expand All @@ -844,16 +854,16 @@ fn process_with_whisper(
if !current_word.trim().is_empty()
&& let Some(ws) = word_start
{
let text = current_word.trim().to_string();
word_end = cap_word_end(&text, ws, word_end);
log::info!(
" -> Final word: '{}' ({:.2}s - {:.2}s)",
current_word.trim(),
ws,
word_end
" -> Final word: '{text}' ({ws:.2}s - {word_end:.2}s)"
);
Comment thread
ganganimaulik marked this conversation as resolved.
words.push(CaptionWord {
text: current_word.trim().to_string(),
text,
start: ws,
end: word_end,
..Default::default()
});
}

Expand Down Expand Up @@ -1000,6 +1010,7 @@ fn process_with_parakeet(
text: t.text.trim().to_string(),
start: t.start,
end: t.end,
..Default::default()
})
.collect();

Expand Down Expand Up @@ -1393,6 +1404,7 @@ pub fn parse_captions_json(json: &str) -> Result<cap_project::CaptionsData, Stri
text: w_text.to_string(),
start: w_start as f32,
end: w_end as f32,
..Default::default()
});
}
}
Expand Down
8 changes: 5 additions & 3 deletions apps/desktop/src/routes/editor/Timeline/ClipTrack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ function WaveformCanvas(props: {
rafId = null;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
if (!ctx || !props.segment) return;

const segmentDuration = props.segment.end - props.segment.start;
const fullSegmentWidth = width();
Expand Down Expand Up @@ -262,8 +262,8 @@ function WaveformCanvas(props: {
timelineBounds.width;
editorState.timeline.transform.position;
editorState.timeline.transform.zoom;
props.segment.start;
props.segment.end;
props.segment?.start;
props.segment?.end;
props.micWaveform;
props.systemWaveform;
project.audio.micVolumeDb;
Expand Down Expand Up @@ -392,6 +392,8 @@ export function ClipTrack(
{(segmentIndex) => {
const i = segmentIndex;
const segment = () => segments()[i()];
if (!segment()) return null;

const [startHandleDrag, setStartHandleDrag] = createSignal<null | {
offset: number;
initialStart: number;
Expand Down
Loading