import streamlit as st
from tg263 import RTSTRUCT_SUBTYPES
import html
import utils
import numpy as np
DEFAULT_SELECT = "< PICK A VALUE >"
def selectbox_with_default(label, values, key=None, help=None):
all_options = np.insert(np.array(values, object), 0, DEFAULT_SELECT)
selected = st.selectbox(
label,
options=all_options,
key=key,
help=help,
format_func=lambda x: "" if x == DEFAULT_SELECT else x,
)
return selected
def render_schema_section(schema_section, section_prefix="", current_task=None):
for key, props in schema_section.items():
if should_render(props, current_task):
render_field(key, props, section_prefix)
def has_renderable_fields(field_keys, schema_section, current_task):
return any(
key in schema_section and should_render(schema_section[key], current_task)
for key in field_keys
)
def render_fields(field_keys, schema_section, section_prefix, current_task):
for key in field_keys:
if key in schema_section and should_render(schema_section[key], current_task):
render_field(key, schema_section[key], section_prefix)
def should_render(props, current_task):
model_types = props.get("model_types")
if not model_types:
return True
if current_task:
return current_task.strip().lower() in map(str.lower, model_types)
return False
def render_field(key, props, section_prefix):
full_key = f"{section_prefix}_{key}"
label = props.get("label") or key or "Field"
description = props.get("description", "")
example = props.get("example", "")
field_type = props.get("type", "")
required = props.get("required", False)
options = props.get("options", [])
placeholder = props.get("placeholder", "")
create_helpicon(label, description, field_type, example, required)
try:
safe_label = label.strip() or "Field"
if key == "type_metrics_other":
render_type_metrics_other(full_key, label)
return
if field_type == "select":
if not options:
st.warning(f"Field '{label}' is missing options for select dropdown.")
else:
if key in ["input_content", "output_content", "model_inputs", "model_outputs"]:
content_list_key = f"{full_key}_list"
type_key = f"{full_key}_new_type"
subtype_key = f"{full_key}_new_subtype"
# Initialize persistent values
utils.load_value(content_list_key, default=[])
utils.load_value(type_key)
utils.load_value(subtype_key)
if st.session_state["_" + type_key] == "RTSTRUCT":
col1, col2, col3 = st.columns([2, 1, 0.4])
with col1:
st.selectbox(
label=".",
options=options,
key="_" + type_key,
on_change=utils.store_value,
args=[type_key],
label_visibility="hidden",
placeholder="-Select an option-",
)
with col2:
st.selectbox(
label=".",
options=RTSTRUCT_SUBTYPES,
key="_" + subtype_key,
on_change=utils.store_value,
args=[subtype_key],
label_visibility="hidden",
placeholder="-Select an option-",
)
with col3:
st.markdown(
"
",
unsafe_allow_html=True,
)
if st.button("โ", key=f"{full_key}_add_button"):
subtype = st.session_state.get(subtype_key, "")
entry = f"RTSTRUCT_{subtype}"
st.session_state[content_list_key].append(entry)
st.session_state[full_key] = st.session_state[
content_list_key
]
st.markdown("
", unsafe_allow_html=True)
else:
col1, col2, col3 = st.columns([2, 1, 0.5])
# Type selectbox
with col1:
st.selectbox(
label=".",
options=options,
key="_" + type_key,
on_change=utils.store_value,
args=[type_key],
label_visibility="hidden",
placeholder="-Select an option-"
)
selected_type = st.session_state.get(type_key)
custom_key = f"{full_key}_custom_text"
utils.load_value(custom_key, default="")
with col2:
st.markdown(
"",
unsafe_allow_html=True,
)
if selected_type == "OT (Other)":
st.text_input(
"Enter custom input",
value=st.session_state.get(custom_key, ""),
key=custom_key,
label_visibility="collapsed",
placeholder="Introduce custom value",
)
st.markdown("
", unsafe_allow_html=True)
else:
st.markdown(" ", unsafe_allow_html=True)
# Add button
with col3:
st.markdown("", unsafe_allow_html=True)
add_clicked = st.button("โ", key=f"{full_key}_add_button")
st.markdown("
", unsafe_allow_html=True)
if add_clicked:
if selected_type in [None, "", DEFAULT_SELECT]:
st.error("Please select an option before adding.")
elif selected_type == "OT (Other)":
custom_text = st.session_state.get(custom_key, "").strip()
if not custom_text:
st.error("Please enter a custom name before adding.")
else:
st.session_state[content_list_key].append(custom_text)
st.session_state[full_key] = st.session_state[content_list_key]
else:
entry = utils.strip_brackets(selected_type)
st.session_state[content_list_key].append(entry)
st.session_state[full_key] = st.session_state[content_list_key]
entries = st.session_state[content_list_key]
if entries:
col1, col2 = st.columns([5, 1])
with col1:
tooltip_items = [
f"{html.escape(utils.strip_brackets(item))}"
for item in entries
]
line = ", ".join(tooltip_items)
st.markdown(f"{line}", unsafe_allow_html=True)
with col2:
if st.button("๐งน Clear", key=f"{full_key}_clear_all"):
st.session_state[content_list_key] = []
st.session_state[full_key] = []
st.rerun()
return
if key in ["treatment_modality_train", "treatment_modality_eval"]:
content_list_key2 = f"{full_key}_modality_list"
type_key2 = f"{full_key}_modality_type"
# Initialize persistent values
utils.load_value(content_list_key2, default=[])
utils.load_value(type_key2)
col1, col2 = st.columns([4, 0.5])
with col1:
st.selectbox(
label=".",
options=options,
key="_" + type_key2,
on_change=utils.store_value,
args=[type_key2],
label_visibility="hidden",
placeholder="-Select an option-"
)
add_clicked = False
with col2:
st.markdown("", unsafe_allow_html=True)
add_clicked = st.button("โ", key=f"{full_key}_modality_add_button")
st.markdown("
", unsafe_allow_html=True)
raw_value2 = st.session_state.get(type_key2)
if add_clicked:
if raw_value2 in [None, "", DEFAULT_SELECT]:
st.error("Please select an option before adding.")
else:
entry = utils.strip_brackets(raw_value2)
st.session_state[content_list_key2].append(entry)
st.session_state[full_key] = st.session_state[content_list_key2]
entries = st.session_state[content_list_key2]
if entries:
col1, col2 = st.columns([5, 1])
with col1:
tooltip_items = [
f"{html.escape(utils.strip_brackets(item))}"
for item in entries
]
line = ", ".join(tooltip_items)
st.markdown(f"{line}", unsafe_allow_html=True)
with col2:
if st.button("Clear", key=f"{full_key}_modality_clear_all"):
st.session_state[content_list_key2] = []
st.session_state[full_key] = []
st.rerun()
return
if key in ["type_ism", "type_gm_seg"]:
type_key = full_key + "_selected"
type_list_key = full_key + "_list"
utils.load_value(type_key)
utils.load_value(type_list_key, default=[])
options = props.get("options", [])
col1, col2, col3 = st.columns([3.5, 0.5, 1])
with col1:
st.selectbox(
label=safe_label,
options=options,
key="_" + type_key,
on_change=utils.store_value,
args=[type_key],
label_visibility="hidden",
placeholder="-Select an option-",
)
add_clicked = False
error_msg = None
with col2:
st.markdown(
"", unsafe_allow_html=True
)
add_clicked = st.button("โ", key=f"{full_key}_add_button")
st.markdown("
", unsafe_allow_html=True)
if add_clicked:
value = st.session_state.get(type_key)
if not value:
error_msg = "Please choose an image similarity metrics before adding."
elif value not in st.session_state[type_list_key]:
st.session_state[type_list_key].append(value)
st.session_state[full_key] = st.session_state[type_list_key]
if error_msg:
st.markdown(" ") # spacing
st.error(error_msg)
with col3:
if st.session_state[type_list_key]:
st.markdown(
"",
unsafe_allow_html=True,
)
if st.button("Clear", key=f"{full_key}_clear_button"):
st.session_state[type_list_key] = []
st.session_state[full_key] = []
st.rerun()
st.markdown("
", unsafe_allow_html=True)
return
if key in ["type_dose_dm", "type_dose_dm_seg", "type_dose_dm_dp"]:
static_options = ["GPR (Gamma Passing Rate)", "MAE (Mean Absolute Error)", "MSE (Mean Squared Error)", "Other"]
parametric_options = ["D", "V"]
dm_key = full_key
dm_list_key = f"{dm_key}_list"
dm_select_key = f"{dm_key}_selected"
dm_dynamic_key = f"{dm_key}_dyn"
utils.load_value(dm_list_key, default=[])
utils.load_value(dm_select_key)
utils.load_value(
dm_dynamic_key, default={"prefix": "D", "value": 95}
)
col1, col2, col3, col4 = st.columns([2, 2, 0.5, 1])
with col1:
st.selectbox(
"Select dose metric",
options=static_options + parametric_options,
key="_" + dm_select_key,
on_change=utils.store_value,
args=[dm_select_key],
label_visibility="hidden",
placeholder="-Select an option-",
)
dm_type = st.session_state[dm_select_key]
with col2:
val = None
if dm_type in parametric_options:
val_key = f"{dm_dynamic_key}_{dm_type}_value"
if val_key not in st.session_state:
st.session_state[val_key] = st.session_state[
dm_dynamic_key
]["value"]
st.markdown(
"",
unsafe_allow_html=True,
)
val = st.number_input(
f"{dm_type} value",
min_value=1,
max_value=100,
value=st.session_state[val_key],
key=val_key,
label_visibility="collapsed",
placeholder=f"Enter {dm_type} value",
)
st.markdown("
", unsafe_allow_html=True)
st.session_state[dm_dynamic_key] = {
"prefix": dm_type,
"value": val,
}
elif dm_type == "Other":
st.markdown(
"",
unsafe_allow_html=True,
)
val = st.text_input(
label="Other dose metric",
label_visibility="collapsed",
placeholder="Enter custom name",
key=f"{dm_key}_other_text",
)
st.markdown("
", unsafe_allow_html=True)
add_clicked = False
error_msg = None
with col3:
st.markdown(
"", unsafe_allow_html=True
)
add_clicked = st.button("โ", key=f"{dm_key}_add_button")
st.markdown("
", unsafe_allow_html=True)
if add_clicked:
metric = None # default
if not dm_type:
error_msg = (
"Please choose a dose metric type before adding."
)
elif dm_type in static_options and dm_type != "Other":
metric = dm_type
elif dm_type == "Other":
metric = val.strip() if val else ""
if not metric:
error_msg = (
"Please enter a custom name for the dose metric."
)
elif dm_type in parametric_options:
val_struct = st.session_state.get(dm_dynamic_key, {})
if not val_struct:
error_msg = "Please enter a value for the dose metric."
else:
metric = f"{dm_type}{val_struct.get('value', '')}"
if error_msg:
st.markdown(" ") # spacing
st.error(error_msg)
elif metric and metric not in st.session_state[dm_list_key]:
st.session_state[dm_list_key].append(metric)
st.session_state[dm_key] = st.session_state[dm_list_key]
with col4:
if st.session_state[dm_list_key]:
st.markdown(
"",
unsafe_allow_html=True,
)
if st.button("Clear", key=f"{dm_key}_clear_button"):
st.session_state[dm_list_key] = []
st.session_state[dm_key] = []
st.rerun()
st.markdown("
", unsafe_allow_html=True)
return
utils.load_value(full_key)
st.selectbox(
safe_label,
options=options,
key="_" + full_key,
on_change=utils.store_value,
args=[full_key],
help=description,
label_visibility="hidden",
placeholder="-Select an option-",
)
elif field_type == "Image":
st.markdown(
"If too big or not readable, please indicate the figure number and attach it to the appendix",
unsafe_allow_html=True,
)
col1, col2 = st.columns([1, 2])
with col1:
st.text_input(
label=".",
placeholder="e.g., Fig. 1",
key=f"{full_key}_appendix_note",
label_visibility="collapsed",
)
with col2:
uploaded_image = st.file_uploader(
label=".",
type=["png", "jpg", "jpeg"],
key=full_key,
label_visibility="collapsed",
)
if uploaded_image:
st.session_state[f"{full_key}_image"] = uploaded_image
else:
utils.load_value(full_key)
raw_input=st.text_input(
safe_label,
key="_" + full_key,
on_change=utils.store_value,
args=[full_key],
label_visibility="hidden",
placeholder=placeholder,
)
# Integer enforcement for specific keys
integer_keys = [
"number_of_inputs",
"number_of_outputs",
"total_number_trainable_parameters",
"batch_size",
"number_of_patients"
]
# SAFELY check and validate
if key in integer_keys:
if raw_input:
stripped = raw_input.strip()
if stripped.isdigit():
st.session_state[full_key] = stripped # store as string
else:
st.error(f"'{label}' must be a valid integer.")
if full_key in st.session_state:
del st.session_state[full_key]
else:
if full_key in st.session_state:
del st.session_state[full_key]
else:
st.session_state[full_key] = raw_input.strip() if raw_input else ""
except Exception as e:
st.error(f"Error rendering field '{label}': {str(e)}")
def render_type_metrics_other(full_key, label):
metrics_list_key = f"{full_key}_list"
metrics_selected_key = f"{full_key}_selected"
utils.load_value(metrics_list_key, default=[])
utils.load_value(metrics_selected_key)
# Warning flag
show_warning = False
col1, col2, col3 = st.columns([3, 0.5, 1])
with col1:
st.text_input(
label=".",
key="_" + metrics_selected_key,
on_change=utils.store_value,
args=[metrics_selected_key],
placeholder="Enter metric name (e.g. MSE)",
label_visibility="hidden"
)
with col2:
st.markdown("", unsafe_allow_html=True)
if st.button("โ", key=f"{full_key}_add_button"):
value = st.session_state.get(metrics_selected_key, "")
if value and value.strip():
value = value.strip()
if value not in st.session_state[metrics_list_key]:
st.session_state[metrics_list_key].append(value)
st.session_state[full_key] = st.session_state[metrics_list_key]
else:
show_warning = True # already exists
else:
show_warning = True # empty input
st.markdown("
", unsafe_allow_html=True)
with col3:
st.markdown("", unsafe_allow_html=True)
if st.button("Clear", key=f"{full_key}_clear_button"):
st.session_state[metrics_list_key] = []
st.session_state[full_key] = []
st.rerun()
st.markdown("
", unsafe_allow_html=True)
# Warning shown below the row
if show_warning:
st.warning("Please enter a valid metric name before adding.")
def create_helpicon(label, description, field_format, example, required=False):
required_tag = (
"*"
if required else ""
)
st.markdown("""
""", unsafe_allow_html=True)
tooltip_html = f"""
{label} {required_tag}
โ
Description: {description}
Format: {field_format}
Example(s): {example}
"""
st.markdown(tooltip_html, unsafe_allow_html=True)