generated from john/python-template
V4.7 Phase 2: Evidence Model Simplification
This commit is contained in:
@@ -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")
|
||||
Reference in New Issue
Block a user