rerankgate 0.2.0__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.
- rerankgate/__init__.py +30 -0
- rerankgate/bm25.py +70 -0
- rerankgate/cli.py +142 -0
- rerankgate/config.py +77 -0
- rerankgate/documents.py +97 -0
- rerankgate/embeddings.py +76 -0
- rerankgate/gate.py +171 -0
- rerankgate/judge.py +88 -0
- rerankgate/metrics.py +106 -0
- rerankgate/pipeline.py +301 -0
- rerankgate/rerank.py +94 -0
- rerankgate/retrieval.py +99 -0
- rerankgate/rewrite.py +38 -0
- rerankgate/store.py +78 -0
- rerankgate/tokenize.py +29 -0
- rerankgate/vectorstore.py +66 -0
- rerankgate-0.2.0.dist-info/METADATA +134 -0
- rerankgate-0.2.0.dist-info/RECORD +21 -0
- rerankgate-0.2.0.dist-info/WHEEL +5 -0
- rerankgate-0.2.0.dist-info/entry_points.txt +2 -0
- rerankgate-0.2.0.dist-info/top_level.txt +1 -0
rerankgate/rewrite.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Query rewriting without an LLM: RM3-style pseudo-relevance feedback.
|
|
2
|
+
|
|
3
|
+
Takes the top documents of a failed attempt and expands the query with
|
|
4
|
+
high-value terms from them — the classic relevance-feedback trick,
|
|
5
|
+
deterministic and free.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections import Counter
|
|
11
|
+
|
|
12
|
+
from rerankgate.retrieval import ScoredChunk
|
|
13
|
+
from rerankgate.tokenize import STOPWORDS, tokenize
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RM3Rewriter:
|
|
17
|
+
"""Expand the query with discriminative terms from top failed-attempt docs."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, expansion_terms: int = 5, top_docs: int = 3) -> None:
|
|
20
|
+
self.expansion_terms = expansion_terms
|
|
21
|
+
self.top_docs = top_docs
|
|
22
|
+
|
|
23
|
+
def rewrite(self, query: str, evidence: list[ScoredChunk]) -> str:
|
|
24
|
+
"""Return an expanded query; returns the original if nothing to add."""
|
|
25
|
+
q_terms = set(tokenize(query))
|
|
26
|
+
term_counts: Counter[str] = Counter()
|
|
27
|
+
for sc in evidence[: self.top_docs]:
|
|
28
|
+
for t in tokenize(sc.chunk.text):
|
|
29
|
+
if t not in STOPWORDS and t not in q_terms and len(t) > 2:
|
|
30
|
+
term_counts[t] += 1
|
|
31
|
+
if not term_counts:
|
|
32
|
+
return query
|
|
33
|
+
# Prefer terms that appear across multiple top docs (consensus terms).
|
|
34
|
+
ranked = sorted(term_counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
|
35
|
+
new_terms = [t for t, _ in ranked[: self.expansion_terms]]
|
|
36
|
+
if not new_terms:
|
|
37
|
+
return query
|
|
38
|
+
return query.rstrip() + " " + " ".join(new_terms)
|
rerankgate/store.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Document store: JSONL persistence for chunks + optional numpy vectors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from dataclasses import asdict
|
|
8
|
+
|
|
9
|
+
from rerankgate.documents import Chunk
|
|
10
|
+
from rerankgate.vectorstore import _HAS_NUMPY
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DocumentStore:
|
|
14
|
+
"""Persist chunks as JSONL; vectors as .npy when numpy is available."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, path: str) -> None:
|
|
17
|
+
self.path = path
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def chunks_file(self) -> str:
|
|
21
|
+
return os.path.join(self.path, "chunks.jsonl")
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def vectors_file(self) -> str:
|
|
25
|
+
return os.path.join(self.path, "vectors.npy")
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def meta_file(self) -> str:
|
|
29
|
+
return os.path.join(self.path, "meta.json")
|
|
30
|
+
|
|
31
|
+
def save(
|
|
32
|
+
self,
|
|
33
|
+
chunks: list[Chunk],
|
|
34
|
+
vectors: list[list[float]] | None = None,
|
|
35
|
+
meta: dict | None = None,
|
|
36
|
+
) -> None:
|
|
37
|
+
os.makedirs(self.path, exist_ok=True)
|
|
38
|
+
with open(self.chunks_file, "w", encoding="utf-8") as f:
|
|
39
|
+
for ch in chunks:
|
|
40
|
+
f.write(json.dumps(asdict(ch)) + "\n")
|
|
41
|
+
with open(self.meta_file, "w", encoding="utf-8") as f:
|
|
42
|
+
json.dump(
|
|
43
|
+
{
|
|
44
|
+
"chunk_count": len(chunks),
|
|
45
|
+
"has_vectors": vectors is not None,
|
|
46
|
+
"dim": len(vectors[0]) if vectors else 0,
|
|
47
|
+
**(meta or {}),
|
|
48
|
+
},
|
|
49
|
+
f,
|
|
50
|
+
)
|
|
51
|
+
if vectors is not None:
|
|
52
|
+
if not _HAS_NUMPY:
|
|
53
|
+
raise RuntimeError("numpy is required to persist vectors")
|
|
54
|
+
import numpy as np
|
|
55
|
+
|
|
56
|
+
np.save(self.vectors_file, np.asarray(vectors, dtype=np.float32))
|
|
57
|
+
|
|
58
|
+
def load(self) -> tuple[list[Chunk], list[list[float]] | None, dict]:
|
|
59
|
+
if not os.path.exists(self.chunks_file):
|
|
60
|
+
raise FileNotFoundError(f"no store at {self.path!r}: run `rerankgate ingest` first")
|
|
61
|
+
chunks: list[Chunk] = []
|
|
62
|
+
with open(self.chunks_file, encoding="utf-8") as f:
|
|
63
|
+
for line in f:
|
|
64
|
+
line = line.strip()
|
|
65
|
+
if line:
|
|
66
|
+
chunks.append(Chunk(**json.loads(line)))
|
|
67
|
+
meta: dict = {}
|
|
68
|
+
if os.path.exists(self.meta_file):
|
|
69
|
+
with open(self.meta_file, encoding="utf-8") as f:
|
|
70
|
+
meta = json.load(f)
|
|
71
|
+
vectors: list[list[float]] | None = None
|
|
72
|
+
if meta.get("has_vectors") and os.path.exists(self.vectors_file):
|
|
73
|
+
if not _HAS_NUMPY:
|
|
74
|
+
raise RuntimeError("store has vectors but numpy is not installed")
|
|
75
|
+
import numpy as np
|
|
76
|
+
|
|
77
|
+
vectors = np.load(self.vectors_file).astype(float).tolist()
|
|
78
|
+
return chunks, vectors, meta
|
rerankgate/tokenize.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Shared tokenization and stopwords."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
_TOKEN = re.compile(r"[a-z0-9]+")
|
|
8
|
+
|
|
9
|
+
STOPWORDS = frozenset(
|
|
10
|
+
"""
|
|
11
|
+
a an the and or but if then else when while of at by for with about into through
|
|
12
|
+
during before after above below to from up down in out on off over under again
|
|
13
|
+
further once here there all any both each few more most other some such no nor
|
|
14
|
+
not only own same so than too very can will just don should now is are was were
|
|
15
|
+
be been being have has had having do does did doing would could ought i you he
|
|
16
|
+
she it we they them his her its our their this that these those am as it s t
|
|
17
|
+
what which who whom how why where when
|
|
18
|
+
""".split()
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def tokenize(text: str) -> list[str]:
|
|
23
|
+
"""Lowercase alphanumeric tokens."""
|
|
24
|
+
return _TOKEN.findall(text.lower())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def content_tokens(text: str) -> list[str]:
|
|
28
|
+
"""Tokens with stopwords removed."""
|
|
29
|
+
return [t for t in tokenize(text) if t not in STOPWORDS]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Cosine-similarity vector store over chunk embeddings.
|
|
2
|
+
|
|
3
|
+
Uses numpy when available; falls back to pure Python otherwise.
|
|
4
|
+
Vectors are expected to be L2-normalized (cosine == dot product).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
|
|
11
|
+
from rerankgate.documents import Chunk
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import numpy as _np
|
|
15
|
+
|
|
16
|
+
_HAS_NUMPY = True
|
|
17
|
+
except ImportError: # pragma: no cover
|
|
18
|
+
_np = None # type: ignore
|
|
19
|
+
_HAS_NUMPY = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class VectorStore:
|
|
23
|
+
def __init__(self, dim: int) -> None:
|
|
24
|
+
self.dim = dim
|
|
25
|
+
self._chunks: list[Chunk] = []
|
|
26
|
+
self._vectors: list[list[float]] = []
|
|
27
|
+
|
|
28
|
+
def __len__(self) -> int:
|
|
29
|
+
return len(self._chunks)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def vectors(self) -> list[list[float]]:
|
|
33
|
+
"""The stored (normalized) vectors, in chunk order."""
|
|
34
|
+
return [list(v) for v in self._vectors]
|
|
35
|
+
|
|
36
|
+
def add(self, chunks: list[Chunk], vectors: list[list[float]]) -> None:
|
|
37
|
+
if len(chunks) != len(vectors):
|
|
38
|
+
raise ValueError("chunks and vectors must have equal length")
|
|
39
|
+
for v in vectors:
|
|
40
|
+
if len(v) != self.dim:
|
|
41
|
+
raise ValueError(f"expected dim {self.dim}, got {len(v)}")
|
|
42
|
+
self._chunks.extend(chunks)
|
|
43
|
+
self._vectors.extend([list(map(float, v)) for v in vectors])
|
|
44
|
+
|
|
45
|
+
def search(self, query_vec: list[float], k: int = 100) -> list[tuple[Chunk, float]]:
|
|
46
|
+
"""Top-k (chunk, cosine similarity) pairs, highest first."""
|
|
47
|
+
if not self._chunks:
|
|
48
|
+
return []
|
|
49
|
+
if _HAS_NUMPY:
|
|
50
|
+
mat = _np.asarray(self._vectors, dtype=_np.float64)
|
|
51
|
+
q = _np.asarray(query_vec, dtype=_np.float64)
|
|
52
|
+
qn = _np.linalg.norm(q) or 1.0
|
|
53
|
+
norms = _np.linalg.norm(mat, axis=1)
|
|
54
|
+
norms[norms == 0] = 1.0
|
|
55
|
+
sims = (mat @ q) / (norms * qn)
|
|
56
|
+
order = _np.argsort(-sims, kind="stable")[:k]
|
|
57
|
+
return [(self._chunks[i], float(sims[i])) for i in order]
|
|
58
|
+
# Pure-python fallback.
|
|
59
|
+
qn = math.sqrt(sum(x * x for x in query_vec)) or 1.0
|
|
60
|
+
scored = []
|
|
61
|
+
for ch, v in zip(self._chunks, self._vectors, strict=True):
|
|
62
|
+
vn = math.sqrt(sum(x * x for x in v)) or 1.0
|
|
63
|
+
sim = sum(a * b for a, b in zip(v, query_vec, strict=True)) / (vn * qn)
|
|
64
|
+
scored.append((ch, sim))
|
|
65
|
+
scored.sort(key=lambda p: p[1], reverse=True)
|
|
66
|
+
return scored[:k]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rerankgate
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Agentic RAG quality gate: hybrid retrieval with a sufficiency gate, query-rewrite retries, and per-stage metrics. Local-first.
|
|
5
|
+
Author: Calas Automations Inc.
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://calasautomations.com
|
|
8
|
+
Keywords: rag,retrieval,rerank,bm25,quality-gate,agentic
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Provides-Extra: local
|
|
16
|
+
Requires-Dist: numpy>=1.24; extra == "local"
|
|
17
|
+
Requires-Dist: sentence-transformers>=2.2; extra == "local"
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
20
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
21
|
+
|
|
22
|
+
# rerankgate
|
|
23
|
+
|
|
24
|
+
**Agentic RAG quality gate.** A drop-in retrieval pipeline with a decision point
|
|
25
|
+
between retrieval and generation:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
query → hybrid retrieval (BM25 + vectors, RRF fusion)
|
|
29
|
+
→ rerank
|
|
30
|
+
→ sufficiency gate ── PASS ─→ evidence (+ optional generation & faithfulness check)
|
|
31
|
+
FAIL ─→ rewrite query (RM3, no LLM) → retry (≤2, early-stop)
|
|
32
|
+
exhausted → ABSTAIN with evidence + reasons
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**The rule:** if the retrieval wasn't good enough, the answer never gets generated.
|
|
36
|
+
Local-first — the sufficiency gate works with zero LLM calls by default.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install rerankgate # zero hard dependencies (BM25-only mode)
|
|
42
|
+
pip install "rerankgate[local]" # + sentence-transformers, numpy (hybrid vectors)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quickstart
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from rerankgate import RAGPipeline, Document
|
|
49
|
+
|
|
50
|
+
pipe = RAGPipeline() # degrades to BM25-only if embeddings aren't installed
|
|
51
|
+
pipe.ingest([
|
|
52
|
+
Document(id="rag", text="Retrieval-augmented generation pairs a retriever..."),
|
|
53
|
+
Document(id="bm25", text="BM25 is a classic probabilistic ranking function..."),
|
|
54
|
+
])
|
|
55
|
+
|
|
56
|
+
result = pipe.ask("What is retrieval-augmented generation?")
|
|
57
|
+
print(result.verdict) # "answerable" | "insufficient" | "needs_review"
|
|
58
|
+
print(result.gate.reasons) # e.g. ["PASS"] or ["LOW_COVERAGE", ...]
|
|
59
|
+
print(result.gate.explanation) # human-readable why
|
|
60
|
+
|
|
61
|
+
# Suspected false negative? Override it — the override is recorded in the trace.
|
|
62
|
+
result = pipe.ask("...", gate_override=True)
|
|
63
|
+
|
|
64
|
+
# Optional: run your own generator through the faithfulness check.
|
|
65
|
+
result = pipe.ask("...", generator=lambda q, ev: my_llm(q, [c.chunk.text for c in ev]))
|
|
66
|
+
# verdict flips to "needs_review" if the answer isn't grounded in the evidence.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Every `ask()` returns a full `trace`: per-stage timings, retrieval modes,
|
|
70
|
+
retry count, gate features, and whether the run was degraded.
|
|
71
|
+
|
|
72
|
+
## CLI
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# JSONL corpus: {"id": ..., "text": ..., ...metadata}
|
|
76
|
+
rerankgate ingest --input corpus.jsonl --store ./store
|
|
77
|
+
|
|
78
|
+
rerankgate query --store ./store "What is RAG?"
|
|
79
|
+
rerankgate query --store ./store --gate-preset lenient --json "..."
|
|
80
|
+
|
|
81
|
+
# Evaluate retrieval + gate on labeled data, then tune the threshold.
|
|
82
|
+
# qrels JSONL: {"query": ..., "relevant_ids": [...], "answerable": true/false}
|
|
83
|
+
rerankgate eval --store ./store --qrels eval.jsonl
|
|
84
|
+
rerankgate eval --store ./store --qrels eval.jsonl --summary # aggregates only
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`rerankgate eval` reports recall@k, MRR (over answerable items), the gate
|
|
88
|
+
confusion matrix (precision/recall of PASS vs your labels), and the abstention
|
|
89
|
+
rate — use it to pick a threshold/preset instead of trusting the defaults.
|
|
90
|
+
|
|
91
|
+
## How the gate works
|
|
92
|
+
|
|
93
|
+
The sufficiency gate is a fixed weighted heuristic over interpretable features —
|
|
94
|
+
top rerank score, query-term coverage, ranking margin, and cross-chunk support —
|
|
95
|
+
plus hard floors on coverage and top score. Every decision carries stable
|
|
96
|
+
machine-readable reason codes (`PASS`, `LOW_TOP_SCORE`, `LOW_COVERAGE`,
|
|
97
|
+
`NO_MARGIN`, `NO_CONSENSUS`, `NO_EVIDENCE`) and a human explanation. Nothing is
|
|
98
|
+
learned, so there's nothing to overfit; tune it with the eval CLI.
|
|
99
|
+
|
|
100
|
+
Presets: `strict` (0.70) · `balanced` (0.55, default) · `lenient` (0.40).
|
|
101
|
+
|
|
102
|
+
## Design notes
|
|
103
|
+
|
|
104
|
+
- **Fusion:** Reciprocal Rank Fusion (k=60) — rank-based, no cross-system score
|
|
105
|
+
normalization hacks. Per-system weights available in `PipelineConfig`.
|
|
106
|
+
- **Retries:** RM3-style pseudo-relevance feedback expands the query from the
|
|
107
|
+
failed attempt's top docs — no LLM needed. Hard cap of 2 retries plus
|
|
108
|
+
diminishing-returns early stop: the loop always terminates.
|
|
109
|
+
- **Abstention > hallucination:** on `insufficient` the pipeline returns
|
|
110
|
+
best-effort evidence with gate reasons so the caller can decide — it never
|
|
111
|
+
silently hands weak context to an LLM.
|
|
112
|
+
- **Pluggable:** `EmbeddingBackend`, `Reranker`, and `Judge` are protocols.
|
|
113
|
+
Bring your own embeddings (OpenAI, Cohere…), a cross-encoder, or an
|
|
114
|
+
LLM-as-judge without touching the pipeline.
|
|
115
|
+
|
|
116
|
+
## Limitations (honest)
|
|
117
|
+
|
|
118
|
+
- The heuristic gate is tuned for English keyword overlap. Synonym-heavy,
|
|
119
|
+
cross-lingual, or highly abstract queries can under-score — use hybrid vectors
|
|
120
|
+
and/or the `lenient` preset, and calibrate with `rerankgate eval`.
|
|
121
|
+
- The default faithfulness judge is token-overlap based: free and instant, but
|
|
122
|
+
gameable by extractive copying. For adversarial settings, plug in `LLMJudge`.
|
|
123
|
+
- Default chunking is a sentence-aware character window, not semantic chunking;
|
|
124
|
+
tables and structured text chunk naively.
|
|
125
|
+
- `pip install rerankgate[local]` pulls PyTorch (~2GB) via sentence-transformers —
|
|
126
|
+
the price of local dense retrieval. BM25-only mode needs nothing.
|
|
127
|
+
- The gate threshold defaults are starting points, not tuned constants — they
|
|
128
|
+
were sanity-checked on a toy corpus, not a benchmark. Calibrate on your data.
|
|
129
|
+
- Not thread-safe; one pipeline per thread. At 500K+ vectors, prefer the numpy
|
|
130
|
+
path (installed with `[local]`) over the pure-Python fallback.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT — Calas Automations Inc.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
rerankgate/__init__.py,sha256=LzI5YMTl2bl3ik6MBC3FT9qZQLVYyrVePSpoFszpkOk,855
|
|
2
|
+
rerankgate/bm25.py,sha256=TzRofy42skIxqDKPTJqR2vCoxVM2V6AyemGMtN2Gruk,2471
|
|
3
|
+
rerankgate/cli.py,sha256=tswWUV1f8oRGsOM0L4LxZxnTVUU3HKTQsllZAze5H-g,4994
|
|
4
|
+
rerankgate/config.py,sha256=UlvgtazRfiVs9EpmoxlVpEBiErDH_YN1aolLaVQLczo,2591
|
|
5
|
+
rerankgate/documents.py,sha256=Eu-Bed4tZ2ztixuierwZu91ORwCV6_4PJhrwzzVHp3Q,2475
|
|
6
|
+
rerankgate/embeddings.py,sha256=CafeivlHHPH8meKFCEIQUP5xO30P54FU9OHiLuPIPTQ,2411
|
|
7
|
+
rerankgate/gate.py,sha256=xnc_f6-7bryHDb8XHFEkkS0Yz9Mnh8psNYnogf_FGAM,5955
|
|
8
|
+
rerankgate/judge.py,sha256=DEm4ZtKYSSSgELfhDmDdfBQ_IWIyxIlz6bNt5f42BQc,3010
|
|
9
|
+
rerankgate/metrics.py,sha256=eC4qj38Wcb_KgK7de4BBqGn1WxZt_K3Qq9sNZ1v5UJw,3755
|
|
10
|
+
rerankgate/pipeline.py,sha256=34wFVV8-ghvU42FFQuZKDDYWqmNx2VvDt4rwQyeoM5E,11819
|
|
11
|
+
rerankgate/rerank.py,sha256=93zekOAx-UKpMjUXn8iS7ebPZpDfs7aQLMAuFIoye-Y,3395
|
|
12
|
+
rerankgate/retrieval.py,sha256=_CH1Ap4-H1XsIeCO2xXjocTVc50rmNhH5MqvH8oodbI,3450
|
|
13
|
+
rerankgate/rewrite.py,sha256=HpIKS1CeaVxPipIDDawQI64ZBwwcNfKAiPGohMMu-_4,1498
|
|
14
|
+
rerankgate/store.py,sha256=0vcpUP1WCusmg2OYEkc3hd8yYTJNNdNo-49TXt-pErA,2693
|
|
15
|
+
rerankgate/tokenize.py,sha256=j0mALMp0SLSg2T7nt49hpiT_DGoUY-4aVmI02Suy9nI,984
|
|
16
|
+
rerankgate/vectorstore.py,sha256=snOyoJ7NHq_BPsXHfweDNUhAjvEvUyj7NYvy7H3xJPs,2359
|
|
17
|
+
rerankgate-0.2.0.dist-info/METADATA,sha256=4zXmMbtFCVNVQZxS3vKdsOTMG9aUTvZrkaY_Tiz1qYw,5912
|
|
18
|
+
rerankgate-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
19
|
+
rerankgate-0.2.0.dist-info/entry_points.txt,sha256=JGTMPUGp3iysG4ift10GXc4D9pmb9XCQ0wwVGoNBL6w,51
|
|
20
|
+
rerankgate-0.2.0.dist-info/top_level.txt,sha256=P95LE_w0SpQ6j-91wwJwYu9bAEf-cYW6xR2gLCJ70IY,11
|
|
21
|
+
rerankgate-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rerankgate
|