cjm-transcript-vad-align
Install
pip install cjm_transcript_vad_alignProject Structure
nbs/
├── components/ (7)
│ ├── audio_controls.ipynb # Audio playback controls for the alignment card stack: auto-navigate toggle
│ ├── callbacks.ipynb # Focus change callback and audio playback JavaScript for the alignment card stack
│ ├── card_stack_config.ipynb # Card stack configuration, HTML IDs, and button IDs for the VAD alignment card stack
│ ├── helpers.ipynb # State getters for the alignment step from InteractionContext
│ ├── keyboard_config.ipynb # Alignment-specific keyboard building blocks for assembly into a shared ZoneManager
│ ├── step_renderer.ipynb # Composable render functions for the alignment card stack column
│ └── vad_card.ipynb # VAD chunk card renderer for the alignment card stack
├── routes/ (5)
│ ├── audio.ipynb # Route handlers for alignment audio playback controls
│ ├── card_stack.ipynb # Card stack operations for the alignment column: navigation, viewport update, width save
│ ├── core.ipynb # Alignment state context, getters, and updaters for route handlers
│ ├── handlers.ipynb # Workflow-specific alignment handlers: init
│ └── init.ipynb # Router assembly for Phase 2 alignment routes
├── services/ (1)
│ └── alignment.ipynb # Alignment service for temporal coordination via Silero VAD plugin
├── html_ids.ipynb # HTML ID constants for Phase 2 Right Column: VAD Alignment
├── models.ipynb # Data models and URL bundles for the alignment package
└── utils.ipynb # Time formatting utilities for VAD alignment display
Total: 16 notebooks across 3 directories
Module Dependencies
graph LR
components_audio_controls[components.audio_controls<br/>audio_controls]
components_callbacks[components.callbacks<br/>callbacks]
components_card_stack_config[components.card_stack_config<br/>card_stack_config]
components_helpers[components.helpers<br/>helpers]
components_keyboard_config[components.keyboard_config<br/>keyboard_config]
components_step_renderer[components.step_renderer<br/>step_renderer]
components_vad_card[components.vad_card<br/>vad_card]
html_ids[html_ids<br/>html_ids]
models[models<br/>models]
routes_audio[routes.audio<br/>audio]
routes_card_stack[routes.card_stack<br/>card_stack]
routes_core[routes.core<br/>core]
routes_handlers[routes.handlers<br/>handlers]
routes_init[routes.init<br/>init]
services_alignment[services.alignment<br/>alignment]
utils[utils<br/>utils]
components_callbacks --> components_audio_controls
components_helpers --> models
components_step_renderer --> utils
components_step_renderer --> components_audio_controls
components_step_renderer --> models
components_step_renderer --> components_card_stack_config
components_step_renderer --> html_ids
components_step_renderer --> components_vad_card
components_step_renderer --> components_callbacks
components_vad_card --> models
components_vad_card --> html_ids
components_vad_card --> utils
routes_audio --> routes_core
routes_audio --> models
routes_card_stack --> routes_core
routes_card_stack --> utils
routes_card_stack --> components_card_stack_config
routes_card_stack --> components_step_renderer
routes_card_stack --> components_vad_card
routes_card_stack --> models
routes_core --> models
routes_handlers --> routes_core
routes_handlers --> models
routes_handlers --> components_step_renderer
routes_handlers --> html_ids
routes_handlers --> services_alignment
routes_init --> services_alignment
routes_init --> routes_handlers
routes_init --> routes_card_stack
routes_init --> routes_audio
routes_init --> models
routes_init --> routes_core
services_alignment --> models
utils --> models
34 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
alignment (alignment.ipynb)
Alignment service for temporal coordination via Silero VAD plugin
Import
from cjm_transcript_vad_align.services.alignment import (
AlignmentService,
check_alignment_ready
)Functions
def check_alignment_ready(
segment_count: int, # Number of text segments
chunk_count: int, # Number of VAD chunks
) -> bool: # True if counts match and alignment can proceed
"Check if segment and VAD chunk counts match for 1:1 alignment."Classes
class AlignmentService:
def __init__(
self,
plugin_manager: PluginManager, # Plugin manager for accessing VAD plugin
plugin_name: str = "cjm-media-plugin-silero-vad" # Name of the VAD plugin
)
"Service for temporal alignment via Silero VAD plugin."
def __init__(
self,
plugin_manager: PluginManager, # Plugin manager for accessing VAD plugin
plugin_name: str = "cjm-media-plugin-silero-vad" # Name of the VAD plugin
)
"Initialize the alignment service."
def is_available(self) -> bool: # True if plugin is loaded and ready
"""Check if the VAD plugin is available."""
return self._manager.get_plugin(self._plugin_name) is not None
def ensure_loaded(
self,
config: Optional[Dict[str, Any]] = None # Optional plugin configuration
) -> bool: # True if successfully loaded
"Check if the VAD plugin is available."
def ensure_loaded(
self,
config: Optional[Dict[str, Any]] = None # Optional plugin configuration
) -> bool: # True if successfully loaded
"Ensure the VAD plugin is loaded."
async def analyze_audio_async(
self,
media_path: str # Path to audio/video file
) -> tuple[List[VADChunk], float]: # (VAD chunks, total duration)
"Analyze audio file and return VAD chunks."
def analyze_audio(
self,
media_path: str # Path to audio/video file
) -> tuple[List[VADChunk], float]: # (VAD chunks, total duration)
"Analyze audio file synchronously."audio (audio.ipynb)
Route handlers for alignment audio playback controls
Import
from cjm_transcript_vad_align.routes.audio import (
init_audio_router
)Functions
def _generate_auto_nav_js(
enabled:bool # Whether auto-navigate is enabled
) -> str: # JavaScript to update auto-navigate flag
"Generate JS to update auto-navigate flag via shared library."def init_audio_router(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
prefix:str, # Base prefix for audio routes
urls:AlignmentUrls, # URL bundle to populate
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, routes dict)
"Initialize alignment audio control routes."audio_controls (audio_controls.ipynb)
Audio playback controls for the alignment card stack: auto-navigate toggle
Import
from cjm_transcript_vad_align.components.audio_controls import (
AlignAudioControlIds,
render_align_auto_navigate_toggle,
render_align_audio_controls
)Functions
def _toggle_color_js(toggle_id:str) -> str: # JS snippet to sync toggle color classes
"""Generate JS to swap bg-error/bg-success on the toggle based on checked state."""
return (
f"var _t=document.getElementById('{toggle_id}');"
f"if(_t){{_t.classList.remove('{_TOGGLE_BG_OFF}','{_TOGGLE_BG_ON}');"
f"_t.classList.add(_t.checked?'{_TOGGLE_BG_ON}':'{_TOGGLE_BG_OFF}');}}"
)
def render_align_auto_navigate_toggle(
enabled:bool=False, # Whether auto-navigate is enabled
) -> Any: # Auto-navigate toggle component
"Generate JS to swap bg-error/bg-success on the toggle based on checked state."def render_align_auto_navigate_toggle(
enabled:bool=False, # Whether auto-navigate is enabled
) -> Any: # Auto-navigate toggle component
"Render auto-navigate toggle switch for alignment audio (client-side only)."def render_align_audio_controls(
auto_navigate:bool=False, # Whether auto-navigate is enabled
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Combined audio controls component
"Render alignment audio controls (auto-navigate toggle)."Classes
class AlignAudioControlIds:
"HTML ID constants for alignment audio control elements."Variables
_TOGGLE_BG_OFF # Red when auto-play disabled
_TOGGLE_BG_ON # Green when auto-play enabledcallbacks (callbacks.ipynb)
Focus change callback and audio playback JavaScript for the alignment card stack
Import
from cjm_transcript_vad_align.components.callbacks import (
ALIGN_AUDIO_CONFIG,
generate_align_callbacks_script
)Functions
def _generate_toggle_auto_play_js() -> str: # JS defining window.toggleAlignAutoPlay
"Generate JS for the A key auto-play toggle function."def generate_align_callbacks_script(
ids:CardStackHtmlIds, # Card stack HTML IDs
button_ids:CardStackButtonIds, # Card stack button IDs
config:CardStackConfig, # Card stack configuration
urls:CardStackUrls, # Card stack URL bundle
container_id:str, # ID of the alignment container (parent of card stack)
focus_input_id:str, # ID of hidden input for focused chunk index
should_play_fn:str="", # Consumer-defined play guard function name (overrides default zone guard)
) -> any: # Script element with all JavaScript callbacks
"Generate JavaScript for alignment card stack with Web Audio API audition."Variables
ALIGN_AUDIO_CONFIGcard_stack (card_stack.ipynb)
Card stack operations for the alignment column: navigation, viewport update, width save
Import
from cjm_transcript_vad_align.routes.card_stack import (
init_card_stack_router
)Functions
def _build_nav_response(
chunk_dicts:List[Dict[str, Any]], # Serialized VAD chunks
state:CardStackState, # Current card stack state
urls:AlignmentUrls, # URL bundle
) -> Tuple: # OOB response elements (slots + progress + focus)
"Build OOB response for navigation changes."def _handle_align_navigate(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess:Any, # FastHTML session object
direction:str, # Navigation direction: up/down/first/last/page_up/page_down
urls:AlignmentUrls, # URL bundle
) -> Tuple: # OOB response elements (slots + progress + focus + source position)
"Navigate the alignment card stack."def _handle_align_navigate_to_index(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess:Any, # FastHTML session object
target_index:int, # Target item index to navigate to
urls:AlignmentUrls, # URL bundle
) -> Tuple: # OOB response elements (slots + progress + focus + source position)
"Navigate the alignment card stack to a specific index."async def _handle_align_update_viewport(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
request:Any, # FastHTML request object
sess:Any, # FastHTML session object
visible_count:int, # New visible card count
urls:AlignmentUrls, # URL bundle
) -> Tuple: # OOB section elements for viewport update
"Update viewport with new card count via OOB section swaps."def _handle_align_save_width(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess:Any, # FastHTML session object
card_width:int, # Card stack width in rem to save
) -> None: # No response body (swap=none on client)
"Save card stack width to server state with config bounds validation."def init_card_stack_router(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
prefix:str, # Route prefix (e.g., "/workflow/align/card_stack")
urls:AlignmentUrls, # URL bundle (populated after routes defined)
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, route_dict)
"Initialize card stack routes for alignment."card_stack_config (card_stack_config.ipynb)
Card stack configuration, HTML IDs, and button IDs for the VAD alignment card stack
Import
from cjm_transcript_vad_align.components.card_stack_config import (
ALIGN_CS_CONFIG,
ALIGN_CS_IDS,
ALIGN_CS_BTN_IDS
)Variables
ALIGN_CS_CONFIG
ALIGN_CS_IDS
ALIGN_CS_BTN_IDScore (core.ipynb)
Alignment state context, getters, and updaters for route handlers
Import
from cjm_transcript_vad_align.routes.core import (
WorkflowStateStore,
DEBUG_ALIGN_STATE,
AlignContext
)Functions
def _get_alignment_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier
) -> AlignmentStepState: # Typed alignment step state
"Get the alignment step state from the workflow state store."def _get_selection_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier
) -> Dict[str, Any]: # Selection step state dictionary
"Get the selection step state (Phase 1) from the workflow state store."def _load_alignment_context(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier
) -> AlignContext: # Loaded context with all common alignment state
"Load commonly-needed alignment state values in a single call."def _update_alignment_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier
vad_chunks=None, # Updated VAD chunks (serialized)
focused_chunk_index=None, # Updated focused chunk index
is_initialized=None, # Initialization flag
visible_count=None, # Visible card count
is_auto_mode=None, # Auto-adjust mode flag
card_width=None, # Card stack width in rem
media_path=None, # First audio file path (backward compat)
media_paths=None, # Ordered list of all audio file paths
audio_duration=None, # Audio duration
auto_navigate=None, # Auto-navigate flag
) -> None
"Update the alignment step state in the workflow state store."def _to_vad_chunks(
chunk_dicts:List[Dict[str, Any]] # Serialized VAD chunk dictionaries
) -> List[VADChunk]: # List of VADChunk objects
"Convert chunk dictionaries to VADChunk objects."def _build_card_stack_state(
ctx:AlignContext, # Loaded alignment context
active_mode:str=None, # Current interaction mode name (unused for alignment)
) -> CardStackState: # Card stack state for library functions
"Build a CardStackState from alignment context for library functions."Classes
class AlignContext(NamedTuple):
"Common alignment state values loaded by handlers."Variables
DEBUG_ALIGN_STATE = Falsehandlers (handlers.ipynb)
Workflow-specific alignment handlers: init
Import
from cjm_transcript_vad_align.routes.handlers import (
DEBUG_ALIGNMENT,
AlignInitResult,
init_workflow_router
)Functions
async def _handle_align_init(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
source_service:SourceService, # Service for fetching source blocks
alignment_service:AlignmentService, # Service for VAD analysis
request, # FastHTML request object
sess, # FastHTML session object
urls:AlignmentUrls, # URL bundle
visible_count:int=DEFAULT_VISIBLE_COUNT, # Initial visible card count
card_width:int=DEFAULT_CARD_WIDTH, # Initial card width in rem
should_play_fn:str="", # Consumer-defined play guard function name
) -> AlignInitResult: # Pure domain result for wrapper to use
"""
Initialize alignment from audio files via VAD plugin.
Processes all selected sources' audio files, generating VAD chunks
for each with correct audio_file_index. Returns pure domain data.
"""def init_workflow_router(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
source_service:SourceService, # Service for fetching source blocks
alignment_service:AlignmentService, # Service for VAD analysis
prefix:str, # Route prefix (e.g., "/workflow/align/workflow")
urls:AlignmentUrls, # URL bundle (populated after routes defined)
handler_init:Callable=None, # Optional wrapped init handler
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, route_dict)
"""
Initialize workflow routes for alignment.
Accepts optional handler override for wrapping with cross-domain
coordination (e.g., shared chrome, alignment status OOB updates).
"""Classes
class AlignInitResult(NamedTuple):
"""
Result from pure alignment init handler.
Contains domain-specific data for the combined layer wrapper to use
when building cross-domain OOB elements (shared chrome, alignment status).
"""Variables
DEBUG_ALIGNMENT = Truehelpers (helpers.ipynb)
State getters for the alignment step from InteractionContext
Import
from cjm_transcript_vad_align.components.helpers import *Functions
def _get_alignment_state(
ctx:InteractionContext # Interaction context with state
) -> AlignmentStepState: # Typed alignment step state
"Get the full alignment step state from context."def _get_vad_chunks(
ctx:InteractionContext # Interaction context with state
) -> List[VADChunk]: # List of VADChunk objects
"Get the list of VAD chunks from step state as VADChunk objects."def _is_alignment_initialized(
ctx:InteractionContext # Interaction context with state
) -> bool: # True if VAD data has been fetched
"Check if alignment has been initialized."def _get_focused_chunk_index(
ctx:InteractionContext, # Interaction context with state
default:int=0, # Default focused chunk index
) -> int: # Currently focused VAD chunk index
"Get the currently focused VAD chunk index."def _get_alignment_visible_count(
ctx:InteractionContext, # Interaction context with state
default:int=5, # Default visible card count (compact cards)
) -> int: # Number of visible cards in viewport
"Get the stored visible card count."def _get_alignment_is_auto_mode(
ctx:InteractionContext, # Interaction context with state
) -> bool: # Whether card count is in auto-adjust mode
"Get whether the card count is in auto-adjust mode."def _get_alignment_card_width(
ctx:InteractionContext, # Interaction context with state
default:int=40, # Default card width in rem (narrower for alignment)
) -> int: # Card stack width in rem
"Get the stored card stack width."def _get_alignment_history(
ctx:InteractionContext # Interaction context with state
) -> list: # Undo history stack
"Get the undo history stack."def _get_media_path(
ctx:InteractionContext # Interaction context with state
) -> Optional[str]: # Path to original audio file or None
"Get the original audio file path."def _get_audio_duration(
ctx:InteractionContext # Interaction context with state
) -> Optional[float]: # Audio duration in seconds or None
"Get the total audio duration."html_ids (html_ids.ipynb)
HTML ID constants for Phase 2 Right Column: VAD Alignment
Import
from cjm_transcript_vad_align.html_ids import (
AlignmentHtmlIds
)Classes
class AlignmentHtmlIds:
"HTML ID constants for Phase 2 Right Column: VAD Alignment."
def as_selector(
id_str:str # The HTML ID to convert
) -> str: # CSS selector with # prefix
"Convert an ID to a CSS selector format."
def vad_chunk(
index:int # VAD chunk index
) -> str: # HTML ID for the VAD chunk element
"Generate HTML ID for a VAD chunk element."init (init.ipynb)
Router assembly for Phase 2 alignment routes
Import
from cjm_transcript_vad_align.routes.init import (
init_alignment_routers
)Functions
def init_alignment_routers(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
source_service:SourceService, # Service for fetching source blocks
alignment_service:AlignmentService, # Service for VAD analysis
prefix:str, # Base prefix for alignment routes (e.g., "/workflow/align")
audio_src_url:str, # URL for audio_src route (from core router)
wrapped_init:Callable=None, # Optional wrapped init handler
) -> Tuple[List[APIRouter], AlignmentUrls, Dict[str, Callable]]: # (routers, urls, merged_routes)
"Initialize and return all alignment routers with URL bundle."keyboard_config (keyboard_config.ipynb)
Alignment-specific keyboard building blocks for assembly into a shared ZoneManager
Import
from cjm_transcript_vad_align.components.keyboard_config import (
create_align_kb_parts
)Functions
def create_align_kb_parts(
ids:CardStackHtmlIds, # Card stack HTML IDs
button_ids:CardStackButtonIds, # Card stack button IDs for navigation
config:CardStackConfig, # Card stack configuration
) -> Tuple[FocusZone, tuple, tuple]: # (zone, actions, modes)
"Create alignment-specific keyboard building blocks."models (models.ipynb)
Data models and URL bundles for the alignment package
Import
from cjm_transcript_vad_align.models import (
AlignmentStepState,
VADChunk,
AlignmentUrls
)Classes
class AlignmentStepState(TypedDict):
"State for Phase 2 (right column): Temporal Alignment."@dataclass
class VADChunk:
"A voice activity detection time range."
index: int # Chunk index in sequence (global across all audio files)
start_time: float # Start time in seconds (relative to its audio file)
end_time: float # End time in seconds (relative to its audio file)
audio_file_index: int = 0 # Which audio file this chunk belongs to
def duration(self) -> float: # Duration in seconds
"""Calculate chunk duration."""
return self.end_time - self.start_time
def to_dict(self) -> Dict[str, Any]: # Dictionary representation
"Calculate chunk duration."
def to_dict(self) -> Dict[str, Any]: # Dictionary representation
"""Convert to dictionary for JSON serialization."""
return asdict(self)
@classmethod
def from_dict(
cls,
data: Dict[str, Any] # Dictionary representation
) -> "VADChunk": # Reconstructed VADChunk
"Convert to dictionary for JSON serialization."
def from_dict(
cls,
data: Dict[str, Any] # Dictionary representation
) -> "VADChunk": # Reconstructed VADChunk
"Create from dictionary."@dataclass
class AlignmentUrls:
"URL bundle for Phase 2 alignment route handlers and renderers."
card_stack: CardStackUrls = field(...)
init: str = '' # Initialize alignment (fetch VAD data)
audio_src: str = '' # Audio file serving URL base
toggle_auto_nav: str = '' # Toggle auto-navigate on/offstep_renderer (step_renderer.ipynb)
Composable render functions for the alignment card stack column
Import
from cjm_transcript_vad_align.components.step_renderer import (
DEBUG_ALIGN_RENDER,
render_align_toolbar,
render_align_stats,
render_align_source_position,
render_align_column_body,
render_align_footer_content,
render_align_mini_stats_text
)Functions
def render_align_toolbar(
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Toolbar component
"Render the alignment toolbar with auto-play toggle."def render_align_stats(
chunks:List[VADChunk], # Current VAD chunks
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Statistics component
"Render alignment statistics."def render_align_source_position(
chunks:List[VADChunk], # Current VAD chunks
focused_index:int=0, # Currently focused chunk index
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Audio file position indicator (empty if single file)
"Render audio file position indicator for the focused chunk."def render_align_column_body(
chunks:List[VADChunk], # VAD chunks to display
focused_index:int, # Currently focused chunk index
visible_count:int, # Number of visible cards in viewport
card_width:int, # Card stack width in rem
urls:AlignmentUrls, # URL bundle for alignment routes
kb_system:Any=None, # Rendered keyboard system (None when KB managed externally)
audio_urls:Optional[List[str]]=None, # Audio file URLs for Web Audio API
should_play_fn:str="", # Consumer-defined play guard function name (overrides default zone guard)
) -> Any: # Div with id=COLUMN_CONTENT
"Render the alignment column content area with card stack viewport."def render_align_footer_content(
chunks:List[VADChunk], # Current VAD chunks
focused_index:int, # Currently focused chunk index
) -> Any: # Footer content with progress indicator, source position, and stats
"Render footer content with progress indicator, source position, and alignment statistics."def render_align_mini_stats_text(
chunks:List[VADChunk], # Current VAD chunks
) -> str: # Compact stats string for column header badge
"Generate compact stats string for the alignment column header badge."Variables
DEBUG_ALIGN_RENDER = Falseutils (utils.ipynb)
Time formatting utilities for VAD alignment display
Import
from cjm_transcript_vad_align.utils import (
format_time_precise,
get_audio_file_boundaries,
get_audio_file_count,
get_audio_file_position
)Functions
def format_time_precise(
seconds: Optional[float] # Time in seconds
) -> str: # Formatted time string (m:ss.s)
"Format seconds as m:ss.s for sub-second display."def get_audio_file_boundaries(
chunks: List["VADChunk"], # Ordered list of VAD chunks
) -> Set[int]: # Indices where audio_file_index changes from the previous chunk
"""
Find indices where audio_file_index changes between adjacent chunks.
A boundary at index N means chunk[N].audio_file_index differs from
chunk[N-1].audio_file_index.
"""def get_audio_file_count(
chunks: List["VADChunk"], # Ordered list of VAD chunks
) -> int: # Number of unique audio files
"Count the number of unique audio files in the chunk list."def get_audio_file_position(
chunks: List["VADChunk"], # Ordered list of VAD chunks
focused_index: int, # Index of the focused chunk
) -> Optional[int]: # 1-based position of the audio file, or None
"""
Get the audio file position (1-based) of the focused chunk.
Returns which audio file the focused chunk belongs to,
based on order of first appearance.
"""vad_card (vad_card.ipynb)
VAD chunk card renderer for the alignment card stack
Import
from cjm_transcript_vad_align.components.vad_card import (
render_vad_card,
create_vad_card_renderer
)Functions
def render_vad_card(
chunk:VADChunk, # VAD chunk to render
card_role:CardRole, # Role of this card in viewport ("focused" or "context")
has_boundary_above:bool=False, # Audio file boundary exists above this card
has_boundary_below:bool=False, # Audio file boundary exists below this card
) -> Any: # VAD chunk card component
"Render a single VAD chunk card with time range, duration, playing indicator, and play button."def create_vad_card_renderer(
audio_file_boundaries:Set[int]=None, # Indices where audio_file_index changes
) -> Callable: # Card renderer callback: (item, CardRenderContext) -> FT
"Create a card renderer callback for VAD chunk cards."