Skip to content

feat: configurable words per caption segment - #3284

Closed
Openroot-MI wants to merge 2 commits into
CapSoftware:mainfrom
Openroot-MI:feat/configurable-caption-segment-words
Closed

Openroot-MI wants to merge 2 commits into
CapSoftware:mainfrom
Openroot-MI:feat/configurable-caption-segment-words

Conversation

@Openroot-MI

@Openroot-MI Openroot-MI commented Oct 25, 2026 •

Copy link
Copy Markdown

Adds a segmentWords caption setting, 1 to 8, default 6, so words on screen at once is actually configurable instead of the hardcoded TARGET/MAX_CAPTION_WORDS_PER_SEGMENT. Covers #3275.

How it behaves: at 1 you get the one word at a time style, every word its own segment, and the multi-word rules (weak boundary extension, short tail merge) are bypassed. Above 1 the same rules apply relative to the size you pick, and the default of 6 reproduces today's behavior exactly, so nothing changes for existing projects.

Where the setting lives:

  • cap_project::CaptionSettings.segmentWords (JSON segmentWords, default 6)
  • a Words Per Caption slider in both editors (Tauri captions tab, gpui captions sidebar)
  • the tauri transcribe_audio command takes an optional segmentWords argument, wired through both transcription pipelines into the shared chunker

Existing transcripts can be re-chunked from the stored word timings without re-transcribing, since the chunker only works on the word list. Doing that as an editor action is not in this PR.

Segmentation presets instead of a free number is still open for discussion in #3275, this just exposes the raw knob.

Tested:

  • cargo test -p cap-project: 197 passed, includes new chunker tests for the 1-word bypass and custom sizes
  • cargo clippy -p cap-project --all-features -- -D warnings
  • cargo fmt --check

Not verified locally yet: the app-level builds (cap-rendering, cap-desktop, cap-desktop-gpui). My environment can't build them (missing system libs, no sudo) so I'm relying on CI here, happy to fix whatever it turns up.

Note: stacked on #3278 (the shared chunker dedup this depends on), the diff here shrinks to just the feature commit once that merges.

RetriggerView in GreptileConfidence Score: 3/5

Fix the GPUI test calls, the track-generation setting, and the comments-rule violation before merging.

Findings

  1. P1 GPUI tests cannot compile ▶
  2. P1 Track generation ignores word count ▶
  3. P2 First generation cannot be configured ▶
  4. P2 Normal builds gain unused imports ▶
  5. P2 Comment repeats the code ▶
Fix with agent prompt
### Issue 1
apps/desktop-gpui/src/transcription.rs:1720
Adding `segment_words` leaves existing tests calling the old signatures. `verify_tests.rs` calls `caption_segments_from_tokens` with one argument twice, and `benchmark_parakeet_transcription` calls `process_with_parakeet` with two. These missing arguments prevent the GPUI test target from compiling; `#[ignore]` does not skip compilation. Pass the default size in these existing tests.

### Issue 2
apps/desktop/src/routes/editor/captions.ts:543
The caption track's Generate action still calls `transcribeEditorCaptions` without `segmentWords`, so this new default silently selects six. A project with a saved custom size and an empty caption track-for example, after deleting its caption segments-gets captions at the wrong size. Pass the project's setting from `generateCaptionsFromTrack`, as the other two callers now do.

### Issue 3
apps/desktop/src/routes/editor/CaptionsTab.tsx:1142-1146
Users cannot choose a word count before their first transcription. In Tauri, the new slider sits inside the `!hasCaptions()` container that blocks pointer input, and `updateCaptionSetting` returns when `project.captions` is missing. GPUI also routes its new slider through `with_caption_settings`, which skips saving when that block is missing. Users must transcribe at the default size before choosing another size and transcribing again. Make this setting available before captions exist and create the settings block when needed.

### Issue 4
apps/desktop-gpui/src/transcription.rs:1866
`caption_word_chunks` is now used only by tests, but both transcription modules import it in normal builds. This adds an unused-import warning. If a check treats warnings as errors, it fails. Move this import into the test modules or gate it with `#[cfg(test)]`.

