cjm-transcript-review

FastHTML Reader View component for verifying transcript segmentation with audio playback and context graph commit.

Install

pip install cjm_transcript_review

Project 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 = False

audio_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 enabled

callbacks (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_CONFIG

card_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_IDS

commit (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 failed

Variables

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 = False

graph (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 = False

utils (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."