V4.7 Phase 2: Evidence Model Simplification

This commit is contained in:
zoltan57
2026-08-18 15:30:51 -05:00
parent f86c0ff27b
commit 7285a87dfb
@@ -1,131 +0,0 @@
"""Reusable transcript UI components."""
from __future__ import annotations
from collections.abc import Awaitable
from collections.abc import Callable
from datetime import datetime
from typing import Any
from nicegui import ui
from transcription.db.models import Job
from transcription.db.models import Source
type RevisionAction = Callable[[Source], Awaitable[None] | None]
def render_original_transcription_card(*, job: Job, classes: str = "w-full") -> Any:
"""Render the immutable original job transcription output."""
latest_error_detail = _latest_job_error_detail(job)
status_label = "Failed" if latest_error_detail else "Transcribed"
header = f"Original Transcription | {status_label}"
provider = job.provider or "unknown"
model = job.model or "unknown"
caption = f"{provider} | {model} | {_format_created_at(job.date_updated)}"
card = ui.card().classes(f"{classes} q-pa-md ui-card-surface")
with card, ui.column().classes("w-full q-gutter-y-sm"):
ui.label(header).classes("text-subtitle1 text-weight-medium")
ui.label(caption).classes("text-caption ui-text-muted")
_metadata_row(label="Prompt", value=_latest_job_prompt(job) or "unknown")
_metadata_row(label="Updated", value=_format_created_at(job.date_updated))
latest_transcription = _latest_job_transcription(job)
if latest_transcription:
with ui.card().classes("w-full q-pa-sm ui-card-surface"):
ui.markdown(latest_transcription)
if latest_error_detail:
with ui.card().classes("w-full ui-card-error q-pa-sm"):
ui.label("Failure detail").classes("text-caption text-uppercase")
ui.label(latest_error_detail).classes("text-body2")
return card
def render_revision_row(
*,
revision: Source | None,
initially_expanded: bool = False,
classes: str = "w-full",
on_delete: RevisionAction | None = None,
) -> Any:
"""Render a collapsible row for the single optional source revision."""
if revision is None:
return None
header = "Source revision | User-authored"
caption = _format_created_at(revision.date_revised or revision.date_uploaded)
expansion = ui.expansion(value=initially_expanded, group="group").classes(f"{classes} ui-card-surface")
with expansion, ui.column().classes("w-full q-gutter-y-sm q-pa-sm"):
with expansion.add_slot("header"), ui.row().classes("w-full items-start justify-between q-gutter-md"):
with ui.column().classes("q-gutter-none"):
ui.label(header).classes("text-subtitle1 text-weight-medium")
ui.label(caption).classes("text-caption ui-text-muted")
if on_delete is not None:
with ui.dialog() as delete_dialog, ui.card().classes("q-pa-md ui-card-surface"):
ui.label("Delete this source revision?").classes("text-body1")
with ui.row().classes("w-full justify-end q-gutter-sm"):
ui.button("Cancel", on_click=lambda: delete_dialog.submit(False)).props("flat")
ui.button("Delete", on_click=lambda: delete_dialog.submit(True)).props(
'unelevated color="negative"'
)
async def delete_current_transcript() -> None:
delete_dialog.open()
confirmed = await delete_dialog
if not confirmed:
return
maybe_awaitable = on_delete(revision)
if isinstance(maybe_awaitable, Awaitable):
await maybe_awaitable
with ui.column(align_items="center").classes("self-center q-gutter-none"):
ui.button(icon="delete", on_click=delete_current_transcript).props(
'flat round dense color="negative"'
)
_metadata_row(label="Created", value=_format_created_at(revision.date_revised or revision.date_uploaded))
if revision.revised_text:
with ui.card().classes("w-full q-pa-sm ui-card-surface"):
ui.markdown(revision.revised_text)
return expansion
def _latest_job_transcription(job: Job) -> str | None:
for job_source in sorted(job.job_sources, key=lambda item: item.executed_at, reverse=True):
if job_source.raw_transcription:
return job_source.raw_transcription
return None
def _latest_job_error_detail(job: Job) -> str | None:
for job_source in sorted(job.job_sources, key=lambda item: item.executed_at, reverse=True):
if job_source.error_detail:
return job_source.error_detail
return None
def _latest_job_prompt(job: Job) -> str | None:
for job_source in sorted(job.job_sources, key=lambda item: item.executed_at, reverse=True):
if job_source.job and job_source.job.prompt_name:
return job_source.job.prompt_name
return None
def _format_created_at(value: datetime) -> str:
"""Return a compact UTC-like timestamp for row captions."""
return value.strftime("%Y-%m-%d %H:%M:%S %Z")
def _metadata_row(*, label: str, value: str) -> None:
with ui.row().classes("w-md items-start justify-between q-gutter-x-md"):
ui.label(label).classes("text-caption ui-text-muted text-uppercase")
ui.label(value).classes("text-body2 text-right break-all")