ragit 0.0.1__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.
- ragit/__init__.py +61 -0
- ragit/core/__init__.py +5 -0
- ragit/core/experiment/__init__.py +22 -0
- ragit/core/experiment/experiment.py +468 -0
- ragit/core/experiment/results.py +132 -0
- ragit/providers/__init__.py +20 -0
- ragit/providers/base.py +146 -0
- ragit/providers/ollama.py +250 -0
- ragit/utils/__init__.py +105 -0
- ragit/version.py +5 -0
- ragit-0.0.1.dist-info/METADATA +83 -0
- ragit-0.0.1.dist-info/RECORD +15 -0
- ragit-0.0.1.dist-info/WHEEL +5 -0
- ragit-0.0.1.dist-info/licenses/LICENSE +201 -0
- ragit-0.0.1.dist-info/top_level.txt +1 -0
ragit/providers/base.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright RODMENA LIMITED 2025
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
#
|
|
5
|
+
"""
|
|
6
|
+
Base provider interfaces for LLM and Embedding providers.
|
|
7
|
+
|
|
8
|
+
These abstract classes define the interface that all providers must implement,
|
|
9
|
+
making it easy to add new providers (Gemini, Claude, OpenAI, etc.)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class LLMResponse:
|
|
19
|
+
"""Response from an LLM call."""
|
|
20
|
+
text: str
|
|
21
|
+
model: str
|
|
22
|
+
provider: str
|
|
23
|
+
usage: Optional[dict] = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class EmbeddingResponse:
|
|
28
|
+
"""Response from an embedding call."""
|
|
29
|
+
embedding: list[float]
|
|
30
|
+
model: str
|
|
31
|
+
provider: str
|
|
32
|
+
dimensions: int
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BaseLLMProvider(ABC):
|
|
36
|
+
"""
|
|
37
|
+
Abstract base class for LLM providers.
|
|
38
|
+
|
|
39
|
+
Implement this to add support for new LLM providers like Gemini, Claude, etc.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def provider_name(self) -> str:
|
|
45
|
+
"""Return the provider name (e.g., 'ollama', 'gemini', 'claude')."""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def generate(
|
|
50
|
+
self,
|
|
51
|
+
prompt: str,
|
|
52
|
+
model: str,
|
|
53
|
+
system_prompt: Optional[str] = None,
|
|
54
|
+
temperature: float = 0.7,
|
|
55
|
+
max_tokens: Optional[int] = None,
|
|
56
|
+
) -> LLMResponse:
|
|
57
|
+
"""
|
|
58
|
+
Generate text from the LLM.
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
prompt : str
|
|
63
|
+
The user prompt/query.
|
|
64
|
+
model : str
|
|
65
|
+
Model identifier (e.g., 'llama3', 'qwen3-vl:235b-instruct-cloud').
|
|
66
|
+
system_prompt : str, optional
|
|
67
|
+
System prompt for context/instructions.
|
|
68
|
+
temperature : float
|
|
69
|
+
Sampling temperature (0.0 to 1.0).
|
|
70
|
+
max_tokens : int, optional
|
|
71
|
+
Maximum tokens to generate.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
LLMResponse
|
|
76
|
+
The generated response.
|
|
77
|
+
"""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
@abstractmethod
|
|
81
|
+
def is_available(self) -> bool:
|
|
82
|
+
"""Check if the provider is available and configured."""
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class BaseEmbeddingProvider(ABC):
|
|
87
|
+
"""
|
|
88
|
+
Abstract base class for embedding providers.
|
|
89
|
+
|
|
90
|
+
Implement this to add support for new embedding providers.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
@abstractmethod
|
|
95
|
+
def provider_name(self) -> str:
|
|
96
|
+
"""Return the provider name."""
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def dimensions(self) -> int:
|
|
102
|
+
"""Return the embedding dimensions for the current model."""
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def embed(self, text: str, model: str) -> EmbeddingResponse:
|
|
107
|
+
"""
|
|
108
|
+
Generate embedding for text.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
text : str
|
|
113
|
+
Text to embed.
|
|
114
|
+
model : str
|
|
115
|
+
Model identifier (e.g., 'nomic-embed-text').
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
EmbeddingResponse
|
|
120
|
+
The embedding response.
|
|
121
|
+
"""
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
@abstractmethod
|
|
125
|
+
def embed_batch(self, texts: list[str], model: str) -> list[EmbeddingResponse]:
|
|
126
|
+
"""
|
|
127
|
+
Generate embeddings for multiple texts.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
texts : list[str]
|
|
132
|
+
Texts to embed.
|
|
133
|
+
model : str
|
|
134
|
+
Model identifier.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
list[EmbeddingResponse]
|
|
139
|
+
List of embedding responses.
|
|
140
|
+
"""
|
|
141
|
+
pass
|
|
142
|
+
|
|
143
|
+
@abstractmethod
|
|
144
|
+
def is_available(self) -> bool:
|
|
145
|
+
"""Check if the provider is available and configured."""
|
|
146
|
+
pass
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright RODMENA LIMITED 2025
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
#
|
|
5
|
+
"""
|
|
6
|
+
Ollama provider for LLM and Embedding operations.
|
|
7
|
+
|
|
8
|
+
This provider connects to a local or remote Ollama server.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from ragit.providers.base import (
|
|
15
|
+
BaseLLMProvider,
|
|
16
|
+
BaseEmbeddingProvider,
|
|
17
|
+
LLMResponse,
|
|
18
|
+
EmbeddingResponse,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OllamaProvider(BaseLLMProvider, BaseEmbeddingProvider):
|
|
23
|
+
"""
|
|
24
|
+
Ollama provider for both LLM and Embedding operations.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
base_url : str
|
|
29
|
+
Ollama server URL (default: http://localhost:11434)
|
|
30
|
+
timeout : int
|
|
31
|
+
Request timeout in seconds (default: 120)
|
|
32
|
+
|
|
33
|
+
Examples
|
|
34
|
+
--------
|
|
35
|
+
>>> provider = OllamaProvider()
|
|
36
|
+
>>> response = provider.generate("What is RAG?", model="llama3")
|
|
37
|
+
>>> print(response.text)
|
|
38
|
+
|
|
39
|
+
>>> embedding = provider.embed("Hello world", model="nomic-embed-text")
|
|
40
|
+
>>> print(len(embedding.embedding))
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Known embedding model dimensions
|
|
44
|
+
EMBEDDING_DIMENSIONS = {
|
|
45
|
+
"nomic-embed-text": 768,
|
|
46
|
+
"nomic-embed-text:latest": 768,
|
|
47
|
+
"mxbai-embed-large": 1024,
|
|
48
|
+
"all-minilm": 384,
|
|
49
|
+
"snowflake-arctic-embed": 1024,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
base_url: str = "http://localhost:11434",
|
|
55
|
+
timeout: int = 120,
|
|
56
|
+
):
|
|
57
|
+
self.base_url = base_url.rstrip("/")
|
|
58
|
+
self.timeout = timeout
|
|
59
|
+
self._current_embed_model: Optional[str] = None
|
|
60
|
+
self._current_dimensions: int = 768 # default
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def provider_name(self) -> str:
|
|
64
|
+
return "ollama"
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def dimensions(self) -> int:
|
|
68
|
+
return self._current_dimensions
|
|
69
|
+
|
|
70
|
+
def is_available(self) -> bool:
|
|
71
|
+
"""Check if Ollama server is reachable."""
|
|
72
|
+
try:
|
|
73
|
+
response = requests.get(f"{self.base_url}/api/tags", timeout=5)
|
|
74
|
+
return response.status_code == 200
|
|
75
|
+
except requests.RequestException:
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def list_models(self) -> list[dict]:
|
|
79
|
+
"""List available models on the Ollama server."""
|
|
80
|
+
try:
|
|
81
|
+
response = requests.get(f"{self.base_url}/api/tags", timeout=10)
|
|
82
|
+
response.raise_for_status()
|
|
83
|
+
return response.json().get("models", [])
|
|
84
|
+
except requests.RequestException as e:
|
|
85
|
+
raise ConnectionError(f"Failed to list Ollama models: {e}") from e
|
|
86
|
+
|
|
87
|
+
def generate(
|
|
88
|
+
self,
|
|
89
|
+
prompt: str,
|
|
90
|
+
model: str,
|
|
91
|
+
system_prompt: Optional[str] = None,
|
|
92
|
+
temperature: float = 0.7,
|
|
93
|
+
max_tokens: Optional[int] = None,
|
|
94
|
+
) -> LLMResponse:
|
|
95
|
+
"""Generate text using Ollama."""
|
|
96
|
+
payload = {
|
|
97
|
+
"model": model,
|
|
98
|
+
"prompt": prompt,
|
|
99
|
+
"stream": False,
|
|
100
|
+
"options": {
|
|
101
|
+
"temperature": temperature,
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if system_prompt:
|
|
106
|
+
payload["system"] = system_prompt
|
|
107
|
+
|
|
108
|
+
if max_tokens:
|
|
109
|
+
payload["options"]["num_predict"] = max_tokens
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
response = requests.post(
|
|
113
|
+
f"{self.base_url}/api/generate",
|
|
114
|
+
json=payload,
|
|
115
|
+
timeout=self.timeout,
|
|
116
|
+
)
|
|
117
|
+
response.raise_for_status()
|
|
118
|
+
data = response.json()
|
|
119
|
+
|
|
120
|
+
return LLMResponse(
|
|
121
|
+
text=data.get("response", ""),
|
|
122
|
+
model=model,
|
|
123
|
+
provider=self.provider_name,
|
|
124
|
+
usage={
|
|
125
|
+
"prompt_tokens": data.get("prompt_eval_count"),
|
|
126
|
+
"completion_tokens": data.get("eval_count"),
|
|
127
|
+
"total_duration": data.get("total_duration"),
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
except requests.RequestException as e:
|
|
131
|
+
raise ConnectionError(f"Ollama generate failed: {e}") from e
|
|
132
|
+
|
|
133
|
+
def embed(self, text: str, model: str) -> EmbeddingResponse:
|
|
134
|
+
"""Generate embedding using Ollama."""
|
|
135
|
+
self._current_embed_model = model
|
|
136
|
+
self._current_dimensions = self.EMBEDDING_DIMENSIONS.get(model, 768)
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
response = requests.post(
|
|
140
|
+
f"{self.base_url}/api/embed",
|
|
141
|
+
json={"model": model, "input": text},
|
|
142
|
+
timeout=self.timeout,
|
|
143
|
+
)
|
|
144
|
+
response.raise_for_status()
|
|
145
|
+
data = response.json()
|
|
146
|
+
|
|
147
|
+
embedding = data.get("embeddings", [[]])[0]
|
|
148
|
+
if not embedding:
|
|
149
|
+
raise ValueError("Empty embedding returned from Ollama")
|
|
150
|
+
|
|
151
|
+
# Update dimensions from actual response
|
|
152
|
+
self._current_dimensions = len(embedding)
|
|
153
|
+
|
|
154
|
+
return EmbeddingResponse(
|
|
155
|
+
embedding=embedding,
|
|
156
|
+
model=model,
|
|
157
|
+
provider=self.provider_name,
|
|
158
|
+
dimensions=len(embedding),
|
|
159
|
+
)
|
|
160
|
+
except requests.RequestException as e:
|
|
161
|
+
raise ConnectionError(f"Ollama embed failed: {e}") from e
|
|
162
|
+
|
|
163
|
+
def embed_batch(self, texts: list[str], model: str) -> list[EmbeddingResponse]:
|
|
164
|
+
"""Generate embeddings for multiple texts."""
|
|
165
|
+
self._current_embed_model = model
|
|
166
|
+
self._current_dimensions = self.EMBEDDING_DIMENSIONS.get(model, 768)
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
response = requests.post(
|
|
170
|
+
f"{self.base_url}/api/embed",
|
|
171
|
+
json={"model": model, "input": texts},
|
|
172
|
+
timeout=self.timeout,
|
|
173
|
+
)
|
|
174
|
+
response.raise_for_status()
|
|
175
|
+
data = response.json()
|
|
176
|
+
|
|
177
|
+
embeddings = data.get("embeddings", [])
|
|
178
|
+
if embeddings:
|
|
179
|
+
self._current_dimensions = len(embeddings[0])
|
|
180
|
+
|
|
181
|
+
return [
|
|
182
|
+
EmbeddingResponse(
|
|
183
|
+
embedding=emb,
|
|
184
|
+
model=model,
|
|
185
|
+
provider=self.provider_name,
|
|
186
|
+
dimensions=len(emb),
|
|
187
|
+
)
|
|
188
|
+
for emb in embeddings
|
|
189
|
+
]
|
|
190
|
+
except requests.RequestException as e:
|
|
191
|
+
raise ConnectionError(f"Ollama batch embed failed: {e}") from e
|
|
192
|
+
|
|
193
|
+
def chat(
|
|
194
|
+
self,
|
|
195
|
+
messages: list[dict],
|
|
196
|
+
model: str,
|
|
197
|
+
temperature: float = 0.7,
|
|
198
|
+
max_tokens: Optional[int] = None,
|
|
199
|
+
) -> LLMResponse:
|
|
200
|
+
"""
|
|
201
|
+
Chat completion using Ollama.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
messages : list[dict]
|
|
206
|
+
List of messages with 'role' and 'content' keys.
|
|
207
|
+
model : str
|
|
208
|
+
Model identifier.
|
|
209
|
+
temperature : float
|
|
210
|
+
Sampling temperature.
|
|
211
|
+
max_tokens : int, optional
|
|
212
|
+
Maximum tokens to generate.
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
216
|
+
LLMResponse
|
|
217
|
+
The generated response.
|
|
218
|
+
"""
|
|
219
|
+
payload = {
|
|
220
|
+
"model": model,
|
|
221
|
+
"messages": messages,
|
|
222
|
+
"stream": False,
|
|
223
|
+
"options": {
|
|
224
|
+
"temperature": temperature,
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if max_tokens:
|
|
229
|
+
payload["options"]["num_predict"] = max_tokens
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
response = requests.post(
|
|
233
|
+
f"{self.base_url}/api/chat",
|
|
234
|
+
json=payload,
|
|
235
|
+
timeout=self.timeout,
|
|
236
|
+
)
|
|
237
|
+
response.raise_for_status()
|
|
238
|
+
data = response.json()
|
|
239
|
+
|
|
240
|
+
return LLMResponse(
|
|
241
|
+
text=data.get("message", {}).get("content", ""),
|
|
242
|
+
model=model,
|
|
243
|
+
provider=self.provider_name,
|
|
244
|
+
usage={
|
|
245
|
+
"prompt_tokens": data.get("prompt_eval_count"),
|
|
246
|
+
"completion_tokens": data.get("eval_count"),
|
|
247
|
+
},
|
|
248
|
+
)
|
|
249
|
+
except requests.RequestException as e:
|
|
250
|
+
raise ConnectionError(f"Ollama chat failed: {e}") from e
|
ragit/utils/__init__.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright RODMENA LIMITED 2025
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
#
|
|
5
|
+
"""
|
|
6
|
+
Ragit utilities module.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from collections import deque
|
|
10
|
+
from collections.abc import Hashable
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from math import floor
|
|
13
|
+
from typing import Sequence
|
|
14
|
+
|
|
15
|
+
import pandas as pd
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_hashable_repr(dct: dict):
|
|
19
|
+
"""
|
|
20
|
+
Returns a hashable representation of the provided dictionary.
|
|
21
|
+
"""
|
|
22
|
+
queue = deque((k, v, 0, None) for k, v in dct.items())
|
|
23
|
+
dict_unpacked = []
|
|
24
|
+
while queue:
|
|
25
|
+
key, val, lvl, p_ref = queue.pop()
|
|
26
|
+
if hasattr(val, "items"): # we have a nested dict
|
|
27
|
+
dict_unpacked.append((key, "+", lvl, p_ref))
|
|
28
|
+
if hash(key) != p_ref:
|
|
29
|
+
lvl += 1
|
|
30
|
+
queue.extendleft((k, v, lvl, hash(key)) for k, v in val.items())
|
|
31
|
+
elif isinstance(val, Hashable):
|
|
32
|
+
dict_unpacked.append((key, val, lvl, p_ref))
|
|
33
|
+
elif isinstance(val, Sequence):
|
|
34
|
+
dict_unpacked.append((key, "+", lvl, p_ref))
|
|
35
|
+
queue.extendleft((key, vv, floor(lvl) + ind * 0.01, hash(key)) for ind, vv in enumerate(val, 1))
|
|
36
|
+
else:
|
|
37
|
+
raise ValueError(f"Unsupported type in dict: {type(val)}")
|
|
38
|
+
|
|
39
|
+
return tuple(sorted(dict_unpacked, key=lambda it: (it[2], it[0])))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def remove_duplicates(items: list[dict]) -> list[dict]:
|
|
43
|
+
"""
|
|
44
|
+
Deduplicates list of provided dictionary items.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
items : list[dict]
|
|
49
|
+
List of items to deduplicate.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
list[dict]
|
|
54
|
+
A deduplicated list of input items.
|
|
55
|
+
"""
|
|
56
|
+
duplicate_tracker = set()
|
|
57
|
+
deduplicated_items = []
|
|
58
|
+
for ind, elem in enumerate(map(get_hashable_repr, items)):
|
|
59
|
+
if elem not in duplicate_tracker:
|
|
60
|
+
duplicate_tracker.add(elem)
|
|
61
|
+
deduplicated_items.append(items[ind])
|
|
62
|
+
return deduplicated_items
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def handle_missing_values_in_combinations(df: pd.DataFrame) -> pd.DataFrame:
|
|
66
|
+
"""
|
|
67
|
+
Handle missing values in experiment data combinations.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
df : pd.DataFrame
|
|
72
|
+
Experiment data with combinations being explored.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
pd.DataFrame
|
|
77
|
+
Data with NaN values properly replaced.
|
|
78
|
+
"""
|
|
79
|
+
if "chunk_overlap" in df.columns:
|
|
80
|
+
df["chunk_overlap"] = df["chunk_overlap"].map(lambda el: 0 if pd.isna(el) else el)
|
|
81
|
+
|
|
82
|
+
return df
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def datetime_str_to_epoch_time(timestamp: str | int) -> str | int:
|
|
86
|
+
"""
|
|
87
|
+
Convert datetime string to epoch time.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
timestamp : str | int
|
|
92
|
+
Either a datetime string or a unix timestamp.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
int
|
|
97
|
+
Unix timestamp or -1 if parsing fails.
|
|
98
|
+
"""
|
|
99
|
+
if not isinstance(timestamp, str):
|
|
100
|
+
return timestamp
|
|
101
|
+
try:
|
|
102
|
+
iso_parseable = datetime.fromisoformat(timestamp)
|
|
103
|
+
except ValueError:
|
|
104
|
+
return -1
|
|
105
|
+
return int(iso_parseable.timestamp())
|
ragit/version.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ragit
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Automatic RAG Pattern Optimization Engine
|
|
5
|
+
Author: RODMENA LIMITED
|
|
6
|
+
Maintainer-email: RODMENA LIMITED <info@rodmena.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Project-URL: Homepage, https://github.com/rodmena-limited/ragit
|
|
9
|
+
Project-URL: Repository, https://github.com/rodmena-limited/ragit
|
|
10
|
+
Project-URL: Issues, https://github.com/rodmena-limited/ragit/issues
|
|
11
|
+
Keywords: AI,RAG,LLM,GenAI,Optimization,Ollama
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Requires-Python: <3.14,>=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.31.0
|
|
22
|
+
Requires-Dist: numpy>=1.26.0
|
|
23
|
+
Requires-Dist: pandas>=2.2.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: scikit-learn>=1.5.0
|
|
26
|
+
Requires-Dist: tqdm>=4.66.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: ragit[test]; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
31
|
+
Requires-Dist: black; extra == "dev"
|
|
32
|
+
Requires-Dist: pylint; extra == "dev"
|
|
33
|
+
Provides-Extra: test
|
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
|
35
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# ragit
|
|
40
|
+
|
|
41
|
+
Automatic RAG (Retrieval-Augmented Generation) hyperparameter optimization engine.
|
|
42
|
+
|
|
43
|
+
## What it does
|
|
44
|
+
|
|
45
|
+
ragit finds the best configuration for your RAG pipeline by testing different combinations of:
|
|
46
|
+
- Chunk sizes and overlaps
|
|
47
|
+
- Number of retrieved chunks
|
|
48
|
+
- Embedding models
|
|
49
|
+
- LLM models
|
|
50
|
+
|
|
51
|
+
You provide documents and benchmark questions, ragit evaluates different configurations and returns the best one.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install ragit
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from ragit import RagitExperiment, Document, BenchmarkQuestion
|
|
63
|
+
|
|
64
|
+
documents = [
|
|
65
|
+
Document(id="doc1", content="Your document text here..."),
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
benchmark = [
|
|
69
|
+
BenchmarkQuestion(
|
|
70
|
+
question="A question about your documents?",
|
|
71
|
+
ground_truth="The expected answer."
|
|
72
|
+
),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
experiment = RagitExperiment(documents, benchmark)
|
|
76
|
+
results = experiment.run()
|
|
77
|
+
|
|
78
|
+
print(results[0]) # Best configuration
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
Apache-2.0 - RODMENA LIMITED
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ragit/__init__.py,sha256=kAHylscZh8-O8YdyO_5x0Wry3yTMBu0aUAPNV6z9tng,1539
|
|
2
|
+
ragit/version.py,sha256=0QBeKFCe0Qwtua_u4nCcHvzZyfARcJVV-zvY4l2wYwA,97
|
|
3
|
+
ragit/core/__init__.py,sha256=j53PFfoSMXwSbK1rRHpMbo8mX2i4R1LJ5kvTxBd7-0w,100
|
|
4
|
+
ragit/core/experiment/__init__.py,sha256=_olxvo2Mf6fcBNhUf5YA-v2KIMb5W3UQA2hl30HLgRw,452
|
|
5
|
+
ragit/core/experiment/experiment.py,sha256=ykbLqmFMsQ7gqcHqzJ8KAEKe-BQFur6aVw5imZlKJ80,14769
|
|
6
|
+
ragit/core/experiment/results.py,sha256=UzPSVlJTfOgu6SQhVIVT8IzN4Eo7tQQ9oNGUVANCTTU,3453
|
|
7
|
+
ragit/providers/__init__.py,sha256=znyg13wFgcNKVT7YYimRRwu3nvdrrQsVA251fY8LOX4,435
|
|
8
|
+
ragit/providers/base.py,sha256=F64KxlQh9Mq1bv842y9yUcAiWdjhPxiYVQoVXqk7ULs,3428
|
|
9
|
+
ragit/providers/ollama.py,sha256=AM4_DeWv7lS78KlIEh3k8XbXOf8mMazpfjKZYIN6t4k,7637
|
|
10
|
+
ragit/utils/__init__.py,sha256=ZTlohzMF_3hMLZDaDZ94BGvP6SdqnTjJ40AVk4S1Cl0,2867
|
|
11
|
+
ragit-0.0.1.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
12
|
+
ragit-0.0.1.dist-info/METADATA,sha256=TXd4diiW82nJaYDvixdkGLXPRi451l_LVQMjI1uIr-0,2329
|
|
13
|
+
ragit-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
+
ragit-0.0.1.dist-info/top_level.txt,sha256=pkPbG7yrw61wt9_y_xcLE2vq2a55fzockASD0yq0g4s,6
|
|
15
|
+
ragit-0.0.1.dist-info/RECORD,,
|