cjm-transcript-segment-align 0.0.8__tar.gz → 0.0.10__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 (33) hide show
  1. {cjm_transcript_segment_align-0.0.8/cjm_transcript_segment_align.egg-info → cjm_transcript_segment_align-0.0.10}/PKG-INFO +153 -47
  2. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/README.md +152 -46
  3. cjm_transcript_segment_align-0.0.10/cjm_transcript_segment_align/__init__.py +1 -0
  4. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/_modidx.py +14 -2
  5. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/components/handlers.py +11 -4
  6. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/components/keyboard_config.py +28 -2
  7. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/components/step_renderer.py +32 -5
  8. cjm_transcript_segment_align-0.0.10/cjm_transcript_segment_align/components/sync_controls.py +141 -0
  9. cjm_transcript_segment_align-0.0.10/cjm_transcript_segment_align/components/toolbar_state.py +64 -0
  10. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/routes/chrome.py +11 -37
  11. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/routes/forced_alignment.py +3 -2
  12. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/routes/init.py +3 -1
  13. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10/cjm_transcript_segment_align.egg-info}/PKG-INFO +153 -47
  14. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/SOURCES.txt +2 -0
  15. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/settings.ini +1 -1
  16. cjm_transcript_segment_align-0.0.8/cjm_transcript_segment_align/__init__.py +0 -1
  17. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/LICENSE +0 -0
  18. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/MANIFEST.in +0 -0
  19. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/components/__init__.py +0 -0
  20. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/components/helpers.py +0 -0
  21. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/html_ids.py +0 -0
  22. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/models.py +0 -0
  23. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/routes/__init__.py +0 -0
  24. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/services/__init__.py +0 -0
  25. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align/services/forced_alignment.py +0 -0
  26. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/dependency_links.txt +0 -0
  27. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/entry_points.txt +0 -0
  28. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/not-zip-safe +0 -0
  29. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/requires.txt +0 -0
  30. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/cjm_transcript_segment_align.egg-info/top_level.txt +0 -0
  31. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/pyproject.toml +0 -0
  32. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/setup.cfg +0 -0
  33. {cjm_transcript_segment_align-0.0.8 → cjm_transcript_segment_align-0.0.10}/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.8
3
+ Version: 0.0.10
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
@@ -48,11 +48,13 @@ pip install cjm_transcript_segment_align
48
48
  ## Project Structure
49
49
 
50
50
  nbs/
51
- ├── components/ (4)
51
+ ├── components/ (6)
52
52
  │ ├── handlers.ipynb # Handler wrappers for cross-domain coordination (alignment status updates)
53
53
  │ ├── helpers.ipynb # State extraction helpers for cross-domain coordination in Phase 2 combined step
54
54
  │ ├── keyboard_config.ipynb # Shared keyboard navigation configuration for the combined Phase 2 step
55
- └── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
55
+ ├── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
56
+ │ ├── sync_controls.ipynb # Synced navigation toggle for the combined Phase 2 dual-column step
57
+ │ └── toolbar_state.ipynb # Centralized client-side toolbar state restoration after HTMX settles
56
58
  ├── routes/ (3)
57
59
  │ ├── chrome.ipynb # Shared chrome switching route handlers for the combined Phase 2 step
58
60
  │ ├── forced_alignment.ipynb # Routes for toggling between NLTK and force-aligned pre-splits, plus rendering helpers for FA UI controls. Trigger and progress are handled by `cjm-fasthtml-job-monitor`.
@@ -62,7 +64,7 @@ pip install cjm_transcript_segment_align
62
64
  ├── html_ids.ipynb # HTML ID constants for Phase 2 Shell: Dual-Column Layout shared chrome
63
65
  └── models.ipynb # Data types and result containers for the segment-align integration surface
64
66
 
65
- Total: 10 notebooks across 3 directories
67
+ Total: 12 notebooks across 3 directories
66
68
 
67
69
  ## Module Dependencies
68
70
 
@@ -72,6 +74,8 @@ graph LR
72
74
  components_helpers[components.helpers<br/>helpers]
73
75
  components_keyboard_config[components.keyboard_config<br/>keyboard_config]
74
76
  components_step_renderer[components.step_renderer<br/>step_combined]
