rushankg commited on
Commit
d41608f
·
verified ·
1 Parent(s): 1a1fe37

Added automatic saving and made UI/UX simpler

Browse files
Files changed (1) hide show
  1. app.py +82 -70
app.py CHANGED
@@ -11,10 +11,17 @@ RESULTS_DIR = "results"
11
 
12
  def load_pairs():
13
  """Load matching image pairs from both folders, keyed by filename."""
14
- ro_files = {f for f in os.listdir(ROENTGEN_DIR)
15
- if os.path.isfile(os.path.join(ROENTGEN_DIR, f))}
16
- pe_files = {f for f in os.listdir(PEDISYNTH_DIR)
17
- if os.path.isfile(os.path.join(PEDISYNTH_DIR, f))}
 
 
 
 
 
 
 
18
 
19
  common = sorted(ro_files & pe_files)
20
  pairs = []
@@ -40,24 +47,31 @@ ALL_PAIRS = load_pairs()
40
  os.makedirs(RESULTS_DIR, exist_ok=True)
41
 
42
 
43
- def start_session(doctor_id):
44
- """Initialize a new randomized session for this doctor."""
 
 
 
 
 
45
  if not ALL_PAIRS:
46
- status = "No matching image pairs found. Check your roentgen/ and pedisynth/ folders."
 
 
 
 
47
  return (
48
- None, # img_a
49
- None, # img_b
50
- "", # condition text
51
- "", # progress text
52
- None, # state
53
- None, # results file
54
- status,
55
- gr.update(value=None), # clear choice
 
56
  )
57
 
58
- if not doctor_id:
59
- doctor_id = "anonymous"
60
-
61
  # Randomize order of pairs
62
  pairs = ALL_PAIRS.copy()
63
  random.shuffle(pairs)
@@ -87,7 +101,7 @@ def start_session(doctor_id):
87
  )
88
 
89
  state = {
90
- "doctor_id": doctor_id,
91
  "pairs": session_pairs,
92
  "idx": 0,
93
  "records": [],
@@ -96,40 +110,41 @@ def start_session(doctor_id):
96
  first = session_pairs[0]
97
  condition_text = f"**Condition:** {first['condition']}"
98
  progress_text = f"Pair 1 of {len(session_pairs)}"
99
- status = f"Session started for doctor: {doctor_id}"
100
 
 
101
  return (
102
  first["left_path"],
103
  first["right_path"],
104
  condition_text,
105
  progress_text,
106
  state,
107
- None, # no CSV yet
108
  status,
109
- gr.update(value=None), # clear choice
 
 
110
  )
111
 
112
 
113
  def next_pair(choice, state):
114
  """Record the doctor's choice and move to the next pair."""
115
- # If no active session
116
  if state is None or not state.get("pairs"):
117
- status = "No active session. Please start a session first."
118
  return (
119
  None,
120
  None,
121
  "",
122
  "",
123
  state,
124
- None,
125
  status,
126
- gr.update(value=None),
127
  )
128
 
129
  idx = state["idx"]
130
  pairs = state["pairs"]
131
 
132
- # Ensure choice is made
133
  if not choice:
134
  status = "Please select A or B before proceeding."
135
  cur_pair = pairs[idx]
@@ -141,7 +156,6 @@ def next_pair(choice, state):
141
  condition_text,
142
  progress_text,
143
  state,
144
- None,
145
  status,
146
  gr.update(), # keep current choice
147
  )
@@ -149,7 +163,9 @@ def next_pair(choice, state):
149
  cur_pair = pairs[idx]
150
 
151
  chosen_side = choice
152
- chosen_model = cur_pair["left_model"] if choice == "A" else cur_pair["right_model"]
 
 
153
 
154
  record = {
155
  "doctor_id": state["doctor_id"],
@@ -170,7 +186,7 @@ def next_pair(choice, state):
170
  state["idx"] += 1
171
  idx = state["idx"]
172
 
173
- # If we've reached the end, save CSV
174
  if idx >= len(pairs):
175
  df = pd.DataFrame(state["records"])
176
  ts = datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")
@@ -183,19 +199,17 @@ def next_pair(choice, state):
183
 
184
  status = (
185
  f"Session complete. Saved {len(state['records'])} comparisons "
186
- f"to `{csv_name}`."
187
  )
188
 
189
- # Optionally, reset session index or leave state as-is for audit
190
  return (
191
- None, # img_a
192
- None, # img_b
193
- "Session finished.", # condition text
194
- "", # progress
195
  state,
196
- csv_path, # file for download
197
  status,
198
- gr.update(value=None),
199
  )
200
 
201
  # Otherwise, show next pair
@@ -210,7 +224,6 @@ def next_pair(choice, state):
210
  condition_text,
211
  progress_text,
212
  state,
213
- None,
214
  status,
215
  gr.update(value=None), # clear choice
216
  )
