mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from semantica.semantic_extract.ner_extractor import Entity, NERExtractor
|
|
from semantica.semantic_extract.semantic_analyzer import SemanticAnalyzer
|
|
|
|
|
|
# Fixtures
|
|
@pytest.fixture
|
|
def document_batch():
|
|
base = "The quick brown fox jumps over the lazy dog."
|
|
docs = [
|
|
f"{base} Variation {i}. Apple Inc released a product in 2024."
|
|
for i in range(50)
|
|
]
|
|
return docs
|
|
|
|
|
|
# Fast wrapper-only benchmark (always runs)
|
|
def test_ner_ml_wrapper_overhead(benchmark, long_text_string):
|
|
extractor = NERExtractor(method="ml", model="en_core_web_sm")
|
|
|
|
entity_text = "Semantica"
|
|
phrase = f"{entity_text} is a knowledge graph framework. "
|
|
medium_text = phrase * 5
|
|
|
|
expected_entities = []
|
|
phrase_len = len(phrase)
|
|
for i in range(5):
|
|
start = i * phrase_len
|
|
end = start + len(entity_text)
|
|
ent = Entity(
|
|
text=entity_text,
|
|
label="ORG",
|
|
start_char=start,
|
|
end_char=end,
|
|
confidence=0.98,
|
|
metadata={"lemma": entity_text},
|
|
)
|
|
expected_entities.append(ent)
|
|
|
|
def custom_ml_extraction(text: str, **method_options):
|
|
min_confidence = method_options.get("min_confidence", 0.5)
|
|
entity_types = method_options.get("entity_types")
|
|
filtered = []
|
|
for ent in expected_entities:
|
|
if entity_types and ent.label not in entity_types:
|
|
continue
|
|
if ent.confidence >= min_confidence:
|
|
filtered.append(ent)
|
|
return filtered
|
|
|
|
with patch(
|
|
"semantica.semantic_extract.methods.get_entity_method"
|
|
) as mock_get_method:
|
|
mock_get_method.side_effect = lambda name: (
|
|
custom_ml_extraction if name == "ml" else (lambda t, **o: [])
|
|
)
|
|
|
|
def op():
|
|
return extractor.extract_entities(text=medium_text)
|
|
|
|
result = benchmark.pedantic(op, rounds=20, iterations=5)
|
|
|
|
assert len(result) == 5
|
|
assert all(e.text == "Semantica" for e in result)
|
|
assert all(e.label == "ORG" for e in result)
|
|
assert all(e.confidence == 0.98 for e in result)
|
|
assert all(medium_text[e.start_char : e.end_char] == e.text for e in result)
|
|
|
|
|
|
# Real spaCy benchmark
|
|
@pytest.mark.benchmark(group="ner_real_ml")
|
|
def test_ner_ml_real_performance(benchmark, long_text_string):
|
|
"""
|
|
Full spaCy inference + wrapper overhead.
|
|
Only runs when real spaCy is loaded (BENCHMARK_REAL_LIBS=1).
|
|
"""
|
|
extractor = NERExtractor(method="ml", model="en_core_web_sm")
|
|
|
|
if (
|
|
extractor.nlp is None
|
|
or not hasattr(extractor.nlp, "pipe_names")
|
|
or "ner" not in extractor.nlp.pipe_names
|
|
):
|
|
pytest.skip(
|
|
"Real spaCy NER pipeline not available — skipping production benchmark"
|
|
)
|
|
|
|
medium_text = long_text_string[:10000]
|
|
|
|
medium_text += " Apple Inc. was founded by Steve Jobs and Steve Wozniak in Cupertino, California on April 1, 1976. Microsoft is a competitor."
|
|
|
|
def op():
|
|
return extractor.extract_entities(text=medium_text)
|
|
|
|
result = benchmark.pedantic(op, rounds=6, iterations=2)
|
|
|
|
assert len(result) >= 6
|
|
assert any("Apple" in e.text and e.label == "ORG" for e in result)
|
|
assert any(e.label == "PERSON" for e in result)
|
|
assert any(e.label in {"GPE", "LOC"} for e in result)
|
|
assert any(e.label == "DATE" for e in result)
|
|
assert any("Microsoft" in e.text and e.label == "ORG" for e in result)
|
|
|
|
|
|
def test_ner_pattern_speed(benchmark, long_text_string):
|
|
extractor = NERExtractor(method="pattern")
|
|
medium_text = long_text_string[:50000]
|
|
text_with_entities = medium_text + " Apple Inc. was founded in 1976. "
|
|
|
|
def op():
|
|
return extractor.extract_entities(text=text_with_entities)
|
|
|
|
result = benchmark.pedantic(op, rounds=20, iterations=5)
|
|
assert len(result) > 0
|
|
assert result[0].label in ["ORG", "DATE", "UNKNOWN"]
|
|
|
|
|
|
def test_ner_batch_throughput(benchmark, document_batch):
|
|
extractor = NERExtractor(method="pattern")
|
|
|
|
def run_batch():
|
|
return extractor.extract_entities_batch(document_batch, max_workers=2)
|
|
|
|
result = benchmark.pedantic(run_batch, rounds=10, iterations=5)
|
|
assert len(result) == len(document_batch)
|
|
assert len(result[0]) > 0
|
|
|
|
|
|
def test_similarity_calculation(benchmark):
|
|
analyzer = SemanticAnalyzer()
|
|
text1 = "The quick brown fox jumps over the lazy dog" * 10
|
|
text2 = "The slow brown fox jumped over the sleeping dog" * 10
|
|
|
|
def op():
|
|
return analyzer.calculate_similarity(text1, text2, method="jaccard")
|
|
|
|
result = benchmark.pedantic(op, rounds=100, iterations=100)
|
|
assert 0.0 <= result <= 1.0
|
|
|
|
|
|
def test_clustering_algorithm(benchmark, document_batch):
|
|
analyzer = SemanticAnalyzer()
|
|
options = {"similarity_threshold": 0.1}
|
|
|
|
def op():
|
|
return analyzer.cluster_semantically(texts=document_batch, **options)
|
|
|
|
result = benchmark.pedantic(op, rounds=10, iterations=5)
|
|
assert len(result) > 0
|
|
assert result[0].texts
|