reguai-engine / src /ontology /builder.py
gitmodelmujtaba's picture
Deploy ReguAI: Neuro-Symbolic AI GRC & Automated Conformity Assessment Engine
4ec721f verified
Raw
History Blame Contribute Delete
5.7 kB
"""
RDF Knowledge Graph Builder.
Constructs RDFLib graphs from system specifications and extracted claims,
binding them to formal legal ontologies.
"""
from typing import Tuple, Dict, Any, List
import re
import rdflib
from rdflib import Graph, URIRef, Literal, RDF, RDFS, XSD
from src.core.config import REGU, EU_ACT, NIST, ISO, PROV, SH, SCHEMAS_DIR
from src.core.models import (
SystemSpecification,
ExtractedClaim,
EntityCategory,
AssertionStatus,
)
class NormativeGraphBuilder:
def __init__(self):
self.category_predicate_map = {
EntityCategory.RISK_MANAGEMENT: (REGU.hasRiskManagementSystem, REGU.RiskManagementSystem),
EntityCategory.DATA_GOVERNANCE: (REGU.hasDataGovernance, REGU.DataGovernanceProcess),
EntityCategory.BIAS_MITIGATION: (REGU.hasBiasMitigation, REGU.BiasMitigationControl),
EntityCategory.TECHNICAL_DOCUMENTATION: (REGU.hasTechnicalDocumentation, REGU.TechnicalDocumentation),
EntityCategory.RECORD_KEEPING: (REGU.hasLoggingCapability, REGU.AutomatedLogging),
EntityCategory.TRANSPARENCY: (REGU.hasTransparencySpecification, REGU.TransparencySpecification),
EntityCategory.HUMAN_OVERSIGHT: (REGU.hasHumanOversight, REGU.HumanOversightMechanism),
EntityCategory.ACCURACY_ROBUSTNESS: (REGU.hasRobustnessControl, REGU.RobustnessControl),
EntityCategory.CYBERSECURITY: (REGU.hasCybersecurityControl, REGU.CybersecurityControl),
EntityCategory.FAIL_SAFE: (REGU.hasEmergencyStop, REGU.StopMechanism),
EntityCategory.WATERMARKING_CONTROL: (REGU.hasWatermarkingControl, REGU.WatermarkingControl),
}
def _bind_namespaces(self, g: Graph) -> None:
g.bind("regu", REGU)
g.bind("eu", EU_ACT)
g.bind("nist", NIST)
g.bind("iso", ISO)
g.bind("prov", PROV)
g.bind("sh", SH)
def load_base_ontologies(self) -> Graph:
"""Loads base OWL/RDFS legal definitions into a Graph."""
g = Graph()
self._bind_namespaces(g)
eu_path = SCHEMAS_DIR / "eu_ai_act.ttl"
if eu_path.exists():
g.parse(str(eu_path), format="turtle")
return g
def build_system_graph(self, spec: SystemSpecification) -> Graph:
"""
Translates a parsed SystemSpecification with extracted claims
into an RDF instance graph ready for SHACL verification.
"""
g = Graph()
self._bind_namespaces(g)
sys_uri = REGU[f"system_{spec.metadata.system_id.replace('-', '_')}"]
# System Node & Regulatory Typing
risk_class_lower = spec.metadata.eu_risk_classification.lower()
is_prohibited = "prohibited" in risk_class_lower or bool(re.search(r"\barticle\s*5\b", risk_class_lower))
if is_prohibited:
g.add((sys_uri, RDF.type, REGU.ProhibitedAISystem))
g.add((sys_uri, REGU.prohibitionStatus, REGU.ProhibitedPracticeDetected))
g.add((sys_uri, REGU.hasProhibitedPracticeType, REGU.ProhibitedPracticeDetected))
elif "generative" in risk_class_lower or "genai" in risk_class_lower or "synthetic" in risk_class_lower or "article 50" in risk_class_lower:
g.add((sys_uri, RDF.type, REGU.GenerativeAISystem))
elif "general purpose" in risk_class_lower or "gpai" in risk_class_lower:
if "systemic" in risk_class_lower or "article 51" in risk_class_lower:
g.add((sys_uri, RDF.type, REGU.GPAISystemicRiskModel))
else:
g.add((sys_uri, RDF.type, REGU.GPAIModel))
elif "high-risk" in risk_class_lower or "annex iii" in risk_class_lower or "annex i" in risk_class_lower:
g.add((sys_uri, RDF.type, REGU.HighRiskAISystem))
else:
g.add((sys_uri, RDF.type, REGU.AISystem))
g.add((sys_uri, RDFS.label, Literal(spec.metadata.name)))
g.add((sys_uri, REGU.domain, Literal(spec.metadata.domain)))
g.add((sys_uri, REGU.version, Literal(spec.metadata.version)))
g.add((sys_uri, REGU.intendedPurpose, Literal(spec.metadata.intended_purpose)))
g.add((sys_uri, REGU.developer, Literal(spec.metadata.developer_name)))
# Process Claims into Instance Nodes
for idx, claim in enumerate(spec.extracted_claims):
if claim.category in self.category_predicate_map:
pred, target_cls = self.category_predicate_map[claim.category]
claim_node_uri = REGU[f"claim_{spec.metadata.system_id}_{idx}"]
g.add((claim_node_uri, RDF.type, target_cls))
g.add((sys_uri, pred, claim_node_uri))
# Implementation Status Mapping
if claim.assertion_status == AssertionStatus.IMPLEMENTED:
g.add((claim_node_uri, REGU.implementationStatus, REGU.Implemented))
elif claim.assertion_status == AssertionStatus.PLANNED:
g.add((claim_node_uri, REGU.implementationStatus, REGU.Planned))
else:
g.add((claim_node_uri, REGU.implementationStatus, REGU.Absent))
# Grounding Metadata
g.add((claim_node_uri, REGU.evidenceSource, Literal(claim.evidence_quote)))
g.add((claim_node_uri, REGU.confidenceScore, Literal(claim.confidence, datatype=XSD.float)))
g.add((claim_node_uri, REGU.normativeArticle, Literal(claim.normative_article)))
return g
def serialize(self, g: Graph, format: str = "turtle") -> str:
"""Serializes the RDF graph to a string."""
return g.serialize(format=format)