Null state test to fix user data being overwritten

#6
by kbuchel - opened
Files changed (1) hide show
  1. app.py +95 -82
app.py CHANGED
@@ -278,99 +278,109 @@ def update_queue_display():
278
  return f"Error getting queue status: {str(e)}"
279
 
280
 
281
- def add_to_queue(student_id, R, Y, B):
282
  global queue_counter
283
-
284
- if student_id == "debug":
285
- yield {
286
- "Status": "Error",
287
- "Message": "Debug ID cannot submit to real experiment queue. Please use your student id to submit experiment."
288
- }
289
- return
290
 
 
291
 
292
- # Validate RYB inputs
293
- validation_result = validate_ryb_input(R, Y, B)
294
- if not validation_result["is_valid"]:
295
- yield {
296
- "Status": "Error",
297
- "Message": validation_result["message"]
298
- }
299
- return
300
-
301
- # Check quota
302
- quota_remaining = check_student_quota(student_id)
303
- if quota_remaining <= 0:
304
- yield {
305
- "Status": "Error",
306
- "Message": "No experiments remaining"
307
- }
308
- return
309
 
310
- # Select well
311
- experiment_id = secrets.token_hex(4)
312
- try:
313
- empty_wells = find_unused_wells()
314
- if not empty_wells:
315
- raise ValueError("No available wells")
316
- selected_well = empty_wells[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
 
319
- except Exception as e:
320
- yield {
321
- "Status": "Error",
322
- "Message": str(e)
 
 
 
 
 
 
 
 
 
 
 
 
323
  }
324
- return
 
 
 
 
 
 
325
 
326
- # NOTE: Create the task and store it in tasks_dict
327
- task = {
328
- "R": R,
329
- "Y": Y,
330
- "B": B,
331
- "well": selected_well,
332
- "session_id": student_id,
333
- "experiment_id": experiment_id,
334
- "status": "queued",
335
- }
336
- tasks_dict[(student_id, experiment_id)] = task # Keep track globally
337
 
338
- # Put only (student_id, experiment_id) in the Queue
339
- task_queue.put((student_id, experiment_id))
340
- queue_counter += 1
341
- update_used_wells([selected_well])
342
- decrement_student_quota(student_id)
343
-
344
 
345
- print(f"Task added: {task}")
346
-
347
- # First yield: "Queued"
348
- yield {
349
- "Status": "Queued",
350
- "Position": queue_counter,
351
- "Student ID": student_id,
352
- "Experiment ID": experiment_id,
353
- "Well": selected_well,
354
- "Volumes": {"R": R, "Y": Y, "B": B}
355
- }
356
 
357
- # NOTE: Wait until the task's status becomes 'processing'
358
- # This ensures we only yield "Running" when the backend actually starts the job.
359
- while tasks_dict[(student_id, experiment_id)]["status"] == "queued":
360
- time.sleep(20)
 
 
 
 
 
 
 
 
 
 
 
361
 
362
- # Second yield: "Running" (happens only after status is 'processing')
363
- yield {
364
- "Status": "Running",
365
- "Student ID": student_id,
366
- "Experiment ID": experiment_id,
367
- "Well": selected_well,
368
- "Volumes": {"R": R, "Y": Y, "B": B}
369
- }
370
 
371
- # Finally, wait for the result
372
- result = result_queue.get()
373
- yield result
374
 
375
  def debug_experiment(student_id, R, Y, B):
376
  if student_id != "debug":
@@ -425,6 +435,9 @@ def debug_experiment(student_id, R, Y, B):
425
 
426
 
427
  with gr.Blocks(title="OT-2 Liquid Color Matching Experiment Queue") as demo:
 
 
 
428
  gr.Markdown("## OT-2 Liquid Color Matching Experiment Queue")
429
  gr.Markdown("Enter R, Y, and B volumes (in µL). Total volume must not exceed 300 µL.(a volume of exactly 300 µL is recommended)")
430
 
@@ -498,8 +511,8 @@ with gr.Blocks(title="OT-2 Liquid Color Matching Experiment Queue") as demo:
498
  # NOTE: concurrency_limit=3 is preserved; no changes here
499
  submit_btn.click(
500
  add_to_queue,
501
- inputs=[student_id_input, r_slider, y_slider, b_slider],
502
- outputs=result_output,
503
  api_name="submit",
504
  concurrency_limit=8
505
  ).then(
 
278
  return f"Error getting queue status: {str(e)}"
279
 
280
 
281
+ def add_to_queue(student_id, R, Y, B, current_state):
282
  global queue_counter
 
 
 
 
 
 
 
283
 
284
+ if current_state is None:
285
 
286
+ if student_id == "debug":
287
+ yield {
288
+ "Status": "Error",
289
+ "Message": "Debug ID cannot submit to real experiment queue. Please use your student id to submit experiment."
290
+ }
291
+ return
 
 
 
 
 
 
 
 
 
 
 
292
 
293
+
294
+ # Validate RYB inputs
295
+ validation_result = validate_ryb_input(R, Y, B)
296
+ if not validation_result["is_valid"]:
297
+ yield {
298
+ "Status": "Error",
299
+ "Message": validation_result["message"]
300
+ }
301
+ return
302
+
303
+ # Check quota
304
+ quota_remaining = check_student_quota(student_id)
305
+ if quota_remaining <= 0:
306
+ yield {
307
+ "Status": "Error",
308
+ "Message": "No experiments remaining"
309
+ }
310
+ return
311
+
312
+ # Select well
313
+ experiment_id = secrets.token_hex(4)
314
+ try:
315
+ empty_wells = find_unused_wells()
316
+ if not empty_wells:
317
+ raise ValueError("No available wells")
318
+ selected_well = empty_wells[0]
319
 
320
 
321
+ except Exception as e:
322
+ yield {
323
+ "Status": "Error",
324
+ "Message": str(e)
325
+ }
326
+ return
327
+
328
+ # NOTE: Create the task and store it in tasks_dict
329
+ task = {
330
+ "R": R,
331
+ "Y": Y,
332
+ "B": B,
333
+ "well": selected_well,
334
+ "session_id": student_id,
335
+ "experiment_id": experiment_id,
336
+ "status": "queued",
337
  }
338
+ tasks_dict[(student_id, experiment_id)] = task # Keep track globally
339
+
340
+ # Put only (student_id, experiment_id) in the Queue
341
+ task_queue.put((student_id, experiment_id))
342
+ queue_counter += 1
343
+ update_used_wells([selected_well])
344
+ decrement_student_quota(student_id)
345
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
+ print(f"Task added: {task}")
348
+
349
+ # First yield: "Queued"
 
 
 
350
 
351
+ current_state = {
352
+ "Status": "Queued",
353
+ "Position": queue_counter,
354
+ "Student ID": student_id,
355
+ "Experiment ID": experiment_id,
356
+ "Well": selected_well,
357
+ "Volumes": {"R": R, "Y": Y, "B": B}
358
+ }
359
+
360
+ yield current_state, current_state
 
361
 
362
+ # NOTE: Wait until the task's status becomes 'processing'
363
+ # This ensures we only yield "Running" when the backend actually starts the job.
364
+ while tasks_dict[(student_id, experiment_id)]["status"] == "queued":
365
+ time.sleep(20)
366
+
367
+ # Second yield: "Running" (happens only after status is 'processing')
368
+ current_state = {
369
+ "Status": "Running",
370
+ "Student ID": student_id,
371
+ "Experiment ID": experiment_id,
372
+ "Well": selected_well,
373
+ "Volumes": {"R": R, "Y": Y, "B": B}
374
+ }
375
+
376
+ yield current_state, current_state
377
 
378
+ # Finally, wait for the result
379
+ result = result_queue.get()
 
 
 
 
 
 
380
 
381
+ current_state = result
382
+
383
+ yield result, current_state
384
 
385
  def debug_experiment(student_id, R, Y, B):
386
  if student_id != "debug":
 
435
 
436
 
437
  with gr.Blocks(title="OT-2 Liquid Color Matching Experiment Queue") as demo:
438
+
439
+ experiment_state = gr.State(None)
440
+
441
  gr.Markdown("## OT-2 Liquid Color Matching Experiment Queue")
442
  gr.Markdown("Enter R, Y, and B volumes (in µL). Total volume must not exceed 300 µL.(a volume of exactly 300 µL is recommended)")
443
 
 
511
  # NOTE: concurrency_limit=3 is preserved; no changes here
512
  submit_btn.click(
513
  add_to_queue,
514
+ inputs=[student_id_input, r_slider, y_slider, b_slider, experimental_state],
515
+ outputs= [result_output, experiment_state]
516
  api_name="submit",
517
  concurrency_limit=8
518
  ).then(