File size: 3,258 Bytes
656439d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Contextual Retrieval — chunk-situating context prepended before embedding.

Offline: a fake LLM supplies deterministic contexts; asserts context is applied
to the embedded text but never to display/citation, and that it's gated off by
default and idempotent.
"""

from __future__ import annotations

from auralynq.config import get_settings, reload_settings
from auralynq.ingest.models import Chunk, Document, SourceType


class _FakeLLM:
    name = "fake"

    def __init__(self):
        self.calls = 0

    def generate(self, prompt, **kw):
        self.calls += 1
        return "This chunk is from the FRAND licensing section of the Ericsson report."


def _doc(n_chunks=3):
    chunks = [
        Chunk(
            id=Chunk.make_id("d1", i),
            doc_id="d1",
            text=f"Sentence number {i} about Ericsson patents.",
            ordinal=i,
            source="e.pdf",
            source_type=SourceType.html,
        )
        for i in range(n_chunks)
    ]
    return Document(
        id="d1",
        source="e.pdf",
        source_type=SourceType.html,
        title="Ericsson",
        content_hash="h",
        chunks=chunks,
    )


def test_embed_text_prepends_context_only_when_present():
    c = Chunk(id="x", doc_id="d", text="raw body")
    assert c.embed_text() == "raw body"
    c.context = "situating context"
    assert c.embed_text() == "situating context\n\nraw body"
    # display/citation text is untouched
    assert c.text == "raw body"


def test_contextual_disabled_by_default():
    reload_settings()
    assert get_settings().retrieval.contextual_enabled is False


def test_contextualize_sets_context_and_is_idempotent():
    from auralynq.ingest.contextualize import contextualize_document

    doc = _doc(3)
    llm = _FakeLLM()
    done = contextualize_document(doc, llm=llm)
    assert done == 3
    assert all(c.context for c in doc.chunks)
    assert all("FRAND licensing section" in c.context for c in doc.chunks)
    # embedded text carries context; raw text unchanged
    assert doc.chunks[0].embed_text().startswith("This chunk is from")
    assert doc.chunks[0].text == "Sentence number 0 about Ericsson patents."
    # idempotent: already-set contexts are not re-generated
    again = contextualize_document(doc, llm=llm)
    assert again == 0 and llm.calls == 3


def test_index_documents_contextualizes_when_enabled(monkeypatch):
    from auralynq.vectorstore.factory import get_store

    monkeypatch.setenv("AURALYNQ_RETRIEVAL__CONTEXTUAL_ENABLED", "true")
    reload_settings()
    get_store.cache_clear()
    llm = _FakeLLM()
    monkeypatch.setattr("auralynq.llm.factory.get_llm", lambda: llm)

    from auralynq.pipeline import index_documents

    doc = _doc(2)
    stats = index_documents([doc])
    assert stats["chunks_indexed"] == 2
    assert llm.calls == 2  # one per chunk
    # the in-memory chunks now carry context, but display text is unchanged
    assert all(c.context for c in doc.chunks)
    assert doc.chunks[0].text.startswith("Sentence number 0")

    # stored chunks keep the original display text (context is separate)
    stored = {c.id: c for c in get_store().all_chunks()}
    assert stored[doc.chunks[0].id].text == "Sentence number 0 about Ericsson patents."