@@ -766,19 +766,22 @@ def step3_cut(ep_num: int, mp3_path: str, aligned: list) -> None:
766766 f"adj_start={ gap_start_adj :.1f} s dur={ gap_dur :.1f} s "
767767 f"→ shifted { len (starts ) - cut_idx } words" , flush = True )
768768
769+ # ── Write w2 in moshi-finetune alignment format ───────────────────────────
770+ # Format matches annotate.py output exactly:
771+ # {"alignments": [[word_text, [start_sec, end_sec], speaker], ...]}
772+ # One file per episode (full stripped audio). Chunking into per-turn clips
773+ # is Phase 2.
769774 w2_path = os .path .join (WHISPER_CACHE , f"ep{ ep_num } _w2.json" )
770- w2 = []
775+ alignments = []
771776 for i , w in enumerate (w2_proto ):
772- w2 .append ({
773- "word" : w ["word" ],
774- "start" : round (starts [i ], 4 ),
775- "end" : round (ends [i ], 4 ),
776- "p" : w ["p" ],
777- "speaker" : w ["speaker" ],
778- "seg_text" : w ["seg_text" ],
779- })
780- json .dump (w2 , open (w2_path , "w" , encoding = "utf-8" ), ensure_ascii = False )
781- print (f" step3: w2 ({ len (w2 )} words, stripped-time) saved → { w2_path } " ,
777+ alignments .append ([
778+ w ["word" ],
779+ [round (starts [i ], 4 ), round (ends [i ], 4 )],
780+ w ["speaker" ] or "SPEAKER_MAIN" ,
781+ ])
782+ w2_out = {"alignments" : alignments }
783+ json .dump (w2_out , open (w2_path , "w" , encoding = "utf-8" ), ensure_ascii = False )
784+ print (f" step3: w2 ({ len (alignments )} words, moshi-finetune format) saved → { w2_path } " ,
782785 flush = True )
783786
784787
@@ -815,7 +818,9 @@ def step4_verify(ep_num: int) -> None:
815818 print (f" step4: { len (w3 )} words saved → { w3_path } " , flush = True )
816819
817820 # ── Compare w2 vs w3 ──────────────────────────────────────────────────────
818- w2 = json .load (open (w2_path , encoding = "utf-8" ))
821+ # w2 is in moshi-finetune format: {"alignments": [[text, [start, end], spk], ...]}
822+ w2_raw = json .load (open (w2_path , encoding = "utf-8" ))
823+ w2_alignments = w2_raw ["alignments" ] # list of [text, [start, end], speaker]
819824
820825 w3_norm = [((norm_words (w ["word" ]) or ["" ])[0 ]) for w in w3 ]
821826 w3_start = [w ["start" ] for w in w3 ]
@@ -825,11 +830,10 @@ def step4_verify(ep_num: int) -> None:
825830 deltas : list = []
826831 large : list = []
827832
828- for w2w in w2 :
829- key = (norm_words (w2w [ "word" ] ) or ["" ])[0 ]
833+ for text , ( t2 , _t2e ), _spk in w2_alignments :
834+ key = (norm_words (text ) or ["" ])[0 ]
830835 if not key :
831836 continue
832- t2 = w2w ["start" ]
833837 lo = bisect .bisect_left (w3_start , t2 - MATCH_WIN )
834838 hi = bisect .bisect_right (w3_start , t2 + MATCH_WIN )
835839 best_d , best_t3 = float ("inf" ), None
@@ -845,7 +849,7 @@ def step4_verify(ep_num: int) -> None:
845849 n_match += 1
846850 deltas .append (best_d )
847851 if best_d > 0.300 :
848- large .append ((w2w [ "word" ] , t2 , best_t3 ))
852+ large .append ((text , t2 , best_t3 ))
849853
850854 total = n_match + n_miss
851855 pct = 100.0 * n_match / total if total else 0
@@ -854,7 +858,7 @@ def step4_verify(ep_num: int) -> None:
854858 over_300 = len (large )
855859
856860 print (f"\n Step 4 — w2 vs w3 timestamp comparison:" , flush = True )
857- print (f" w2 words : { len (w2 )} " , flush = True )
861+ print (f" w2 words : { len (w2_alignments )} " , flush = True )
858862 print (f" w3 words : { len (w3 )} " , flush = True )
859863 print (f" Matched : { n_match } /{ total } ({ pct :.1f} %)" , flush = True )
860864 print (f" Mean |Δ| : { mean_d * 1000 :.0f} ms" , flush = True )
0 commit comments