jcat / app.py
fabsssss's picture
Upload app.py with huggingface_hub
9f2dd72 verified
Raw
History Blame Contribute Delete
4.11 kB
"""JCAT ontology engine β€” Hugging Face Space.
A Gradio front-end over the open `jcat` engine. Paste terms, pick taxonomy or ontology,
choose the layer depth, and get standards-compliant SKOS/OWL Turtle plus a readable tree.
When the optional engine (open-ontologies-lite / Oxigraph) is installed, the Space also
validates the graph for real and runs live SPARQL over it. Mirrors the demo at
https://jcatlabs.com/#demo.
"""
import json
import gradio as gr
import jcat
from jcat import Graph
from jcat.core import build_tree, parse_terms
EXAMPLE = """credit risk
market risk
operational risk
liquidity risk
savings account
current account
business account
fixed deposit
retail customer
corporate customer
private customer
mortgage loan
personal loan
business loan"""
DEFAULT_SPARQL = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 15"
def _tree_text(node, prefix=""):
lines = []
n = len(node.children)
for i, c in enumerate(node.children):
last = i == n - 1
lines.append(prefix + ("└─ " if last else "β”œβ”€ ") + c.label)
lines.append(_tree_text(c, prefix + (" " if last else "β”‚ ")))
return "\n".join(l for l in lines if l)
def _is_owl(mode):
return mode.startswith("Ont")
def run(text, mode, depth):
terms = parse_terms(text)
if not terms:
return "Add a few terms first.", "", "β€”"
g = Graph(terms)
owl = _is_owl(mode)
ttl = g.ontology(int(depth)) if owl else g.taxonomy(int(depth))
root = build_tree(terms, "ontology" if owl else "taxonomy", int(depth))
if jcat.has_engine():
rep = g.validate(mode="ontology" if owl else "taxonomy", depth=int(depth))
ok = "valid" if rep.get("valid") else "INVALID"
status = f"βœ“ {ok} Β· {rep.get('triples')} triples Β· validated by open-ontologies-lite (Oxigraph)"
else:
status = "light mode β€” engine not installed (synthesis only)"
return ttl, (root.label + "\n" + _tree_text(root)), status
def run_sparql(text, mode, depth, sparql):
if not jcat.has_engine():
return "Engine not available in this Space."
terms = parse_terms(text)
if not terms:
return "Add terms first."
try:
res = Graph(terms).query(
sparql, mode="ontology" if _is_owl(mode) else "taxonomy", depth=int(depth)
)
rows = res.get("rows", res)
return json.dumps(rows, indent=2)
except Exception as e: # noqa: BLE001
return f"Error: {e}"
with gr.Blocks(title="JCAT ontology engine", theme=gr.themes.Soft(primary_hue="green")) as demo:
gr.Markdown(
"# 🐱 JCAT ontology engine\n"
"Paste a flat list of terms. Get a standards-compliant **SKOS taxonomy** or "
"**OWL ontology**, validated for real and queryable with SPARQL. This is the open "
"[`jcat`](https://github.com/fabio-rovai/jcat) engine running on "
"[open-ontologies-lite](https://pypi.org/project/open-ontologies-lite/) "
"(Oxigraph), the same stack behind [jcatlabs.com](https://jcatlabs.com). Free forever."
)
with gr.Row():
with gr.Column():
inp = gr.Textbox(EXAMPLE, lines=14, label="Your terms")
mode = gr.Radio(
["Taxonomy (SKOS)", "Ontology (OWL)"],
value="Taxonomy (SKOS)", label="Output",
)
depth = gr.Slider(1, 3, value=2, step=1, label="Layer depth")
btn = gr.Button("Give it a try", variant="primary")
with gr.Column():
status = gr.Markdown("β€”")
tree = gr.Textbox(label="Structure", lines=8)
ttl = gr.Code(label="Turtle")
with gr.Accordion("Run SPARQL over the graph (powered by open-ontologies-lite)", open=False):
sparql = gr.Textbox(DEFAULT_SPARQL, lines=3, label="SPARQL")
sbtn = gr.Button("Run query")
sout = gr.Code(label="Results")
sbtn.click(run_sparql, [inp, mode, depth, sparql], sout)
btn.click(run, [inp, mode, depth], [ttl, tree, status])
demo.load(run, [inp, mode, depth], [ttl, tree, status])
if __name__ == "__main__":
demo.launch()