mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-09 04:00:52 +00:00
11 KiB
11 KiB
In [ ]:
%pip install semantica
# spaCy models are distributed separately from the spaCy library. This lesson
# relies on the English model to recognize standalone places such as Cupertino.
import sys
import subprocess
import spacy
try:
spacy.load("en_core_web_sm")
except OSError:
subprocess.check_call([sys.executable, "-m", "spacy", "download", "en_core_web_sm"])
In [ ]:
from semantica.semantic_extract import NERExtractor, RelationExtractor
text = (
"Apple Inc. is headquartered in Cupertino, California. "
"Tim Cook is the CEO of Apple Inc. "
"The company is a technology company."
)
ner_extractor = NERExtractor()
relation_extractor = RelationExtractor()
mentions = ner_extractor.extract(text)
relations = relation_extractor.extract(text, mentions)
print("Entity mentions:")
for mention in mentions:
print(f" {mention.text!r:<13} {mention.label:<7} span=[{mention.start_char}:{mention.end_char}]")
print("\nExtracted relations:")
for rel in relations:
print(f" {rel.subject.text!r} --{rel.predicate}--> {rel.object.text!r}")In [ ]:
from semantica.kg import GraphBuilder
entities = []
span_to_id = {}
for i, mention in enumerate(mentions, 1):
graph_id = f"e{i}"
span_to_id[(mention.start_char, mention.end_char)] = graph_id
entities.append({
"id": graph_id,
"type": mention.label,
"name": mention.text,
"properties": {},
})
relationships = []
for rel in relations:
source_id = span_to_id.get((rel.subject.start_char, rel.subject.end_char))
target_id = span_to_id.get((rel.object.start_char, rel.object.end_char))
if source_id is None or target_id is None:
print(f"Skipping relation with unmapped endpoint: "
f"{rel.subject.text!r} --{rel.predicate}--> {rel.object.text!r}")
continue
relationships.append({
"source": source_id,
"target": target_id,
"type": rel.predicate,
"properties": {},
})
builder = GraphBuilder()
knowledge_graph = builder.build({"entities": entities, "relationships": relationships})
id_to_name = {entity["id"]: entity["name"] for entity in entities}
print(f"Graph entities ({len(knowledge_graph['entities'])}):")
for entity in knowledge_graph["entities"]:
print(f" {entity['id']}: {entity['name']} ({entity['type']})")
print(f"\nGraph relationships ({len(knowledge_graph['relationships'])}):")
for relationship in knowledge_graph["relationships"]:
print(f" {id_to_name[relationship['source']]} "
f"--{relationship['type']}--> {id_to_name[relationship['target']]}")
edges = {
(id_to_name[r["source"]], r["type"], id_to_name[r["target"]])
for r in knowledge_graph["relationships"]
}
assert ("Apple Inc.", "located_in", "Cupertino") in edges
assert ("Tim Cook", "works_for", "Apple Inc.") in edgesIn [ ]:
from semantica.kg import EntityResolver
entity_resolver = EntityResolver()
resolved_entities = entity_resolver.resolve_entities(entities)
canonical_id = {}
for entity in resolved_entities:
for source_id in entity.get("merged_from", [entity["id"]]):
canonical_id[source_id] = entity["id"]
if entity.get("merged_from"):
print(f"Merged {entity['merged_from']} -> {entity['id']}: {entity['name']}")
print(f"\nMentions in: {len(entities)}, resolved entities out: {len(resolved_entities)}")
resolved_names = {entity["id"]: entity["name"] for entity in resolved_entities}
print("\nRelationships remapped onto canonical entities:")
for relationship in relationships:
source = canonical_id[relationship["source"]]
target = canonical_id[relationship["target"]]
print(f" {resolved_names[source]} --{relationship['type']}--> {resolved_names[target]}")
canonical_entities = {(entity["name"], entity["type"]) for entity in resolved_entities}
assert canonical_entities == {
("Apple Inc.", "ORG"),
("Tim Cook", "PERSON"),
("Cupertino", "GPE"),
("California", "GPE"),
}
assert len(resolved_entities) == 4In [ ]:
from semantica.deduplication import DuplicateDetector, EntityMerger, MergeStrategy
detector = DuplicateDetector(similarity_threshold=0.8)
duplicate_groups = detector.detect_duplicate_groups(entities)
print(f"Duplicate groups: {len(duplicate_groups)}")
for group in duplicate_groups:
print(f" {[entity['name'] for entity in group.entities]} "
f"(confidence={group.confidence:.2f})")
merger = EntityMerger()
merge_operations = merger.merge_duplicates(
entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE
)
merged_source_ids = {
entity["id"] for op in merge_operations for entity in op.source_entities
}
untouched_entities = [e for e in entities if e["id"] not in merged_source_ids]
deduplicated_entities = untouched_entities + [
op.merged_entity for op in merge_operations
]
print(f"\nMerge operations: {len(merge_operations)}")
print(f"Deduplicated entities ({len(deduplicated_entities)}):")
for entity in deduplicated_entities:
print(f" {entity['id']}: {entity['name']} ({entity['type']})")
assert len(merge_operations) == 1
assert len(deduplicated_entities) == 4