77
+ components_sync_controls[components.sync_controls<br/>sync_controls]
78
+ components_toolbar_state[components.toolbar_state<br/>toolbar_state]
75
79
  html_ids[html_ids<br/>html_ids]
76
80
  models[models<br/>models]
77
81
  routes_chrome[routes.chrome<br/>chrome]
@@ -79,31 +83,39 @@ graph LR
79
83
  routes_init[routes.init<br/>routes/init]
80
84
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
81
85
 
86
+ components_handlers --> html_ids
82
87
  components_handlers --> components_keyboard_config
83
- components_handlers --> services_forced_alignment
84
88
  components_handlers --> components_step_renderer
85
- components_handlers --> html_ids
89
+ components_handlers --> services_forced_alignment
90
+ components_handlers --> components_sync_controls
86
91
  components_handlers --> routes_forced_alignment
87
92
  components_keyboard_config --> html_ids
88
- components_step_renderer --> components_keyboard_config
93
+ components_keyboard_config --> components_sync_controls
89
94
  components_step_renderer --> html_ids
90
95
  components_step_renderer --> components_helpers
96
+ components_step_renderer --> components_sync_controls
97
+ components_step_renderer --> components_keyboard_config
98
+ components_step_renderer --> components_toolbar_state
99
+ components_toolbar_state --> components_sync_controls
100
+ routes_chrome --> html_ids
91
101
  routes_chrome --> components_handlers
102
+ routes_chrome --> components_sync_controls
92
103
  routes_chrome --> components_step_renderer
93
- routes_chrome --> html_ids
94
- routes_forced_alignment --> components_step_renderer
95
104
  routes_forced_alignment --> html_ids
96
- routes_init --> components_step_renderer
97
- routes_init --> components_handlers
98
- routes_init --> routes_chrome
105
+ routes_forced_alignment --> components_step_renderer
106
+ routes_forced_alignment --> components_sync_controls
99
107
  routes_init --> components_keyboard_config
100
108
  routes_init --> html_ids
101
- routes_init --> routes_forced_alignment
109
+ routes_init --> components_handlers
102
110
  routes_init --> models
103
111
  routes_init --> services_forced_alignment
112
+ routes_init --> components_sync_controls
113
+ routes_init --> components_step_renderer
114
+ routes_init --> routes_forced_alignment
115
+ routes_init --> routes_chrome
104
116
  ```
105
117
 
106
- *22 cross-module dependencies detected*
118
+ *30 cross-module dependencies detected*
107
119
 
108
120
  ## CLI Reference
109
121
 
@@ -128,17 +140,6 @@ from cjm_transcript_segment_align.routes.chrome import (
128
140
 
129
141
  #### Functions
130
142
 
131
- ``` python
132
- def _restore_align_auto_nav_js() -> str
133
- """
134
- Generate JS to sync the auto-navigate toggle checkbox and color classes with the Web Audio state.
135
-
136
- After chrome switch re-renders the toolbar, the checkbox starts unchecked with bg-error.
137
- This reads the JS state (source of truth) and restores the checkbox + color classes.
138
- Included inside the toolbar OOB so it runs after HTMX inserts the new content.
139
- """
140
- ```
141
-
142
143
  ``` python