### Issue 5
crates/project/src/caption_words.rs:90-91
The new comment above `normalize_caption_words` only lists what the function does. `AGENTS.md` explicitly bans comments that narrate code and allows comments only for non-obvious context. Remove this summary before merging to satisfy that requirement. Keep the nearby explanation of inflated word durations, which supplies useful context.

```suggestion

```

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds segmentWords with a default of six and exposes it in both caption editors.

  • Editors can set the word count for each newly generated caption.

Openroot-MI explicitly deferred an editor action for re-chunking stored word timings. Boundary extension and short-tail merging above one word are intentional.

Reviews (1) · Last reviewed commit: "feat: configurable words per caption seg..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

@Ker102 is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

)

caption_text_from_words, the attach-to-previous helpers,
normalize_caption_words, caption_word_chunks and the segment size constants
were copy-pasted across captions.rs (tauri), transcription.rs (gpui),
editor_window.rs (gpui) and caption_timing.rs, and the copies had drifted.
They now all consume the single set in cap_project::caption_words.

One behavior change: the weak-word boundary check on the Tauri side compared
byte length (normalized.len() <= 1), so non-ASCII one letter words like "à"
counted as two letters there. The shared version compares chars().count(),
matching what CapSoftware#2685 landed in the gpui backend.
Adds a segmentWords caption setting (1-8, default 6) that controls how many
words a generated caption segment holds, threaded from the captions panels
through both transcription pipelines into the shared chunker.

At 1 the chunker switches to the one word on screen at a time style: every
word becomes its own segment and the multi-word rules (weak boundary
extension, short tail merge) are bypassed. Above 1 the existing rules apply
relative to the chosen size, so the default of 6 reproduces current behavior
exactly.

