Spaces:
Build error
Build error
Download app.py from thearnabsarkar/json-semval-validator: direct link, hf CLI and curl.
- Browser
- Download file 6.03 kB
-
https://huggingface.co/spaces/thearnabsarkar/json-semval-validator/resolve/main/app.py
- Command line
-
hf download hf://spaces/thearnabsarkar/json-semval-validator/app.py
-
curl -L -o app.py https://huggingface.co/spaces/thearnabsarkar/json-semval-validator/resolve/main/app.py
6.03 kB
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| import gradio as gr | |
| from json_semval.pipeline import run_validation | |
| def load_fixtures() -> tuple[str, str]: | |
| try: | |
| schema = Path("tests/fixtures/sample_schema.json").read_text(encoding="utf-8") | |
| bad = Path("tests/fixtures/sample_bad.json").read_text(encoding="utf-8") | |
| return schema, bad | |
| except Exception: | |
| example_schema = '{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}' | |
| example_json = '{"name":"Alice"}' | |
| return example_schema, example_json | |
| def infer( | |
| schema_text: str, json_text: str, backend: str, apply_minimal: bool | |
| ) -> tuple[str, str, str]: | |
| try: | |
| schema = json.loads(schema_text) | |
| payload = json.loads(json_text) | |
| except Exception as e: | |
| return "[]", f"Invalid input JSON: {e}", json_text | |
| report = run_validation(schema, payload, apply_fixes=apply_minimal, backend=backend) | |
| rule_errors = json.dumps(report.get("rule_errors", []), indent=2) | |
| ml_preds = json.dumps(report.get("ml_predictions", []), indent=2) | |
| corrected = json.dumps(report.get("corrected_json", payload), indent=2) | |
| return rule_errors, ml_preds, corrected | |
| EXAMPLES = { | |
| "Example 1: Fixtures (bad)": ( | |
| ( | |
| Path("tests/fixtures/sample_schema.json").read_text(encoding="utf-8") | |
| if Path("tests/fixtures/sample_schema.json").exists() | |
| else '{"type":"object","properties":{"age":{"type":"integer"},"start_date":{"type":"string","format":"date"},"active":{"type":"boolean"},"status":{"type":"string","enum":["pending","approved","rejected"]}},"required":["age","start_date","active","status"]}' | |
| ), | |
| ( | |
| Path("tests/fixtures/sample_bad.json").read_text(encoding="utf-8") | |
| if Path("tests/fixtures/sample_bad.json").exists() | |
| else '{"age":"twenty five","active":"yes","start_date":"15 Jan 2024","status":"pendng"}' | |
| ), | |
| ), | |
| "Example 2: Minimal valid": ( | |
| '{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}', | |
| '{"name":"Alice"}', | |
| ), | |
| "Example 3: Enum/date mix": ( | |
| '{"type":"object","properties":{"status":{"type":"string","enum":["pending","approved","rejected"]},"d":{"type":"string","format":"date"}},"required":["status","d"]}', | |
| '{"status":"Pendng","d":"01/02/2024"}', | |
| ), | |
| } | |
| with gr.Blocks(title="JSON Semantic Validator") as demo: | |
| gr.Markdown( | |
| """ | |
| # JSON Semantic Validator | |
| Hybrid rules + tiny ML to validate and auto-fix JSON against a schema. | |
| """ | |
| ) | |
| with gr.Row(): | |
| schema_in = gr.Code(label="JSON Schema", language="json") | |
| json_in = gr.Code(label="JSON Payload", language="json") | |
| with gr.Row(): | |
| backend = gr.Dropdown( | |
| ["rules-only", "local", "onnx"], value="rules-only", label="Backend" | |
| ) | |
| apply_minimal = gr.Checkbox(value=True, label="Apply minimal fixes") | |
| example_dd = gr.Dropdown(list(EXAMPLES.keys()), label="Load Example") | |
| load_btn = gr.Button("Load Fixtures") | |
| run_btn = gr.Button("Run Validation") | |
| with gr.Row(): | |
| rule_errors_out = gr.Code(label="Rule Errors", language="json") | |
| ml_preds_out = gr.Code(label="ML Predictions", language="json") | |
| corrected_out = gr.Code(label="Corrected JSON", language="json") | |
| validity_md = gr.Markdown(visible=True) | |
| def _backend_value(b: str) -> str: | |
| if b == "rules-only": | |
| return "local" # we will set apply_minimal False when executing | |
| return b | |
| def on_load() -> tuple[str, str]: | |
| return load_fixtures() | |
| def on_example_select(label: str) -> tuple[str, str]: | |
| pair = EXAMPLES.get(label) | |
| if not pair: | |
| return "", "" | |
| return pair | |
| def on_run( | |
| schema_text: str, json_text: str, b: str, do_fix: bool | |
| ) -> tuple[str, str, str, str]: | |
| # Compute rules-only and hybrid validity to show a delta badge | |
| validity_text = "" | |
| try: | |
| schema = json.loads(schema_text) | |
| payload = json.loads(json_text) | |
| rules_only = run_validation( | |
| schema, payload, apply_fixes=False, backend="rules-only" | |
| ) | |
| hybrid = run_validation( | |
| schema, | |
| payload, | |
| apply_fixes=(False if b == "rules-only" else do_fix), | |
| backend=_backend_value(b), | |
| ) | |
| r_ok = 1 if rules_only.get("valid") else 0 | |
| h_ok = 1 if hybrid.get("valid") else 0 | |
| delta = (h_ok - r_ok) * 100 | |
| validity_text = f"**Validity** — Rules-only: {r_ok*100}% · Hybrid: {h_ok*100}% · Δ: {delta:+d}%" | |
| # Return details based on the hybrid run to keep UX consistent | |
| rule_errors = json.dumps(hybrid.get("rule_errors", []), indent=2) | |
| ml_preds = json.dumps(hybrid.get("ml_predictions", []), indent=2) | |
| corrected = json.dumps(hybrid.get("corrected_json", payload), indent=2) | |
| return rule_errors, ml_preds, corrected, validity_text | |
| except Exception as e: | |
| return "[]", f"Invalid input JSON: {e}", json_text, "" | |
| load_btn.click(fn=on_load, outputs=[schema_in, json_in]) | |
| example_dd.change( | |
| fn=on_example_select, inputs=[example_dd], outputs=[schema_in, json_in] | |
| ) | |
| run_btn.click( | |
| fn=on_run, | |
| inputs=[schema_in, json_in, backend, apply_minimal], | |
| outputs=[rule_errors_out, ml_preds_out, corrected_out, validity_md], | |
| ) | |
| # Disable the "Apply minimal fixes" checkbox when backend == rules-only | |
| def on_backend_change(b: str, current: bool): | |
| if b == "rules-only": | |
| return gr.update(value=False, interactive=False) | |
| return gr.update(interactive=True) | |
| backend.change( | |
| fn=on_backend_change, inputs=[backend, apply_minimal], outputs=apply_minimal | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(share=True) | |