TheBug95's picture
Solucion de problemas con los botones de volver a grabar y restaurar original. Solucion de incongruencias en los dialogos de descargas e implementacion de internacionalizacion de la herramienta
1f7c87f
"""OphthalmoCapture — Labeling Component
Provides:
1. Categorical radio selector: Normal / Cataract / Bad quality / Needs dilation
2. LOCS III dropdowns (only when "Cataract" is selected):
- Nuclear Opalescence (NO) 0-6
- Nuclear Color (NC) 0-6
- Cortical Opacity (C) 0-5
3. Auto-saves (upsert) to audit DB on every change.
Numeric values are stored for ML; only text labels are shown in the UI.
"""
import streamlit as st
import config
import database as db
from i18n import t, label_display, label_from_display, locs_display
from services import session_manager as sm
def _save_to_db(img: dict, image_id: str):
"""Persist current label + LOCS data to audit DB (non-blocking)."""
try:
db.save_or_update_annotation(
image_filename=img["filename"],
label=img["label"],
transcription=img.get("transcription", ""),
doctor_name=st.session_state.get("doctor_name", ""),
session_id=st.session_state.get("session_id", ""),
locs_data=img.get("locs_data", {}),
)
except Exception:
pass
def _render_locs_dropdown(field: dict, image_id: str, current_locs: dict) -> int | None:
"""Render a single LOCS dropdown and return the selected numeric value."""
field_id = field["field_id"]
options = field["options"]
display_labels = [locs_display(opt["display"]) for opt in options]
# Determine current index from stored data
stored_value = current_locs.get(field_id)
if stored_value is not None:
current_index = next(
(i for i, opt in enumerate(options) if opt["value"] == stored_value),
None,
)
else:
current_index = None
# Use index=None so nothing is pre-selected until doctor chooses
selected_display = st.selectbox(
locs_display(field["label"]),
display_labels,
index=current_index,
key=f"locs_{field_id}_{image_id}",
placeholder=t("locs_placeholder"),
)
if selected_display is not None and selected_display in display_labels:
idx = display_labels.index(selected_display)
return options[idx]["value"]
return None
def render_labeler(image_id: str):
"""Render the full labeling panel for the given image."""
img = st.session_state.images.get(image_id)
if img is None:
return
st.subheader(t("labeling"))
# ── 1. Categorical classification ────────────────────────────────────
# Translated display (UI only); storage always uses English name.
translated_options = [label_display(opt["display"]) for opt in config.LABEL_OPTIONS]
current_label = img.get("label") # English, e.g. "Cataract"
if current_label is not None:
translated_current = label_display(current_label)
if translated_current in translated_options:
current_index = translated_options.index(translated_current)
else:
current_index = None
else:
current_index = None
with st.container(border=True):
if current_index is None:
st.caption(t("select_label_hint"))
selected = st.radio(
t("classification"),
translated_options,
index=current_index,
key=f"label_radio_{image_id}",
horizontal=True,
label_visibility="collapsed",
)
# Map translated selection back to English for storage
new_label = label_from_display(selected) if selected in translated_options else None
# Detect categorical change
label_changed = new_label is not None and new_label != current_label
if label_changed:
img["label"] = new_label
img["labeled_by"] = st.session_state.get("doctor_name", "")
# If switching away from Cataract, clear LOCS data
if new_label != "Cataract":
img["locs_data"] = {}
sm.update_activity()
_save_to_db(img, image_id)
# ── 2. LOCS III Classification (only for "Cataract") ─────────────────
effective_label = new_label or current_label
if effective_label == "Cataract":
st.markdown("---")
st.markdown(t("locs_title"))
current_locs = img.get("locs_data", {})
locs_changed = False
with st.container(border=True):
for field_def in config.LOCS_FIELDS:
value = _render_locs_dropdown(field_def, image_id, current_locs)
field_id = field_def["field_id"]
if value is not None and value != current_locs.get(field_id):
current_locs[field_id] = value
locs_changed = True
img["locs_data"] = current_locs
if locs_changed:
sm.update_activity()
_save_to_db(img, image_id)
# LOCS summary
filled = sum(1 for f in config.LOCS_FIELDS if f["field_id"] in current_locs)
total_fields = len(config.LOCS_FIELDS)
if filled < total_fields:
st.info(t("locs_progress", filled=filled, total=total_fields))
else:
st.success(t("locs_complete", filled=filled, total=total_fields))
# ── 3. Visual feedback ───────────────────────────────────────────────────
if effective_label is None:
st.warning(t("unlabeled"))
else:
st.success(f"{t('label_set')}: **{label_display(effective_label)}**")