- Introduced `test_nlp_extractor.py` with unit tests for the InstitutionExtractor, covering various extraction patterns (ISIL, Wikidata, VIAF, city names) and ensuring proper classification of institutions (museum, library, archive). - Added tests for extracted entities and result handling to validate the extraction process. - Created `test_partnership_rdf_integration.py` to validate the end-to-end process of extracting partnerships from a conversation and exporting them to RDF format. - Implemented tests for temporal properties in partnerships and ensured compliance with W3C Organization Ontology patterns. - Verified that extracted partnerships are correctly linked with PROV-O provenance metadata.
164 lines
5.1 KiB
Python
164 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test integration of subagent NER with V5 validation methods.
|
|
|
|
This demonstrates how clean NER extraction (via subagent) combined with
|
|
V5 validation filters produces high-precision results.
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
from pathlib import Path
|
|
|
|
# Add project root to path
|
|
project_root = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(project_root / "src"))
|
|
|
|
from glam_extractor.extractors.nlp_extractor import InstitutionExtractor
|
|
|
|
|
|
# Simulated subagent NER output (clean, accurate names)
|
|
SUBAGENT_NER_OUTPUT = [
|
|
{
|
|
"name": "Van Abbemuseum",
|
|
"institution_type": "MUSEUM",
|
|
"city": "Eindhoven",
|
|
"country": "NL",
|
|
"isil_code": "NL-EhdVAM",
|
|
"confidence": 0.95
|
|
},
|
|
{
|
|
"name": "Zeeuws Archief",
|
|
"institution_type": "ARCHIVE",
|
|
"city": "Middelburg",
|
|
"country": "NL",
|
|
"isil_code": "NL-MdlZA",
|
|
"confidence": 0.95
|
|
},
|
|
{
|
|
"name": "Historisch Centrum Overijssel",
|
|
"institution_type": "ARCHIVE",
|
|
"city": "Zwolle",
|
|
"country": "NL",
|
|
"isil_code": "NL-ZwHCO",
|
|
"confidence": 0.95
|
|
},
|
|
{
|
|
"name": "National Museum of Malaysia",
|
|
"institution_type": "MUSEUM",
|
|
"city": "Kuala Lumpur",
|
|
"country": "MY",
|
|
"isil_code": None,
|
|
"confidence": 0.90
|
|
}
|
|
]
|
|
|
|
|
|
def test_v5_validation_on_clean_ner():
|
|
"""Test V5 validation methods on clean NER output"""
|
|
print("=" * 70)
|
|
print("Subagent NER + V5 Validation Integration Test")
|
|
print("=" * 70)
|
|
print()
|
|
|
|
# Initialize extractor to access V5 validation methods
|
|
extractor = InstitutionExtractor()
|
|
|
|
print("Input: Clean NER output from subagent (4 institutions)")
|
|
print("-" * 70)
|
|
for inst in SUBAGENT_NER_OUTPUT:
|
|
print(f" - {inst['name']} ({inst['institution_type']}, {inst['country']})")
|
|
print()
|
|
|
|
# Apply V5 validation filters
|
|
print("Applying V5 Validation Filters:")
|
|
print("-" * 70)
|
|
|
|
validated = []
|
|
filtered = []
|
|
|
|
for inst in SUBAGENT_NER_OUTPUT:
|
|
name = inst['name']
|
|
country = inst['country']
|
|
|
|
# Dummy sentence for context (in real implementation, this comes from text)
|
|
sentence = f"The {name} in {inst['city']} is a renowned heritage institution."
|
|
|
|
# V5 Filter 1: Organization/Network check
|
|
if extractor._is_organization_or_network(name, sentence):
|
|
print(f" ✗ Filtered: {name} (organization/network)")
|
|
filtered.append((name, "organization/network"))
|
|
continue
|
|
|
|
# V5 Filter 2: Proper institutional name check
|
|
if not extractor._is_proper_institutional_name(name, sentence):
|
|
print(f" ✗ Filtered: {name} (improper name)")
|
|
filtered.append((name, "improper name"))
|
|
continue
|
|
|
|
# V5 Filter 3: Country validation (assuming Dutch focus)
|
|
expected_country = extractor._infer_country_from_name("Netherlands_GLAM_test")
|
|
if expected_country and country != expected_country:
|
|
print(f" ✗ Filtered: {name} (wrong country: {country} != {expected_country})")
|
|
filtered.append((name, f"wrong country: {country}"))
|
|
continue
|
|
|
|
# Passed all filters
|
|
print(f" ✓ Valid: {name}")
|
|
validated.append(inst)
|
|
|
|
print()
|
|
print("=" * 70)
|
|
print("Results:")
|
|
print("=" * 70)
|
|
print()
|
|
|
|
print(f"Input: 4 institutions")
|
|
print(f"Validated: {len(validated)} institutions")
|
|
print(f"Filtered: {len(filtered)} institutions")
|
|
print()
|
|
|
|
print("Validated Institutions:")
|
|
for inst in validated:
|
|
print(f" ✓ {inst['name']} ({inst['institution_type']}, {inst['city']}, {inst['country']})")
|
|
print()
|
|
|
|
if filtered:
|
|
print("Filtered Institutions:")
|
|
for name, reason in filtered:
|
|
print(f" ✗ {name} (reason: {reason})")
|
|
print()
|
|
|
|
# Calculate precision
|
|
expected_valid = ["Van Abbemuseum", "Zeeuws Archief", "Historisch Centrum Overijssel"]
|
|
correct_extractions = [inst for inst in validated if inst['name'] in expected_valid]
|
|
|
|
precision = len(correct_extractions) / len(SUBAGENT_NER_OUTPUT) * 100
|
|
|
|
print("=" * 70)
|
|
print("Precision Analysis:")
|
|
print("=" * 70)
|
|
print()
|
|
print(f"Expected to extract: 3 Dutch institutions")
|
|
print(f"Actually extracted: {len(validated)} institutions")
|
|
print(f"Correct extractions: {len(correct_extractions)}")
|
|
print(f"Precision: {precision:.1f}% ({len(correct_extractions)}/{len(SUBAGENT_NER_OUTPUT)})")
|
|
print()
|
|
|
|
# Compare to V4 baseline
|
|
print("V4 Baseline: 50.0% precision (6/12 valid, 6 false positives)")
|
|
print("V4 Test (pattern-based): 0.0% precision (0/7, names mangled)")
|
|
print(f"V5 (subagent NER + validation): {precision:.1f}% precision")
|
|
print()
|
|
|
|
if precision >= 75.0:
|
|
print("✓ V5 ACHIEVES ≥75% precision target!")
|
|
return True
|
|
else:
|
|
print(f"✗ V5 below 75% target (achieved {precision:.1f}%)")
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
success = test_v5_validation_on_clean_ner()
|
|
sys.exit(0 if success else 1)
|