diff --git a/app.py b/app.py index 65c2d13..50a25ab 100644 --- a/app.py +++ b/app.py @@ -366,10 +366,6 @@ f"症例 {cid}" + (" ✓" if cid in st.session_state.annotated_cases else "") for cid in st.session_state.case_ids ] - - # 症例選択のコールバック - def on_case_change(): - pass selected_idx = st.selectbox( "症例リスト", @@ -414,24 +410,36 @@ if st.session_state.zoom_percent not in zoom_levels: st.session_state.zoom_percent = 80 - current_idx = zoom_levels.index(st.session_state.zoom_percent) + current_zoom_idx = zoom_levels.index(st.session_state.zoom_percent) + + # Zoom変更用コールバック関数 + def change_zoom(amount: int): + new_idx = current_zoom_idx + amount + if 0 <= new_idx < len(zoom_levels): + st.session_state.zoom_percent = zoom_levels[new_idx] col_z1, col_z2, col_z3 = st.columns([1, 2, 1]) with col_z1: - if st.button("-", key="zoom_out", use_container_width=True): - if current_idx > 0: - st.session_state.zoom_percent = zoom_levels[current_idx - 1] - st.rerun() + st.button( + "-", + key="zoom_out", + use_container_width=True, + on_click=change_zoom, + args=(-1,) + ) with col_z2: st.markdown(f"
{st.session_state.zoom_percent} %
", unsafe_allow_html=True) with col_z3: - if st.button("+", key="zoom_in", use_container_width=True): - if current_idx < len(zoom_levels) - 1: - st.session_state.zoom_percent = zoom_levels[current_idx + 1] - st.rerun() + st.button( + "+", + key="zoom_in", + use_container_width=True, + on_click=change_zoom, + args=(1,) + ) def render_image_viewer(case_id: Union[int, float], container): @@ -534,7 +542,8 @@ PREDICTION_OPTIONS, key=f"prediction_{case_id}", horizontal=True, # 変更: 横並びにして省スペース化 - label_visibility="collapsed" + label_visibility="collapsed", + index=1 # デフォルトは「なし」 ) # Q2: Confidence (横並び) @@ -542,7 +551,7 @@ confidence = container.radio( "確信度", CONFIDENCE_OPTIONS, - index=2, # 50% + index=3, # 50% format_func=lambda x: f"{x}%", key=f"confidence_{case_id}", label_visibility="collapsed", @@ -575,6 +584,23 @@ } +def render_complete_screen(): + """全てのアノテーションが完了した際に表示する終了画面""" + st.balloons() # 完了のお祝いエフェクト + + st.markdown(""" +
+

🎉 アノテーション完了 🎉

+

全症例の判定が終了しました。ご協力ありがとうございました!

+
+ """, unsafe_allow_html=True) + + st.success(f"データは以下の場所に保存されました:") + st.code(st.session_state.csv_path, language=None) + + st.info("ブラウザのタブを閉じて終了してください。") + + def validate_annotation(annotation_data: dict) -> tuple[bool, str]: """ 保存前にアノテーションデータを検証。 @@ -610,6 +636,14 @@ # Get ground truth label for this case (may be None) ground_truth = st.session_state.ground_truth_labels.get(case_id, None) + # 見つからず,CaseIDに小数点を含む場合 + if ground_truth is None: + try: + int_case_id = int(case_id) + ground_truth = st.session_state.ground_truth_labels.get(int_case_id, None) + except: + pass + save_annotation( csv_path=st.session_state.csv_path, case_id=case_id, @@ -642,7 +676,7 @@ st.session_state.current_case_idx = next_idx st.rerun() else: - container.info("全症例のアノテーションが完了しました! 🎉") + st.rerun() except Exception as e: container.error(f"保存エラー: {e}") @@ -665,6 +699,14 @@ render_sidebar_ui() + # 完了判定ロジック + total_cases = len(st.session_state.case_ids) + annotated_count = len(st.session_state.annotated_cases) + + if total_cases > 0 and annotated_count >= total_cases: + render_complete_screen() + return + current_case_id = get_current_case_id() if current_case_id is None: