NathanRoll commited on
Commit
23ffae0
·
verified ·
1 Parent(s): 95693a7

Simplify JSON submission workflow

Browse files
Files changed (1) hide show
  1. app.py +95 -39
app.py CHANGED
@@ -32,6 +32,7 @@ DATA_DIR.mkdir(parents=True, exist_ok=True)
32
  FAVICON_PATH = SPACE_ROOT / "assets" / "favicon.svg"
33
  HYDRATE_STATUS = maybe_hydrate_from_dataset(DATA_DIR)
34
  STORE = SolutionStore(DATA_DIR)
 
35
 
36
 
37
  @lru_cache(maxsize=1)
@@ -1540,7 +1541,13 @@ Coordinate convention:
1540
  - touching is legal; overlap and protrusion are rejected
1541
  """
1542
 
1543
- EXAMPLES_MD = f"""### Minimal Triangle Example
 
 
 
 
 
 
1544
 
1545
  This is the smallest legal record and a good shape for checking the schema:
1546
 
@@ -1554,6 +1561,7 @@ This is the smallest legal record and a good shape for checking the schema:
1554
  - Use container-centered coordinates.
1555
  - Use radians for `rotation_radians`.
1556
  - Click **Verify** before submitting; the preview is rendered from the same canonical JSON that is archived.
 
1557
  """
1558
 
1559
  SCHEMA_DOCS_MD = """### Canonical Fields
@@ -1575,7 +1583,7 @@ Supported shape specs:
1575
  - `circle`: `radius` or `diameter`
1576
  - `rectangle`: `width` and `height`
1577
 
1578
- The verifier rejects boundary protrusion and pair overlap above the selected tolerance.
1579
  """ + f"""
1580
 
1581
  ### Four Circles In A Square
@@ -2571,32 +2579,76 @@ def submit_schema_intro_html() -> str:
2571
  <div>
2572
  <h2>Submit Entry</h2>
2573
  <p class="section-note">
2574
- Paste canonical coordinate JSON, verify the geometry, and archive a renderer-ready record.
2575
  </p>
2576
  </div>
2577
  </div>
2578
- <div class="submit-flow" aria-label="Submission steps">
2579
- <div class="submit-step"><strong>1. Identify</strong><span>Choose a credited author from the searchable list, or type a new name.</span></div>
2580
- <div class="submit-step"><strong>2. Verify</strong><span>Paste or upload canonical JSON and run the same geometric evaluator used by the leaderboard.</span></div>
2581
- <div class="submit-step"><strong>3. Submit</strong><span>Accepted records are stored with normalized JSON and rendered directly as vector geometry.</span></div>
2582
- </div>
2583
  </div>
2584
  </section>
2585
  </main>
2586
  """
2587
 
2588
 
2589
- def load_submission(json_text: str, json_file: str | None) -> dict[str, Any]:
2590
- if json_file:
2591
- return load_solution_json(Path(json_file).read_text())
2592
  if not json_text or not json_text.strip():
2593
- raise ValueError("Paste canonical JSON or upload a .json file.")
2594
  return load_solution_json(json_text)
2595
 
2596
 
2597
- def result_markdown(result: dict[str, Any]) -> str:
2598
- if result["ok"]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2599
  return (
 
 
 
 
 
 
 
 
 
 
 
 
 
2600
  "### Verification Passed\n\n"
2601
  f"- Case: `{result['case']}`\n"
2602
  f"- Items: `{result['n']}`\n"
@@ -2605,12 +2657,17 @@ def result_markdown(result: dict[str, Any]) -> str:
2605
  f"- Max boundary excess: `{result['max_boundary_excess']:.3e}`\n"
2606
  f"- Max pair overlap depth: `{result['max_pair_overlap_depth']:.3e}`\n"
2607
  )
 
 
 
 
 
2608
  errors = "\n".join(f"- {e}" for e in result["errors"])
2609
  return "### Verification Failed\n\n" + errors
2610
 
2611
 
2612
  def empty_report_markdown() -> str:
2613
- return "### Ready To Verify\n\nPaste JSON or upload a file, then run the verifier. Results and geometry diagnostics will appear here."
2614
 
2615
 
2616
  def empty_preview_html() -> str:
@@ -2647,38 +2704,41 @@ def preview_html(solution: dict[str, Any]) -> str:
2647
  """
2648
 
2649
 
2650
- def verify_only(json_text: str, json_file: str | None, tolerance: float):
2651
  try:
2652
- solution = normalize_solution(load_submission(json_text, json_file))
2653
- result = verify_solution(solution, tolerance=tolerance).as_dict()
 
2654
  pretty = json.dumps(solution, indent=2, sort_keys=True)
2655
  preview = preview_html(solution) if result["ok"] else ""
2656
- return result_markdown(result), preview, pretty
2657
  except Exception as exc:
2658
  return f"### Verification Failed\n\n- {exc}", empty_preview_html(), json_text
2659
 
2660
 
2661
  def submit_solution(
2662
  json_text: str,
2663
- json_file: str | None,
2664
  submitter: str,
2665
  notes: str,
2666
  source_url: str,
2667
- tolerance: float,
2668
  ):
2669
  try:
2670
- solution = normalize_solution(load_submission(json_text, json_file))
 
 
 
 
2671
  record, result = STORE.append_verified_submission(
2672
  solution,
2673
  submitter=submitter,
2674
  notes=notes,
2675
  source_url=source_url,
2676
- tolerance=tolerance,
2677
  )
2678
  stored = STORE.solution_for_record(record)
2679
  pretty = json.dumps(stored, indent=2, sort_keys=True)
2680
  sync_status = record.get("sync_status", "dataset sync disabled")
2681
- message = result_markdown(result) + f"\n\nSaved as record `{record['id']}`.\n\nDataset sync: `{sync_status}`."
2682
  clear_page_caches()
2683
  return (
2684
  message,
@@ -2718,24 +2778,23 @@ with gr.Blocks(
2718
  with gr.Row(elem_classes=["submit-layout"]):
2719
  with gr.Column(scale=7, elem_classes=["submit-editor"]):
2720
  with gr.Group(elem_classes=["submit-panel"]):
2721
- gr.HTML('<div class="submit-panel-title">Canonical Geometry</div>')
2722
- gr.HTML('<p class="submit-panel-note">Paste JSON here, or upload a file below. Verification normalizes the payload before archival.</p>')
2723
  json_code = gr.Textbox(
2724
  **supported_gradio_kwargs(
2725
  gr.Textbox,
2726
  value=SAMPLE_JSON,
2727
  label="Coordinate JSON",
2728
- lines=20,
2729
  max_lines=30,
2730
  show_copy_button=True,
2731
  )
2732
  )
2733
- json_file = gr.File(label="Upload .json", file_types=[".json"], type="filepath")
2734
 
2735
  with gr.Column(scale=5, elem_classes=["submit-meta"]):
2736
  with gr.Group(elem_classes=["submit-panel"]):
2737
- gr.HTML('<div class="submit-panel-title">Record Details</div>')
2738
- gr.HTML('<p class="submit-panel-note">Search past credited authors, or type a new name directly into the same field.</p>')
2739
  submitter = gr.Dropdown(
2740
  **supported_gradio_kwargs(
2741
  gr.Dropdown,
@@ -2747,9 +2806,8 @@ with gr.Blocks(
2747
  info="Start typing to search existing authors. New names are accepted.",
2748
  )
2749
  )
2750
- source_url = gr.Textbox(label="Source URL", placeholder="Optional paper, repo, run log, or note URL")
2751
- notes = gr.Textbox(label="Notes", lines=3, placeholder="Optional method, provenance, or contact note")
2752
- tolerance = gr.Number(value=DEFAULT_TOLERANCE, label="Verification tolerance")
2753
  with gr.Row(elem_classes=["submit-actions"]):
2754
  verify_btn = gr.Button("Verify", variant="secondary")
2755
  submit_btn = gr.Button("Submit Entry", variant="primary")
@@ -2776,16 +2834,14 @@ with gr.Blocks(
2776
  )
2777
 
2778
  with gr.Group(elem_classes=["submit-docs"]):
2779
- with gr.Accordion("Examples", open=False):
2780
- gr.Markdown(EXAMPLES_MD)
2781
- with gr.Accordion("Schema And Coordinate Rules", open=False):
2782
- gr.Markdown(SCHEMA_DOCS_MD)
2783
 
2784
  demo.load(home_page_for_request, outputs=[browse_page], show_progress="hidden")
2785
- verify_btn.click(verify_only, inputs=[json_code, json_file, tolerance], outputs=[report, preview, normalized_json])
2786
  submit_btn.click(
2787
  submit_solution,
2788
- inputs=[json_code, json_file, submitter, notes, source_url, tolerance],
2789
  outputs=[report, preview, normalized_json, leaderboard_page, submitter],
2790
  )
2791
 
 
32
  FAVICON_PATH = SPACE_ROOT / "assets" / "favicon.svg"
33
  HYDRATE_STATUS = maybe_hydrate_from_dataset(DATA_DIR)
34
  STORE = SolutionStore(DATA_DIR)
35
+ SUBMISSION_MIN_IMPROVEMENT = 1.0e-4
36
 
37
 
38
  @lru_cache(maxsize=1)
 
1541
  - touching is legal; overlap and protrusion are rejected
1542
  """
1543
 
1544
+ EXAMPLES_MD = f"""### How Submission Works
1545
+
1546
+ Paste one canonical coordinate JSON object, click **Verify**, then click **Submit Entry** if it passes.
1547
+
1548
+ The geometry tolerance is fixed by the evaluator and is not user-selectable. For an existing case, a submission must improve the current top metric by at least `0.0001` to be accepted as a new record. In these tables, smaller metric values are better.
1549
+
1550
+ ### Minimal Triangle Example
1551
 
1552
  This is the smallest legal record and a good shape for checking the schema:
1553
 
 
1561
  - Use container-centered coordinates.
1562
  - Use radians for `rotation_radians`.
1563
  - Click **Verify** before submitting; the preview is rendered from the same canonical JSON that is archived.
1564
+ - Existing cases must beat the current top metric by at least `0.0001`.
1565
  """
1566
 
1567
  SCHEMA_DOCS_MD = """### Canonical Fields
 
1583
  - `circle`: `radius` or `diameter`
1584
  - `rectangle`: `width` and `height`
1585
 
1586
+ The verifier uses a fixed geometry tolerance. Existing cases must improve the current top metric by at least `0.0001` before they can be submitted as records.
1587
  """ + f"""
1588
 
1589
  ### Four Circles In A Square
 
2579
  <div>
2580
  <h2>Submit Entry</h2>
2581
  <p class="section-note">
2582
+ Paste one canonical coordinate JSON object. Existing cases must beat the current top metric by at least 0.0001.
2583
  </p>
2584
  </div>
2585
  </div>
 
 
 
 
 
2586
  </div>
2587
  </section>
2588
  </main>
2589
  """
2590
 
2591
 
2592
+ def load_submission(json_text: str) -> dict[str, Any]:
 
 
2593
  if not json_text or not json_text.strip():
2594
+ raise ValueError("Paste canonical coordinate JSON.")
2595
  return load_solution_json(json_text)
2596
 
2597
 
2598
+ def record_metric_float(record: dict[str, Any]) -> float | None:
2599
+ value = record.get("metric_value")
2600
+ if value is None:
2601
+ value = record.get("side")
2602
+ try:
2603
+ metric = float(value)
2604
+ except (TypeError, ValueError):
2605
+ return None
2606
+ return metric if math.isfinite(metric) else None
2607
+
2608
+
2609
+ def current_top_for_case(case: str) -> dict[str, Any] | None:
2610
+ candidates = [record for record in cached_public_records("", False) if str(record.get("case")) == case]
2611
+ candidates = [record for record in candidates if record_metric_float(record) is not None]
2612
+ if not candidates:
2613
+ return None
2614
+ return min(candidates, key=lambda record: record_metric_float(record) or float("inf"))
2615
+
2616
+
2617
+ def submission_gate(result: dict[str, Any]) -> tuple[bool, str]:
2618
+ if not result.get("ok"):
2619
+ return False, "Geometry verification failed."
2620
+ submitted = result.get("side")
2621
+ try:
2622
+ submitted_metric = float(submitted)
2623
+ except (TypeError, ValueError):
2624
+ return False, "The evaluator could not compute a submitted metric."
2625
+ if not math.isfinite(submitted_metric):
2626
+ return False, "The evaluator returned a non-finite metric."
2627
+
2628
+ current = current_top_for_case(str(result.get("case") or ""))
2629
+ if current is None:
2630
+ return True, "No current top record exists for this case; a valid geometry can be submitted."
2631
+
2632
+ current_metric = record_metric_float(current)
2633
+ if current_metric is None:
2634
+ return True, "No comparable current top metric exists; a valid geometry can be submitted."
2635
+
2636
+ improvement = current_metric - submitted_metric
2637
+ if improvement >= SUBMISSION_MIN_IMPROVEMENT:
2638
  return (
2639
+ True,
2640
+ f"Improves the current top metric by {improvement:.10f}; required improvement is at least {SUBMISSION_MIN_IMPROVEMENT:.4f}.",
2641
+ )
2642
+ return (
2643
+ False,
2644
+ f"Current top metric is {current_metric:.10f}. Submitted metric is {submitted_metric:.10f}. "
2645
+ f"Improvement is {improvement:.10f}; required improvement is at least {SUBMISSION_MIN_IMPROVEMENT:.4f}.",
2646
+ )
2647
+
2648
+
2649
+ def result_markdown(result: dict[str, Any], gate: tuple[bool, str] | None = None) -> str:
2650
+ if result["ok"]:
2651
+ text = (
2652
  "### Verification Passed\n\n"
2653
  f"- Case: `{result['case']}`\n"
2654
  f"- Items: `{result['n']}`\n"
 
2657
  f"- Max boundary excess: `{result['max_boundary_excess']:.3e}`\n"
2658
  f"- Max pair overlap depth: `{result['max_pair_overlap_depth']:.3e}`\n"
2659
  )
2660
+ if gate is not None:
2661
+ passed, message = gate
2662
+ status = "Passed" if passed else "Needs improvement"
2663
+ text += f"\n### Record Gate\n\n- Status: `{status}`\n- {message}\n"
2664
+ return text
2665
  errors = "\n".join(f"- {e}" for e in result["errors"])
2666
  return "### Verification Failed\n\n" + errors
2667
 
2668
 
2669
  def empty_report_markdown() -> str:
2670
+ return "### Ready To Verify\n\nPaste canonical JSON, then run the verifier. Existing cases must improve the current top metric by at least `0.0001`."
2671
 
2672
 
2673
  def empty_preview_html() -> str:
 
2704
  """
2705
 
2706
 
2707
+ def verify_only(json_text: str):
2708
  try:
2709
+ solution = normalize_solution(load_submission(json_text))
2710
+ result = verify_solution(solution, tolerance=DEFAULT_TOLERANCE).as_dict()
2711
+ gate = submission_gate(result) if result["ok"] else None
2712
  pretty = json.dumps(solution, indent=2, sort_keys=True)
2713
  preview = preview_html(solution) if result["ok"] else ""
2714
+ return result_markdown(result, gate), preview, pretty
2715
  except Exception as exc:
2716
  return f"### Verification Failed\n\n- {exc}", empty_preview_html(), json_text
2717
 
2718
 
2719
  def submit_solution(
2720
  json_text: str,
 
2721
  submitter: str,
2722
  notes: str,
2723
  source_url: str,
 
2724
  ):
2725
  try:
2726
+ solution = normalize_solution(load_submission(json_text))
2727
+ preflight = verify_solution(solution, tolerance=DEFAULT_TOLERANCE).as_dict()
2728
+ gate_ok, gate_message = submission_gate(preflight)
2729
+ if not gate_ok:
2730
+ return result_markdown(preflight, (gate_ok, gate_message)), preview_html(solution), json.dumps(solution, indent=2, sort_keys=True), gr.update(), gr.update()
2731
  record, result = STORE.append_verified_submission(
2732
  solution,
2733
  submitter=submitter,
2734
  notes=notes,
2735
  source_url=source_url,
2736
+ tolerance=DEFAULT_TOLERANCE,
2737
  )
2738
  stored = STORE.solution_for_record(record)
2739
  pretty = json.dumps(stored, indent=2, sort_keys=True)
2740
  sync_status = record.get("sync_status", "dataset sync disabled")
2741
+ message = result_markdown(result, (gate_ok, gate_message)) + f"\n\nSaved as record `{record['id']}`.\n\nDataset sync: `{sync_status}`."
2742
  clear_page_caches()
2743
  return (
2744
  message,
 
2778
  with gr.Row(elem_classes=["submit-layout"]):
2779
  with gr.Column(scale=7, elem_classes=["submit-editor"]):
2780
  with gr.Group(elem_classes=["submit-panel"]):
2781
+ gr.HTML('<div class="submit-panel-title">Paste JSON</div>')
2782
+ gr.HTML('<p class="submit-panel-note">Paste one canonical coordinate JSON object. The evaluator uses a fixed tolerance and requires a 0.0001 metric improvement for existing cases.</p>')
2783
  json_code = gr.Textbox(
2784
  **supported_gradio_kwargs(
2785
  gr.Textbox,
2786
  value=SAMPLE_JSON,
2787
  label="Coordinate JSON",
2788
+ lines=18,
2789
  max_lines=30,
2790
  show_copy_button=True,
2791
  )
2792
  )
 
2793
 
2794
  with gr.Column(scale=5, elem_classes=["submit-meta"]):
2795
  with gr.Group(elem_classes=["submit-panel"]):
2796
+ gr.HTML('<div class="submit-panel-title">Author</div>')
2797
+ gr.HTML('<p class="submit-panel-note">Choose an existing credited author or type a new name.</p>')
2798
  submitter = gr.Dropdown(
2799
  **supported_gradio_kwargs(
2800
  gr.Dropdown,
 
2806
  info="Start typing to search existing authors. New names are accepted.",
2807
  )
2808
  )
2809
+ source_url = gr.Textbox(label="Source URL", placeholder="Optional")
2810
+ notes = gr.Textbox(label="Notes", lines=3, placeholder="Optional method or provenance note")
 
2811
  with gr.Row(elem_classes=["submit-actions"]):
2812
  verify_btn = gr.Button("Verify", variant="secondary")
2813
  submit_btn = gr.Button("Submit Entry", variant="primary")
 
2834
  )
2835
 
2836
  with gr.Group(elem_classes=["submit-docs"]):
2837
+ with gr.Accordion("Submission Documentation", open=False):
2838
+ gr.Markdown(EXAMPLES_MD + "\n\n" + SCHEMA_DOCS_MD)
 
 
2839
 
2840
  demo.load(home_page_for_request, outputs=[browse_page], show_progress="hidden")
2841
+ verify_btn.click(verify_only, inputs=[json_code], outputs=[report, preview, normalized_json])
2842
  submit_btn.click(
2843
  submit_solution,
2844
+ inputs=[json_code, submitter, notes, source_url],
2845
  outputs=[report, preview, normalized_json, leaderboard_page, submitter],
2846
  )
2847