haiku.rag 0.5.1__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of haiku.rag might be problematic. Click here for more details.
- haiku/rag/app.py +2 -2
- haiku/rag/cli.py +2 -2
- haiku/rag/client.py +4 -3
- haiku/rag/config.py +2 -3
- haiku/rag/reranking/__init__.py +19 -16
- haiku/rag/reranking/ollama.py +84 -0
- {haiku_rag-0.5.1.dist-info → haiku_rag-0.5.2.dist-info}/METADATA +4 -3
- {haiku_rag-0.5.1.dist-info → haiku_rag-0.5.2.dist-info}/RECORD +11 -10
- {haiku_rag-0.5.1.dist-info → haiku_rag-0.5.2.dist-info}/WHEEL +0 -0
- {haiku_rag-0.5.1.dist-info → haiku_rag-0.5.2.dist-info}/entry_points.txt +0 -0
- {haiku_rag-0.5.1.dist-info → haiku_rag-0.5.2.dist-info}/licenses/LICENSE +0 -0
haiku/rag/app.py
CHANGED
|
@@ -32,9 +32,9 @@ class HaikuRAGApp:
|
|
|
32
32
|
f"[b]Document with id [cyan]{doc.id}[/cyan] added successfully.[/b]"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
async def add_document_from_source(self,
|
|
35
|
+
async def add_document_from_source(self, source: str):
|
|
36
36
|
async with HaikuRAG(db_path=self.db_path) as self.client:
|
|
37
|
-
doc = await self.client.create_document_from_source(
|
|
37
|
+
doc = await self.client.create_document_from_source(source)
|
|
38
38
|
self._rich_print_document(doc, truncate=True)
|
|
39
39
|
self.console.print(
|
|
40
40
|
f"[b]Document with id [cyan]{doc.id}[/cyan] added successfully.[/b]"
|
haiku/rag/cli.py
CHANGED
|
@@ -81,7 +81,7 @@ def add_document_text(
|
|
|
81
81
|
|
|
82
82
|
@cli.command("add-src", help="Add a document from a file path or URL")
|
|
83
83
|
def add_document_src(
|
|
84
|
-
|
|
84
|
+
source: str = typer.Argument(
|
|
85
85
|
help="The file path or URL of the document to add",
|
|
86
86
|
),
|
|
87
87
|
db: Path = typer.Option(
|
|
@@ -91,7 +91,7 @@ def add_document_src(
|
|
|
91
91
|
),
|
|
92
92
|
):
|
|
93
93
|
app = HaikuRAGApp(db_path=db)
|
|
94
|
-
asyncio.run(app.add_document_from_source(
|
|
94
|
+
asyncio.run(app.add_document_from_source(source=source))
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
@cli.command("get", help="Get and display a document by its ID")
|
haiku/rag/client.py
CHANGED
|
@@ -319,7 +319,7 @@ class HaikuRAG:
|
|
|
319
319
|
return await self.document_repository.list_all(limit=limit, offset=offset)
|
|
320
320
|
|
|
321
321
|
async def search(
|
|
322
|
-
self, query: str, limit: int = 5, k: int = 60
|
|
322
|
+
self, query: str, limit: int = 5, k: int = 60
|
|
323
323
|
) -> list[tuple[Chunk, float]]:
|
|
324
324
|
"""Search for relevant chunks using hybrid search (vector similarity + full-text search) with reranking.
|
|
325
325
|
|
|
@@ -331,8 +331,10 @@ class HaikuRAG:
|
|
|
331
331
|
Returns:
|
|
332
332
|
List of (chunk, score) tuples ordered by relevance.
|
|
333
333
|
"""
|
|
334
|
+
# Get reranker if available
|
|
335
|
+
reranker = get_reranker()
|
|
334
336
|
|
|
335
|
-
if
|
|
337
|
+
if reranker is None:
|
|
336
338
|
return await self.chunk_repository.search_chunks_hybrid(query, limit, k)
|
|
337
339
|
|
|
338
340
|
# Get more initial results (3X) for reranking
|
|
@@ -340,7 +342,6 @@ class HaikuRAG:
|
|
|
340
342
|
query, limit * 3, k
|
|
341
343
|
)
|
|
342
344
|
# Apply reranking
|
|
343
|
-
reranker = get_reranker()
|
|
344
345
|
chunks = [chunk for chunk, _ in search_results]
|
|
345
346
|
reranked_results = await reranker.rerank(query, chunks, top_n=limit)
|
|
346
347
|
|
haiku/rag/config.py
CHANGED
|
@@ -19,9 +19,8 @@ class AppConfig(BaseModel):
|
|
|
19
19
|
EMBEDDINGS_MODEL: str = "mxbai-embed-large"
|
|
20
20
|
EMBEDDINGS_VECTOR_DIM: int = 1024
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
RERANK_MODEL: str = "mixedbread-ai/mxbai-rerank-base-v2"
|
|
22
|
+
RERANK_PROVIDER: str = "ollama"
|
|
23
|
+
RERANK_MODEL: str = "qwen3"
|
|
25
24
|
|
|
26
25
|
QA_PROVIDER: str = "ollama"
|
|
27
26
|
QA_MODEL: str = "qwen3"
|
haiku/rag/reranking/__init__.py
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
from haiku.rag.config import Config
|
|
2
2
|
from haiku.rag.reranking.base import RerankerBase
|
|
3
3
|
|
|
4
|
-
try:
|
|
5
|
-
from haiku.rag.reranking.cohere import CohereReranker
|
|
6
|
-
except ImportError:
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
4
|
_reranker: RerankerBase | None = None
|
|
10
5
|
|
|
11
6
|
|
|
12
|
-
def get_reranker() -> RerankerBase:
|
|
7
|
+
def get_reranker() -> RerankerBase | None:
|
|
13
8
|
"""
|
|
14
9
|
Factory function to get the appropriate reranker based on the configuration.
|
|
10
|
+
Returns None if if reranking is disabled.
|
|
15
11
|
"""
|
|
16
12
|
global _reranker
|
|
17
13
|
if _reranker is not None:
|
|
18
14
|
return _reranker
|
|
15
|
+
|
|
19
16
|
if Config.RERANK_PROVIDER == "mxbai":
|
|
20
|
-
|
|
17
|
+
try:
|
|
18
|
+
from haiku.rag.reranking.mxbai import MxBAIReranker
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
_reranker = MxBAIReranker()
|
|
21
|
+
return _reranker
|
|
22
|
+
except ImportError:
|
|
23
|
+
return None
|
|
24
24
|
|
|
25
25
|
if Config.RERANK_PROVIDER == "cohere":
|
|
26
26
|
try:
|
|
27
27
|
from haiku.rag.reranking.cohere import CohereReranker
|
|
28
|
+
|
|
29
|
+
_reranker = CohereReranker()
|
|
30
|
+
return _reranker
|
|
28
31
|
except ImportError:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
_reranker =
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
if Config.RERANK_PROVIDER == "ollama":
|
|
35
|
+
from haiku.rag.reranking.ollama import OllamaReranker
|
|
36
|
+
|
|
37
|
+
_reranker = OllamaReranker()
|
|
35
38
|
return _reranker
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
return None
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from ollama import AsyncClient
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from haiku.rag.config import Config
|
|
7
|
+
from haiku.rag.reranking.base import RerankerBase
|
|
8
|
+
from haiku.rag.store.models.chunk import Chunk
|
|
9
|
+
|
|
10
|
+
OLLAMA_OPTIONS = {"temperature": 0.0, "seed": 42, "num_ctx": 16384}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RerankResult(BaseModel):
|
|
14
|
+
"""Individual rerank result with index and relevance score."""
|
|
15
|
+
|
|
16
|
+
index: int
|
|
17
|
+
relevance_score: float
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RerankResponse(BaseModel):
|
|
21
|
+
"""Response from the reranking model containing ranked results."""
|
|
22
|
+
|
|
23
|
+
results: list[RerankResult]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OllamaReranker(RerankerBase):
|
|
27
|
+
def __init__(self, model: str = Config.RERANK_MODEL):
|
|
28
|
+
self._model = model
|
|
29
|
+
self._client = AsyncClient(host=Config.OLLAMA_BASE_URL)
|
|
30
|
+
|
|
31
|
+
async def rerank(
|
|
32
|
+
self, query: str, chunks: list[Chunk], top_n: int = 10
|
|
33
|
+
) -> list[tuple[Chunk, float]]:
|
|
34
|
+
if not chunks:
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
documents = []
|
|
38
|
+
for i, chunk in enumerate(chunks):
|
|
39
|
+
documents.append({"index": i, "content": chunk.content})
|
|
40
|
+
|
|
41
|
+
# Create the prompt for reranking
|
|
42
|
+
system_prompt = """You are a document reranking assistant. Given a query and a list of document chunks, you must rank them by relevance to the query.
|
|
43
|
+
|
|
44
|
+
Return your response as a JSON object with a "results" array. Each result should have:
|
|
45
|
+
- "index": the original index of the document (integer)
|
|
46
|
+
- "relevance_score": a score between 0.0 and 1.0 indicating relevance (float, where 1.0 is most relevant)
|
|
47
|
+
|
|
48
|
+
Only return the top documents up to the requested limit, ordered by decreasing relevance score."""
|
|
49
|
+
|
|
50
|
+
documents_text = ""
|
|
51
|
+
for doc in documents:
|
|
52
|
+
documents_text += f"Index {doc['index']}: {doc['content']}\n\n"
|
|
53
|
+
|
|
54
|
+
user_prompt = f"""Query: {query}
|
|
55
|
+
|
|
56
|
+
Documents to rerank:
|
|
57
|
+
{documents_text.strip()}
|
|
58
|
+
|
|
59
|
+
Please rank these documents by relevance to the query and return the top {top_n} results as JSON."""
|
|
60
|
+
|
|
61
|
+
messages = [
|
|
62
|
+
{"role": "system", "content": system_prompt},
|
|
63
|
+
{"role": "user", "content": user_prompt},
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
response = await self._client.chat(
|
|
68
|
+
model=self._model,
|
|
69
|
+
messages=messages,
|
|
70
|
+
format=RerankResponse.model_json_schema(),
|
|
71
|
+
options=OLLAMA_OPTIONS,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
content = response["message"]["content"]
|
|
75
|
+
|
|
76
|
+
parsed_response = RerankResponse.model_validate(json.loads(content))
|
|
77
|
+
return [
|
|
78
|
+
(chunks[result.index], result.relevance_score)
|
|
79
|
+
for result in parsed_response.results[:top_n]
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
except Exception:
|
|
83
|
+
# Fallback: return chunks in original order with same score
|
|
84
|
+
return [(chunks[i], 1.0) for i in range(min(top_n, len(chunks)))]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haiku.rag
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Retrieval Augmented Generation (RAG) with SQLite
|
|
5
5
|
Author-email: Yiorgis Gozadinos <ggozadinos@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -21,8 +21,7 @@ Requires-Python: >=3.11
|
|
|
21
21
|
Requires-Dist: docling>=2.15.0
|
|
22
22
|
Requires-Dist: fastmcp>=2.8.1
|
|
23
23
|
Requires-Dist: httpx>=0.28.1
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist: ollama>=0.5.1
|
|
24
|
+
Requires-Dist: ollama>=0.5.3
|
|
26
25
|
Requires-Dist: pydantic>=2.11.7
|
|
27
26
|
Requires-Dist: python-dotenv>=1.1.0
|
|
28
27
|
Requires-Dist: rich>=14.0.0
|
|
@@ -34,6 +33,8 @@ Provides-Extra: anthropic
|
|
|
34
33
|
Requires-Dist: anthropic>=0.56.0; extra == 'anthropic'
|
|
35
34
|
Provides-Extra: cohere
|
|
36
35
|
Requires-Dist: cohere>=5.16.1; extra == 'cohere'
|
|
36
|
+
Provides-Extra: mxbai
|
|
37
|
+
Requires-Dist: mxbai-rerank>=0.1.6; extra == 'mxbai'
|
|
37
38
|
Provides-Extra: openai
|
|
38
39
|
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
39
40
|
Provides-Extra: voyageai
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
haiku/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
haiku/rag/app.py,sha256=
|
|
2
|
+
haiku/rag/app.py,sha256=kuvULOIdgwqzJMaKtb1znStc1YAqB1-RkZ0fwdg6TBk,7642
|
|
3
3
|
haiku/rag/chunker.py,sha256=PVe6ysv8UlacUd4Zb3_8RFWIaWDXnzBAy2VDJ4TaUsE,1555
|
|
4
|
-
haiku/rag/cli.py,sha256=
|
|
5
|
-
haiku/rag/client.py,sha256=
|
|
6
|
-
haiku/rag/config.py,sha256=
|
|
4
|
+
haiku/rag/cli.py,sha256=5CcWcBQ47KCZ1wl7DpLzMXtgJZ1nz5Hci8AYp72oXEI,5855
|
|
5
|
+
haiku/rag/client.py,sha256=K51l_orUc3BeKGTHX4xC7YClY9M4Eijpac5Hg1_q6LE,15815
|
|
6
|
+
haiku/rag/config.py,sha256=jiy5vg-YbYa7yY-834Dd9omFtfMBXQBYXmHRJXMPjrs,1581
|
|
7
7
|
haiku/rag/logging.py,sha256=zTTGpGq5tPdcd7RpCbd9EGw1IZlQDbYkrCg9t9pqRc4,580
|
|
8
8
|
haiku/rag/mcp.py,sha256=tMN6fNX7ZtAER1R6DL1GkC9HZozTC4HzuQs199p7icI,4551
|
|
9
9
|
haiku/rag/monitor.py,sha256=r386nkhdlsU8UECwIuVwnrSlgMk3vNIuUZGNIzkZuec,2770
|
|
@@ -20,10 +20,11 @@ haiku/rag/qa/base.py,sha256=4ZTM_l5FAZ9cA0f8NeqRJiUAmjatwCTmSoclFw0gTFQ,1349
|
|
|
20
20
|
haiku/rag/qa/ollama.py,sha256=EGUi4urSx9nrnsr5j-qHVDVOnvRTbSMKUbMvXEMIcxM,2381
|
|
21
21
|
haiku/rag/qa/openai.py,sha256=dF32sGgVt8mZi5oVxByaeECs9NqLjvDiZnnpJBsrHm8,3968
|
|
22
22
|
haiku/rag/qa/prompts.py,sha256=8uYMxHzbzI9vo2FPkCSSNTh_RNL96WkBbUWPCMBlLpo,1315
|
|
23
|
-
haiku/rag/reranking/__init__.py,sha256=
|
|
23
|
+
haiku/rag/reranking/__init__.py,sha256=fwC3pauteJwh9Ulm2270QvwAdwr4NMr4RUEuolC-wKU,1063
|
|
24
24
|
haiku/rag/reranking/base.py,sha256=LM9yUSSJ414UgBZhFTgxGprlRqzfTe4I1vgjricz2JY,405
|
|
25
25
|
haiku/rag/reranking/cohere.py,sha256=1iTdiaa8vvb6oHVB2qpWzUOVkyfUcimVSZp6Qr4aq4c,1049
|
|
26
26
|
haiku/rag/reranking/mxbai.py,sha256=46sVTsTIkzIX9THgM3u8HaEmgY7evvEyB-N54JTHvK8,867
|
|
27
|
+
haiku/rag/reranking/ollama.py,sha256=tCrLlNNDBCZu7J3to1gvBq-sOvN1flYEA7E3H3Jq0mU,2790
|
|
27
28
|
haiku/rag/store/__init__.py,sha256=hq0W0DAC7ysqhWSP2M2uHX8cbG6kbr-sWHxhq6qQcY0,103
|
|
28
29
|
haiku/rag/store/engine.py,sha256=cOMBToLilI1Di1qQrFzGLqtRMsuvtiX0Q5RNIEzQy9w,6232
|
|
29
30
|
haiku/rag/store/models/__init__.py,sha256=s0E72zneGlowvZrFWaNxHYjOAUjgWdLxzdYsnvNRVlY,88
|
|
@@ -36,8 +37,8 @@ haiku/rag/store/repositories/document.py,sha256=ki8LiDukwU1469Yw51i0rQFvBzUQeYkF
|
|
|
36
37
|
haiku/rag/store/repositories/settings.py,sha256=qZLXvLsErnCWL0nBQQNfRnatHzCKhtUDLvUK9k-W_fU,2463
|
|
37
38
|
haiku/rag/store/upgrades/__init__.py,sha256=kKS1YWT_P-CYKhKtokOLTIFNKf9jlfjFFr8lyIMeogM,100
|
|
38
39
|
haiku/rag/store/upgrades/v0_3_4.py,sha256=GLogKZdZ40NX1vBHKdOJju7fFzNUCHoEnjSZg17Hm2U,663
|
|
39
|
-
haiku_rag-0.5.
|
|
40
|
-
haiku_rag-0.5.
|
|
41
|
-
haiku_rag-0.5.
|
|
42
|
-
haiku_rag-0.5.
|
|
43
|
-
haiku_rag-0.5.
|
|
40
|
+
haiku_rag-0.5.2.dist-info/METADATA,sha256=b91HARmgPKSy_4LIhna9EoacKb9I_f-cRRTgHqaG-S8,4238
|
|
41
|
+
haiku_rag-0.5.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
42
|
+
haiku_rag-0.5.2.dist-info/entry_points.txt,sha256=G1U3nAkNd5YDYd4v0tuYFbriz0i-JheCsFuT9kIoGCI,48
|
|
43
|
+
haiku_rag-0.5.2.dist-info/licenses/LICENSE,sha256=eXZrWjSk9PwYFNK9yUczl3oPl95Z4V9UXH7bPN46iPo,1065
|
|
44
|
+
haiku_rag-0.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|