Settings surface: cap_project::CaptionSettings.segmentWords (JSON
segmentWords), a Words Per Caption slider in the Tauri editor's captions tab
and in the gpui captions sidebar, and the tauri transcribe_audio command
gains an optional segmentWords argument.
@Openroot-MI
Openroot-MI force-pushed the feat/configurable-caption-segment-words branch from 1b6697f to 77b2909 Compare October 25, 2026 21:27
#[cfg(any(test, not(all(target_os = "macos", target_arch = "x86_64"))))]
fn caption_segments_from_tokens(
tokens: impl IntoIterator<Item = CaptionWord>,
segment_words: usize,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 GPUI tests cannot compile

Adding segment_words leaves existing tests calling the old signatures. verify_tests.rs calls caption_segments_from_tokens with one argument twice, and benchmark_parakeet_transcription calls process_with_parakeet with two. These missing arguments prevent the GPUI test target from compiling; #[ignore] does not skip compilation. Pass the default size in these existing tests.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/transcription.rs
Line: 1720

Comment:
**GPUI tests cannot compile**

Adding `segment_words` leaves existing tests calling the old signatures. `verify_tests.rs` calls `caption_segments_from_tokens` with one argument twice, and `benchmark_parakeet_transcription` calls `process_with_parakeet` with two. These missing arguments prevent the GPUI test target from compiling; `#[ignore]` does not skip compilation. Pass the default size in these existing tests.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

videoPath: string,
modelName = DEFAULT_CAPTION_MODEL,
language = DEFAULT_CAPTION_LANGUAGE,
segmentWords = 6,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Track generation ignores word count

The caption track's Generate action still calls transcribeEditorCaptions without segmentWords, so this new default silently selects six. A project with a saved custom size and an empty caption track—for example, after deleting its caption segments—gets captions at the wrong size. Pass the project's setting from generateCaptionsFromTrack, as the other two callers now do.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/captions.ts
Line: 543

Comment:
**Track generation ignores word count**

The caption track's Generate action still calls `transcribeEditorCaptions` without `segmentWords`, so this new default silently selects six. A project with a saved custom size and an empty caption track—for example, after deleting its caption segments—gets captions at the wrong size. Pass the project's setting from `generateCaptionsFromTrack`, as the other two callers now do.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +1142 to +1146
<Field name="Words Per Caption" inline>
<Slider
value={[getSetting("segmentWords")]}
onChange={(v: number[]) =>
updateCaptionSetting("segmentWords", Math.max(1, v[0]))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 First generation cannot be configured

Users cannot choose a word count before their first transcription. In Tauri, the new slider sits inside the !hasCaptions() container that blocks pointer input, and updateCaptionSetting returns when project.captions is missing. GPUI also routes its new slider through with_caption_settings, which skips saving when that block is missing. Users must transcribe at the default size before choosing another size and transcribing again. Make this setting available before captions exist and create the settings block when needed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/CaptionsTab.tsx
Line: 1142-1146

Comment:
**First generation cannot be configured**

Users cannot choose a word count before their first transcription. In Tauri, the new slider sits inside the `!hasCaptions()` container that blocks pointer input, and `updateCaptionSetting` returns when `project.captions` is missing. GPUI also routes its new slider through `with_caption_settings`, which skips saving when that block is missing. Users must transcribe at the default size before choosing another size and transcribing again. Make this setting available before captions exist and create the settings block when needed.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

chunks
}
use cap_project::caption_words::{
caption_text_from_words, caption_word_chunks, caption_word_chunks_with, normalize_caption_words,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Normal builds gain unused imports

caption_word_chunks is now used only by tests, but both transcription modules import it in normal builds. This adds an unused-import warning. If a check treats warnings as errors, it fails. Move this import into the test modules or gate it with #[cfg(test)].

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/transcription.rs
Line: 1866

Comment:
**Normal builds gain unused imports**

`caption_word_chunks` is now used only by tests, but both transcription modules import it in normal builds. This adds an unused-import warning. If a check treats warnings as errors, it fails. Move this import into the test modules or gate it with `#[cfg(test)]`.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +90 to +91
/// Drops empty tokens, attaches punctuation-only tokens to the previous word,
/// and clamps inflated trailing word durations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Comment repeats the code

The new comment above normalize_caption_words only lists what the function does. AGENTS.md explicitly bans comments that narrate code and allows comments only for non-obvious context. Remove this summary before merging to satisfy that requirement. Keep the nearby explanation of inflated word durations, which supplies useful context.

Suggested change
/// Drops empty tokens, attaches punctuation-only tokens to the previous word,
/// and clamps inflated trailing word durations.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/project/src/caption_words.rs
Line: 90-91

Comment:
**Comment repeats the code**

The new comment above `normalize_caption_words` only lists what the function does. `AGENTS.md` explicitly bans comments that narrate code and allows comments only for non-obvious context. Remove this summary before merging to satisfy that requirement. Keep the nearby explanation of inflated word durations, which supplies useful context.

```suggestion

```

**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks @Openroot-MI! This is stacked on #3278, so it can only merge after that one.

It needs a 5/5 from Greptile on its latest commit and green CI before we can merge. It's at 3/5 right now:

  • The GPUI test target doesn't compile. verify_tests.rs still calls caption_segments_from_tokens with one argument, and benchmark_parakeet_transcription calls process_with_parakeet with two.
  • You can't pick the word count before the first transcription: the GPUI slider goes through with_caption_setting, which does nothing until project.captions exists.
  • caption_word_chunks is now only used by tests but is imported in normal builds. Gate the import with #[cfg(test)] or move it into the test modules.
  • Remove the comment above normalize_caption_words (AGENTS.md doesn't allow comments that restate the code).

The desktop app now ships only from apps/desktop-gpui, so please drop the apps/desktop (Tauri) changes, which also removes the Tauri findings. Since this adds a new caption setting, we'll also confirm the direction on #3275 (raw count vs presets) before merging.

@Ker102

Ker102 commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

sorry, this one went up from the wrong account. replaced by #3296 with the review notes folded in.

@Openroot-MI

Copy link
Copy Markdown
Author

Closing in favor of #3296

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants