cjm-transcript-segment-align 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {cjm_transcript_segment_align-0.0.2/cjm_transcript_segment_align.egg-info → cjm_transcript_segment_align-0.0.3}/PKG-INFO +88 -47
  2. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/README.md +87 -46
  3. cjm_transcript_segment_align-0.0.3/cjm_transcript_segment_align/__init__.py +1 -0
  4. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/_modidx.py +9 -5
  5. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/components/handlers.py +167 -69
  6. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/components/step_renderer.py +25 -7
  7. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/html_ids.py +2 -3
  8. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/routes/chrome.py +24 -1
  9. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/routes/forced_alignment.py +83 -114
  10. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3/cjm_transcript_segment_align.egg-info}/PKG-INFO +88 -47
  11. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/settings.ini +1 -1
  12. cjm_transcript_segment_align-0.0.2/cjm_transcript_segment_align/__init__.py +0 -1
  13. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/LICENSE +0 -0
  14. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/MANIFEST.in +0 -0
  15. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/components/__init__.py +0 -0
  16. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/components/helpers.py +0 -0
  17. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/components/keyboard_config.py +0 -0
  18. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/routes/__init__.py +0 -0
  19. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/services/__init__.py +0 -0
  20. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align/services/forced_alignment.py +0 -0
  21. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/SOURCES.txt +0 -0
  22. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/dependency_links.txt +0 -0
  23. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/entry_points.txt +0 -0
  24. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/not-zip-safe +0 -0
  25. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/requires.txt +0 -0
  26. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/cjm_transcript_segment_align.egg-info/top_level.txt +0 -0
  27. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/pyproject.toml +0 -0
  28. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/setup.cfg +0 -0
  29. {cjm_transcript_segment_align-0.0.2 → cjm_transcript_segment_align-0.0.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cjm-transcript-segment-align
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: FastHTML dual-column text segmentation & VAD alignment UI for transcript decomposition workflows with forced alignment-based text splitting for aligning text segments with VAD chunks.
5
5
  Home-page: https://github.com/cj-mills/cjm-transcript-segment-align
6
6
  Author: Christian J. Mills
@@ -74,6 +74,7 @@ graph LR
74
74
  routes_forced_alignment[routes.forced_alignment<br/>forced_alignment]
75
75
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
76
76
 
77
+ components_handlers --> routes_forced_alignment
77
78
  components_handlers --> components_keyboard_config
78
79
  components_handlers --> html_ids
79
80
  components_handlers --> components_step_renderer
@@ -81,15 +82,16 @@ graph LR
81
82
  components_step_renderer --> components_helpers
82
83
  components_step_renderer --> components_keyboard_config
83
84
  components_step_renderer --> html_ids
85
+ routes_chrome --> components_handlers
84
86
  routes_chrome --> html_ids
85
- routes_chrome --> components_keyboard_config
86
87
  routes_chrome --> components_step_renderer
88
+ routes_chrome --> components_keyboard_config
89
+ routes_forced_alignment --> services_forced_alignment
87
90
  routes_forced_alignment --> html_ids
88
91
  routes_forced_alignment --> components_step_renderer
89
- routes_forced_alignment --> services_forced_alignment
90
92
  ```
91
93
 
92
- *13 cross-module dependencies detected*
94
+ *15 cross-module dependencies detected*
93
95
 
94
96
  ## CLI Reference
95
97
 
@@ -122,6 +124,9 @@ async def _handle_switch_chrome(
122
124
  sess, # FastHTML session object
123
125
  seg_urls:SegmentationUrls, # URL bundle for segmentation routes
124
126
  align_urls:AlignmentUrls, # URL bundle for alignment routes
127
+ fa_trigger_url:str="", # URL for FA trigger route
128
+ fa_toggle_url:str="", # URL for FA toggle route
129
+ fa_available:bool=False, # Whether FA plugin is available
125
130
  ) -> tuple: # OOB swaps for shared chrome containers
126
131
  "Switch shared chrome content based on active column."
127
132
  ```
@@ -133,6 +138,9 @@ def init_chrome_router(
133
138
  seg_urls: SegmentationUrls, # URL bundle for segmentation routes
134
139
  align_urls: AlignmentUrls, # URL bundle for alignment routes
135
140
  prefix: str, # Route prefix (e.g., "/workflow/core/chrome")
141
+ fa_trigger_url: str = "", # URL for FA trigger route
142
+ fa_toggle_url: str = "", # URL for FA toggle route
143
+ fa_available: bool = False, # Whether FA plugin is available
136
144
  ) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, route_dict)
