cjm-transcript-review
Install
pip install cjm_transcript_reviewProject Structure
nbs/
├── components/ (7)
│ ├── audio_controls.ipynb # Audio playback controls: speed selector and auto-navigate toggle
│ ├── callbacks.ipynb # Focus change callback and audio playback JavaScript for the review card stack
│ ├── card_stack_config.ipynb # Card stack configuration, HTML IDs, and button IDs for the review card stack
│ ├── helpers.ipynb # State getters for the review step from InteractionContext
│ ├── keyboard_config.ipynb # Review-specific keyboard building blocks for assembly into a KeyboardManager
│ ├── review_card.ipynb # Review card component showing assembled segment with timing and source info
│ └── step_renderer.ipynb # Composable render functions for the review card stack step
├── routes/ (5)
│ ├── audio.ipynb # Route handlers for audio playback controls
│ ├── card_stack.ipynb # Card stack UI operations — navigation, viewport, and response builders
│ ├── commit.ipynb # Route handler for committing the document to the context graph
│ ├── core.ipynb # Review step state management helpers
│ └── init.ipynb # Router assembly for Phase 3 review routes
├── services/ (1)
│ └── graph.ipynb # Graph service for committing documents and segments to the context graph
├── html_ids.ipynb # HTML ID constants for Phase 3: Review & Commit
├── models.ipynb # Review step state and working document model for Phase 3: Review & Commit
└── utils.ipynb # Time formatting and source info display utilities for review cards
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_review_card[components.review_card<br/>review_card]
components_step_renderer[components.step_renderer<br/>step_renderer]
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_commit[routes.commit<br/>commit]
routes_core[routes.core<br/>core]
routes_init[routes.init<br/>init]
services_graph[services.graph<br/>graph]
utils[utils<br/>utils]
components_callbacks --> components_audio_controls
components_helpers --> models
components_review_card --> utils
components_review_card --> html_ids
components_step_renderer --> components_callbacks
components_step_renderer --> components_audio_controls
components_step_renderer --> components_review_card
components_step_renderer --> components_card_stack_config
components_step_renderer --> models
components_step_renderer --> components_keyboard_config
components_step_renderer --> html_ids
routes_audio --> models
routes_audio --> routes_core
routes_audio --> components_callbacks
routes_card_stack --> routes_core
routes_card_stack --> components_review_card
routes_card_stack --> components_card_stack_config
routes_card_stack --> components_step_renderer
routes_card_stack --> models
routes_commit --> routes_core
routes_commit --> services_graph
routes_commit --> models
routes_commit --> utils
routes_core --> models
routes_core --> components_review_card
routes_init --> routes_commit
routes_init --> routes_audio
routes_init --> routes_core
routes_init --> models
routes_init --> services_graph
routes_init --> routes_card_stack
31 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
audio (audio.ipynb)
Route handlers for audio playback controls
Import
from cjm_transcript_review.routes.audio import (
DEBUG_AUDIO_ROUTES,
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 _generate_replay_js() -> str: # JavaScript to replay current segment
"Generate JS to replay the current segment's audio."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:ReviewUrls, # URL bundle to populate
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, routes dict)
"Initialize audio control routes."Variables
DEBUG_AUDIO_ROUTES = Falseaudio_controls (audio_controls.ipynb)
Audio playback controls: speed selector and auto-navigate toggle
Import
from cjm_transcript_review.components.audio_controls import (
AudioControlIds,
render_auto_navigate_toggle,
render_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_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_auto_navigate_toggle(
enabled:bool=False, # Whether auto-navigate is enabled
) -> Any: # Auto-navigate toggle component
"Render auto-navigate toggle switch (client-side only, no server persistence)."def render_audio_controls(
current_speed:float=1.0, # Current playback speed
auto_navigate:bool=False, # Whether auto-navigate is enabled
speed_url:str="", # URL for speed changes
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Combined audio controls component
"Render combined audio controls (speed selector + auto-navigate toggle)."Classes
class AudioControlIds:
"HTML ID constants for audio control elements."Variables
_REVIEW_SPEED_CONFIG
_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 review card stack
Import
from cjm_transcript_review.components.callbacks import (
REVIEW_AUDIO_CONFIG,
generate_review_callbacks_script
)Functions
def _generate_toggle_auto_play_js() -> str: # JS defining window.toggleReviewAutoPlay
"Generate JS for the A key auto-play toggle function."def generate_review_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 review container (parent of card stack)
focus_input_id:str, # ID of hidden input for focused segment index
) -> any: # Script element with all JavaScript callbacks
"Generate JavaScript for review card stack with Web Audio API audition."Variables
REVIEW_AUDIO_CONFIGcard_stack (card_stack.ipynb)
Card stack UI operations — navigation, viewport, and response builders
Import
from cjm_transcript_review.routes.card_stack import (
init_card_stack_router
)Functions
def _build_slots_oob(
assembled:List[AssembledSegment], # Assembled segments with VAD chunks
state:CardStackState, # Card stack viewport state
urls:ReviewUrls, # URL bundle
) -> List[Any]: # OOB slot elements
"Build OOB slot updates for the viewport sections."def _build_nav_response(
assembled:List[AssembledSegment], # Assembled segments with VAD chunks
state:CardStackState, # Card stack viewport state
urls:ReviewUrls, # URL bundle
) -> Tuple: # OOB elements (slots + progress + focus)
"Build OOB response for navigation."def _handle_review_navigate(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess, # FastHTML session object
direction:str, # Navigation direction: "up", "down", "first", "last", "page_up", "page_down"
urls:ReviewUrls, # URL bundle for review routes
): # OOB slot updates with progress, focus, and source position
"Navigate to a different segment in the viewport using OOB slot swaps."def _handle_review_navigate_to_index(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess, # FastHTML session object
target_index:int, # Target item index to navigate to
urls:ReviewUrls, # URL bundle for review routes
): # OOB slot updates with progress, focus, and source position
"Navigate to a specific segment index using OOB slot swaps."async def _handle_review_update_viewport(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
request, # FastHTML request object
sess, # FastHTML session object
visible_count:int, # New number of visible cards
urls:ReviewUrls, # URL bundle for review routes
): # Full viewport component (outerHTML swap)
"Update the viewport with a new card count."def _handle_review_save_width(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
sess, # FastHTML session object
card_width:int, # Card stack width in rem
) -> None: # No response body (swap=none on client)
"Save the card stack width to server state."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/review/card_stack")
urls:ReviewUrls, # URL bundle (populated after routes defined)
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, route_dict)
"Initialize card stack routes for review."card_stack_config (card_stack_config.ipynb)
Card stack configuration, HTML IDs, and button IDs for the review card stack
Import
from cjm_transcript_review.components.card_stack_config import (
REVIEW_CS_CONFIG,
REVIEW_CS_IDS,
REVIEW_CS_BTN_IDS
)Variables
REVIEW_CS_CONFIG
REVIEW_CS_IDS
REVIEW_CS_BTN_IDScommit (commit.ipynb)
Route handler for committing the document to the context graph
Import
from cjm_transcript_review.routes.commit import (
DEBUG_COMMIT_ROUTES,
COMMIT_ALERT_ID,
CommitResult,
init_commit_router
)Functions
def _render_commit_alert(
result:CommitResult, # Commit operation result
auto_dismiss_ms:int=5000, # Auto-dismiss after milliseconds (0 = no auto-dismiss)
) -> Div: # Alert element with optional auto-dismiss script
"Render a success or error alert for commit result."async def _handle_commit(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier string
graph_service:GraphService, # Graph service for committing
document_title:Optional[str]=None, # Override document title (None = auto-generate)
) -> CommitResult: # Result of the commit operation
"Handle committing the document to the context graph."def init_commit_router(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
prefix:str, # Base prefix for commit route
graph_service:GraphService, # Graph service for committing
urls:ReviewUrls, # URL bundle to populate
alert_container_id:str="commit-alert-container", # ID of container for alert OOB swap
) -> Tuple[APIRouter, Dict[str, Callable]]: # (router, routes dict)
"Initialize commit route."Classes
@dataclass
class CommitResult:
"Result of a commit operation."
success: bool # Whether the commit succeeded
document_id: Optional[str] # Created document node ID
segment_count: int = 0 # Number of segments committed
edge_count: int = 0 # Number of edges created
error: Optional[str] # Error message if failedVariables
DEBUG_COMMIT_ROUTES = False
COMMIT_ALERT_ID = 'commit-alert'core (core.ipynb)
Review step state management helpers
Import
from cjm_transcript_review.routes.core import (
WorkflowStateStore,
DEBUG_REVIEW_STATE,
ReviewContext
)Functions
def _get_review_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str # Session identifier string
) -> ReviewStepState: # Review step state dictionary
"Get the review step state from the workflow state store."def _get_segmentation_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str # Session identifier string
) -> Dict[str, Any]: # Segmentation step state dictionary
"Get the segmentation step state from the workflow state store."def _get_alignment_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str # Session identifier string
) -> Dict[str, Any]: # Alignment step state dictionary
"Get the alignment step state from the workflow state store."def _load_review_context(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str # Session identifier string
) -> ReviewContext: # Common review state values
"Load commonly-needed review state values including cross-step data."def _get_assembled_segments(
ctx:ReviewContext # Loaded review context
) -> List[AssembledSegment]: # Paired segments with VAD chunks
"Pair segments with VAD chunks for review display."def _update_review_state(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier string
focused_index:int=None, # Updated focused index (None = don't change)
visible_count:int=None, # Visible card count (None = don't change)
is_auto_mode:bool=None, # Auto-adjust mode flag (None = don't change)
card_width:int=None, # Card stack width in rem (None = don't change)
document_title:str=None, # Document title (None = don't change)
is_validated:bool=None, # Validation flag (None = don't change)
playback_speed:float=None, # Playback speed (None = don't change)
auto_navigate:bool=None, # Auto-navigate flag (None = don't change)
) -> None
"Update the review step state in the workflow state store."def _handle_update_title(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
session_id:str, # Session identifier string
document_title:str, # New document title from form input
) -> None
"Update the document title in review state."def _build_card_stack_state(
ctx:ReviewContext, # Loaded review context
) -> CardStackState: # Card stack state for library functions
"Build a CardStackState from review context for library calls."Classes
class ReviewContext(NamedTuple):
"Common review state values loaded by handlers."Variables
DEBUG_REVIEW_STATE = Falsegraph (graph.ipynb)
Graph service for committing documents and segments to the context graph
Import
from cjm_transcript_review.services.graph import (
GraphService
)Classes
class GraphService:
def __init__(
self,
plugin_manager:PluginManager, # Plugin manager for accessing graph plugin
plugin_name:str="cjm-graph-plugin-sqlite", # Name of the graph plugin
)
"Service for committing structure to context graph."
def __init__(
self,
plugin_manager:PluginManager, # Plugin manager for accessing graph plugin
plugin_name:str="cjm-graph-plugin-sqlite", # Name of the graph plugin
)
"Initialize the graph service."
def is_available(self) -> bool: # True if plugin is loaded and ready
"""Check if the graph 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 graph plugin is available."
def ensure_loaded(
self,
config:Optional[Dict[str, Any]]=None, # Optional plugin configuration
) -> bool: # True if successfully loaded
"Ensure the graph plugin is loaded."
async def commit_document_async(
self,
title:str, # Document title
text_segments:List[TextSegment], # Text segments from decomposition
vad_chunks:List[VADChunk], # VAD chunks for timing (1:1 with segments)
media_type:str="audio", # Source media type
) -> Dict[str, Any]: # Result with document_id and segment_ids
"Commit a document to the context graph.
Assembles text segments with VAD timing at commit time.
Requires 1:1 alignment: len(text_segments) == len(vad_chunks)."
def commit_document(
self,
title:str, # Document title
text_segments:List[TextSegment], # Text segments from decomposition
vad_chunks:List[VADChunk], # VAD chunks for timing
media_type:str="audio", # Source media type
) -> Dict[str, Any]: # Result with document_id and segment_ids
"Commit a document to the context graph synchronously."helpers (helpers.ipynb)
State getters for the review step from InteractionContext
Import
from cjm_transcript_review.components.helpers import *Functions
def _get_review_state(
ctx:InteractionContext # Interaction context with state
) -> ReviewStepState: # Typed review step state
"Get the full review step state from context."def _get_focused_index(
ctx:InteractionContext, # Interaction context with state
default:int=0, # Default focused index
) -> int: # Currently focused segment index
"Get the currently focused segment index."def _get_visible_count(
ctx:InteractionContext, # Interaction context with state
default:int=5, # Default visible card count
) -> int: # Number of visible cards in viewport
"Get the stored visible card count."def _get_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_card_width(
ctx:InteractionContext, # Interaction context with state
default:int=50, # Default card width in rem
) -> int: # Card stack width in rem
"Get the stored card stack width."def _get_segments(
ctx:InteractionContext # Interaction context with state
) -> List[TextSegment]: # List of TextSegment objects from segmentation step
"Get text segments from segmentation step state."def _get_vad_chunks(
ctx:InteractionContext # Interaction context with state
) -> List[VADChunk]: # List of VADChunk objects from alignment step
"Get VAD chunks from alignment step state."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 from alignment step."def _is_aligned(
ctx:InteractionContext # Interaction context with state
) -> bool: # True if segment count matches VAD chunk count
"Check if segments are aligned with VAD chunks (1:1 match)."html_ids (html_ids.ipynb)
HTML ID constants for Phase 3: Review & Commit
Import
from cjm_transcript_review.html_ids import (
ReviewHtmlIds
)Classes
class ReviewHtmlIds:
"HTML ID constants for Phase 3: Review & Commit."
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 review_card(
index:int # Segment index
) -> str: # HTML ID for review card
"Generate HTML ID for a review card."init (init.ipynb)
Router assembly for Phase 3 review routes
Import
from cjm_transcript_review.routes.init import (
init_review_routers
)Functions
def init_review_routers(
state_store:WorkflowStateStore, # The workflow state store
workflow_id:str, # The workflow identifier
prefix:str, # Base prefix for review routes (e.g., "/workflow/review")
audio_src_url:str="", # Audio source route (from core routes)
graph_service:Optional[GraphService]=None, # Graph service for commit (None = no commit route)
alert_container_id:str="commit-alert-container", # ID of container for commit alerts
) -> Tuple[List[APIRouter], ReviewUrls, Dict[str, Callable]]: # (routers, urls, routes)
"Initialize and return all review routers with URL bundle."keyboard_config (keyboard_config.ipynb)
Review-specific keyboard building blocks for assembly into a KeyboardManager
Import
from cjm_transcript_review.components.keyboard_config import (
create_review_kb_parts,
create_review_keyboard_manager
)Functions
def create_review_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 review-specific keyboard building blocks."def create_review_keyboard_manager(
ids:CardStackHtmlIds, # Card stack HTML IDs
button_ids:CardStackButtonIds, # Card stack button IDs for navigation
config:CardStackConfig, # Card stack configuration
) -> ZoneManager: # Configured keyboard zone manager
"Create the keyboard zone manager for the review step."models (models.ipynb)
Review step state and working document model for Phase 3: Review & Commit
Import
from cjm_transcript_review.models import (
ReviewStepState,
ReviewUrls,
WorkingDocument
)Classes
class ReviewStepState(TypedDict):
"State for Phase 3: Review & Commit."@dataclass
class ReviewUrls:
"URL bundle for Phase 3 review route handlers and renderers."
card_stack: CardStackUrls = field(...)
audio_src: str = '' # Audio source route
speed_change: str = '' # Playback speed change handler
toggle_auto_nav: str = '' # Auto-navigate toggle handler
replay_current: str = '' # Replay current segment handler
update_title: str = '' # Document title update handler
commit: str = '' # Commit handler route@dataclass
class WorkingDocument:
"Container for workflow state during structure decomposition."
title: str = '' # Document title
media_type: str = 'audio' # Source media type ('audio', 'video', 'text')
media_path: Optional[str] # Path to primary source media
source_blocks: List[SourceBlock] = field(...) # Ordered source blocks
combined_text: str = '' # Concatenated text from all sources
segments: List[TextSegment] = field(...) # Decomposed segments
vad_chunks: List[VADChunk] = field(...) # VAD time ranges
audio_duration: Optional[float] # Total audio duration in seconds
def to_dict(self) -> Dict[str, Any]: # Dictionary representation
"""Convert to dictionary for JSON serialization."""
return {
'title': self.title,
"Convert to dictionary for JSON serialization."
def from_dict(
cls,
data: Dict[str, Any] # Dictionary representation
) -> "WorkingDocument": # Reconstructed WorkingDocument
"Create from dictionary."review_card (review_card.ipynb)
Review card component showing assembled segment with timing and source info
Import
from cjm_transcript_review.components.review_card import (
AssembledSegment,
render_review_card,
create_review_card_renderer
)Functions
def render_review_card(
assembled:AssembledSegment, # Assembled segment with text and timing
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: # Review card component
"Render a single review card with text, timing, source info, playing indicator, and play button."def create_review_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 review cards."Classes
@dataclass
class AssembledSegment:
"A segment paired with its corresponding VAD chunk for review."
segment: TextSegment # Text segment with content and source info
vad_chunk: VADChunk # VAD chunk with timing
def index(self) -> int: # Segment index for card stack
"""Get the index from the segment."""
return self.segment.index
@property
def text(self) -> str: # Segment text content
"Get the index from the segment."
def text(self) -> str: # Segment text content
"""Get the text content from the segment."""
return self.segment.text
@property
def start_time(self) -> float: # Start time from VAD chunk
"Get the text content from the segment."
def start_time(self) -> float: # Start time from VAD chunk
"""Get the start time from the VAD chunk."""
return self.vad_chunk.start_time
@property
def end_time(self) -> float: # End time from VAD chunk
"Get the start time from the VAD chunk."
def end_time(self) -> float: # End time from VAD chunk
"Get the end time from the VAD chunk."step_renderer (step_renderer.ipynb)
Composable render functions for the review card stack step
Import
from cjm_transcript_review.components.step_renderer import (
DEBUG_REVIEW_RENDER,
render_review_toolbar,
render_review_stats,
render_review_source_position,
render_review_content,
render_review_footer,
render_review_step
)Functions
def render_review_toolbar(
playback_speed:float=1.0, # Current playback speed
auto_navigate:bool=False, # Whether auto-navigate is enabled
document_title:str="", # Current document title
urls:ReviewUrls=None, # URL bundle for audio control routes
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Toolbar component
"Render the review toolbar with title input and audio controls."def render_review_stats(
assembled:List[AssembledSegment], # Assembled segments
oob:bool=False, # Whether to render as OOB swap
) -> Any: # Statistics component
"Render review statistics."def render_review_source_position(
assembled:List[AssembledSegment], # Assembled segments
focused_index:int=0, # Currently focused segment 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 segment."def render_review_content(
assembled:List[AssembledSegment], # Assembled segments to display
focused_index:int, # Currently focused segment index
visible_count:int, # Number of visible cards in viewport
card_width:int, # Card stack width in rem
urls:ReviewUrls, # URL bundle for review routes
audio_urls:Optional[List[str]]=None, # Audio file URLs for Web Audio API
) -> Any: # Main content area
"Render the review content area with card stack viewport and keyboard system."def render_review_footer(
assembled:List[AssembledSegment], # Assembled segments
focused_index:int, # Currently focused segment index
) -> Any: # Footer content with progress indicator, source position, and stats
"Render footer content with progress indicator, source position, and statistics."def render_review_step(
assembled:List[AssembledSegment], # Assembled segments to display
focused_index:int=0, # Currently focused segment index
visible_count:int=DEFAULT_VISIBLE_COUNT, # Number of visible cards
is_auto_mode:bool=False, # Whether card count is in auto-adjust mode
card_width:int=DEFAULT_CARD_WIDTH, # Card stack width in rem
playback_speed:float=1.0, # Current playback speed
auto_navigate:bool=False, # Whether auto-navigate is enabled
document_title:str="", # Current document title
urls:ReviewUrls=None, # URL bundle for review routes
audio_urls:Optional[List[str]]=None, # Audio file URLs for Web Audio API
) -> Any: # Complete review step component
"Render the complete review step with toolbar, content, and footer."Variables
DEBUG_REVIEW_RENDER = Falseutils (utils.ipynb)
Time formatting and source info display utilities for review cards
Import
from cjm_transcript_review.utils import (
format_time,
format_duration,
truncate_id,
format_char_range,
format_source_info,
generate_document_title
)Functions
def format_time(
seconds:Optional[float] # Time in seconds
) -> str: # Formatted time string (m:ss.s)
"Format seconds as m:ss.s for sub-second display."def format_duration(
start:Optional[float], # Start time in seconds
end:Optional[float], # End time in seconds
) -> str: # Formatted duration string (e.g., "3.2s")
"Format duration from start/end times."def truncate_id(
id_str:Optional[str], # Full ID string
length:int=8, # Number of characters to keep
) -> str: # Truncated ID with ellipsis if needed
"Truncate an ID string for display, adding ellipsis if truncated."def format_char_range(
start_char:Optional[int], # Start character index
end_char:Optional[int], # End character index
) -> str: # Formatted range string (e.g., "char:25-68")
"Format character range for source reference display."def format_source_info(
provider_id:Optional[str], # Source provider identifier
source_id:Optional[str], # Source record ID
start_char:Optional[int]=None, # Start character index
end_char:Optional[int]=None, # End character index
) -> str: # Formatted source info string
"Format source info for display in review cards."def generate_document_title(
media_path:Optional[str], # Path to media file
default:str="Untitled Document", # Fallback title if path is None
) -> str: # Clean document title
"Generate a document title from a media file path."