vivamais / tests /unit /application /test_chunking.py
marinarosa's picture
Add Embedder port, corpus chunker, and hybrid retrieval logic
4de4c2e
Raw
History Blame Contribute Delete
4.84 kB
"""Chunker: deterministic, content-addressed retrieval documents."""
from __future__ import annotations
from datetime import datetime, timedelta
from pathlib import Path
from vivamais.adapters.persistence.inmemory import InMemoryRepository
from vivamais.application.chunking import (
MESSAGE_WINDOW_SIZE,
build_chunk_specs,
)
from vivamais.application.qa_context import customer_facts
from vivamais.domain.artifacts import (
ArtifactKind,
MediaArtifact,
PaymentProof,
)
from vivamais.domain.entities import Customer, Message
from vivamais.domain.enums import MessageKind
from vivamais.domain.money import Money
def _message(i: int, text: str = "", contact: str = "Maria Silva") -> Message:
return Message(
contact=contact,
kind=MessageKind.TEXT,
text=text or f"mensagem numero {i}",
media_path=None,
timestamp=datetime(2026, 5, 1, 10, 0) + timedelta(minutes=i),
from_me=i % 2 == 0,
)
def _repo_with_customer() -> InMemoryRepository:
repo = InMemoryRepository()
repo.save_customer(Customer(name="Maria Silva", contacts=["+55 11 99999-0000"]))
return repo
def test_facts_chunk_renders_customer_facts() -> None:
repo = _repo_with_customer()
repo.save_artifact(
MediaArtifact(
id="a1",
kind=ArtifactKind.PAYMENT_PROOF,
source_path="recibo.jpg",
full_transcription="PIX R$ 100,00",
customer_id="Maria Silva",
payload=PaymentProof(payer="Maria Silva", amount=Money(cents=10000)),
)
)
specs = build_chunk_specs(repo)
facts = [s for s in specs if s.chunk.source == "facts"]
assert len(facts) == 1
customer = repo.get_customer("Maria Silva")
assert customer is not None
assert facts[0].chunk.text == customer_facts(repo, customer)
assert facts[0].chunk.id.startswith("facts:Maria Silva:")
assert facts[0].chunk.customer_id == "Maria Silva"
def test_message_windows_overlap_and_cover_all_messages() -> None:
repo = _repo_with_customer()
for i in range(20):
repo.save_message(_message(i))
windows = [s.chunk for s in build_chunk_specs(repo) if s.chunk.source == "messages"]
assert len(windows) == 2
assert "mensagem numero 0" in windows[0].text
assert "mensagem numero 19" in windows[-1].text
assert "mensagem numero 8" in windows[0].text or len(windows[0].text.splitlines()) <= (
MESSAGE_WINDOW_SIZE
)
def test_chunk_ids_are_stable_across_runs() -> None:
repo = _repo_with_customer()
for i in range(5):
repo.save_message(_message(i))
first = {s.chunk.id for s in build_chunk_specs(repo)}
second = {s.chunk.id for s in build_chunk_specs(repo)}
assert first == second
def test_appending_a_message_changes_only_tail_window_ids() -> None:
repo = _repo_with_customer()
for i in range(5):
repo.save_message(_message(i))
before = {s.chunk.id for s in build_chunk_specs(repo)}
repo.save_message(_message(5))
after = {s.chunk.id for s in build_chunk_specs(repo)}
assert before != after
assert all(cid.split(":")[0] in {"facts", "msg", "art"} for cid in after)
def test_artifact_chunk_degrades_to_text_when_media_missing(tmp_path: Path) -> None:
repo = _repo_with_customer()
repo.save_artifact(
MediaArtifact(
id="a1",
kind=ArtifactKind.PAYMENT_PROOF,
source_path="recibo-sumido.jpg",
full_transcription="PIX R$ 250,00 Maria Silva",
customer_id="Maria Silva",
payload=PaymentProof(payer="Maria Silva", amount=Money(cents=25000)),
)
)
specs = [
s for s in build_chunk_specs(repo, media_dir=str(tmp_path)) if s.chunk.id.startswith("art:")
]
assert len(specs) == 1
assert specs[0].image is None
assert "PIX R$ 250,00" in specs[0].chunk.text
assert "Documento PAYMENT_PROOF" in specs[0].chunk.text
assert "pagador Maria Silva" in specs[0].chunk.text
def test_artifact_chunk_carries_image_bytes_when_file_exists(tmp_path: Path) -> None:
media_dir = tmp_path
(media_dir / "recibo.jpg").write_bytes(b"fake-jpeg-bytes")
repo = _repo_with_customer()
repo.save_artifact(
MediaArtifact(
id="a1",
kind=ArtifactKind.PAYMENT_PROOF,
source_path="recibo.jpg",
full_transcription="PIX",
customer_id="Maria Silva",
payload=PaymentProof(payer="Maria Silva", amount=Money(cents=100)),
)
)
specs = [
s
for s in build_chunk_specs(repo, media_dir=str(media_dir))
if s.chunk.id.startswith("art:")
]
assert specs[0].image == b"fake-jpeg-bytes"
def test_empty_repo_yields_no_chunks() -> None:
assert build_chunk_specs(InMemoryRepository()) == []