137
145
  "Initialize chrome switching routes."
138
146
  ```
@@ -152,12 +160,10 @@ DEBUG_SWITCH_CHROME = False
152
160
 
153
161
  ``` python
154
162
  from cjm_transcript_segment_align.routes.forced_alignment import (
155
- FA_CONTAINER_ID,
156
- FA_STATUS_ID,
163
+ FA_SLOT_ID,
157
164
  render_fa_trigger_button,
158
165
  render_fa_progress,
159
166
  render_fa_toggle,
160
- render_fa_controls,
161
167
  init_forced_alignment_routers
162
168
  )
163
169
  ```
@@ -189,24 +195,6 @@ def render_fa_toggle(
189
195
  "Render the NLTK / Force Aligned toggle button group."
190
196
  ```
191
197
 
192
- ``` python
193
- def render_fa_controls(
194
- trigger_url: str = "", # URL for trigger route
195
- toggle_url: str = "", # URL for toggle route
196
- active_presplit: Optional[str] = None, # Current active mode (None = no FA done yet)
197
- fa_available: bool = False, # Whether FA plugin is available
198
- oob: bool = False, # Whether to render as OOB swap
199
- ) -> Any: # FA controls container
200
- """
201
- Render the forced alignment controls container.
202
-
203
- Shows either:
204
- - Trigger button (if FA not yet run)
205
- - Toggle (if FA has been run)
206
- - Nothing (if FA plugin not available)
207
- """
208
- ```
209
-
210
198
  ``` python
211
199
  async def _handle_fa_trigger(
212
200
  state_store: SQLiteWorkflowStateStore,
@@ -216,10 +204,9 @@ async def _handle_fa_trigger(
216
204
  request: Any,
217
205
  sess: Any,
218
206
  seg_urls: SegmentationUrls,
219
- progress_url: str,
220
207
  toggle_url: str,
221
- ) -> Any: # OOB updates for card stack, alignment status, FA controls, mini-stats
222
- "Trigger forced alignment and replace working segments."
208
+ ) -> Any: # Targeted OOB updates (slots + stats + toolbar with toggle + alignment status + mini-stats)
209
+ "Trigger forced alignment and replace working segments with FA splits."
223
210
  ```
224
211
 
225
212
  ``` python
@@ -230,8 +217,13 @@ async def _handle_fa_toggle(
230
217
  sess: Any,
231
218
  seg_urls: SegmentationUrls,
232
219
  toggle_url: str,
233
- ) -> Any: # OOB updates for card stack, alignment status, FA controls, mini-stats
234
- "Toggle between NLTK and force-aligned pre-splits."
220
+ ) -> Any: # Targeted OOB updates (slots + stats + toolbar with toggle + alignment status + mini-stats)
221
+ """
222
+ Toggle between NLTK and force-aligned pre-split snapshots.
223
+
224
+ Loads the selected pre-split snapshot as the current working state.
225
+ Pushes the previous working state to undo history (single history model).
226
+ """
235
227
  ```
236
228
 
237
229
  ``` python
@@ -249,8 +241,7 @@ def init_forced_alignment_routers(
249
241
  #### Variables
250
242
 
251
243
  ``` python
252
- FA_CONTAINER_ID
253
- FA_STATUS_ID
244
+ FA_SLOT_ID
254
245
  ```
255
246
 
256
247
  ### forced_alignment (`forced_alignment.ipynb`)
@@ -398,15 +389,13 @@ _PUNCT_RE
398
389
 
399
390
  ``` python
400
391
  from cjm_transcript_segment_align.components.handlers import (
401
- wrapped_seg_split,
402
- wrapped_seg_merge,
403
- wrapped_seg_undo,
404
- wrapped_seg_reset,
405
- wrapped_seg_ai_split,
406
- wrap_seg_mutation_handler,
392
+ segments_match_presplit,
393
+ build_fa_extra_actions,
394
+ create_seg_mutation_wrapper,
407
395
  wrap_align_mutation_handler,
408
396
  create_seg_init_chrome_wrapper,
409
- create_align_init_chrome_wrapper
397
+ create_align_init_chrome_wrapper,
398
+ create_seg_mutation_wrappers
410
399
  )
411
400
  ```
412
401
 
@@ -415,19 +404,50 @@ from cjm_transcript_segment_align.components.handlers import (
415
404
  ``` python
416
405
  def _find_session_id(args, kwargs):
417
406
  """Find session_id from args or kwargs."""
418
- # First check kwargs
419
407
  if 'sess' in kwargs
420
408
  "Find session_id from args or kwargs."
421
409
  ```
422
410
 
423
411
  ``` python
424
- def wrap_seg_mutation_handler(
425
- handler: Callable, # Handler function to wrap
426
- ) -> Callable: # Wrapped handler that appends alignment status OOB
412
+ def segments_match_presplit(
413
+ current_segments: list, # Current segment dicts
414
+ presplit: list, # Pre-split snapshot segment dicts
415
+ ) -> bool: # Whether current segments match the pre-split
416
+ "Check if current segments match a pre-split snapshot by text content."
417
+ ```
418
+
419
+ ``` python
420
+ def build_fa_extra_actions(
421
+ seg_state: dict, # Segmentation step state dict
422
+ fa_trigger_url: str = "", # URL for FA trigger route
423
+ fa_toggle_url: str = "", # URL for FA toggle route
424
+ fa_available: bool = False, # Whether FA plugin is available
425
+ ) -> Any: # FA controls wrapped in slot div (or None)
427
426
  """
428
- Wrap a segmentation mutation handler to add alignment status OOB.
427
+ Build FA controls for the toolbar extra_actions slot.
429
428
 
430
- The handler is expected to take (state_store, workflow_id, ...) as first params.
429
+ Shows toggle when current segments match either pre-split snapshot.
430
+ Shows trigger button when FA pre-split doesn't exist or current doesn't match either.
431
+ """
432
+ ```
433
+
434
+ ``` python
435
+ def create_seg_mutation_wrapper(
436
+ handler_result: Callable, # _handle_seg_*_result function
437
+ fa_trigger_url: str = "", # URL for FA trigger route
438
+ fa_toggle_url: str = "", # URL for FA toggle route
439
+ fa_available: bool = False, # Whether FA plugin is available
440
+ clear_fa_presplit: bool = False, # Whether to clear fa_presplit after handler (for NLTK Split)
441
+ ) -> Callable: # Wrapped handler that builds OOB with FA extra_actions + alignment status
442
+ """
443
+ Create a wrapped mutation handler that uses SegMutationResult.
444
+
445
+ Calls the _result handler variant, builds targeted OOB response with FA
446
+ controls in toolbar, and appends alignment status + mini-stats OOB.
447
+ Computes nltk_split_disabled from state for toolbar rendering.
448
+
449
+ When clear_fa_presplit=True (used for NLTK Split), clears the FA pre-split
450
+ snapshot so the toggle is replaced with the Force Align button.
431
451
  """
432
452
  ```
433
453
 
@@ -453,8 +473,8 @@ def create_seg_init_chrome_wrapper(
453
473
  """
454
474
  Create a wrapper for seg init that builds combined KB system and shared chrome.
455
475
 
456
- This is a factory that captures the URLs needed for KB system assembly.
457
- Optionally includes forced alignment controls if FA plugin is available.
476
+ Saves nltk_presplit snapshot at init time for match detection.
477
+ FA controls are rendered in the toolbar via extra_actions.
458
478
  """
459
479
  ```
460
480
 
@@ -486,6 +506,22 @@ def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds
486
506
  """
487
507
  ```
488
508
 
509
+ ``` python
510
+ def create_seg_mutation_wrappers(
511
+ fa_trigger_url: str = "", # URL for FA trigger route
512
+ fa_toggle_url: str = "", # URL for FA toggle route
513
+ fa_available: bool = False, # Whether FA plugin is available
514
+ ) -> dict: # Dict with keys: split, merge, undo, reset, ai_split
515
+ """
516
+ Create wrapped mutation handlers with FA controls in toolbar.
517
+
518
+ Returns a dict of handler name → wrapped handler function.
519
+ Called at setup time when FA URLs are known.
520
+ The ai_split wrapper has clear_fa_presplit=True — clicking NLTK Split
521
+ discards the FA pre-split snapshot and replaces the toggle with the trigger button.
522
+ """
523
+ ```
524
+
489
525
  ### helpers (`helpers.ipynb`)
490
526
 
491
527
  > State extraction helpers for cross-domain coordination in Phase 2
@@ -720,6 +756,8 @@ def _render_shared_chrome(
720
756
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
721
757
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
722
758
  kb_manager:Any=None, # Keyboard manager (required when seg_state provided)
759
+ fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
760
+ nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
723
761
  ) -> tuple: # (hints, toolbar, controls, footer)
724
762
  """
725
763
  Render shared chrome containers, populated with segmentation content when initialized.
@@ -763,6 +801,9 @@ def render_combined_step(
763
801
  seg_urls:SegmentationUrls=None, # URL bundle for segmentation routes
764
802
  align_urls:AlignmentUrls=None, # URL bundle for alignment routes
765
803
  switch_chrome_url:str="", # URL for chrome switching route
804
+ fa_available:bool=False, # Whether forced alignment plugin is available
805
+ fa_trigger_url:str="", # URL for forced alignment trigger route
806
+ fa_toggle_url:str="", # URL for forced alignment toggle route
766
807
  ) -> Any: # FastHTML component with full dual-column layout
767
808
  "Render Phase 2: Combined Segment & Align step with dual-column layout."
768
809
  ```
@@ -39,6 +39,7 @@ graph LR
39
39
  routes_forced_alignment[routes.forced_alignment<br/>forced_alignment]
40
40
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
41
41
 
42
+ components_handlers --> routes_forced_alignment
42
43
  components_handlers --> components_keyboard_config
43
44
  components_handlers --> html_ids
44
45
  components_handlers --> components_step_renderer
@@ -46,15 +47,16 @@ graph LR
46
47
  components_step_renderer --> components_helpers
47
48
  components_step_renderer --> components_keyboard_config
48
49
  components_step_renderer --> html_ids
50
+ routes_chrome --> components_handlers
49
51
  routes_chrome --> html_ids
50
- routes_chrome --> components_keyboard_config
51
52
  routes_chrome --> components_step_renderer
53
+ routes_chrome --> components_keyboard_config
54
+ routes_forced_alignment --> services_forced_alignment
52
55
  routes_forced_alignment --> html_ids
53
56
  routes_forced_alignment --> components_step_renderer
54
- routes_forced_alignment --> services_forced_alignment
55
57
  ```
56
58
 
57
- *13 cross-module dependencies detected*
59
+ *15 cross-module dependencies detected*
58
60
 
59
61
  ## CLI Reference
60
62
 
@@ -87,6 +89,9 @@ async def _handle_switch_chrome(
87
89
  sess, # FastHTML session object
88
90
  seg_urls:SegmentationUrls, # URL bundle for segmentation routes
89
91
  align_urls:AlignmentUrls, # URL bundle for alignment routes
92
+ fa_trigger_url:str="", # URL for FA trigger route
93
+ fa_toggle_url:str="", # URL for FA toggle route
94
+ fa_available:bool=False, # Whether FA plugin is available
90
95
  ) -> tuple: # OOB swaps for shared chrome containers
91
96
  "Switch shared chrome content based on active column."
92
97
  ```
@@ -98,6 +103,9 @@ def init_chrome_router(
98
103
  seg_urls: SegmentationUrls, # URL bundle for segmentation routes
99
104
  align_urls: AlignmentUrls, # URL bundle for alignment routes
100
105
  prefix: str, # Route prefix (e.g., "/workflow/core/chrome")
106
+ fa_trigger_url: str = "", # URL for FA trigger route
107
+ fa_toggle_url: str = "", # URL for FA toggle route
108
+ fa_available: bool = False, # Whether FA plugin is available
101
109
  ) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, route_dict)
102
110
  "Initialize chrome switching routes."
103
111
  ```
@@ -117,12 +125,10 @@ DEBUG_SWITCH_CHROME = False
117
125
 
118
126
  ``` python
119
127
  from cjm_transcript_segment_align.routes.forced_alignment import (
120
- FA_CONTAINER_ID,
121
- FA_STATUS_ID,
128
+ FA_SLOT_ID,
122
129
  render_fa_trigger_button,
123
130
  render_fa_progress,
124
131
  render_fa_toggle,
125
- render_fa_controls,
126
132
  init_forced_alignment_routers
127
133
  )
128
134
  ```
@@ -154,24 +160,6 @@ def render_fa_toggle(
154
160
  "Render the NLTK / Force Aligned toggle button group."
155
161
  ```
156
162
 
157
- ``` python
158
- def render_fa_controls(
159
- trigger_url: str = "", # URL for trigger route
160
- toggle_url: str = "", # URL for toggle route
161
- active_presplit: Optional[str] = None, # Current active mode (None = no FA done yet)
162
- fa_available: bool = False, # Whether FA plugin is available
163
- oob: bool = False, # Whether to render as OOB swap
164
- ) -> Any: # FA controls container
165
- """
166
- Render the forced alignment controls container.
167
-
168
- Shows either:
169
- - Trigger button (if FA not yet run)
170
- - Toggle (if FA has been run)
171
- - Nothing (if FA plugin not available)
172
- """
173
- ```
174
-
175
163
  ``` python
176
164
  async def _handle_fa_trigger(
177
165
  state_store: SQLiteWorkflowStateStore,
@@ -181,10 +169,9 @@ async def _handle_fa_trigger(
181
169
  request: Any,
182
170
  sess: Any,
183
171
  seg_urls: SegmentationUrls,
184
- progress_url: str,
185
172
  toggle_url: str,
186
- ) -> Any: # OOB updates for card stack, alignment status, FA controls, mini-stats
187
- "Trigger forced alignment and replace working segments."
173
+ ) -> Any: # Targeted OOB updates (slots + stats + toolbar with toggle + alignment status + mini-stats)
174
+ "Trigger forced alignment and replace working segments with FA splits."
188
175
  ```
189
176
 
190
177
  ``` python
@@ -195,8 +182,13 @@ async def _handle_fa_toggle(
195
182
  sess: Any,
196
183
  seg_urls: SegmentationUrls,
197
184
  toggle_url: str,
198
- ) -> Any: # OOB updates for card stack, alignment status, FA controls, mini-stats
199
- "Toggle between NLTK and force-aligned pre-splits."
185
+ ) -> Any: # Targeted OOB updates (slots + stats + toolbar with toggle + alignment status + mini-stats)
186
+ """
187
+ Toggle between NLTK and force-aligned pre-split snapshots.
188
+
189
+ Loads the selected pre-split snapshot as the current working state.
190
+ Pushes the previous working state to undo history (single history model).
191
+ """
200
192
  ```
201
193
 
202
194
  ``` python
