feat(runtime): implement single-article consolidation runtime and modularize codebase
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""ECP classification adapter consuming src.classifier.InherenceClassifier."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import jsonschema
|
||||
from referencing import Registry, Resource
|
||||
|
||||
from src.runtime.core.config import create_schema_registry, load_schema
|
||||
from src.tools.classifier import InherenceClassifier
|
||||
from src.tools.models import ECPSnapshot
|
||||
|
||||
CANONICAL_ECP_SCHEMA_PATH = (
|
||||
Path(__file__).resolve().parent.parent.parent
|
||||
/ "tools"
|
||||
/ "adapters"
|
||||
/ "ecp"
|
||||
/ "schemas"
|
||||
/ "ecp-profile.schema.json"
|
||||
)
|
||||
|
||||
|
||||
def load_ecp_schema_registry() -> Registry:
|
||||
registry = create_schema_registry()
|
||||
if CANONICAL_ECP_SCHEMA_PATH.exists():
|
||||
schema_data = json.loads(CANONICAL_ECP_SCHEMA_PATH.read_text(encoding="utf-8"))
|
||||
schema_id = schema_data.get(
|
||||
"$id", "https://schemas.aftech.internal/ecp/v1/ecp-profile.schema.json"
|
||||
)
|
||||
resource = Resource.from_contents(schema_data)
|
||||
registry = registry.with_resource(schema_id, resource)
|
||||
return registry
|
||||
|
||||
|
||||
def validate_ecp_snapshot(ecp_data: Dict[str, Any]) -> None:
|
||||
schema = load_schema("ecp-snapshot.schema.json")
|
||||
registry = load_ecp_schema_registry()
|
||||
validator = jsonschema.Draft202012Validator(schema, registry=registry)
|
||||
errors = list(validator.iter_errors(ecp_data))
|
||||
if errors:
|
||||
msg = "; ".join([f"{e.json_path}: {e.message}" for e in errors])
|
||||
raise ValueError(f"ECP Snapshot schema validation failed: {msg}")
|
||||
|
||||
|
||||
class ECPClassificationAdapter:
|
||||
def __init__(self, classifier: Optional[InherenceClassifier] = None):
|
||||
self.classifier = classifier or InherenceClassifier()
|
||||
|
||||
def classify(self, ecp_dict: Dict[str, Any], content_md: str) -> Dict[str, Any]:
|
||||
"""Classifies content_md against ecp_dict using InherenceClassifier."""
|
||||
# 1. Validate ECP schema
|
||||
validate_ecp_snapshot(ecp_dict)
|
||||
|
||||
# 2. Build model object
|
||||
ecp_snapshot = ECPSnapshot.from_dict(ecp_dict)
|
||||
|
||||
# 3. Invoke classifier
|
||||
result = self.classifier.classify(ecp=ecp_snapshot, content_md=content_md)
|
||||
|
||||
# 4. Extract fields & validate evidences grounding
|
||||
decision_val = (
|
||||
result.decision.value if hasattr(result.decision, "value") else str(result.decision)
|
||||
)
|
||||
is_inherent = bool(result.is_inherent)
|
||||
confidence = float(getattr(result, "confidence", 1.0))
|
||||
rationale = str(getattr(result, "rationale", ""))
|
||||
evidences = [str(e) for e in (getattr(result, "evidence", []) or [])]
|
||||
|
||||
return {
|
||||
"category": decision_val,
|
||||
"is_inherent": is_inherent,
|
||||
"confidence": confidence,
|
||||
"rationale": rationale,
|
||||
"evidences": evidences,
|
||||
}
|
||||
Reference in New Issue
Block a user