Files
mem0ai--mem0/tests/utils/test_entity_extraction.py
wehub-resource-sync 555e282cc4
ci / changelog_check (push) Waiting to run
ci / check_changes (push) Waiting to run
ci / build_mem0 (3.10) (push) Blocked by required conditions
ci / build_mem0 (3.11) (push) Blocked by required conditions
ci / build_mem0 (3.12) (push) Blocked by required conditions
CLI Node CI / lint (push) Waiting to run
CLI Node CI / test (20) (push) Waiting to run
CLI Node CI / test (22) (push) Waiting to run
CLI Node CI / build (push) Waiting to run
CLI Python CI / lint (push) Waiting to run
CLI Python CI / test (3.10) (push) Waiting to run
CLI Python CI / test (3.11) (push) Waiting to run
CLI Python CI / test (3.12) (push) Waiting to run
CLI Python CI / build (push) Waiting to run
openclaw checks / lint (push) Waiting to run
openclaw checks / test (20) (push) Waiting to run
openclaw checks / test (22) (push) Waiting to run
openclaw checks / build (push) Waiting to run
opencode-plugin checks / build (push) Waiting to run
pi-agent-plugin checks / lint (push) Waiting to run
pi-agent-plugin checks / test (20) (push) Waiting to run
pi-agent-plugin checks / test (22) (push) Waiting to run
pi-agent-plugin checks / build (push) Waiting to run
TypeScript SDK CI / check_changes (push) Waiting to run
TypeScript SDK CI / changelog_check (push) Blocked by required conditions
TypeScript SDK CI / build_ts_sdk (20) (push) Blocked by required conditions
TypeScript SDK CI / build_ts_sdk (22) (push) Blocked by required conditions
TypeScript SDK CI / integration_ts_sdk (20) (push) Blocked by required conditions
TypeScript SDK CI / integration_ts_sdk (22) (push) Blocked by required conditions
chore: import upstream snapshot with attribution
2026-07-13 13:03:45 +08:00

142 lines
5.7 KiB
Python

import pytest
@pytest.fixture(autouse=True)
def _ensure_spacy():
"""Skip tests if spaCy model is not available."""
try:
import spacy
spacy.load("en_core_web_sm")
except Exception:
pytest.skip("spaCy en_core_web_sm model not available")
class TestExtractEntities:
def test_proper_nouns(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("John Smith works at Google on machine learning projects")
entity_texts = [e[1] for e in entities]
# Should extract proper nouns
found_proper = any("John" in t or "Google" in t for t in entity_texts)
assert found_proper, f"Expected proper nouns, got {entities}"
def test_quoted_text(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities('She is reading "The Great Gatsby" this week')
entity_texts = [e[1] for e in entities]
assert any("Great Gatsby" in t for t in entity_texts), f"Expected quoted text, got {entities}"
def test_compound_nouns(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("The machine learning engineer built a neural network")
entity_texts = [e[1].lower() for e in entities]
has_compound = any("machine" in t and "learning" in t for t in entity_texts) or any(
"neural" in t and "network" in t for t in entity_texts
)
assert has_compound, f"Expected compound nouns, got {entities}"
def test_empty_string(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("")
assert entities == []
def test_no_entities(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("I like things and stuff")
# Generic words should be filtered out
entity_texts = [e[1].lower() for e in entities]
assert "things" not in entity_texts
assert "stuff" not in entity_texts
def test_deduplication(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("Google is great. I love working at Google.")
google_count = sum(1 for _, t in entities if "Google" in t)
assert google_count <= 1, f"Expected dedup, got {entities}"
def test_substring_dedup_respects_word_boundaries(self):
from mem0.utils.entity_extraction import extract_entities
# "Sam" is a mid-word substring of "Samsung", not a separate token, so it
# must not be dropped as a substring of the longer entity.
entities = extract_entities("At Samsung, Sam leads design.")
entity_texts = [e[1] for e in entities]
assert "Sam" in entity_texts, f"Expected 'Sam' to survive alongside 'Samsung', got {entities}"
assert any("Samsung" in t for t in entity_texts), f"Expected 'Samsung', got {entities}"
def test_returns_tuples(self):
from mem0.utils.entity_extraction import extract_entities
entities = extract_entities("John Smith lives in New York City")
for entity in entities:
assert isinstance(entity, tuple)
assert len(entity) == 2
assert entity[0] in ("PROPER", "QUOTED", "TOPIC", "IDENTIFIER")
assert isinstance(entity[1], str)
def test_handles_names_lists_and_identifiers(self):
from mem0.utils.entity_extraction import extract_entities
text = (
"User reported top inbound integration pages: OpenClaw 25,443, "
"Claude Code 8,916, Codex 2,573, Dify 656. "
"User compared Cartesia and Deepgram. "
"The email field for Mem0 lives at person.properties.email. "
"The qwen endpoint uses person.properties.email. "
"Johnson & Johnson was mentioned. "
"Glasses around my window. "
"On 2026-05-27 there were 90 days of stats."
)
entities = extract_entities(text)
entity_texts = {entity_text for _, entity_text in entities}
normalized = {entity_text.lower() for entity_text in entity_texts}
assert {"OpenClaw", "Claude Code", "Codex", "Dify", "Cartesia", "Deepgram", "Mem0"}.issubset(entity_texts)
assert "person.properties.email" in entity_texts
assert "qwen endpoint" in entity_texts
assert "Johnson & Johnson" in entity_texts
assert "top" not in normalized
assert "glasses" not in normalized
assert "Cartesia and Deepgram" not in entity_texts
assert "Claude Code 8,916" not in entity_texts
assert not {"8,916", "2,573", "656", "2026-05-27", "90"}.intersection(entity_texts)
class TestExtractEntitiesBatch:
def test_batch_processing(self):
from mem0.utils.entity_extraction import extract_entities_batch
texts = [
"John works at Google",
"Mary lives in Paris",
"The cat sat on the mat",
]
results = extract_entities_batch(texts)
assert len(results) == 3
assert isinstance(results[0], list)
assert isinstance(results[1], list)
assert isinstance(results[2], list)
def test_empty_input(self):
from mem0.utils.entity_extraction import extract_entities_batch
assert extract_entities_batch([]) == []
def test_consistency_with_single(self):
from mem0.utils.entity_extraction import extract_entities, extract_entities_batch
text = "John Smith works at Google headquarters"
single = extract_entities(text)
batch = extract_entities_batch([text])
assert len(batch) == 1
# Both should extract the same entities
assert set(t for _, t in single) == set(t for _, t in batch[0])