@@ -214,8 +206,7 @@ def init_forced_alignment_routers(
214
206
  #### Variables
215
207
 
216
208
  ``` python
217
- FA_CONTAINER_ID
218
- FA_STATUS_ID
209
+ FA_SLOT_ID
219
210
  ```
220
211
 
221
212
  ### forced_alignment (`forced_alignment.ipynb`)
@@ -363,15 +354,13 @@ _PUNCT_RE
363
354
 
364
355
  ``` python
365
356
  from cjm_transcript_segment_align.components.handlers import (
366
- wrapped_seg_split,
367
- wrapped_seg_merge,
368
- wrapped_seg_undo,
369
- wrapped_seg_reset,
370
- wrapped_seg_ai_split,
371
- wrap_seg_mutation_handler,
357
+ segments_match_presplit,
358
+ build_fa_extra_actions,
359
+ create_seg_mutation_wrapper,
372
360
  wrap_align_mutation_handler,
373
361
  create_seg_init_chrome_wrapper,
374
- create_align_init_chrome_wrapper
362
+ create_align_init_chrome_wrapper,
363
+ create_seg_mutation_wrappers
375
364
  )
376
365
  ```
377
366
 
@@ -380,19 +369,50 @@ from cjm_transcript_segment_align.components.handlers import (
380
369
  ``` python
381
370
  def _find_session_id(args, kwargs):
382
371
  """Find session_id from args or kwargs."""
383
- # First check kwargs
384
372
  if 'sess' in kwargs
385
373
  "Find session_id from args or kwargs."
386
374
  ```
387
375
 
388
376
  ``` python
389
- def wrap_seg_mutation_handler(
390
- handler: Callable, # Handler function to wrap
391
- ) -> Callable: # Wrapped handler that appends alignment status OOB
377
+ def segments_match_presplit(
378
+ current_segments: list, # Current segment dicts
379
+ presplit: list, # Pre-split snapshot segment dicts
380
+ ) -> bool: # Whether current segments match the pre-split
381
+ "Check if current segments match a pre-split snapshot by text content."
382
+ ```
383
+
384
+ ``` python
385
+ def build_fa_extra_actions(
386
+ seg_state: dict, # Segmentation step state dict
387
+ fa_trigger_url: str = "", # URL for FA trigger route
388
+ fa_toggle_url: str = "", # URL for FA toggle route
389
+ fa_available: bool = False, # Whether FA plugin is available
390
+ ) -> Any: # FA controls wrapped in slot div (or None)
392
391
  """
393
- Wrap a segmentation mutation handler to add alignment status OOB.
392
+ Build FA controls for the toolbar extra_actions slot.
394
393
 
395
- The handler is expected to take (state_store, workflow_id, ...) as first params.
394
+ Shows toggle when current segments match either pre-split snapshot.
395
+ Shows trigger button when FA pre-split doesn't exist or current doesn't match either.
396
+ """
397
+ ```
398
+
399
+ ``` python
400
+ def create_seg_mutation_wrapper(
401
+ handler_result: Callable, # _handle_seg_*_result function
402
+ fa_trigger_url: str = "", # URL for FA trigger route
403
+ fa_toggle_url: str = "", # URL for FA toggle route
404
+ fa_available: bool = False, # Whether FA plugin is available
405
+ clear_fa_presplit: bool = False, # Whether to clear fa_presplit after handler (for NLTK Split)
406
+ ) -> Callable: # Wrapped handler that builds OOB with FA extra_actions + alignment status
407
+ """
408
+ Create a wrapped mutation handler that uses SegMutationResult.
409
+
410
+ Calls the _result handler variant, builds targeted OOB response with FA
411
+ controls in toolbar, and appends alignment status + mini-stats OOB.
412
+ Computes nltk_split_disabled from state for toolbar rendering.
413
+
414
+ When clear_fa_presplit=True (used for NLTK Split), clears the FA pre-split
415
+ snapshot so the toggle is replaced with the Force Align button.
396
416
  """
397
417
  ```
398
418
 
@@ -418,8 +438,8 @@ def create_seg_init_chrome_wrapper(
418
438
  """
419
439
  Create a wrapper for seg init that builds combined KB system and shared chrome.
420
440
 
421
- This is a factory that captures the URLs needed for KB system assembly.
422
- Optionally includes forced alignment controls if FA plugin is available.
441
+ Saves nltk_presplit snapshot at init time for match detection.
442
+ FA controls are rendered in the toolbar via extra_actions.
423
443
  """
424
444
  ```
425
445
 
@@ -451,6 +471,22 @@ def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds
451
471
  """
452
472
  ```
453
473
 
474
+ ``` python
475
+ def create_seg_mutation_wrappers(
476
+ fa_trigger_url: str = "", # URL for FA trigger route
477
+ fa_toggle_url: str = "", # URL for FA toggle route
478
+ fa_available: bool = False, # Whether FA plugin is available
479
+ ) -> dict: # Dict with keys: split, merge, undo, reset, ai_split
480
+ """
481
+ Create wrapped mutation handlers with FA controls in toolbar.
482
+
483
+ Returns a dict of handler name → wrapped handler function.
484
+ Called at setup time when FA URLs are known.
485
+ The ai_split wrapper has clear_fa_presplit=True — clicking NLTK Split
486
+ discards the FA pre-split snapshot and replaces the toggle with the trigger button.
487
+ """
488
+ ```
489
+
454
490
  ### helpers (`helpers.ipynb`)
455
491
 
456
492
  > State extraction helpers for cross-domain coordination in Phase 2
@@ -685,6 +721,8 @@ def _render_shared_chrome(
685
721
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
686
722
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
687
723
  kb_manager:Any=None, # Keyboard manager (required when seg_state provided)
724
+ fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
725
+ nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
688
726
  ) -> tuple: # (hints, toolbar, controls, footer)
689
727
  """
690
728
  Render shared chrome containers, populated with segmentation content when initialized.
@@ -728,6 +766,9 @@ def render_combined_step(
728
766
  seg_urls:SegmentationUrls=None, # URL bundle for segmentation routes
729
767
  align_urls:AlignmentUrls=None, # URL bundle for alignment routes
730
768
  switch_chrome_url:str="", # URL for chrome switching route
769
+ fa_available:bool=False, # Whether forced alignment plugin is available
770
+ fa_trigger_url:str="", # URL for forced alignment trigger route
771
+ fa_toggle_url:str="", # URL for forced alignment toggle route
731
772
  ) -> Any: # FastHTML component with full dual-column layout
732
773
  "Render Phase 2: Combined Segment & Align step with dual-column layout."
733
774
  ```
@@ -0,0 +1 @@
1
+ __version__ = "0.0.3"
@@ -7,14 +7,20 @@ d = { 'settings': { 'branch': 'main',
7
7
  'lib_path': 'cjm_transcript_segment_align'},
8
8
  'syms': { 'cjm_transcript_segment_align.components.handlers': { 'cjm_transcript_segment_align.components.handlers._find_session_id': ( 'components/handlers.html#_find_session_id',
9
9
  'cjm_transcript_segment_align/components/handlers.py'),
10
+ 'cjm_transcript_segment_align.components.handlers.build_fa_extra_actions': ( 'components/handlers.html#build_fa_extra_actions',
11
+ 'cjm_transcript_segment_align/components/handlers.py'),
10
12
  'cjm_transcript_segment_align.components.handlers.create_align_init_chrome_wrapper': ( 'components/handlers.html#create_align_init_chrome_wrapper',
11
13
  'cjm_transcript_segment_align/components/handlers.py'),
12
14
  'cjm_transcript_segment_align.components.handlers.create_seg_init_chrome_wrapper': ( 'components/handlers.html#create_seg_init_chrome_wrapper',
13
15
  'cjm_transcript_segment_align/components/handlers.py'),
14
- 'cjm_transcript_segment_align.components.handlers.wrap_align_mutation_handler': ( 'components/handlers.html#wrap_align_mutation_handler',
16
+ 'cjm_transcript_segment_align.components.handlers.create_seg_mutation_wrapper': ( 'components/handlers.html#create_seg_mutation_wrapper',
15
17
  'cjm_transcript_segment_align/components/handlers.py'),
16
- 'cjm_transcript_segment_align.components.handlers.wrap_seg_mutation_handler': ( 'components/handlers.html#wrap_seg_mutation_handler',
17
- 'cjm_transcript_segment_align/components/handlers.py')},
18
+ 'cjm_transcript_segment_align.components.handlers.create_seg_mutation_wrappers': ( 'components/handlers.html#create_seg_mutation_wrappers',
19
+ 'cjm_transcript_segment_align/components/handlers.py'),
20
+ 'cjm_transcript_segment_align.components.handlers.segments_match_presplit': ( 'components/handlers.html#segments_match_presplit',
21
+ 'cjm_transcript_segment_align/components/handlers.py'),
22
+ 'cjm_transcript_segment_align.components.handlers.wrap_align_mutation_handler': ( 'components/handlers.html#wrap_align_mutation_handler',
23
+ 'cjm_transcript_segment_align/components/handlers.py')},
18
24
  'cjm_transcript_segment_align.components.helpers': { 'cjm_transcript_segment_align.components.helpers.check_alignment_ready': ( 'components/helpers.html#check_alignment_ready',
19
25
  'cjm_transcript_segment_align/components/helpers.py'),
20
26
  'cjm_transcript_segment_align.components.helpers.extract_alignment_state': ( 'components/helpers.html#extract_alignment_state',
@@ -69,8 +75,6 @@ d = { 'settings': { 'branch': 'main',
69
75
  'cjm_transcript_segment_align/routes/forced_alignment.py'),
70
76
  'cjm_transcript_segment_align.routes.forced_alignment.init_forced_alignment_routers': ( 'routes/forced_alignment.html#init_forced_alignment_routers',
71
77
  'cjm_transcript_segment_align/routes/forced_alignment.py'),
72
- 'cjm_transcript_segment_align.routes.forced_alignment.render_fa_controls': ( 'routes/forced_alignment.html#render_fa_controls',
73
- 'cjm_transcript_segment_align/routes/forced_alignment.py'),
74
78
  'cjm_transcript_segment_align.routes.forced_alignment.render_fa_progress': ( 'routes/forced_alignment.html#render_fa_progress',
75
79
  'cjm_transcript_segment_align/routes/forced_alignment.py'),
76
80
  'cjm_transcript_segment_align.routes.forced_alignment.render_fa_toggle': ( 'routes/forced_alignment.html#render_fa_toggle',