143
144
  async def _handle_switch_chrome(
144
145
  state_store:SQLiteWorkflowStateStore, # State store instance
@@ -151,7 +152,12 @@ async def _handle_switch_chrome(
151
152
  fa_toggle_url:str="", # URL for FA toggle route
152
153
  fa_available:bool=False, # Whether FA plugin is available
153
154
  ) -> tuple: # OOB swaps for shared chrome containers
154
- "Switch shared chrome content based on active column."
155
+ """
156
+ Switch shared chrome content based on active column.
157
+
158
+ Client-side toolbar state restoration (sync button, auto-play toggle)
159
+ is handled by the centralized settle handler from toolbar_state.py.
160
+ """
155
161
  ```
156
162
 
157
163
  ``` python
@@ -507,26 +513,9 @@ def create_seg_init_chrome_wrapper(
507
513
  ```
508
514
 
509
515
  ``` python
510
- def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds alignment status
511
- """Create a wrapper for align init that adds mini-stats and alignment status.
512
-
513
- Returns a footer OOB (not a standalone alignment status badge) to avoid
514
- a race condition: both seg and align init auto-trigger on load, and the
515
- alignment status badge only exists inside the footer after seg init's
516
- footer OOB is processed. Using a footer OOB is safe because the footer
517
- container always exists in the DOM.
518
- """
519
- async def wrapped_align_init(
520
- state_store:WorkflowStateStore,
521
- workflow_id:str,
522
- source_service:SourceService,
523
- alignment_service:AlignmentService,
524
- request:Any,
525
- sess:Any,
526
- urls:AlignmentUrls,
527
- visible_count:int=5,
528
- card_width:int=40,
529
- )
516
+ def create_align_init_chrome_wrapper(
517
+ should_play_fn:str="", # Consumer-defined play guard function name
518
+ ) -> Callable: # Wrapped handler that adds alignment status
530
519
  """
531
520
  Create a wrapper for align init that adds mini-stats and alignment status.
532
521
 
@@ -851,7 +840,7 @@ def _render_shared_chrome(
851
840
  seg_state:dict=None, # Extracted segmentation state (None = show placeholders)
852
841
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
853
842
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
854
- fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
843
+ extra_actions:tuple=(), # Extra toolbar elements (FA controls, sync toggle, etc.)
855
844
  nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
856
845
  ) -> tuple: # (toolbar, controls, footer)
857
846
  """
@@ -919,3 +908,120 @@ _FOOTER_INNER_CLS
919
908
  _SEG_COLUMN_CLS
920
909
  _ALIGNMENT_COLUMN_CLS
921
910
  ```
911
+
912
+ ### sync_controls (`sync_controls.ipynb`)
913
+
914
+ > Synced navigation toggle for the combined Phase 2 dual-column step
915
+
916
+ #### Import
917
+
918
+ ``` python
919
+ from cjm_transcript_segment_align.components.sync_controls import (
920
+ SYNC_TOGGLE_FN,
921
+ SYNC_KEY,
922
+ SYNC_BTN_ID,
923
+ SHOULD_PLAY_FN,
924
+ render_sync_toggle_button,
925
+ generate_sync_script,
926
+ generate_sync_key_toggle_js,
927
+ generate_should_play_js,
928
+ generate_sync_restore_js,
929
+ build_extra_actions
930
+ )
931
+ ```
932
+
933
+ #### Functions
934
+
935
+ ``` python
936
+ def render_sync_toggle_button() -> Any: # Sync toggle button element
937
+ "Render the synced navigation toggle button for the seg toolbar."
938
+ ```
939
+
940
+ ``` python
941
+ def generate_sync_script(
942
+ source_input_id:str, # Seg card stack's focused_index hidden input ID
943
+ target_nav_url:str, # Align card stack's nav_to_index URL
944
+ ) -> Any: # Script element with sync JS
945
+ "Generate the sync JS Script element for the combined step."
946
+ ```
947
+
948
+ ``` python
949
+ def generate_sync_key_toggle_js() -> str: # JS defining window._segAlignSyncKeyToggle
950
+ "Generate JS for the S key sync toggle wrapper function."
951
+ ```
952
+
953
+ ``` python
954
+ def generate_should_play_js() -> str: # JS defining window.shouldAlignPlay
955
+ """
956
+ Generate JS for the custom play guard function.
957
+
958
+ Returns true when audio should play:
959
+ - Zone is active (direct align navigation), OR
960
+ - Auto-navigate is on (auto-play through align stack), OR
961
+ - Sync is enabled (seg navigation driving align)
962
+ """
963
+ ```
964
+
965
+ ``` python
966
+ def generate_sync_restore_js() -> str: # JS to restore sync button styling from client state
967
+ """
968
+ Generate JS to sync the toolbar button styling with the client-side sync state.
969
+
970
+ After chrome switch re-renders the seg toolbar, the sync button starts
971
+ with btn-outline. This reads the JS state and restores btn-primary if
972
+ sync is enabled.
973
+ """
974
+ ```
975
+
976
+ ``` python
977
+ def build_extra_actions(
978
+ fa_extra:Any=None, # FA controls element (from build_fa_extra_actions, or None)
979
+ ) -> tuple: # Tuple of toolbar extra action elements
980
+ """
981
+ Build the extra_actions tuple for the seg toolbar.
982
+
983
+ Combines FA controls (if available) with the sync toggle button.
984
+ Client-side state restoration (sync button styling) is handled by
985
+ the centralized toolbar restore settle handler in toolbar_state.py.
986
+ Returns a tuple compatible with render_toolbar(extra_actions=...).
987
+ """
988
+ ```
989
+
990
+ #### Variables
991
+
992
+ ``` python
993
+ SYNC_TOGGLE_FN = 'toggleSegAlignSync'
994
+ SYNC_KEY = '_segAlignSync'
995
+ SYNC_BTN_ID = 'sd-sync-toggle-btn'
996
+ SHOULD_PLAY_FN = 'shouldAlignPlay'
997
+ ```
998
+
999
+ ### toolbar_state (`toolbar_state.ipynb`)
1000
+
1001
+ > Centralized client-side toolbar state restoration after HTMX settles
1002
+
1003
+ #### Import
1004
+
1005
+ ``` python
1006
+ from cjm_transcript_segment_align.components.toolbar_state import (
1007
+ generate_toolbar_restore_js
1008
+ )
1009
+ ```
1010
+
1011
+ #### Functions
1012
+
1013
+ ``` python
1014
+ def generate_toolbar_restore_js() -> Script: # Script element with settle handler
1015
+ """
1016
+ Generate the centralized toolbar state restore settle handler.
1017
+
1018
+ Restores client-side state for all toolbar toggles/buttons after any
1019
+ HTMX settle that re-renders the toolbar. Runs once per settle event.
1020
+ """
1021
+ ```
1022
+
1023
+ #### Variables
1024
+
1025
+ ``` python
1026
+ _TOOLBAR_RESTORE_KEY = '_sdToolbarRestoreHandler'
1027
+ ```
@@ -12,11 +12,13 @@ pip install cjm_transcript_segment_align
12
12
  ## Project Structure
13
13
 
14
14
  nbs/
15
- ├── components/ (4)
15
+ ├── components/ (6)
16
16
  │ ├── handlers.ipynb # Handler wrappers for cross-domain coordination (alignment status updates)
17
17
  │ ├── helpers.ipynb # State extraction helpers for cross-domain coordination in Phase 2 combined step
18
18
  │ ├── keyboard_config.ipynb # Shared keyboard navigation configuration for the combined Phase 2 step
19
- └── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
19
+ ├── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
20
+ │ ├── sync_controls.ipynb # Synced navigation toggle for the combined Phase 2 dual-column step
21
+ │ └── toolbar_state.ipynb # Centralized client-side toolbar state restoration after HTMX settles
20
22
  ├── routes/ (3)
21
23
  │ ├── chrome.ipynb # Shared chrome switching route handlers for the combined Phase 2 step
22
24
  │ ├── forced_alignment.ipynb # Routes for toggling between NLTK and force-aligned pre-splits, plus rendering helpers for FA UI controls. Trigger and progress are handled by `cjm-fasthtml-job-monitor`.
@@ -26,7 +28,7 @@ pip install cjm_transcript_segment_align
26
28
  ├── html_ids.ipynb # HTML ID constants for Phase 2 Shell: Dual-Column Layout shared chrome
27
29
  └── models.ipynb # Data types and result containers for the segment-align integration surface
28
30
 
29
- Total: 10 notebooks across 3 directories
31
+ Total: 12 notebooks across 3 directories
30
32
 
31
33
  ## Module Dependencies
32
34
 
@@ -36,6 +38,8 @@ graph LR
36
38
  components_helpers[components.helpers<br/>helpers]
37
39
  components_keyboard_config[components.keyboard_config<br/>keyboard_config]
38
40
  components_step_renderer[components.step_renderer<br/>step_combined]
41
+ components_sync_controls[components.sync_controls<br/>sync_controls]
42
+ components_toolbar_state[components.toolbar_state<br/>toolbar_state]
39
43
  html_ids[html_ids<br/>html_ids]
40
44
  models[models<br/>models]
41
45
  routes_chrome[routes.chrome<br/>chrome]
@@ -43,31 +47,39 @@ graph LR
43
47
  routes_init[routes.init<br/>routes/init]
44
48
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
45
49
 
50
+ components_handlers --> html_ids
46
51
  components_handlers --> components_keyboard_config
47
- components_handlers --> services_forced_alignment
48
52
  components_handlers --> components_step_renderer
49
- components_handlers --> html_ids
53
+ components_handlers --> services_forced_alignment
54
+ components_handlers --> components_sync_controls
50
55
  components_handlers --> routes_forced_alignment
51
56
  components_keyboard_config --> html_ids
52
- components_step_renderer --> components_keyboard_config
57
+ components_keyboard_config --> components_sync_controls
53
58
  components_step_renderer --> html_ids
54
59
  components_step_renderer --> components_helpers
60
+ components_step_renderer --> components_sync_controls
61
+ components_step_renderer --> components_keyboard_config
62
+ components_step_renderer --> components_toolbar_state
63
+ components_toolbar_state --> components_sync_controls
64
+ routes_chrome --> html_ids
55
65
  routes_chrome --> components_handlers
66
+ routes_chrome --> components_sync_controls
56
67
  routes_chrome --> components_step_renderer
57
- routes_chrome --> html_ids
58
- routes_forced_alignment --> components_step_renderer
59
68
  routes_forced_alignment --> html_ids
60
- routes_init --> components_step_renderer
61
- routes_init --> components_handlers
62
- routes_init --> routes_chrome
69
+ routes_forced_alignment --> components_step_renderer
70
+ routes_forced_alignment --> components_sync_controls
63
71
  routes_init --> components_keyboard_config
64
72
  routes_init --> html_ids
65
- routes_init --> routes_forced_alignment
73
+ routes_init --> components_handlers
66
74
  routes_init --> models
67
75
  routes_init --> services_forced_alignment
76
+ routes_init --> components_sync_controls
77
+ routes_init --> components_step_renderer
78
+ routes_init --> routes_forced_alignment
79
+ routes_init --> routes_chrome
68
80
  ```
69
81
 
70
- *22 cross-module dependencies detected*
82
+ *30 cross-module dependencies detected*
71
83
 
72
84
  ## CLI Reference
73
85
 
@@ -92,17 +104,6 @@ from cjm_transcript_segment_align.routes.chrome import (
92
104
 
93
105
  #### Functions
94
106
 
95
- ``` python
96
- def _restore_align_auto_nav_js() -> str
97
- """
98
- Generate JS to sync the auto-navigate toggle checkbox and color classes with the Web Audio state.
99
-
100
- After chrome switch re-renders the toolbar, the checkbox starts unchecked with bg-error.
101
- This reads the JS state (source of truth) and restores the checkbox + color classes.
102
- Included inside the toolbar OOB so it runs after HTMX inserts the new content.
103
- """
104
- ```
105
-
106
107
  ``` python
107
108
  async def _handle_switch_chrome(
108
109
  state_store:SQLiteWorkflowStateStore, # State store instance
@@ -115,7 +116,12 @@ async def _handle_switch_chrome(
115
116
  fa_toggle_url:str="", # URL for FA toggle route
116
117
  fa_available:bool=False, # Whether FA plugin is available
117
118
  ) -> tuple: # OOB swaps for shared chrome containers
118
- "Switch shared chrome content based on active column."
119
+ """
120
+ Switch shared chrome content based on active column.
121
+
122
+ Client-side toolbar state restoration (sync button, auto-play toggle)
123
+ is handled by the centralized settle handler from toolbar_state.py.
124
+ """
119
125
  ```
120
126
 
121
127
  ``` python
@@ -471,26 +477,9 @@ def create_seg_init_chrome_wrapper(
471
477
  ```
472
478
 
473
479
  ``` python
474
- def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds alignment status
475
- """Create a wrapper for align init that adds mini-stats and alignment status.
476
-
477
- Returns a footer OOB (not a standalone alignment status badge) to avoid
478
- a race condition: both seg and align init auto-trigger on load, and the
479
- alignment status badge only exists inside the footer after seg init's
480
- footer OOB is processed. Using a footer OOB is safe because the footer
481
- container always exists in the DOM.
482
- """
483
- async def wrapped_align_init(
484
- state_store:WorkflowStateStore,
485
- workflow_id:str,
486
- source_service:SourceService,
487
- alignment_service:AlignmentService,
488
- request:Any,
489
- sess:Any,
490
- urls:AlignmentUrls,
491
- visible_count:int=5,
492
- card_width:int=40,
493
- )
480
+ def create_align_init_chrome_wrapper(
481
+ should_play_fn:str="", # Consumer-defined play guard function name
482
+ ) -> Callable: # Wrapped handler that adds alignment status
494
483
  """
495
484
  Create a wrapper for align init that adds mini-stats and alignment status.
496
485
 
@@ -815,7 +804,7 @@ def _render_shared_chrome(
815
804
  seg_state:dict=None, # Extracted segmentation state (None = show placeholders)
816
805
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
817
806
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
818
- fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
807
+ extra_actions:tuple=(), # Extra toolbar elements (FA controls, sync toggle, etc.)
819
808
  nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
820
809
  ) -> tuple: # (toolbar, controls, footer)
821
810
  """
@@ -883,3 +872,120 @@ _FOOTER_INNER_CLS
883
872
  _SEG_COLUMN_CLS
884
873
  _ALIGNMENT_COLUMN_CLS
885
874
  ```
875
+
876
+ ### sync_controls (`sync_controls.ipynb`)
877
+
878
+ > Synced navigation toggle for the combined Phase 2 dual-column step
879
+
880
+ #### Import
881
+
882
+ ``` python
883
+ from cjm_transcript_segment_align.components.sync_controls import (
884
+ SYNC_TOGGLE_FN,
885
+ SYNC_KEY,
886
+ SYNC_BTN_ID,
887
+ SHOULD_PLAY_FN,
888
+ render_sync_toggle_button,
889
+ generate_sync_script,
890
+ generate_sync_key_toggle_js,
891
+ generate_should_play_js,
892
+ generate_sync_restore_js,
893
+ build_extra_actions
894
+ )
895
+ ```
896
+
897
+ #### Functions
898
+
899
+ ``` python
900
+ def render_sync_toggle_button() -> Any: # Sync toggle button element
901
+ "Render the synced navigation toggle button for the seg toolbar."
902
+ ```
903
+
904
+ ``` python
905
+ def generate_sync_script(
906
+ source_input_id:str, # Seg card stack's focused_index hidden input ID
907
+ target_nav_url:str, # Align card stack's nav_to_index URL
908
+ ) -> Any: # Script element with sync JS
909
+ "Generate the sync JS Script element for the combined step."
910
+ ```
911
+
912
+ ``` python
913
+ def generate_sync_key_toggle_js() -> str: # JS defining window._segAlignSyncKeyToggle
914
+ "Generate JS for the S key sync toggle wrapper function."
915
+ ```
916
+
917
+ ``` python
918
+ def generate_should_play_js() -> str: # JS defining window.shouldAlignPlay
919
+ """
920
+ Generate JS for the custom play guard function.
921
+
922
+ Returns true when audio should play:
923
+ - Zone is active (direct align navigation), OR
924
+ - Auto-navigate is on (auto-play through align stack), OR
925
+ - Sync is enabled (seg navigation driving align)
926
+ """
927
+ ```
928
+
929
+ ``` python
930
+ def generate_sync_restore_js() -> str: # JS to restore sync button styling from client state
931
+ """
932
+ Generate JS to sync the toolbar button styling with the client-side sync state.
933
+
934
+ After chrome switch re-renders the seg toolbar, the sync button starts
935
+ with btn-outline. This reads the JS state and restores btn-primary if
936
+ sync is enabled.
937
+ """
938
+ ```
939
+
940
+ ``` python
941
+ def build_extra_actions(
942
+ fa_extra:Any=None, # FA controls element (from build_fa_extra_actions, or None)
943
+ ) -> tuple: # Tuple of toolbar extra action elements
944
+ """
945
+ Build the extra_actions tuple for the seg toolbar.
946
+
947
+ Combines FA controls (if available) with the sync toggle button.
948
+ Client-side state restoration (sync button styling) is handled by
949
+ the centralized toolbar restore settle handler in toolbar_state.py.
950
+ Returns a tuple compatible with render_toolbar(extra_actions=...).
951
+ """
952
+ ```
953
+
954
+ #### Variables
955
+
956
+ ``` python
957
+ SYNC_TOGGLE_FN = 'toggleSegAlignSync'
958
+ SYNC_KEY = '_segAlignSync'
959
+ SYNC_BTN_ID = 'sd-sync-toggle-btn'
960
+ SHOULD_PLAY_FN = 'shouldAlignPlay'
961
+ ```
962
+
963
+ ### toolbar_state (`toolbar_state.ipynb`)
964
+
965
+ > Centralized client-side toolbar state restoration after HTMX settles
966
+
967
+ #### Import
968
+
969
+ ``` python
970
+ from cjm_transcript_segment_align.components.toolbar_state import (
971
+ generate_toolbar_restore_js
972
+ )
973
+ ```
974
+
975
+ #### Functions
976
+
977
+ ``` python
978
+ def generate_toolbar_restore_js() -> Script: # Script element with settle handler
979
+ """
980
+ Generate the centralized toolbar state restore settle handler.
981
+
982
+ Restores client-side state for all toolbar toggles/buttons after any
983
+ HTMX settle that re-renders the toolbar. Runs once per settle event.
984
+ """
985
+ ```
986
+
987
+ #### Variables
988
+
989
+ ``` python
990
+ _TOOLBAR_RESTORE_KEY = '_sdToolbarRestoreHandler'
991
+ ```
@@ -0,0 +1 @@
1
+ __version__ = "0.0.10"
@@ -63,6 +63,20 @@ d = { 'settings': { 'branch': 'main',
63
63
  'cjm_transcript_segment_align/components/step_renderer.py'),
64
64
  'cjm_transcript_segment_align.components.step_renderer.render_seg_mini_stats_badge': ( 'components/step_renderer.html#render_seg_mini_stats_badge',
65
65
  'cjm_transcript_segment_align/components/step_renderer.py')},
66
+ 'cjm_transcript_segment_align.components.sync_controls': { 'cjm_transcript_segment_align.components.sync_controls.build_extra_actions': ( 'components/sync_controls.html#build_extra_actions',
67
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
68
+ 'cjm_transcript_segment_align.components.sync_controls.generate_should_play_js': ( 'components/sync_controls.html#generate_should_play_js',
69
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
70
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_key_toggle_js': ( 'components/sync_controls.html#generate_sync_key_toggle_js',
71
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
72
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_restore_js': ( 'components/sync_controls.html#generate_sync_restore_js',
73
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
74
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_script': ( 'components/sync_controls.html#generate_sync_script',
75
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
76
+ 'cjm_transcript_segment_align.components.sync_controls.render_sync_toggle_button': ( 'components/sync_controls.html#render_sync_toggle_button',
77
+ 'cjm_transcript_segment_align/components/sync_controls.py')},
78
+ 'cjm_transcript_segment_align.components.toolbar_state': { 'cjm_transcript_segment_align.components.toolbar_state.generate_toolbar_restore_js': ( 'components/toolbar_state.html#generate_toolbar_restore_js',
79
+ 'cjm_transcript_segment_align/components/toolbar_state.py')},
66
80
  'cjm_transcript_segment_align.html_ids': { 'cjm_transcript_segment_align.html_ids.CombinedHtmlIds': ( 'html_ids.html#combinedhtmlids',
67
81
  'cjm_transcript_segment_align/html_ids.py'),
68
82
  'cjm_transcript_segment_align.html_ids.CombinedHtmlIds.as_selector': ( 'html_ids.html#combinedhtmlids.as_selector',
@@ -73,8 +87,6 @@ d = { 'settings': { 'branch': 'main',
73
87
  'cjm_transcript_segment_align/models.py')},
74
88
  'cjm_transcript_segment_align.routes.chrome': { 'cjm_transcript_segment_align.routes.chrome._handle_switch_chrome': ( 'routes/chrome.html#_handle_switch_chrome',
75
89
  'cjm_transcript_segment_align/routes/chrome.py'),
76
- 'cjm_transcript_segment_align.routes.chrome._restore_align_auto_nav_js': ( 'routes/chrome.html#_restore_align_auto_nav_js',
77
- 'cjm_transcript_segment_align/routes/chrome.py'),
78
90
  'cjm_transcript_segment_align.routes.chrome.init_chrome_router': ( 'routes/chrome.html#init_chrome_router',
79
91
  'cjm_transcript_segment_align/routes/chrome.py')},
80
92
  'cjm_transcript_segment_align.routes.forced_alignment': { 'cjm_transcript_segment_align.routes.forced_alignment._handle_fa_toggle': ( 'routes/forced_alignment.html#_handle_fa_toggle',
@@ -31,6 +31,7 @@ from cjm_transcript_segment_align.components.keyboard_config import (
31
31
  build_combined_kb_system,
32
32
  generate_zone_change_js, SWITCH_CHROME_BTN_ID,
33
33
  )
34
+ from .sync_controls import build_extra_actions
34
35
  from cjm_transcript_segmentation.models import TextSegment, SegmentationUrls
35
36
  from cjm_transcript_segmentation.routes.core import WorkflowStateStore
36
37
  from cjm_transcript_segmentation.routes.handlers import (
@@ -249,7 +250,7 @@ def build_fa_on_complete(
249
250
  visible_count=seg_state.get("visible_count", DEFAULT_VISIBLE_COUNT),
250
251
  history_depth=0,
251
252
  urls=seg_urls,
252
- extra_actions=fa_toggle,
253
+ extra_actions=build_extra_actions(fa_toggle),
253
254
  nltk_split_disabled=False,
254
255
  )
255
256
 
@@ -333,13 +334,14 @@ def create_seg_mutation_wrapper(
333
334
  seg_oob = build_mutation_response(
334
335
  result.segment_dicts, result.focused_index, result.visible_count,
335
336
  result.history_depth, urls, is_auto_mode=result.is_auto_mode,
336
- extra_actions=fa_extra, nltk_split_disabled=nltk_disabled,
337
+ extra_actions=build_extra_actions(fa_extra), nltk_split_disabled=nltk_disabled,
337
338
  )
338
339
 
339
340
  return (*seg_oob, *result.extra_oob, *alignment_status_oob, *mini_stats_oob)
340
341
 
341
342
  return wrapped
342
343
 
344
+
343
345
  # %% ../../nbs/components/handlers.ipynb #f6a7b8c9
344
346
  def wrap_align_mutation_handler(
345
347
  handler: Callable, # Handler function to wrap
@@ -460,7 +462,7 @@ def create_seg_init_chrome_wrapper(
460
462
  can_undo=(result.history_depth > 0),
461
463
  visible_count=result.visible_count,
462
464
  is_auto_mode=result.is_auto_mode,
463
- extra_actions=fa_extra,
465
+ extra_actions=build_extra_actions(fa_extra),
464
466
  nltk_split_disabled=True,
465
467
  ),
466
468
  id=CombinedHtmlIds.SHARED_TOOLBAR,
@@ -502,8 +504,11 @@ def create_seg_init_chrome_wrapper(
502
504
 
503
505
  return wrapped_seg_init
504
506
 
507
+
505
508
  # %% ../../nbs/components/handlers.ipynb #ecvyiypdxk
506
- def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds alignment status
509
+ def create_align_init_chrome_wrapper(
510
+ should_play_fn:str="", # Consumer-defined play guard function name
511
+ ) -> Callable: # Wrapped handler that adds alignment status
507
512
  """Create a wrapper for align init that adds mini-stats and alignment status.
508
513
 
509
514
  Returns a footer OOB (not a standalone alignment status badge) to avoid
@@ -528,6 +533,7 @@ def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds
528
533
  result: AlignInitResult = await _handle_align_init(
529
534
  state_store, workflow_id, source_service, alignment_service,
530
535
  request, sess, urls, visible_count, card_width,
536
+ should_play_fn=should_play_fn,
531
537
  )
532
538
 
533
539
  session_id = get_session_id(sess)
@@ -558,6 +564,7 @@ def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds
558
564
 
559
565
  return wrapped_align_init
560
566
 
567
+
561
568
  # %% ../../nbs/components/handlers.ipynb #b8c9d0e1
562
569
  def create_seg_mutation_wrappers(
563
570
  jm_trigger: Any = None, # Pre-rendered job monitor trigger element