@@ -31,8 +31,10 @@ pub fn system_prompt(language: &str, summary_hint: Option<&str>) -> String {
3131 format ! (
3232 "You create YouTube chapter lists. Respond in {language}. First \
3333 chapter must start at 00:00. Keep titles short (under 8 words), \
34- meaningful, and descriptive of the upcoming section. Aim for 5-10 \
35- chapters for a 10-minute video; scale with length.{hint}"
34+ meaningful, and descriptive of the upcoming section. \
35+ MINIMUM chapter length: 3 minutes (180000 ms) — do NOT create \
36+ chapters shorter than this. Merge short sections into broader \
37+ topics instead of splitting aggressively.{hint}"
3638 )
3739}
3840
@@ -134,6 +136,18 @@ impl<'a> ChapterRunner for ProviderChapterRunner<'a> {
134136 first. timestamp_ms = 0 ;
135137 }
136138
139+ // Enforce minimum 3-minute gap between chapters. Drop any chapter
140+ // that starts less than 180_000 ms after the previously kept one.
141+ const MIN_GAP_MS : i64 = 180_000 ;
142+ let mut filtered: Vec < Chapter > = Vec :: with_capacity ( chapters. len ( ) ) ;
143+ for c in chapters {
144+ match filtered. last ( ) {
145+ Some ( prev) if c. timestamp_ms - prev. timestamp_ms < MIN_GAP_MS => { }
146+ _ => filtered. push ( c) ,
147+ }
148+ }
149+ chapters = filtered;
150+
137151 Ok ( ChapterList {
138152 language : language. into ( ) ,
139153 chapters,
@@ -181,16 +195,16 @@ mod tests {
181195 response : json ! ( {
182196 "chapters" : [
183197 { "timestampMs" : 3_000 , "title" : "Intro" } ,
184- { "timestampMs" : 60_000 , "title" : "Main" }
198+ { "timestampMs" : 240_000 , "title" : "Main" }
185199 ]
186200 } ) ,
187201 } ;
188202 let runner = ProviderChapterRunner { provider : & stub } ;
189- let segments = vec ! [ TranscriptionSegment :: new( 0 , 120_000 , "full talk" ) ] ;
190- let list = runner. run ( & segments, "English" , "claude-3" ) . await . unwrap ( ) ;
203+ let segments = vec ! [ TranscriptionSegment :: new( 0 , 600_000 , "full talk" ) ] ;
204+ let list = runner. run ( & segments, "English" , "claude-3" , None ) . await . unwrap ( ) ;
191205 assert_eq ! ( list. chapters. len( ) , 2 ) ;
192206 assert_eq ! ( list. chapters[ 0 ] . timestamp_ms, 0 ) ;
193- assert_eq ! ( list. chapters[ 1 ] . timestamp_ms, 60_000 ) ;
207+ assert_eq ! ( list. chapters[ 1 ] . timestamp_ms, 240_000 ) ;
194208 }
195209
196210 #[ tokio:: test]
@@ -201,12 +215,12 @@ mod tests {
201215 "chapters" : [
202216 { "timestampMs" : 0 , "title" : "a" } ,
203217 { "timestampMs" : 0 , "title" : "a dup" } ,
204- { "timestampMs" : 5_000 , "title" : "b" }
218+ { "timestampMs" : 200_000 , "title" : "b" }
205219 ]
206220 } ) ,
207221 } ;
208222 let runner = ProviderChapterRunner { provider : & stub } ;
209- let list = runner. run ( & [ ] , "English" , "claude-3" ) . await . unwrap ( ) ;
223+ let list = runner. run ( & [ ] , "English" , "claude-3" , None ) . await . unwrap ( ) ;
210224 assert_eq ! ( list. chapters. len( ) , 2 ) ;
211225 }
212226}
0 commit comments