MichaelDeutges commited on
Commit
71fcdff
·
verified ·
1 Parent(s): 8ec9286

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -24
app.py CHANGED
@@ -7,15 +7,20 @@ import streamlit as st
7
  import pandas as pd
8
  from PIL import Image
9
  from filelock import FileLock
 
10
 
11
  # ---------------- Config ----------------
12
- BASE_DIR = Path(".").resolve() # Space root
13
  IMAGE_DIR = os.getenv("IMAGE_DIR", "images")
14
- LABELS_CSV = os.getenv("LABELS_CSV", str(BASE_DIR / "labels.csv"))
15
  LABEL_LEFT = os.getenv("LABEL_A", "Class A")
16
  LABEL_RIGHT = os.getenv("LABEL_B", "Class B")
17
  SUPPORTED_EXTS = (".png", ".jpg", ".jpeg", ".bmp", ".gif", ".tif", ".tiff", ".webp")
18
 
 
 
 
 
 
19
  st.set_page_config(page_title="Two-Button Image Labeler", layout="centered")
20
 
21
  # --------------- Helpers ----------------
@@ -41,7 +46,7 @@ def rel_to_image_dir(p: str):
41
  return p
42
 
43
  def write_label(image_path: str, label: str, annotator: str):
44
- os.makedirs(Path(LABELS_CSV).parent, exist_ok=True)
45
  record = {
46
  "image": rel_to_image_dir(image_path),
47
  "label": label,
@@ -53,9 +58,21 @@ def write_label(image_path: str, label: str, annotator: str):
53
  df = pd.DataFrame([record])
54
  df.to_csv(LABELS_CSV, mode="a", header=not exists, index=False)
55
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  # --------------- UI ---------------------
57
  st.title("🏷️ Two-Button Image Labeler")
58
- st.write("Enter your name, click **Start**, then label each image using the big buttons. Use **Skip** to bypass an image.")
59
 
60
  with st.sidebar:
61
  default_name = st.session_state.get("annotator", "")
@@ -65,7 +82,7 @@ with st.sidebar:
65
  with c1:
66
  start_btn = st.button("Start", type="primary")
67
  with c2:
68
- restart_req = st.button("Restart")
69
 
70
  continue_by_name = st.toggle(
71
  "Only show images I haven't labeled yet",
@@ -82,16 +99,13 @@ if "total" not in st.session_state:
82
  st.session_state.total = 0
83
  if "started" not in st.session_state:
84
  st.session_state.started = False
85
- if "annotator" not in st.session_state:
86
- st.session_state.annotator = ""
87
 
88
- # restart clears state
89
- if restart_req:
 
90
  st.session_state.order = []
91
  st.session_state.idx = 0
92
  st.session_state.total = 0
93
- st.session_state.started = False
94
- st.session_state.annotator = ""
95
  st.rerun()
96
 
97
  # start
@@ -99,18 +113,19 @@ if start_btn:
99
  if not annotator.strip():
100
  st.sidebar.error("Please enter your name.")
101
  else:
102
- st.session_state.annotator = annotator.strip()
103
  imgs = list_images()
104
  labels_df = read_labels()
105
 
106
- # Already labeled by this annotator?
107
  if continue_by_name and len(labels_df) > 0:
108
- labeled = set(labels_df.query("annotator == @annotator")["image"].astype(str).tolist())
 
 
109
  rel_imgs = [rel_to_image_dir(p) for p in imgs]
110
- imgs = [p for p, r in zip(imgs, rel_imgs) if r not in labeled]
111
 
112
  if not imgs:
113
- st.warning("No images found (or all labeled by you). Upload PNG/JPG/etc. to the `images/` folder.")
114
  else:
115
  st.session_state.order = imgs
116
  st.session_state.idx = 0
@@ -127,13 +142,11 @@ else:
127
  st.success("All done 🎉 Thank you!")
128
  else:
129
  current_image = st.session_state.order[idx]
130
- st.caption(f"{idx} / {total}")
131
  try:
132
  img = Image.open(current_image)
133
- # If multipage TIFF, show first page
134
  if getattr(img, "n_frames", 1) > 1:
135
  img.seek(0)
136
- # Convert to RGB for browsers
137
  if img.mode not in ("RGB", "RGBA"):
138
  img = img.convert("RGB")
139
  st.image(img, use_container_width=True)
@@ -143,20 +156,19 @@ else:
143
  col1, col2, col3 = st.columns([1,1,1])
144
  with col1:
145
  if st.button(f"⬅️ {LABEL_LEFT}", use_container_width=True):
146
- write_label(current_image, LABEL_LEFT, st.session_state.annotator)
147
  st.session_state.idx += 1
148
  st.rerun()
149
  with col2:
150
  if st.button("Skip", use_container_width=True):
151
- write_label(current_image, "Skip", st.session_state.annotator)
152
  st.session_state.idx += 1
153
  st.rerun()
154
  with col3:
155
  if st.button(f"{LABEL_RIGHT} ➡️", use_container_width=True):
156
- write_label(current_image, LABEL_RIGHT, st.session_state.annotator)
157
  st.session_state.idx += 1
158
  st.rerun()
159
 
160
- # Footer / admin
161
  st.divider()
162
- st.caption("Labels are saved to `labels.csv` in this Space. You can download it from the Files tab.")
 
7
  import pandas as pd
8
  from PIL import Image
9
  from filelock import FileLock
10
+ from huggingface_hub import HfApi
11
 
12
  # ---------------- Config ----------------
 
13
  IMAGE_DIR = os.getenv("IMAGE_DIR", "images")
14
+ LABELS_CSV = os.getenv("LABELS_CSV", "labels.csv")
15
  LABEL_LEFT = os.getenv("LABEL_A", "Class A")
16
  LABEL_RIGHT = os.getenv("LABEL_B", "Class B")
17
  SUPPORTED_EXTS = (".png", ".jpg", ".jpeg", ".bmp", ".gif", ".tif", ".tiff", ".webp")
18
 
19
+ HF_TOKEN = os.getenv("HF_TOKEN") # stored in Space secrets
20
+ SPACE_ID = os.getenv("SPACE_ID", "MichaelDeutges/LabelingTest") # change if repo name differs
21
+
22
+ api = HfApi()
23
+
24
  st.set_page_config(page_title="Two-Button Image Labeler", layout="centered")
25
 
26
  # --------------- Helpers ----------------
 
46
  return p
47
 
48
  def write_label(image_path: str, label: str, annotator: str):
49
+ os.makedirs(os.path.dirname(LABELS_CSV) or ".", exist_ok=True)
50
  record = {
51
  "image": rel_to_image_dir(image_path),
52
  "label": label,
 
58
  df = pd.DataFrame([record])
59
  df.to_csv(LABELS_CSV, mode="a", header=not exists, index=False)
60
 
61
+ # Upload to Hugging Face repo
62
+ try:
63
+ api.upload_file(
64
+ path_or_fileobj=LABELS_CSV,
65
+ path_in_repo="labels.csv",
66
+ repo_id=SPACE_ID,
67
+ repo_type="space",
68
+ token=HF_TOKEN
69
+ )
70
+ except Exception as e:
71
+ print("Upload failed:", e)
72
+
73
  # --------------- UI ---------------------
74
  st.title("🏷️ Two-Button Image Labeler")
75
+ st.write("Enter your name, click **Start**, then label each image. Use **Skip** to bypass an image.")
76
 
77
  with st.sidebar:
78
  default_name = st.session_state.get("annotator", "")
 
82
  with c1:
83
  start_btn = st.button("Start", type="primary")
84
  with c2:
85
+ reset_btn = st.button("🔄 Reset Session")
86
 
87
  continue_by_name = st.toggle(
88
  "Only show images I haven't labeled yet",
 
99
  st.session_state.total = 0
100
  if "started" not in st.session_state:
101
  st.session_state.started = False
 
 
102
 
103
+ # reset
104
+ if reset_btn:
105
+ st.session_state.started = False
106
  st.session_state.order = []
107
  st.session_state.idx = 0
108
  st.session_state.total = 0
 
 
109
  st.rerun()
110
 
111
  # start
 
113
  if not annotator.strip():
114
  st.sidebar.error("Please enter your name.")
115
  else:
116
+ st.session_state["annotator"] = annotator.strip()
117
  imgs = list_images()
118
  labels_df = read_labels()
119
 
 
120
  if continue_by_name and len(labels_df) > 0:
121
+ already = set(
122
+ labels_df.query("annotator == @annotator")["image"].astype(str).tolist()
123
+ )
124
  rel_imgs = [rel_to_image_dir(p) for p in imgs]
125
+ imgs = [p for p, r in zip(imgs, rel_imgs) if r not in already]
126
 
127
  if not imgs:
128
+ st.warning("No images found (or all labeled).")
129
  else:
130
  st.session_state.order = imgs
131
  st.session_state.idx = 0
 
142
  st.success("All done 🎉 Thank you!")
143
  else:
144
  current_image = st.session_state.order[idx]
145
+ st.caption(f"{idx+1} / {total}")
146
  try:
147
  img = Image.open(current_image)
 
148
  if getattr(img, "n_frames", 1) > 1:
149
  img.seek(0)
 
150
  if img.mode not in ("RGB", "RGBA"):
151
  img = img.convert("RGB")
152
  st.image(img, use_container_width=True)
 
156
  col1, col2, col3 = st.columns([1,1,1])
157
  with col1:
158
  if st.button(f"⬅️ {LABEL_LEFT}", use_container_width=True):
159
+ write_label(current_image, LABEL_LEFT, annotator.strip())
160
  st.session_state.idx += 1
161
  st.rerun()
162
  with col2:
163
  if st.button("Skip", use_container_width=True):
164
+ write_label(current_image, "Skip", annotator.strip())
165
  st.session_state.idx += 1
166
  st.rerun()
167
  with col3:
168
  if st.button(f"{LABEL_RIGHT} ➡️", use_container_width=True):
169
+ write_label(current_image, LABEL_RIGHT, annotator.strip())
170
  st.session_state.idx += 1
171
  st.rerun()
172
 
 
173
  st.divider()
174
+ st.caption("Labels are saved to `labels.csv` and synced to this Space.")