haiku.rag 0.13.1__tar.gz → 0.13.3__tar.gz
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-0.13.1 → haiku_rag-0.13.3}/PKG-INFO +19 -11
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/README.md +4 -1
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/pyproject.toml +20 -17
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/benchmark.py +38 -17
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/app.py +7 -12
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/cli.py +7 -1
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/client.py +17 -13
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/config/__init__.py +2 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/config/loader.py +11 -5
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/config/models.py +7 -1
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/monitor.py +62 -7
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reranking/__init__.py +18 -0
- haiku_rag-0.13.3/src/haiku/rag/reranking/zeroentropy.py +59 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/repositories/chunk.py +48 -7
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/uv.lock +392 -308
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/.dockerignore +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/.gitignore +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/.pre-commit-config.yaml +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/.python-version +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/LICENSE +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/mkdocs.yml +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/server.json +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/config.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/datasets/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/datasets/repliqa.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/datasets/wix.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/llm_judge.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/evaluations/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/client.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/context.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/models.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/skills.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/storage.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/a2a/worker.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/chunker.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/base.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/ollama.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/openai.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/vllm.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/embeddings/voyageai.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/base.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/common.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/models.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/nodes/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/nodes/analysis.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/nodes/plan.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/nodes/search.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/nodes/synthesize.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/graph/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/logging.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/mcp.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/agent.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/dependencies.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/graph.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/models.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/nodes.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/deep/state.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/qa/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reader.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reranking/base.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reranking/cohere.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reranking/mxbai.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/reranking/vllm.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/common.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/dependencies.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/graph.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/models.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/prompts.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/state.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/research/stream.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/engine.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/models/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/models/chunk.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/models/document.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/repositories/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/repositories/document.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/repositories/settings.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/upgrades/__init__.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/upgrades/v0_10_1.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/store/upgrades/v0_9_3.py +0 -0
- {haiku_rag-0.13.1 → haiku_rag-0.13.3}/src/haiku/rag/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haiku.rag
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.3
|
|
4
4
|
Summary: Agentic Retrieval Augmented Generation (RAG) with LanceDB
|
|
5
5
|
Author-email: Yiorgis Gozadinos <ggozadinos@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -17,25 +17,30 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: >=3.12
|
|
20
|
-
Requires-Dist: docling>=2.
|
|
21
|
-
Requires-Dist: fastmcp>=2.
|
|
20
|
+
Requires-Dist: docling>=2.58.0
|
|
21
|
+
Requires-Dist: fastmcp>=2.13.0.2
|
|
22
22
|
Requires-Dist: httpx>=0.28.1
|
|
23
23
|
Requires-Dist: lancedb>=0.25.2
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist: pydantic-
|
|
26
|
-
Requires-Dist: pydantic>=
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: pathspec>=0.12.1
|
|
25
|
+
Requires-Dist: pydantic-ai>=1.7.0
|
|
26
|
+
Requires-Dist: pydantic-graph>=1.7.0
|
|
27
|
+
Requires-Dist: pydantic>=2.12.3
|
|
28
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
29
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
29
30
|
Requires-Dist: rich>=14.2.0
|
|
30
31
|
Requires-Dist: tiktoken>=0.12.0
|
|
31
|
-
Requires-Dist: typer
|
|
32
|
-
Requires-Dist: watchfiles>=1.1.
|
|
32
|
+
Requires-Dist: typer<0.20.0,>=0.19.2
|
|
33
|
+
Requires-Dist: watchfiles>=1.1.1
|
|
33
34
|
Provides-Extra: a2a
|
|
34
35
|
Requires-Dist: fasta2a>=0.1.0; extra == 'a2a'
|
|
36
|
+
Provides-Extra: cohere
|
|
37
|
+
Requires-Dist: cohere>=5.0.0; extra == 'cohere'
|
|
35
38
|
Provides-Extra: mxbai
|
|
36
39
|
Requires-Dist: mxbai-rerank>=0.1.6; extra == 'mxbai'
|
|
37
40
|
Provides-Extra: voyageai
|
|
38
41
|
Requires-Dist: voyageai>=0.3.5; extra == 'voyageai'
|
|
42
|
+
Provides-Extra: zeroentropy
|
|
43
|
+
Requires-Dist: zeroentropy>=0.1.0a6; extra == 'zeroentropy'
|
|
39
44
|
Description-Content-Type: text/markdown
|
|
40
45
|
|
|
41
46
|
# Haiku RAG
|
|
@@ -55,7 +60,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
55
60
|
- **Multiple QA providers**: Any provider/model supported by Pydantic AI
|
|
56
61
|
- **Research graph (multi‑agent)**: Plan → Search → Evaluate → Synthesize with agentic AI
|
|
57
62
|
- **Native hybrid search**: Vector + full-text search with native LanceDB RRF reranking
|
|
58
|
-
- **Reranking**: Default search result reranking with MixedBread AI, Cohere, or vLLM
|
|
63
|
+
- **Reranking**: Default search result reranking with MixedBread AI, Cohere, Zero Entropy, or vLLM
|
|
59
64
|
- **Question answering**: Built-in QA agents on your documents
|
|
60
65
|
- **File monitoring**: Auto-index files when run as server
|
|
61
66
|
- **40+ file formats**: PDF, DOCX, HTML, Markdown, code files, URLs
|
|
@@ -78,6 +83,9 @@ haiku-rag add-src document.pdf --meta source=manual
|
|
|
78
83
|
# Search
|
|
79
84
|
haiku-rag search "query"
|
|
80
85
|
|
|
86
|
+
# Search with filters
|
|
87
|
+
haiku-rag search "query" --filter "uri LIKE '%.pdf' AND title LIKE '%paper%'"
|
|
88
|
+
|
|
81
89
|
# Ask questions
|
|
82
90
|
haiku-rag ask "Who is the author of haiku.rag?"
|
|
83
91
|
|
|
@@ -15,7 +15,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
15
15
|
- **Multiple QA providers**: Any provider/model supported by Pydantic AI
|
|
16
16
|
- **Research graph (multi‑agent)**: Plan → Search → Evaluate → Synthesize with agentic AI
|
|
17
17
|
- **Native hybrid search**: Vector + full-text search with native LanceDB RRF reranking
|
|
18
|
-
- **Reranking**: Default search result reranking with MixedBread AI, Cohere, or vLLM
|
|
18
|
+
- **Reranking**: Default search result reranking with MixedBread AI, Cohere, Zero Entropy, or vLLM
|
|
19
19
|
- **Question answering**: Built-in QA agents on your documents
|
|
20
20
|
- **File monitoring**: Auto-index files when run as server
|
|
21
21
|
- **40+ file formats**: PDF, DOCX, HTML, Markdown, code files, URLs
|
|
@@ -38,6 +38,9 @@ haiku-rag add-src document.pdf --meta source=manual
|
|
|
38
38
|
# Search
|
|
39
39
|
haiku-rag search "query"
|
|
40
40
|
|
|
41
|
+
# Search with filters
|
|
42
|
+
haiku-rag search "query" --filter "uri LIKE '%.pdf' AND title LIKE '%paper%'"
|
|
43
|
+
|
|
41
44
|
# Ask questions
|
|
42
45
|
haiku-rag ask "Who is the author of haiku.rag?"
|
|
43
46
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
name = "haiku.rag"
|
|
4
4
|
description = "Agentic Retrieval Augmented Generation (RAG) with LanceDB"
|
|
5
|
-
version = "0.13.
|
|
5
|
+
version = "0.13.3"
|
|
6
6
|
authors = [{ name = "Yiorgis Gozadinos", email = "ggozadinos@gmail.com" }]
|
|
7
7
|
license = { text = "MIT" }
|
|
8
8
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
@@ -22,25 +22,28 @@ classifiers = [
|
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
dependencies = [
|
|
25
|
-
"docling>=2.
|
|
26
|
-
"fastmcp>=2.
|
|
25
|
+
"docling>=2.58.0",
|
|
26
|
+
"fastmcp>=2.13.0.2",
|
|
27
27
|
"httpx>=0.28.1",
|
|
28
28
|
"lancedb>=0.25.2",
|
|
29
|
-
"
|
|
30
|
-
"pydantic
|
|
31
|
-
"pydantic-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
29
|
+
"pathspec>=0.12.1",
|
|
30
|
+
"pydantic>=2.12.3",
|
|
31
|
+
"pydantic-ai>=1.7.0",
|
|
32
|
+
"pydantic-graph>=1.7.0",
|
|
33
|
+
"python-dotenv>=1.2.1",
|
|
34
|
+
"pyyaml>=6.0.3",
|
|
34
35
|
"rich>=14.2.0",
|
|
35
36
|
"tiktoken>=0.12.0",
|
|
36
|
-
"typer>=0.19.2",
|
|
37
|
-
"watchfiles>=1.1.
|
|
37
|
+
"typer>=0.19.2,<0.20.0",
|
|
38
|
+
"watchfiles>=1.1.1",
|
|
38
39
|
]
|
|
39
40
|
|
|
40
41
|
[project.optional-dependencies]
|
|
41
42
|
voyageai = ["voyageai>=0.3.5"]
|
|
42
43
|
mxbai = ["mxbai-rerank>=0.1.6"]
|
|
43
44
|
a2a = ["fasta2a>=0.1.0"]
|
|
45
|
+
cohere = ["cohere>=5.0.0"]
|
|
46
|
+
zeroentropy = ["zeroentropy>=0.1.0a6"]
|
|
44
47
|
|
|
45
48
|
[project.scripts]
|
|
46
49
|
haiku-rag = "haiku.rag.cli:cli"
|
|
@@ -57,17 +60,17 @@ packages = ["src/haiku"]
|
|
|
57
60
|
|
|
58
61
|
[dependency-groups]
|
|
59
62
|
dev = [
|
|
60
|
-
"datasets>=4.
|
|
61
|
-
"logfire>=4.
|
|
63
|
+
"datasets>=4.3.0",
|
|
64
|
+
"logfire>=4.14.2",
|
|
62
65
|
"mkdocs>=1.6.1",
|
|
63
|
-
"mkdocs-material>=9.6.
|
|
64
|
-
"pydantic-evals>=1.0
|
|
65
|
-
"pre-commit>=4.
|
|
66
|
-
"pyright>=1.1.
|
|
66
|
+
"mkdocs-material>=9.6.22",
|
|
67
|
+
"pydantic-evals>=1.7.0",
|
|
68
|
+
"pre-commit>=4.3.0",
|
|
69
|
+
"pyright>=1.1.407",
|
|
67
70
|
"pytest>=8.4.2",
|
|
68
71
|
"pytest-asyncio>=1.2.0",
|
|
69
72
|
"pytest-cov>=7.0.0",
|
|
70
|
-
"ruff>=0.
|
|
73
|
+
"ruff>=0.14.2",
|
|
71
74
|
]
|
|
72
75
|
|
|
73
76
|
[tool.ruff]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections.abc import Mapping
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Any, cast
|
|
4
5
|
|
|
5
6
|
import logfire
|
|
@@ -12,13 +13,12 @@ from pydantic_evals.reporting import ReportCaseFailure
|
|
|
12
13
|
from rich.console import Console
|
|
13
14
|
from rich.progress import Progress
|
|
14
15
|
|
|
15
|
-
from evaluations.config import DatasetSpec
|
|
16
|
+
from evaluations.config import DatasetSpec
|
|
16
17
|
from evaluations.datasets import DATASETS
|
|
17
18
|
from evaluations.llm_judge import ANSWER_EQUIVALENCE_RUBRIC
|
|
18
19
|
from evaluations.prompts import WIX_SUPPORT_PROMPT
|
|
19
|
-
from haiku.rag import logging # noqa: F401
|
|
20
20
|
from haiku.rag.client import HaikuRAG
|
|
21
|
-
from haiku.rag.config import
|
|
21
|
+
from haiku.rag.config import AppConfig, find_config_file, load_yaml_config
|
|
22
22
|
from haiku.rag.logging import configure_cli_logging
|
|
23
23
|
from haiku.rag.qa import get_qa_agent
|
|
24
24
|
|
|
@@ -30,7 +30,7 @@ configure_cli_logging()
|
|
|
30
30
|
console = Console()
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
async def populate_db(spec: DatasetSpec) -> None:
|
|
33
|
+
async def populate_db(spec: DatasetSpec, config: AppConfig) -> None:
|
|
34
34
|
spec.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
35
35
|
corpus = spec.document_loader()
|
|
36
36
|
if spec.document_limit is not None:
|
|
@@ -38,7 +38,7 @@ async def populate_db(spec: DatasetSpec) -> None:
|
|
|
38
38
|
|
|
39
39
|
with Progress() as progress:
|
|
40
40
|
task = progress.add_task("[green]Populating database...", total=len(corpus))
|
|
41
|
-
async with HaikuRAG(spec.db_path) as rag:
|
|
41
|
+
async with HaikuRAG(spec.db_path, config=config) as rag:
|
|
42
42
|
for doc in corpus:
|
|
43
43
|
doc_mapping = cast(Mapping[str, Any], doc)
|
|
44
44
|
payload = spec.document_mapper(doc_mapping)
|
|
@@ -64,11 +64,9 @@ async def populate_db(spec: DatasetSpec) -> None:
|
|
|
64
64
|
progress.advance(task)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
async def run_retrieval_benchmark(spec: DatasetSpec) -> dict[str, float] | None:
|
|
67
|
+
async def run_retrieval_benchmark(
|
|
68
|
+
spec: DatasetSpec, config: AppConfig
|
|
69
|
+
) -> dict[str, float] | None:
|
|
72
70
|
if spec.retrieval_loader is None or spec.retrieval_mapper is None:
|
|
73
71
|
console.print("Skipping retrieval benchmark; no retrieval config.")
|
|
74
72
|
return None
|
|
@@ -91,7 +89,7 @@ async def run_retrieval_benchmark(spec: DatasetSpec) -> dict[str, float] | None:
|
|
|
91
89
|
task = progress.add_task(
|
|
92
90
|
"[blue]Running retrieval benchmark...", total=len(corpus)
|
|
93
91
|
)
|
|
94
|
-
async with HaikuRAG(spec.db_path) as rag:
|
|
92
|
+
async with HaikuRAG(spec.db_path, config=config) as rag:
|
|
95
93
|
for doc in corpus:
|
|
96
94
|
doc_mapping = cast(Mapping[str, Any], doc)
|
|
97
95
|
sample = spec.retrieval_mapper(doc_mapping)
|
|
@@ -161,7 +159,7 @@ async def run_retrieval_benchmark(spec: DatasetSpec) -> dict[str, float] | None:
|
|
|
161
159
|
|
|
162
160
|
|
|
163
161
|
async def run_qa_benchmark(
|
|
164
|
-
spec: DatasetSpec, qa_limit: int | None = None
|
|
162
|
+
spec: DatasetSpec, config: AppConfig, qa_limit: int | None = None
|
|
165
163
|
) -> ReportCaseFailure[str, str, dict[str, str]] | None:
|
|
166
164
|
corpus = spec.qa_loader()
|
|
167
165
|
if qa_limit is not None:
|
|
@@ -174,7 +172,7 @@ async def run_qa_benchmark(
|
|
|
174
172
|
|
|
175
173
|
judge_model = OpenAIChatModel(
|
|
176
174
|
model_name=QA_JUDGE_MODEL,
|
|
177
|
-
provider=OllamaProvider(base_url=f"{
|
|
175
|
+
provider=OllamaProvider(base_url=f"{config.providers.ollama.base_url}/v1"),
|
|
178
176
|
)
|
|
179
177
|
|
|
180
178
|
evaluation_dataset = EvalDataset[str, str, dict[str, str]](
|
|
@@ -204,7 +202,7 @@ async def run_qa_benchmark(
|
|
|
204
202
|
total=len(evaluation_dataset.cases),
|
|
205
203
|
)
|
|
206
204
|
|
|
207
|
-
async with HaikuRAG(spec.db_path) as rag:
|
|
205
|
+
async with HaikuRAG(spec.db_path, config=config) as rag:
|
|
208
206
|
system_prompt = WIX_SUPPORT_PROMPT if spec.key == "wix" else None
|
|
209
207
|
qa = get_qa_agent(rag, system_prompt=system_prompt)
|
|
210
208
|
|
|
@@ -272,6 +270,7 @@ async def run_qa_benchmark(
|
|
|
272
270
|
|
|
273
271
|
async def evaluate_dataset(
|
|
274
272
|
spec: DatasetSpec,
|
|
273
|
+
config: AppConfig,
|
|
275
274
|
skip_db: bool,
|
|
276
275
|
skip_retrieval: bool,
|
|
277
276
|
skip_qa: bool,
|
|
@@ -279,15 +278,15 @@ async def evaluate_dataset(
|
|
|
279
278
|
) -> None:
|
|
280
279
|
if not skip_db:
|
|
281
280
|
console.print(f"Using dataset: {spec.key}", style="bold magenta")
|
|
282
|
-
await populate_db(spec)
|
|
281
|
+
await populate_db(spec, config)
|
|
283
282
|
|
|
284
283
|
if not skip_retrieval:
|
|
285
284
|
console.print("Running retrieval benchmarks...", style="bold blue")
|
|
286
|
-
await run_retrieval_benchmark(spec)
|
|
285
|
+
await run_retrieval_benchmark(spec, config)
|
|
287
286
|
|
|
288
287
|
if not skip_qa:
|
|
289
288
|
console.print("\nRunning QA benchmarks...", style="bold yellow")
|
|
290
|
-
await run_qa_benchmark(spec, qa_limit=qa_limit)
|
|
289
|
+
await run_qa_benchmark(spec, config, qa_limit=qa_limit)
|
|
291
290
|
|
|
292
291
|
|
|
293
292
|
app = typer.Typer(help="Run retrieval and QA benchmarks for configured datasets.")
|
|
@@ -296,6 +295,9 @@ app = typer.Typer(help="Run retrieval and QA benchmarks for configured datasets.
|
|
|
296
295
|
@app.command()
|
|
297
296
|
def run(
|
|
298
297
|
dataset: str = typer.Argument(..., help="Dataset key to evaluate."),
|
|
298
|
+
config: Path | None = typer.Option(
|
|
299
|
+
None, "--config", help="Path to haiku.rag YAML config file."
|
|
300
|
+
),
|
|
299
301
|
skip_db: bool = typer.Option(
|
|
300
302
|
False, "--skip-db", help="Skip updateing the evaluation db."
|
|
301
303
|
),
|
|
@@ -314,9 +316,28 @@ def run(
|
|
|
314
316
|
f"Unknown dataset '{dataset}'. Choose from: {valid_datasets}"
|
|
315
317
|
)
|
|
316
318
|
|
|
319
|
+
# Load config from file or use defaults
|
|
320
|
+
if config:
|
|
321
|
+
if not config.exists():
|
|
322
|
+
raise typer.BadParameter(f"Config file not found: {config}")
|
|
323
|
+
console.print(f"Loading config from: {config}", style="dim")
|
|
324
|
+
yaml_data = load_yaml_config(config)
|
|
325
|
+
app_config = AppConfig.model_validate(yaml_data)
|
|
326
|
+
else:
|
|
327
|
+
# Try to find config file using standard search path
|
|
328
|
+
config_path = find_config_file(None)
|
|
329
|
+
if config_path:
|
|
330
|
+
console.print(f"Loading config from: {config_path}", style="dim")
|
|
331
|
+
yaml_data = load_yaml_config(config_path)
|
|
332
|
+
app_config = AppConfig.model_validate(yaml_data)
|
|
333
|
+
else:
|
|
334
|
+
console.print("No config file found, using defaults", style="dim")
|
|
335
|
+
app_config = AppConfig()
|
|
336
|
+
|
|
317
337
|
asyncio.run(
|
|
318
338
|
evaluate_dataset(
|
|
319
339
|
spec=spec,
|
|
340
|
+
config=app_config,
|
|
320
341
|
skip_db=skip_db,
|
|
321
342
|
skip_retrieval=skip_retrieval,
|
|
322
343
|
skip_qa=skip_qa,
|
|
@@ -81,13 +81,10 @@ class HaikuRAGApp:
|
|
|
81
81
|
raw = rows[0].get("settings") or "{}"
|
|
82
82
|
data = json.loads(raw) if isinstance(raw, str) else (raw or {})
|
|
83
83
|
stored_version = str(data.get("version", stored_version))
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if data.get("EMBEDDINGS_VECTOR_DIM") is not None
|
|
89
|
-
else None
|
|
90
|
-
)
|
|
84
|
+
embeddings = data.get("embeddings", {})
|
|
85
|
+
embed_provider = embeddings.get("provider")
|
|
86
|
+
embed_model = embeddings.get("model")
|
|
87
|
+
vector_dim = embeddings.get("vector_dim")
|
|
91
88
|
|
|
92
89
|
num_docs = 0
|
|
93
90
|
if "documents" in table_names:
|
|
@@ -195,9 +192,9 @@ class HaikuRAGApp:
|
|
|
195
192
|
f"[yellow]Document with id {doc_id} not found.[/yellow]"
|
|
196
193
|
)
|
|
197
194
|
|
|
198
|
-
async def search(self, query: str, limit: int = 5):
|
|
195
|
+
async def search(self, query: str, limit: int = 5, filter: str | None = None):
|
|
199
196
|
async with HaikuRAG(db_path=self.db_path) as self.client:
|
|
200
|
-
results = await self.client.search(query, limit=limit)
|
|
197
|
+
results = await self.client.search(query, limit=limit, filter=filter)
|
|
201
198
|
if not results:
|
|
202
199
|
self.console.print("[yellow]No results found.[/yellow]")
|
|
203
200
|
return
|
|
@@ -474,9 +471,7 @@ class HaikuRAGApp:
|
|
|
474
471
|
|
|
475
472
|
# Start file monitor if enabled
|
|
476
473
|
if enable_monitor:
|
|
477
|
-
monitor = FileWatcher(
|
|
478
|
-
paths=Config.storage.monitor_directories, client=client
|
|
479
|
-
)
|
|
474
|
+
monitor = FileWatcher(client=client)
|
|
480
475
|
monitor_task = asyncio.create_task(monitor.observe())
|
|
481
476
|
tasks.append(monitor_task)
|
|
482
477
|
|
|
@@ -221,6 +221,12 @@ def search(
|
|
|
221
221
|
"-l",
|
|
222
222
|
help="Maximum number of results to return",
|
|
223
223
|
),
|
|
224
|
+
filter: str | None = typer.Option(
|
|
225
|
+
None,
|
|
226
|
+
"--filter",
|
|
227
|
+
"-f",
|
|
228
|
+
help="SQL WHERE clause to filter documents (e.g., \"uri LIKE '%arxiv%'\")",
|
|
229
|
+
),
|
|
224
230
|
db: Path = typer.Option(
|
|
225
231
|
Config.storage.data_dir / "haiku.rag.lancedb",
|
|
226
232
|
"--db",
|
|
@@ -230,7 +236,7 @@ def search(
|
|
|
230
236
|
from haiku.rag.app import HaikuRAGApp
|
|
231
237
|
|
|
232
238
|
app = HaikuRAGApp(db_path=db)
|
|
233
|
-
asyncio.run(app.search(query=query, limit=limit))
|
|
239
|
+
asyncio.run(app.search(query=query, limit=limit, filter=filter))
|
|
234
240
|
|
|
235
241
|
|
|
236
242
|
@cli.command("ask", help="Ask a question using the QA agent")
|
|
@@ -135,9 +135,6 @@ class HaikuRAG:
|
|
|
135
135
|
ValueError: If the file/URL cannot be parsed or doesn't exist
|
|
136
136
|
httpx.RequestError: If URL request fails
|
|
137
137
|
"""
|
|
138
|
-
# Lazy import to avoid loading docling
|
|
139
|
-
from haiku.rag.reader import FileReader
|
|
140
|
-
|
|
141
138
|
# Normalize metadata
|
|
142
139
|
metadata = metadata or {}
|
|
143
140
|
|
|
@@ -157,15 +154,17 @@ class HaikuRAG:
|
|
|
157
154
|
|
|
158
155
|
# Handle directories
|
|
159
156
|
if source_path.is_dir():
|
|
157
|
+
from haiku.rag.monitor import FileFilter
|
|
158
|
+
|
|
160
159
|
documents = []
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
):
|
|
160
|
+
filter = FileFilter(
|
|
161
|
+
ignore_patterns=self._config.monitor.ignore_patterns or None,
|
|
162
|
+
include_patterns=self._config.monitor.include_patterns or None,
|
|
163
|
+
)
|
|
164
|
+
for path in source_path.rglob("*"):
|
|
165
|
+
if path.is_file() and filter.include_file(str(path)):
|
|
167
166
|
doc = await self._create_document_from_file(
|
|
168
|
-
|
|
167
|
+
path, title=None, metadata=metadata
|
|
169
168
|
)
|
|
170
169
|
documents.append(doc)
|
|
171
170
|
return documents
|
|
@@ -424,7 +423,11 @@ class HaikuRAG:
|
|
|
424
423
|
return await self.document_repository.list_all(limit=limit, offset=offset)
|
|
425
424
|
|
|
426
425
|
async def search(
|
|
427
|
-
self,
|
|
426
|
+
self,
|
|
427
|
+
query: str,
|
|
428
|
+
limit: int = 5,
|
|
429
|
+
search_type: str = "hybrid",
|
|
430
|
+
filter: str | None = None,
|
|
428
431
|
) -> list[tuple[Chunk, float]]:
|
|
429
432
|
"""Search for relevant chunks using the specified search method with optional reranking.
|
|
430
433
|
|
|
@@ -432,6 +435,7 @@ class HaikuRAG:
|
|
|
432
435
|
query: The search query string.
|
|
433
436
|
limit: Maximum number of results to return.
|
|
434
437
|
search_type: Type of search - "vector", "fts", or "hybrid" (default).
|
|
438
|
+
filter: Optional SQL WHERE clause to filter documents before searching chunks.
|
|
435
439
|
|
|
436
440
|
Returns:
|
|
437
441
|
List of (chunk, score) tuples ordered by relevance.
|
|
@@ -441,12 +445,12 @@ class HaikuRAG:
|
|
|
441
445
|
|
|
442
446
|
if reranker is None:
|
|
443
447
|
# No reranking - return direct search results
|
|
444
|
-
return await self.chunk_repository.search(query, limit, search_type)
|
|
448
|
+
return await self.chunk_repository.search(query, limit, search_type, filter)
|
|
445
449
|
|
|
446
450
|
# Get more initial results (3X) for reranking
|
|
447
451
|
search_limit = limit * 3
|
|
448
452
|
search_results = await self.chunk_repository.search(
|
|
449
|
-
query, search_limit, search_type
|
|
453
|
+
query, search_limit, search_type, filter
|
|
450
454
|
)
|
|
451
455
|
|
|
452
456
|
# Apply reranking
|
|
@@ -11,6 +11,7 @@ from haiku.rag.config.models import (
|
|
|
11
11
|
AppConfig,
|
|
12
12
|
EmbeddingsConfig,
|
|
13
13
|
LanceDBConfig,
|
|
14
|
+
MonitorConfig,
|
|
14
15
|
OllamaConfig,
|
|
15
16
|
ProcessingConfig,
|
|
16
17
|
ProvidersConfig,
|
|
@@ -25,6 +26,7 @@ __all__ = [
|
|
|
25
26
|
"Config",
|
|
26
27
|
"AppConfig",
|
|
27
28
|
"StorageConfig",
|
|
29
|
+
"MonitorConfig",
|
|
28
30
|
"LanceDBConfig",
|
|
29
31
|
"EmbeddingsConfig",
|
|
30
32
|
"RerankingConfig",
|
|
@@ -10,7 +10,7 @@ def find_config_file(cli_path: Path | None = None) -> Path | None:
|
|
|
10
10
|
Search order:
|
|
11
11
|
1. CLI-provided path (via HAIKU_RAG_CONFIG_PATH env var or parameter)
|
|
12
12
|
2. ./haiku.rag.yaml (current directory)
|
|
13
|
-
3.
|
|
13
|
+
3. Platform-specific user config directory
|
|
14
14
|
|
|
15
15
|
Returns None if no config file is found.
|
|
16
16
|
"""
|
|
@@ -29,8 +29,10 @@ def find_config_file(cli_path: Path | None = None) -> Path | None:
|
|
|
29
29
|
if cwd_config.exists():
|
|
30
30
|
return cwd_config
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
# Use same directory as data storage for config
|
|
33
|
+
from haiku.rag.utils import get_default_data_dir
|
|
34
|
+
|
|
35
|
+
user_config = get_default_data_dir() / "config.yaml"
|
|
34
36
|
if user_config.exists():
|
|
35
37
|
return user_config
|
|
36
38
|
|
|
@@ -50,10 +52,14 @@ def generate_default_config() -> dict:
|
|
|
50
52
|
"environment": "production",
|
|
51
53
|
"storage": {
|
|
52
54
|
"data_dir": "",
|
|
53
|
-
"monitor_directories": [],
|
|
54
55
|
"disable_autocreate": False,
|
|
55
56
|
"vacuum_retention_seconds": 60,
|
|
56
57
|
},
|
|
58
|
+
"monitor": {
|
|
59
|
+
"directories": [],
|
|
60
|
+
"ignore_patterns": [],
|
|
61
|
+
"include_patterns": [],
|
|
62
|
+
},
|
|
57
63
|
"lancedb": {"uri": "", "api_key": "", "region": ""},
|
|
58
64
|
"embeddings": {
|
|
59
65
|
"provider": "ollama",
|
|
@@ -88,7 +94,7 @@ def load_config_from_env() -> dict:
|
|
|
88
94
|
env_mappings = {
|
|
89
95
|
"ENV": "environment",
|
|
90
96
|
"DEFAULT_DATA_DIR": ("storage", "data_dir"),
|
|
91
|
-
"MONITOR_DIRECTORIES": ("
|
|
97
|
+
"MONITOR_DIRECTORIES": ("monitor", "directories"),
|
|
92
98
|
"DISABLE_DB_AUTOCREATE": ("storage", "disable_autocreate"),
|
|
93
99
|
"VACUUM_RETENTION_SECONDS": ("storage", "vacuum_retention_seconds"),
|
|
94
100
|
"LANCEDB_URI": ("lancedb", "uri"),
|
|
@@ -7,11 +7,16 @@ from haiku.rag.utils import get_default_data_dir
|
|
|
7
7
|
|
|
8
8
|
class StorageConfig(BaseModel):
|
|
9
9
|
data_dir: Path = Field(default_factory=get_default_data_dir)
|
|
10
|
-
monitor_directories: list[Path] = []
|
|
11
10
|
disable_autocreate: bool = False
|
|
12
11
|
vacuum_retention_seconds: int = 60
|
|
13
12
|
|
|
14
13
|
|
|
14
|
+
class MonitorConfig(BaseModel):
|
|
15
|
+
directories: list[Path] = []
|
|
16
|
+
ignore_patterns: list[str] = []
|
|
17
|
+
include_patterns: list[str] = []
|
|
18
|
+
|
|
19
|
+
|
|
15
20
|
class LanceDBConfig(BaseModel):
|
|
16
21
|
uri: str = ""
|
|
17
22
|
api_key: str = ""
|
|
@@ -72,6 +77,7 @@ class A2AConfig(BaseModel):
|
|
|
72
77
|
class AppConfig(BaseModel):
|
|
73
78
|
environment: str = "production"
|
|
74
79
|
storage: StorageConfig = Field(default_factory=StorageConfig)
|
|
80
|
+
monitor: MonitorConfig = Field(default_factory=MonitorConfig)
|
|
75
81
|
lancedb: LanceDBConfig = Field(default_factory=LanceDBConfig)
|
|
76
82
|
embeddings: EmbeddingsConfig = Field(default_factory=EmbeddingsConfig)
|
|
77
83
|
reranking: RerankingConfig = Field(default_factory=RerankingConfig)
|
|
@@ -2,9 +2,12 @@ import logging
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
import pathspec
|
|
6
|
+
from pathspec.patterns.gitwildmatch import GitWildMatchPattern
|
|
5
7
|
from watchfiles import Change, DefaultFilter, awatch
|
|
6
8
|
|
|
7
9
|
from haiku.rag.client import HaikuRAG
|
|
10
|
+
from haiku.rag.config import AppConfig, Config
|
|
8
11
|
from haiku.rag.store.models.document import Document
|
|
9
12
|
|
|
10
13
|
if TYPE_CHECKING:
|
|
@@ -14,25 +17,70 @@ logger = logging.getLogger(__name__)
|
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
class FileFilter(DefaultFilter):
|
|
17
|
-
def __init__(
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
*,
|
|
23
|
+
ignore_patterns: list[str] | None = None,
|
|
24
|
+
include_patterns: list[str] | None = None,
|
|
25
|
+
) -> None:
|
|
18
26
|
# Lazy import to avoid loading docling
|
|
19
27
|
from haiku.rag.reader import FileReader
|
|
20
28
|
|
|
21
29
|
self.extensions = tuple(FileReader.extensions)
|
|
22
|
-
|
|
30
|
+
self.ignore_spec = (
|
|
31
|
+
pathspec.PathSpec.from_lines(GitWildMatchPattern, ignore_patterns)
|
|
32
|
+
if ignore_patterns
|
|
33
|
+
else None
|
|
34
|
+
)
|
|
35
|
+
self.include_spec = (
|
|
36
|
+
pathspec.PathSpec.from_lines(GitWildMatchPattern, include_patterns)
|
|
37
|
+
if include_patterns
|
|
38
|
+
else None
|
|
39
|
+
)
|
|
40
|
+
super().__init__()
|
|
23
41
|
|
|
24
42
|
def __call__(self, change: Change, path: str) -> bool:
|
|
25
|
-
|
|
43
|
+
if not self.include_file(path):
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
# Apply default watchfiles filter
|
|
47
|
+
return super().__call__(change, path)
|
|
48
|
+
|
|
49
|
+
def include_file(self, path: str) -> bool:
|
|
50
|
+
"""Check if a file should be included based on filters."""
|
|
51
|
+
# Check extension filter
|
|
52
|
+
if not path.endswith(self.extensions):
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
# Apply include patterns if specified (whitelist mode)
|
|
56
|
+
if self.include_spec:
|
|
57
|
+
if not self.include_spec.match_file(path):
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
# Apply ignore patterns (blacklist mode)
|
|
61
|
+
if self.ignore_spec:
|
|
62
|
+
if self.ignore_spec.match_file(path):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
return True
|
|
26
66
|
|
|
27
67
|
|
|
28
68
|
class FileWatcher:
|
|
29
|
-
def __init__(
|
|
30
|
-
self
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
client: HaikuRAG,
|
|
72
|
+
config: AppConfig = Config,
|
|
73
|
+
):
|
|
74
|
+
self.paths = config.monitor.directories
|
|
31
75
|
self.client = client
|
|
76
|
+
self.ignore_patterns = config.monitor.ignore_patterns or None
|
|
77
|
+
self.include_patterns = config.monitor.include_patterns or None
|
|
32
78
|
|
|
33
79
|
async def observe(self):
|
|
34
80
|
logger.info(f"Watching files in {self.paths}")
|
|
35
|
-
filter = FileFilter(
|
|
81
|
+
filter = FileFilter(
|
|
82
|
+
ignore_patterns=self.ignore_patterns, include_patterns=self.include_patterns
|
|
83
|
+
)
|
|
36
84
|
await self.refresh()
|
|
37
85
|
|
|
38
86
|
async for changes in awatch(*self.paths, watch_filter=filter):
|
|
@@ -49,10 +97,17 @@ class FileWatcher:
|
|
|
49
97
|
# Lazy import to avoid loading docling
|
|
50
98
|
from haiku.rag.reader import FileReader
|
|
51
99
|
|
|
100
|
+
# Create filter to apply same logic as observe()
|
|
101
|
+
filter = FileFilter(
|
|
102
|
+
ignore_patterns=self.ignore_patterns, include_patterns=self.include_patterns
|
|
103
|
+
)
|
|
104
|
+
|
|
52
105
|
for path in self.paths:
|
|
53
106
|
for f in Path(path).rglob("**/*"):
|
|
54
107
|
if f.is_file() and f.suffix in FileReader.extensions:
|
|
55
|
-
|
|
108
|
+
# Apply pattern filters
|
|
109
|
+
if filter(Change.added, str(f)):
|
|
110
|
+
await self._upsert_document(f)
|
|
56
111
|
|
|
57
112
|
async def _upsert_document(self, file: Path) -> Document | None:
|
|
58
113
|
try:
|
|
@@ -41,5 +41,23 @@ def get_reranker(config: AppConfig = Config) -> RerankerBase | None:
|
|
|
41
41
|
except ImportError:
|
|
42
42
|
reranker = None
|
|
43
43
|
|
|
44
|
+
elif config.reranking.provider == "vllm":
|
|
45
|
+
try:
|
|
46
|
+
from haiku.rag.reranking.vllm import VLLMReranker
|
|
47
|
+
|
|
48
|
+
reranker = VLLMReranker(config.reranking.model)
|
|
49
|
+
except ImportError:
|
|
50
|
+
reranker = None
|
|
51
|
+
|
|
52
|
+
elif config.reranking.provider == "zeroentropy":
|
|
53
|
+
try:
|
|
54
|
+
from haiku.rag.reranking.zeroentropy import ZeroEntropyReranker
|
|
55
|
+
|
|
56
|
+
# Use configured model or default to zerank-1
|
|
57
|
+
model = config.reranking.model or "zerank-1"
|
|
58
|
+
reranker = ZeroEntropyReranker(model)
|
|
59
|
+
except ImportError:
|
|
60
|
+
reranker = None
|
|
61
|
+
|
|
44
62
|
_reranker_cache[config_id] = reranker
|
|
45
63
|
return reranker
|