@@ -219,50 +232,50 @@ def next_pair(choice, state):
219
  with gr.Blocks() as demo:
220
  gr.Markdown("# Synthetic Chest X-ray A/B Evaluation")
221
 
222
- with gr.Row():
223
- doctor_id = gr.Textbox(
224
- label="Doctor ID (or initials)",
225
- placeholder="e.g., dr_smith",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  )
227
- start_button = gr.Button("Start New Session", variant="primary")
228
-
229
- state = gr.State()
230
-
231
- with gr.Row():
232
- condition_text = gr.Markdown("")
233
- progress_text = gr.Markdown("")
234
 
235
- with gr.Row():
236
- img_a = gr.Image(label="Image A", interactive=False)
237
- img_b = gr.Image(label="Image B", interactive=False)
238
-
239
- choice = gr.Radio(
240
- choices=["A", "B"],
241
- label="Which image better matches the stated condition?",
242
- interactive=True,
243
- )
244
-
245
- next_button = gr.Button("Next")
246
-
247
- results_file = gr.File(
248
- label="Download session CSV",
249
- interactive=False,
250
- )
251
- status_text = gr.Markdown("")
252
 
253
  # Wire callbacks
254
  start_button.click(
255
  fn=start_session,
256
- inputs=doctor_id,
257
  outputs=[
258
  img_a,
259
  img_b,
260
  condition_text,
261
  progress_text,
262
  state,
263
- results_file,
264
  status_text,
265
  choice,
 
 
266
  ],
267
  )
268
 
@@ -275,7 +288,6 @@ with gr.Blocks() as demo:
275
  condition_text,
276
  progress_text,
277
  state,
278
- results_file,
279
  status_text,
280
  choice,
281
  ],
 
11
 
12
  def load_pairs():
13
  """Load matching image pairs from both folders, keyed by filename."""
14
+ if not os.path.isdir(ROENTGEN_DIR) or not os.path.isdir(PEDISYNTH_DIR):
15
+ return []
16
+
17
+ ro_files = {
18
+ f for f in os.listdir(ROENTGEN_DIR)
19
+ if os.path.isfile(os.path.join(ROENTGEN_DIR, f))
20
+ }
21
+ pe_files = {
22
+ f for f in os.listdir(PEDISYNTH_DIR)
23
+ if os.path.isfile(os.path.join(PEDISYNTH_DIR, f))
24
+ }
25
 
26
  common = sorted(ro_files & pe_files)
27
  pairs = []
 
47
  os.makedirs(RESULTS_DIR, exist_ok=True)
48
 
49
 
50
+ def start_session(doctor_initials):
51
+ """Initialize a new randomized session."""
52
+ # Default initials if nothing entered
53
+ if not doctor_initials:
54
+ doctor_initials = "anonymous"
55
+
56
+ # No pairs found
57
  if not ALL_PAIRS:
58
+ status = (
59
+ "No matching image pairs found. "
60
+ "Check your `roentgen/` and `pedisynth/` folders."
61
+ )
62
+ # Keep intro visible, keep session hidden
63
  return (
64
+ None, # img_a
65
+ None, # img_b
66
+ "", # condition_text
67
+ "", # progress_text
68
+ None, # state
69
+ status, # status_text
70
+ gr.update(value=None), # clear choice
71
+ gr.update(visible=True), # intro_group visible
72
+ gr.update(visible=False), # session_group hidden
73
  )
74
 
 
 
 
75
  # Randomize order of pairs
76
  pairs = ALL_PAIRS.copy()
77
  random.shuffle(pairs)
 
101
  )
102
 
103
  state = {
104
+ "doctor_id": doctor_initials,
105
  "pairs": session_pairs,
106
  "idx": 0,
107
  "records": [],
 
110
  first = session_pairs[0]
111
  condition_text = f"**Condition:** {first['condition']}"
112
  progress_text = f"Pair 1 of {len(session_pairs)}"
113
+ status = f"Session started for doctor: {doctor_initials}"
114
 
115
+ # Hide intro group, show session group
116
  return (
117
  first["left_path"],
118
  first["right_path"],
119
  condition_text,
120
  progress_text,
121
  state,
 
122
  status,
123
+ gr.update(value=None), # clear choice
124
+ gr.update(visible=False), # intro_group hidden
125
+ gr.update(visible=True), # session_group visible
126
  )
127
 
128
 
129
  def next_pair(choice, state):
130
  """Record the doctor's choice and move to the next pair."""
131
+ # No active session
132
  if state is None or not state.get("pairs"):
133
+ status = "No active session. Please refresh and start a new session."
134
  return (
135
  None,
136
  None,
137
  "",
138
  "",
139
  state,
 
140
  status,
141
+ gr.update(), # leave choice alone
142
  )
143
 
144
  idx = state["idx"]
145
  pairs = state["pairs"]
146
 
147
+ # Ensure a choice is made
148
  if not choice:
149
  status = "Please select A or B before proceeding."
150
  cur_pair = pairs[idx]
 
156
  condition_text,
157
  progress_text,
158
  state,
 
159
  status,
160
  gr.update(), # keep current choice
161
  )
 
163
  cur_pair = pairs[idx]
164
 
165
  chosen_side = choice
166
+ chosen_model = (
167
+ cur_pair["left_model"] if choice == "A" else cur_pair["right_model"]
168
+ )
169
 
170
  record = {
171
  "doctor_id": state["doctor_id"],
 
186
  state["idx"] += 1
187
  idx = state["idx"]
188
 
189
+ # If we've reached the end, save CSV (backend only)
190
  if idx >= len(pairs):
191
  df = pd.DataFrame(state["records"])
192
  ts = datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")
 
199
 
200
  status = (
201
  f"Session complete. Saved {len(state['records'])} comparisons "
202
+ f"to `{csv_name}` on the Space."
203
  )
204
 
 
205
  return (
206
+ None, # img_a
207
+ None, # img_b
208
+ "Session finished.", # condition_text
209
+ "", # progress_text
210
  state,
 
211
  status,
212
+ gr.update(value=None), # clear choice
213
  )
214
 
215
  # Otherwise, show next pair
 
224
  condition_text,
225
  progress_text,
226
  state,
 
227
  status,
228
  gr.update(value=None), # clear choice
229
  )
 
232
  with gr.Blocks() as demo:
233
  gr.Markdown("# Synthetic Chest X-ray A/B Evaluation")
234
 
235
+ # Intro screen: just initials + Start
236
+ with gr.Group() as intro_group:
237
+ with gr.Row():
238
+ doctor_initials = gr.Textbox(
239
+ label="Doctor initials",
240
+ placeholder="e.g., RG",
241
+ )
242
+ start_button = gr.Button("Start New Session", variant="primary")
243
+
244
+ # Main session UI (hidden initially)
245
+ with gr.Group(visible=False) as session_group:
246
+ state = gr.State()
247
+
248
+ with gr.Row():
249
+ condition_text = gr.Markdown("")
250
+ progress_text = gr.Markdown("")
251
+
252
+ with gr.Row():
253
+ img_a = gr.Image(label="Image A", interactive=False)
254
+ img_b = gr.Image(label="Image B", interactive=False)
255
+
256
+ choice = gr.Radio(
257
+ choices=["A", "B"],
258
+ label="Which image better matches the stated condition?",
259
+ interactive=True,
260
  )
 
 
 
 
 
 
 
261
 
262
+ next_button = gr.Button("Next")
263
+ status_text = gr.Markdown("")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
  # Wire callbacks
266
  start_button.click(
267
  fn=start_session,
268
+ inputs=doctor_initials,
269
  outputs=[
270
  img_a,
271
  img_b,
272
  condition_text,
273
  progress_text,
274
  state,
 
275
  status_text,
276
  choice,
277
+ intro_group, # visibility toggle
278
+ session_group, # visibility toggle
279
  ],
280
  )
281
 
 
288
  condition_text,
289
  progress_text,
290
  state,
 
291
  status_text,
292
  choice,
293
  ],