mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
169 lines
5.8 KiB
Python
169 lines
5.8 KiB
Python
"""
|
|
Extraction tools — NER, relation extraction, event detection, triplets.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from mcp.schemas import EXTRACT_ALL, EXTRACT_ENTITIES, EXTRACT_RELATIONS
|
|
|
|
log = logging.getLogger("semantica.mcp.tools.extraction")
|
|
|
|
|
|
def _clear_cache() -> None:
|
|
try:
|
|
from semantica.semantic_extract.cache import _result_cache
|
|
_result_cache.clear()
|
|
except Exception:
|
|
log.debug("Could not clear semantic_extract cache; continuing", exc_info=True)
|
|
|
|
|
|
def handle_extract_entities(args: dict) -> dict:
|
|
"""Extract named entities from text using Semantica NER."""
|
|
text = args.get("text", "").strip()
|
|
if not text:
|
|
return {"error": "text is required", "entities": []}
|
|
_clear_cache()
|
|
try:
|
|
from semantica.semantic_extract import NamedEntityRecognizer
|
|
entities = NamedEntityRecognizer().extract(text) or []
|
|
return {
|
|
"entities": [
|
|
{
|
|
"label": getattr(e, "label", str(e)),
|
|
"type": getattr(e, "type", None),
|
|
"start": getattr(e, "start", None),
|
|
"end": getattr(e, "end", None),
|
|
"confidence": getattr(e, "confidence", None),
|
|
}
|
|
for e in entities
|
|
],
|
|
"count": len(entities),
|
|
}
|
|
except Exception as exc:
|
|
log.exception("extract_entities failed")
|
|
return {"error": str(exc), "entities": []}
|
|
|
|
|
|
def handle_extract_relations(args: dict) -> dict:
|
|
"""Extract relations and triplets from text."""
|
|
text = args.get("text", "").strip()
|
|
if not text:
|
|
return {"error": "text is required", "relations": [], "triplets": []}
|
|
_clear_cache()
|
|
try:
|
|
from semantica.semantic_extract import NamedEntityRecognizer, RelationExtractor, TripletExtractor
|
|
entities = NamedEntityRecognizer().extract(text) or []
|
|
relations = RelationExtractor().extract(text, entities) or []
|
|
triplets = TripletExtractor().extract(text) or []
|
|
return {
|
|
"relations": [
|
|
{
|
|
"source": getattr(r, "source", None),
|
|
"type": getattr(r, "type", None),
|
|
"target": getattr(r, "target", None),
|
|
"confidence": getattr(r, "confidence", None),
|
|
}
|
|
for r in relations
|
|
],
|
|
"triplets": [
|
|
{
|
|
"subject": getattr(t, "subject", None),
|
|
"predicate": getattr(t, "predicate", None),
|
|
"object": getattr(t, "object", None),
|
|
}
|
|
for t in triplets
|
|
],
|
|
"relation_count": len(relations),
|
|
"triplet_count": len(triplets),
|
|
}
|
|
except Exception as exc:
|
|
log.exception("extract_relations failed")
|
|
return {"error": str(exc), "relations": [], "triplets": []}
|
|
|
|
|
|
def handle_extract_all(args: dict) -> dict:
|
|
"""Run the full extraction pipeline: NER + relations + events + triplets."""
|
|
text = args.get("text", "").strip()
|
|
if not text:
|
|
return {"error": "text is required"}
|
|
include_events = args.get("include_events", True)
|
|
include_triplets = args.get("include_triplets", True)
|
|
_clear_cache()
|
|
result: dict[str, Any] = {}
|
|
try:
|
|
from semantica.semantic_extract import (
|
|
CoreferenceResolver,
|
|
EventDetector,
|
|
NamedEntityRecognizer,
|
|
RelationExtractor,
|
|
TripletExtractor,
|
|
)
|
|
|
|
entities = NamedEntityRecognizer().extract(text) or []
|
|
result["entities"] = [
|
|
{"label": getattr(e, "label", str(e)), "type": getattr(e, "type", None)}
|
|
for e in entities
|
|
]
|
|
|
|
resolved = CoreferenceResolver().resolve(text)
|
|
relations = RelationExtractor().extract(resolved, entities) or []
|
|
result["relations"] = [
|
|
{"source": getattr(r, "source", None),
|
|
"type": getattr(r, "type", None),
|
|
"target": getattr(r, "target", None)}
|
|
for r in relations
|
|
]
|
|
|
|
if include_events:
|
|
events = EventDetector().extract(text) or []
|
|
result["events"] = [
|
|
{"type": getattr(ev, "type", None),
|
|
"trigger": getattr(ev, "trigger", str(ev))}
|
|
for ev in events
|
|
]
|
|
|
|
if include_triplets:
|
|
triplets = TripletExtractor().extract(resolved) or []
|
|
result["triplets"] = [
|
|
{"subject": getattr(t, "subject", None),
|
|
"predicate": getattr(t, "predicate", None),
|
|
"object": getattr(t, "object", None)}
|
|
for t in triplets
|
|
]
|
|
|
|
result["summary"] = {
|
|
"entities": len(result.get("entities", [])),
|
|
"relations": len(result.get("relations", [])),
|
|
"events": len(result.get("events", [])),
|
|
"triplets": len(result.get("triplets", [])),
|
|
}
|
|
return result
|
|
except Exception as exc:
|
|
log.exception("extract_all failed")
|
|
return {"error": str(exc)}
|
|
|
|
|
|
EXTRACTION_TOOLS = [
|
|
{
|
|
"name": "extract_entities",
|
|
"description": "Extract named entities (people, places, organisations, concepts) from text.",
|
|
"inputSchema": EXTRACT_ENTITIES,
|
|
"_handler": handle_extract_entities,
|
|
},
|
|
{
|
|
"name": "extract_relations",
|
|
"description": "Extract relations and (subject, predicate, object) triplets from text.",
|
|
"inputSchema": EXTRACT_RELATIONS,
|
|
"_handler": handle_extract_relations,
|
|
},
|
|
{
|
|
"name": "extract_all",
|
|
"description": "Run the full Semantica extraction pipeline: NER, coreference resolution, relation extraction, event detection, and triplet generation.",
|
|
"inputSchema": EXTRACT_ALL,
|
|
"_handler": handle_extract_all,
|
|
},
|
|
]
|