Tomatillo's picture
Update src/streamlit_app.py
a582d42 verified
import streamlit as st
from segments import SegmentsClient
import sys
import copy
from get_labels_from_samples import export_all_sensor_frames_and_annotations
# ---------------- Streamlit UI ----------------
st.title("Copy annotations from one dataset to another")
st.subheader("For Multi-sensor datasets - Cuboids and bounding boxes")
# Initialize success message in session state
if "success" not in st.session_state:
st.session_state.success = ""
api_key = st.text_input("Enter your API Key", type="password")
source_uuid = st.text_input("Source UUID (the sample you want to copy from)", value="")
source_frame_num = st.number_input("Source Frame Number", min_value=1, value=50, step=1)
target_uuid = st.text_input("Target UUID (the sample you want to copy to)", value="")
target_frame_num = st.number_input("Target Frame Number", min_value=1, value=1, step=1)
if st.button("Overwrite Target Frame Annotations"):
st.session_state.success = "" # Clear previous success message
if not api_key or not source_uuid or not target_uuid:
st.error("Please fill in all fields.")
else:
try:
client = SegmentsClient(api_key)
# Fetch source and target labels
source_label = client.get_label(source_uuid)
target_label = client.get_label(target_uuid)
# Extract all sensor frames/annotations
source_sensors = export_all_sensor_frames_and_annotations(source_label)
target_sensors = export_all_sensor_frames_and_annotations(target_label)
# Defensive copy
new_target_label = copy.deepcopy(target_label)
sensors_attr = getattr(new_target_label.attributes, "sensors", None)
if sensors_attr is None:
st.error("Target label has no sensors.")
st.stop()
# For each sensor in both source and target
for sensor_idx, sensor in enumerate(sensors_attr):
sensor_name = getattr(sensor, "name", None)
if not sensor_name or sensor_name not in source_sensors:
continue # skip sensors not found in source
source_frames = source_sensors[sensor_name]
target_frames = target_sensors.get(sensor_name, [])
# Frame indices are 1-indexed for user, 0-indexed in list
src_idx = source_frame_num - 1
tgt_idx = target_frame_num - 1
if src_idx >= len(source_frames) or tgt_idx >= len(target_frames):
st.warning(f"Sensor '{sensor_name}': Frame index out of range. Skipped.")
continue
# Overwrite target frame's annotations with source frame's annotations
src_anns = source_frames[src_idx]["annotations"]
tgt_frame = getattr(sensor.attributes.frames[tgt_idx], "annotations", None)
if tgt_frame is not None:
sensor.attributes.frames[tgt_idx].annotations = copy.deepcopy(src_anns)
else:
st.warning(f"Sensor '{sensor_name}': Could not access target frame annotations.")
# Upload the updated label to Segments.ai (only the specified frames/annotations are changed)
client.update_label(
target_uuid,
labelset="ground-truth", # Change this if you use a different labelset name
attributes=new_target_label.attributes.model_dump()
)
st.session_state.success = "Target label updated and uploaded to Segments.ai!"
except Exception as e:
st.error(f"Error: {e}")
# Always show the success message after the button handler
if st.session_state.success:
st.success(st.session_state.success)