Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -321,6 +321,16 @@ def find_flip_point(data, fit_params):
|
|
| 321 |
return None
|
| 322 |
|
| 323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 325 |
# Consensus, Routing & State Machine
|
| 326 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -497,6 +507,8 @@ def ingest_files(files):
|
|
| 497 |
# 22: exp_data
|
| 498 |
# 23-28: flip_reg_info, flip_reg_tag, flip_ai_info, flip_ai_tag,
|
| 499 |
# flip_dual_col, flip_dual_state (dual/diverging mode)
|
|
|
|
|
|
|
| 500 |
|
| 501 |
def _empty_ws(msg=""):
|
| 502 |
return (msg,
|
|
@@ -508,7 +520,8 @@ def _empty_ws(msg=""):
|
|
| 508 |
"", None, gr.Column(visible=False), None,
|
| 509 |
None,
|
| 510 |
"", None, "", None, gr.Column(visible=False), None,
|
| 511 |
-
gr.Column(visible=True), gr.Column(visible=True)
|
|
|
|
| 512 |
|
| 513 |
|
| 514 |
def fetch_next(username):
|
|
@@ -607,7 +620,8 @@ def fetch_next(username):
|
|
| 607 |
flip_reg_info, None, flip_ai_info, None,
|
| 608 |
gr.Column(visible=show_flip_dual), dual_state,
|
| 609 |
gr.Column(visible=show_flip_reg_sub),
|
| 610 |
-
gr.Column(visible=show_flip_ai_sub)
|
|
|
|
| 611 |
except Exception as e:
|
| 612 |
print(f"fetch_next render error: {e}\n{traceback.format_exc()}")
|
| 613 |
return _empty_ws(f"β Render failed: {e}")
|
|
@@ -738,7 +752,7 @@ def reset_ratings():
|
|
| 738 |
|
| 739 |
|
| 740 |
def update_workspace_state(data_val, fit_s_val, fit_reg_val, fit_ai_val,
|
| 741 |
-
model_preds, overlap, exp_data):
|
| 742 |
"""Centralized state recalculation. Called when user changes any rating.
|
| 743 |
Recomputes flip points, redraws plot, recalculates all visibility.
|
| 744 |
|
|
@@ -748,18 +762,22 @@ def update_workspace_state(data_val, fit_s_val, fit_reg_val, fit_ai_val,
|
|
| 748 |
- None (cleared) or Borderline/Perfect β show sections
|
| 749 |
Flip-point gating:
|
| 750 |
- Uses effective quality (user > model) for computation
|
|
|
|
|
|
|
|
|
|
| 751 |
|
| 752 |
-
Outputs
|
| 753 |
flip_info, flip_tag, flip_col, flip_state,
|
| 754 |
flip_reg_info, flip_reg_tag, flip_ai_info, flip_ai_tag,
|
| 755 |
flip_dual_col, flip_dual_state,
|
| 756 |
-
flip_reg_sub, flip_ai_sub)
|
| 757 |
"""
|
| 758 |
_empty = (None,
|
| 759 |
gr.Column(visible=True), gr.Column(visible=False),
|
| 760 |
"", None, gr.Column(visible=False), None,
|
| 761 |
"", None, "", None, gr.Column(visible=False), None,
|
| 762 |
-
gr.Column(visible=True), gr.Column(visible=True)
|
|
|
|
| 763 |
if exp_data is None:
|
| 764 |
return _empty
|
| 765 |
|
|
@@ -803,9 +821,13 @@ def update_workspace_state(data_val, fit_s_val, fit_reg_val, fit_ai_val,
|
|
| 803 |
if not overlap and ai_params and ai_fit_gate:
|
| 804 |
flip_ai = find_flip_point(raw_data, ai_params)
|
| 805 |
|
| 806 |
-
# ββ
|
| 807 |
-
|
| 808 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 809 |
|
| 810 |
# ββ Section visibility ββ
|
| 811 |
show_fit_single = overlap and ui_show
|
|
@@ -851,7 +873,8 @@ def update_workspace_state(data_val, fit_s_val, fit_reg_val, fit_ai_val,
|
|
| 851 |
gr.Column(visible=show_flip_dual),
|
| 852 |
dual_state,
|
| 853 |
gr.Column(visible=show_flip_reg_sub),
|
| 854 |
-
gr.Column(visible=show_flip_ai_sub)
|
|
|
|
| 855 |
|
| 856 |
|
| 857 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββββββ
|
|
@@ -1199,6 +1222,7 @@ def build_ui():
|
|
| 1199 |
|
| 1200 |
ws_exp_data = gr.State(None)
|
| 1201 |
ws_flip_state = gr.State(None)
|
|
|
|
| 1202 |
|
| 1203 |
ws_reset = gr.Button("π Clear All Ratings", size="sm")
|
| 1204 |
|
|
@@ -1270,29 +1294,29 @@ def build_ui():
|
|
| 1270 |
ws_flip_tag, ws_flip_reg_tag, ws_flip_ai_tag]).then(
|
| 1271 |
update_workspace_state,
|
| 1272 |
[ws_dr, ws_fs, ws_fr, ws_fa,
|
| 1273 |
-
ws_preds, ws_overlap, ws_exp_data],
|
| 1274 |
[ws_plot, ws_fs_col, ws_fd_col,
|
| 1275 |
ws_flip_info, ws_flip_tag, ws_flip_col, ws_flip_state,
|
| 1276 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1277 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1278 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1279 |
-
ws_flip_reg_sub, ws_flip_ai_sub])
|
| 1280 |
|
| 1281 |
# Centralized state recalculation on any rating change
|
| 1282 |
_state_inputs = [ws_dr, ws_fs, ws_fr, ws_fa,
|
| 1283 |
-
ws_preds, ws_overlap, ws_exp_data]
|
| 1284 |
_state_outputs = [ws_plot, ws_fs_col, ws_fd_col,
|
| 1285 |
ws_flip_info, ws_flip_tag, ws_flip_col, ws_flip_state,
|
| 1286 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1287 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1288 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1289 |
-
ws_flip_reg_sub, ws_flip_ai_sub]
|
| 1290 |
ws_dr.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1291 |
ws_fs.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1292 |
ws_fr.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1293 |
ws_fa.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1294 |
|
| 1295 |
-
# Output list β
|
| 1296 |
ws_outs = [ws_status, ws_plot, ws_info, ws_ov_msg, ws_conf,
|
| 1297 |
ws_fs_col, ws_fd_col,
|
| 1298 |
ws_dr, ws_fs, ws_fr, ws_fa,
|
|
@@ -1303,7 +1327,8 @@ def build_ui():
|
|
| 1303 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1304 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1305 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1306 |
-
ws_flip_reg_sub, ws_flip_ai_sub
|
|
|
|
| 1307 |
|
| 1308 |
ws_fetch.click(fetch_next, [ws_user], ws_outs)
|
| 1309 |
ws_submit.click(submit_feedback,
|
|
@@ -1495,6 +1520,45 @@ def run_validation_tests():
|
|
| 1495 |
check("0-vote docs served last",
|
| 1496 |
sorted_docs[2]['num_votes'] == 0 and sorted_docs[3]['num_votes'] == 0)
|
| 1497 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1498 |
print(f"\n{'=' * 60}")
|
| 1499 |
print(f"RESULTS: {passed} passed, {failed} failed")
|
| 1500 |
print(f"{'=' * 60}")
|
|
|
|
| 321 |
return None
|
| 322 |
|
| 323 |
|
| 324 |
+
def _plot_fingerprint(flip_reg, flip_ai, overlap):
|
| 325 |
+
"""Create a hashable fingerprint of the plot's visual state.
|
| 326 |
+
The plot only changes when flip-point markers or overlap status change;
|
| 327 |
+
raw data and fit curves are constant for a given experiment."""
|
| 328 |
+
fr = (flip_reg['x'], flip_reg['y'], flip_reg['type']) if flip_reg else None
|
| 329 |
+
fa = (flip_ai['x'], flip_ai['y'], flip_ai['type']) if flip_ai else None
|
| 330 |
+
return (fr, fa, overlap)
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
|
| 334 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 335 |
# Consensus, Routing & State Machine
|
| 336 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 507 |
# 22: exp_data
|
| 508 |
# 23-28: flip_reg_info, flip_reg_tag, flip_ai_info, flip_ai_tag,
|
| 509 |
# flip_dual_col, flip_dual_state (dual/diverging mode)
|
| 510 |
+
# 29-30: flip_reg_sub, flip_ai_sub
|
| 511 |
+
# 31: plot_fp (plot fingerprint state for skip optimization)
|
| 512 |
|
| 513 |
def _empty_ws(msg=""):
|
| 514 |
return (msg,
|
|
|
|
| 520 |
"", None, gr.Column(visible=False), None,
|
| 521 |
None,
|
| 522 |
"", None, "", None, gr.Column(visible=False), None,
|
| 523 |
+
gr.Column(visible=True), gr.Column(visible=True),
|
| 524 |
+
None)
|
| 525 |
|
| 526 |
|
| 527 |
def fetch_next(username):
|
|
|
|
| 620 |
flip_reg_info, None, flip_ai_info, None,
|
| 621 |
gr.Column(visible=show_flip_dual), dual_state,
|
| 622 |
gr.Column(visible=show_flip_reg_sub),
|
| 623 |
+
gr.Column(visible=show_flip_ai_sub),
|
| 624 |
+
None)
|
| 625 |
except Exception as e:
|
| 626 |
print(f"fetch_next render error: {e}\n{traceback.format_exc()}")
|
| 627 |
return _empty_ws(f"β Render failed: {e}")
|
|
|
|
| 752 |
|
| 753 |
|
| 754 |
def update_workspace_state(data_val, fit_s_val, fit_reg_val, fit_ai_val,
|
| 755 |
+
model_preds, overlap, exp_data, prev_fp):
|
| 756 |
"""Centralized state recalculation. Called when user changes any rating.
|
| 757 |
Recomputes flip points, redraws plot, recalculates all visibility.
|
| 758 |
|
|
|
|
| 762 |
- None (cleared) or Borderline/Perfect β show sections
|
| 763 |
Flip-point gating:
|
| 764 |
- Uses effective quality (user > model) for computation
|
| 765 |
+
Plot optimization:
|
| 766 |
+
- Uses _plot_fingerprint to detect if the plot's visual state changed.
|
| 767 |
+
- Returns gr.skip() for the plot output when unchanged, saving bandwidth.
|
| 768 |
|
| 769 |
+
Outputs 16 items: (plot, fs_col, fd_col,
|
| 770 |
flip_info, flip_tag, flip_col, flip_state,
|
| 771 |
flip_reg_info, flip_reg_tag, flip_ai_info, flip_ai_tag,
|
| 772 |
flip_dual_col, flip_dual_state,
|
| 773 |
+
flip_reg_sub, flip_ai_sub, new_fp)
|
| 774 |
"""
|
| 775 |
_empty = (None,
|
| 776 |
gr.Column(visible=True), gr.Column(visible=False),
|
| 777 |
"", None, gr.Column(visible=False), None,
|
| 778 |
"", None, "", None, gr.Column(visible=False), None,
|
| 779 |
+
gr.Column(visible=True), gr.Column(visible=True),
|
| 780 |
+
None)
|
| 781 |
if exp_data is None:
|
| 782 |
return _empty
|
| 783 |
|
|
|
|
| 821 |
if not overlap and ai_params and ai_fit_gate:
|
| 822 |
flip_ai = find_flip_point(raw_data, ai_params)
|
| 823 |
|
| 824 |
+
# ββ Plot optimization: skip rebuild if visual state unchanged ββ
|
| 825 |
+
new_fp = _plot_fingerprint(flip_reg, flip_ai, overlap)
|
| 826 |
+
if new_fp == prev_fp:
|
| 827 |
+
fig = gr.skip()
|
| 828 |
+
else:
|
| 829 |
+
fig = create_plot(raw_data, fname, reg_params, ai_params, overlap,
|
| 830 |
+
flip_reg=flip_reg, flip_ai=flip_ai)
|
| 831 |
|
| 832 |
# ββ Section visibility ββ
|
| 833 |
show_fit_single = overlap and ui_show
|
|
|
|
| 873 |
gr.Column(visible=show_flip_dual),
|
| 874 |
dual_state,
|
| 875 |
gr.Column(visible=show_flip_reg_sub),
|
| 876 |
+
gr.Column(visible=show_flip_ai_sub),
|
| 877 |
+
new_fp)
|
| 878 |
|
| 879 |
|
| 880 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββββββ
|
|
|
|
| 1222 |
|
| 1223 |
ws_exp_data = gr.State(None)
|
| 1224 |
ws_flip_state = gr.State(None)
|
| 1225 |
+
ws_plot_fp = gr.State(None)
|
| 1226 |
|
| 1227 |
ws_reset = gr.Button("π Clear All Ratings", size="sm")
|
| 1228 |
|
|
|
|
| 1294 |
ws_flip_tag, ws_flip_reg_tag, ws_flip_ai_tag]).then(
|
| 1295 |
update_workspace_state,
|
| 1296 |
[ws_dr, ws_fs, ws_fr, ws_fa,
|
| 1297 |
+
ws_preds, ws_overlap, ws_exp_data, ws_plot_fp],
|
| 1298 |
[ws_plot, ws_fs_col, ws_fd_col,
|
| 1299 |
ws_flip_info, ws_flip_tag, ws_flip_col, ws_flip_state,
|
| 1300 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1301 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1302 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1303 |
+
ws_flip_reg_sub, ws_flip_ai_sub, ws_plot_fp])
|
| 1304 |
|
| 1305 |
# Centralized state recalculation on any rating change
|
| 1306 |
_state_inputs = [ws_dr, ws_fs, ws_fr, ws_fa,
|
| 1307 |
+
ws_preds, ws_overlap, ws_exp_data, ws_plot_fp]
|
| 1308 |
_state_outputs = [ws_plot, ws_fs_col, ws_fd_col,
|
| 1309 |
ws_flip_info, ws_flip_tag, ws_flip_col, ws_flip_state,
|
| 1310 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1311 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1312 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1313 |
+
ws_flip_reg_sub, ws_flip_ai_sub, ws_plot_fp]
|
| 1314 |
ws_dr.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1315 |
ws_fs.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1316 |
ws_fr.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1317 |
ws_fa.input(update_workspace_state, _state_inputs, _state_outputs)
|
| 1318 |
|
| 1319 |
+
# Output list β 32 components
|
| 1320 |
ws_outs = [ws_status, ws_plot, ws_info, ws_ov_msg, ws_conf,
|
| 1321 |
ws_fs_col, ws_fd_col,
|
| 1322 |
ws_dr, ws_fs, ws_fr, ws_fa,
|
|
|
|
| 1327 |
ws_flip_reg_info, ws_flip_reg_tag,
|
| 1328 |
ws_flip_ai_info, ws_flip_ai_tag,
|
| 1329 |
ws_flip_dual_col, ws_flip_dual_state,
|
| 1330 |
+
ws_flip_reg_sub, ws_flip_ai_sub,
|
| 1331 |
+
ws_plot_fp]
|
| 1332 |
|
| 1333 |
ws_fetch.click(fetch_next, [ws_user], ws_outs)
|
| 1334 |
ws_submit.click(submit_feedback,
|
|
|
|
| 1520 |
check("0-vote docs served last",
|
| 1521 |
sorted_docs[2]['num_votes'] == 0 and sorted_docs[3]['num_votes'] == 0)
|
| 1522 |
|
| 1523 |
+
# --- 8. Plot Fingerprint / gr.skip() Optimization ---
|
| 1524 |
+
print("\n8. Plot Fingerprint Optimization (_plot_fingerprint)")
|
| 1525 |
+
fp_a = _plot_fingerprint(None, None, True)
|
| 1526 |
+
fp_b = _plot_fingerprint(None, None, True)
|
| 1527 |
+
check("Same inputs β identical fingerprint", fp_a == fp_b)
|
| 1528 |
+
fp_with_flip = _plot_fingerprint({'x': 0.25, 'y': 0.5, 'type': 'max'}, None, True)
|
| 1529 |
+
check("Flip vs no-flip β different fingerprint", fp_with_flip != fp_a)
|
| 1530 |
+
fp_overlap_t = _plot_fingerprint(None, None, True)
|
| 1531 |
+
fp_overlap_f = _plot_fingerprint(None, None, False)
|
| 1532 |
+
check("Overlap True vs False β different fingerprint", fp_overlap_t != fp_overlap_f)
|
| 1533 |
+
# Verify update_workspace_state returns gr.skip() when fingerprint unchanged
|
| 1534 |
+
mock_exp = {
|
| 1535 |
+
'raw_data': {'measured_data': {'x_values': list(np.linspace(0, 1, 50)),
|
| 1536 |
+
'y_values': list(np.sin(np.linspace(0, 1, 50)))}},
|
| 1537 |
+
'reg_params': {'amplitude': 0.5, 'T': 1.0, 'phase': 0.0, 'offset': 0.0},
|
| 1538 |
+
'ai_params': None, 'filename': 'test'
|
| 1539 |
+
}
|
| 1540 |
+
mock_mp = {'model_classes': {'data_quality': 2, 'regular_fit_quality': 2}}
|
| 1541 |
+
# First call: prev_fp=None β must draw (not skip)
|
| 1542 |
+
result1 = update_workspace_state('Perfect (2)', 'Perfect (2)', None, None,
|
| 1543 |
+
mock_mp, True, mock_exp, None)
|
| 1544 |
+
check("First call (prev_fp=None) β plot is NOT gr.skip()",
|
| 1545 |
+
not isinstance(result1[0], type(gr.skip())))
|
| 1546 |
+
new_fp = result1[-1] # last element is the new fingerprint
|
| 1547 |
+
check("First call returns a fingerprint tuple", isinstance(new_fp, tuple))
|
| 1548 |
+
# Second call: same ratings β fingerprint unchanged β gr.skip()
|
| 1549 |
+
result2 = update_workspace_state('Perfect (2)', 'Perfect (2)', None, None,
|
| 1550 |
+
mock_mp, True, mock_exp, new_fp)
|
| 1551 |
+
is_skip = (result2[0].__class__.__name__ == 'skip'
|
| 1552 |
+
or result2[0] is gr.skip() # Gradio skip sentinel
|
| 1553 |
+
or repr(result2[0]) == repr(gr.skip()))
|
| 1554 |
+
check("Second call (same ratings) β plot IS gr.skip()", is_skip)
|
| 1555 |
+
# Third call: change rating to cross gate β fingerprint changes β redraw
|
| 1556 |
+
result3 = update_workspace_state('Bad (0)', 'Perfect (2)', None, None,
|
| 1557 |
+
mock_mp, True, mock_exp, new_fp)
|
| 1558 |
+
check("Gate-crossing rating change β plot is NOT gr.skip()",
|
| 1559 |
+
not isinstance(result3[0], type(gr.skip()))
|
| 1560 |
+
or repr(result3[0]) != repr(gr.skip()))
|
| 1561 |
+
|
| 1562 |
print(f"\n{'=' * 60}")
|
| 1563 |
print(f"RESULTS: {passed} passed, {failed} failed")
|
| 1564 |
print(f"{'=' * 60}")
|