AutoRAG 0.0.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.
- autorag/__init__.py +82 -0
- autorag/chunker.py +51 -0
- autorag/cli.py +209 -0
- autorag/dashboard.py +199 -0
- autorag/data/__init__.py +109 -0
- autorag/data/chunk/__init__.py +2 -0
- autorag/data/chunk/base.py +128 -0
- autorag/data/chunk/langchain_chunk.py +76 -0
- autorag/data/chunk/llama_index_chunk.py +96 -0
- autorag/data/chunk/run.py +38 -0
- autorag/data/legacy/__init__.py +0 -0
- autorag/data/legacy/corpus/__init__.py +2 -0
- autorag/data/legacy/corpus/langchain.py +47 -0
- autorag/data/legacy/corpus/llama_index.py +93 -0
- autorag/data/legacy/qacreation/__init__.py +6 -0
- autorag/data/legacy/qacreation/base.py +239 -0
- autorag/data/legacy/qacreation/llama_index.py +253 -0
- autorag/data/legacy/qacreation/llama_index_default_prompt.txt +54 -0
- autorag/data/legacy/qacreation/ragas.py +75 -0
- autorag/data/legacy/qacreation/simple.py +99 -0
- autorag/data/parse/__init__.py +1 -0
- autorag/data/parse/base.py +79 -0
- autorag/data/parse/clova.py +194 -0
- autorag/data/parse/langchain_parse.py +87 -0
- autorag/data/parse/llamaparse.py +126 -0
- autorag/data/parse/run.py +141 -0
- autorag/data/parse/table_hybrid_parse.py +134 -0
- autorag/data/qa/__init__.py +3 -0
- autorag/data/qa/evolve/__init__.py +0 -0
- autorag/data/qa/evolve/llama_index_query_evolve.py +64 -0
- autorag/data/qa/evolve/openai_query_evolve.py +81 -0
- autorag/data/qa/evolve/prompt.py +288 -0
- autorag/data/qa/extract_evidence.py +1 -0
- autorag/data/qa/filter/__init__.py +0 -0
- autorag/data/qa/filter/dontknow.py +117 -0
- autorag/data/qa/filter/passage_dependency.py +88 -0
- autorag/data/qa/filter/prompt.py +73 -0
- autorag/data/qa/generation_gt/__init__.py +0 -0
- autorag/data/qa/generation_gt/base.py +16 -0
- autorag/data/qa/generation_gt/llama_index_gen_gt.py +41 -0
- autorag/data/qa/generation_gt/openai_gen_gt.py +84 -0
- autorag/data/qa/generation_gt/prompt.py +27 -0
- autorag/data/qa/query/__init__.py +0 -0
- autorag/data/qa/query/llama_gen_query.py +82 -0
- autorag/data/qa/query/openai_gen_query.py +95 -0
- autorag/data/qa/query/prompt.py +201 -0
- autorag/data/qa/sample.py +26 -0
- autorag/data/qa/schema.py +322 -0
- autorag/data/utils/__init__.py +0 -0
- autorag/data/utils/util.py +103 -0
- autorag/deploy/__init__.py +9 -0
- autorag/deploy/api.py +303 -0
- autorag/deploy/base.py +235 -0
- autorag/deploy/gradio.py +74 -0
- autorag/deploy/swagger.yml +202 -0
- autorag/embedding/__init__.py +0 -0
- autorag/embedding/base.py +144 -0
- autorag/embedding/vllm.py +256 -0
- autorag/evaluation/__init__.py +3 -0
- autorag/evaluation/generation.py +88 -0
- autorag/evaluation/metric/__init__.py +22 -0
- autorag/evaluation/metric/deepeval_prompt.py +322 -0
- autorag/evaluation/metric/g_eval_prompts/coh_detailed.txt +32 -0
- autorag/evaluation/metric/g_eval_prompts/con_detailed.txt +33 -0
- autorag/evaluation/metric/g_eval_prompts/flu_detailed.txt +26 -0
- autorag/evaluation/metric/g_eval_prompts/rel_detailed.txt +33 -0
- autorag/evaluation/metric/generation.py +504 -0
- autorag/evaluation/metric/retrieval.py +115 -0
- autorag/evaluation/metric/retrieval_contents.py +65 -0
- autorag/evaluation/metric/util.py +88 -0
- autorag/evaluation/retrieval.py +83 -0
- autorag/evaluation/retrieval_contents.py +65 -0
- autorag/evaluation/util.py +43 -0
- autorag/evaluator.py +559 -0
- autorag/node_line.py +65 -0
- autorag/nodes/__init__.py +0 -0
- autorag/nodes/generator/__init__.py +4 -0
- autorag/nodes/generator/base.py +103 -0
- autorag/nodes/generator/llama_index_llm.py +169 -0
- autorag/nodes/generator/openai_llm.py +329 -0
- autorag/nodes/generator/run.py +148 -0
- autorag/nodes/generator/vllm.py +147 -0
- autorag/nodes/generator/vllm_api.py +191 -0
- autorag/nodes/hybridretrieval/__init__.py +2 -0
- autorag/nodes/hybridretrieval/base.py +58 -0
- autorag/nodes/hybridretrieval/hybrid_cc.py +227 -0
- autorag/nodes/hybridretrieval/hybrid_rrf.py +149 -0
- autorag/nodes/hybridretrieval/run.py +137 -0
- autorag/nodes/lexicalretrieval/__init__.py +1 -0
- autorag/nodes/lexicalretrieval/bm25.py +381 -0
- autorag/nodes/lexicalretrieval/run.py +148 -0
- autorag/nodes/passageaugmenter/__init__.py +2 -0
- autorag/nodes/passageaugmenter/base.py +76 -0
- autorag/nodes/passageaugmenter/pass_passage_augmenter.py +43 -0
- autorag/nodes/passageaugmenter/prev_next_augmenter.py +155 -0
- autorag/nodes/passageaugmenter/run.py +131 -0
- autorag/nodes/passagecompressor/__init__.py +4 -0
- autorag/nodes/passagecompressor/base.py +78 -0
- autorag/nodes/passagecompressor/longllmlingua.py +115 -0
- autorag/nodes/passagecompressor/pass_compressor.py +16 -0
- autorag/nodes/passagecompressor/refine.py +54 -0
- autorag/nodes/passagecompressor/run.py +186 -0
- autorag/nodes/passagecompressor/tree_summarize.py +56 -0
- autorag/nodes/passagefilter/__init__.py +6 -0
- autorag/nodes/passagefilter/base.py +40 -0
- autorag/nodes/passagefilter/pass_passage_filter.py +14 -0
- autorag/nodes/passagefilter/percentile_cutoff.py +58 -0
- autorag/nodes/passagefilter/recency.py +105 -0
- autorag/nodes/passagefilter/run.py +138 -0
- autorag/nodes/passagefilter/similarity_percentile_cutoff.py +134 -0
- autorag/nodes/passagefilter/similarity_threshold_cutoff.py +112 -0
- autorag/nodes/passagefilter/threshold_cutoff.py +78 -0
- autorag/nodes/passagereranker/__init__.py +16 -0
- autorag/nodes/passagereranker/base.py +44 -0
- autorag/nodes/passagereranker/cohere.py +118 -0
- autorag/nodes/passagereranker/colbert.py +213 -0
- autorag/nodes/passagereranker/flag_embedding.py +112 -0
- autorag/nodes/passagereranker/flag_embedding_llm.py +101 -0
- autorag/nodes/passagereranker/flashrank.py +245 -0
- autorag/nodes/passagereranker/jina.py +115 -0
- autorag/nodes/passagereranker/koreranker.py +136 -0
- autorag/nodes/passagereranker/mixedbreadai.py +126 -0
- autorag/nodes/passagereranker/monot5.py +190 -0
- autorag/nodes/passagereranker/openvino.py +191 -0
- autorag/nodes/passagereranker/pass_reranker.py +31 -0
- autorag/nodes/passagereranker/rankgpt.py +170 -0
- autorag/nodes/passagereranker/run.py +145 -0
- autorag/nodes/passagereranker/sentence_transformer.py +129 -0
- autorag/nodes/passagereranker/tart/__init__.py +1 -0
- autorag/nodes/passagereranker/tart/modeling_enc_t5.py +152 -0
- autorag/nodes/passagereranker/tart/tart.py +139 -0
- autorag/nodes/passagereranker/tart/tokenization_enc_t5.py +112 -0
- autorag/nodes/passagereranker/time_reranker.py +72 -0
- autorag/nodes/passagereranker/upr.py +160 -0
- autorag/nodes/passagereranker/voyageai.py +109 -0
- autorag/nodes/promptmaker/__init__.py +12 -0
- autorag/nodes/promptmaker/base.py +32 -0
- autorag/nodes/promptmaker/chat_fstring.py +73 -0
- autorag/nodes/promptmaker/fstring.py +49 -0
- autorag/nodes/promptmaker/long_context_reorder.py +83 -0
- autorag/nodes/promptmaker/run.py +283 -0
- autorag/nodes/promptmaker/window_replacement.py +85 -0
- autorag/nodes/queryexpansion/__init__.py +4 -0
- autorag/nodes/queryexpansion/base.py +62 -0
- autorag/nodes/queryexpansion/hyde.py +43 -0
- autorag/nodes/queryexpansion/multi_query_expansion.py +57 -0
- autorag/nodes/queryexpansion/pass_query_expansion.py +22 -0
- autorag/nodes/queryexpansion/query_decompose.py +111 -0
- autorag/nodes/queryexpansion/run.py +308 -0
- autorag/nodes/retrieval/__init__.py +0 -0
- autorag/nodes/retrieval/base.py +127 -0
- autorag/nodes/retrieval/run_util.py +152 -0
- autorag/nodes/semanticretrieval/__init__.py +1 -0
- autorag/nodes/semanticretrieval/run.py +148 -0
- autorag/nodes/semanticretrieval/vectordb.py +339 -0
- autorag/nodes/util.py +16 -0
- autorag/parser.py +37 -0
- autorag/schema/__init__.py +3 -0
- autorag/schema/base.py +35 -0
- autorag/schema/metricinput.py +99 -0
- autorag/schema/module.py +24 -0
- autorag/schema/node.py +144 -0
- autorag/strategy.py +165 -0
- autorag/support.py +235 -0
- autorag/utils/__init__.py +8 -0
- autorag/utils/cast.py +45 -0
- autorag/utils/preprocess.py +149 -0
- autorag/utils/util.py +759 -0
- autorag/validator.py +98 -0
- autorag/vectordb/__init__.py +75 -0
- autorag/vectordb/base.py +73 -0
- autorag/vectordb/chroma.py +118 -0
- autorag/vectordb/couchbase.py +239 -0
- autorag/vectordb/milvus.py +169 -0
- autorag/vectordb/pinecone.py +121 -0
- autorag/vectordb/qdrant.py +155 -0
- autorag/vectordb/weaviate.py +184 -0
- autorag/web.py +81 -0
- autorag-0.0.0.dist-info/METADATA +780 -0
- autorag-0.0.0.dist-info/RECORD +184 -0
- autorag-0.0.0.dist-info/WHEEL +5 -0
- autorag-0.0.0.dist-info/entry_points.txt +2 -0
- autorag-0.0.0.dist-info/licenses/LICENSE +201 -0
- autorag-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import List, Tuple, Union
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from autorag.embedding.base import EmbeddingModel
|
|
8
|
+
from autorag.evaluation.metric.util import calculate_cosine_similarity
|
|
9
|
+
from autorag.nodes.passagefilter.base import BasePassageFilter
|
|
10
|
+
from autorag.nodes.passagefilter.similarity_threshold_cutoff import (
|
|
11
|
+
embedding_query_content,
|
|
12
|
+
)
|
|
13
|
+
from autorag.utils import result_to_dataframe
|
|
14
|
+
from autorag.utils.util import empty_cuda_cache, pop_params
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SimilarityPercentileCutoff(BasePassageFilter):
|
|
18
|
+
def __init__(self, project_dir: Union[str, Path], *args, **kwargs):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the SimilarityPercentileCutoff module
|
|
21
|
+
|
|
22
|
+
:param project_dir: The project directory to use for initializing the module
|
|
23
|
+
:param embedding_model: The embedding model string to use for calculating similarity
|
|
24
|
+
Default is "openai" which is OpenAI text-embedding-ada-002 embedding model.
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(project_dir, *args, **kwargs)
|
|
27
|
+
embedding_model = kwargs.pop("embedding_model", "openai")
|
|
28
|
+
self.embedding_model = EmbeddingModel.load(embedding_model)()
|
|
29
|
+
|
|
30
|
+
def __del__(self):
|
|
31
|
+
super().__del__()
|
|
32
|
+
del self.embedding_model
|
|
33
|
+
|
|
34
|
+
empty_cuda_cache()
|
|
35
|
+
|
|
36
|
+
@result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
|
|
37
|
+
def pure(self, previous_result: pd.DataFrame, **kwargs):
|
|
38
|
+
queries, contents, scores, ids = self.cast_to_run(previous_result)
|
|
39
|
+
kwargs = pop_params(self._pure, kwargs)
|
|
40
|
+
return self._pure(queries, contents, scores, ids, **kwargs)
|
|
41
|
+
|
|
42
|
+
def _pure(
|
|
43
|
+
self,
|
|
44
|
+
queries: List[str],
|
|
45
|
+
contents_list: List[List[str]],
|
|
46
|
+
scores_list: List[List[float]],
|
|
47
|
+
ids_list: List[List[str]],
|
|
48
|
+
percentile: float,
|
|
49
|
+
batch: int = 128,
|
|
50
|
+
) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
|
|
51
|
+
"""
|
|
52
|
+
Re-calculate each content's similarity with the query and filter out the contents that are below the content's
|
|
53
|
+
length times percentile. If This is a filter and does not override scores. The output of scores is not coming from
|
|
54
|
+
query-content similarity.
|
|
55
|
+
If the value of content's length times percentile is less than 1, keep the only one highest similarity content.
|
|
56
|
+
|
|
57
|
+
:param queries: The list of queries to use for filtering
|
|
58
|
+
:param contents_list: The list of lists of contents to filter
|
|
59
|
+
:param scores_list: The list of lists of scores retrieved
|
|
60
|
+
:param ids_list: The list of lists of ids retrieved
|
|
61
|
+
:param percentile: The percentile to cut off
|
|
62
|
+
:param batch: The number of queries to be processed in a batch
|
|
63
|
+
Default is 128.
|
|
64
|
+
:return: Tuple of lists containing the filtered contents, ids, and scores
|
|
65
|
+
"""
|
|
66
|
+
query_embeddings, content_embeddings = embedding_query_content(
|
|
67
|
+
queries, contents_list, self.embedding_model, batch
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
results = list(
|
|
71
|
+
map(
|
|
72
|
+
lambda x: self.__row_pure(x[0], x[1], x[2], x[3], x[4], percentile),
|
|
73
|
+
zip(
|
|
74
|
+
query_embeddings,
|
|
75
|
+
content_embeddings,
|
|
76
|
+
contents_list,
|
|
77
|
+
ids_list,
|
|
78
|
+
scores_list,
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
remain_content_list = list(map(lambda x: x[0], results))
|
|
84
|
+
remain_ids_list = list(map(lambda x: x[1], results))
|
|
85
|
+
remain_scores_list = list(map(lambda x: x[2], results))
|
|
86
|
+
|
|
87
|
+
return remain_content_list, remain_ids_list, remain_scores_list
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def __row_pure(
|
|
91
|
+
query_embedding: str,
|
|
92
|
+
content_embeddings: List[List[float]],
|
|
93
|
+
content_list: List[str],
|
|
94
|
+
ids_list: List[str],
|
|
95
|
+
scores_list: List[float],
|
|
96
|
+
percentile: float,
|
|
97
|
+
) -> Tuple[List[str], List[str], List[float]]:
|
|
98
|
+
"""
|
|
99
|
+
Return tuple of lists containing the filtered contents, ids, and scores
|
|
100
|
+
|
|
101
|
+
:param query_embedding: Query embedding
|
|
102
|
+
:param content_embeddings: Each content embedding
|
|
103
|
+
:param content_list: Each content
|
|
104
|
+
:param ids_list: Each id
|
|
105
|
+
:param scores_list: Each score
|
|
106
|
+
:param percentile: The percentile to cut off
|
|
107
|
+
:return: Tuple of lists containing the filtered contents, ids, and scores
|
|
108
|
+
"""
|
|
109
|
+
num_top_k = int(len(content_embeddings) * percentile)
|
|
110
|
+
|
|
111
|
+
if num_top_k == 0:
|
|
112
|
+
num_top_k = 1
|
|
113
|
+
|
|
114
|
+
similarities = np.array(
|
|
115
|
+
list(
|
|
116
|
+
map(
|
|
117
|
+
lambda x: calculate_cosine_similarity(query_embedding, x),
|
|
118
|
+
content_embeddings,
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
).tolist()
|
|
122
|
+
|
|
123
|
+
content_id_score_similarity = list(
|
|
124
|
+
zip(ids_list, content_list, scores_list, similarities)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
sorted_content_id_score_similarity = sorted(
|
|
128
|
+
content_id_score_similarity, key=lambda x: x[3], reverse=True
|
|
129
|
+
)[:num_top_k]
|
|
130
|
+
|
|
131
|
+
content_result, id_result, score_result, _ = zip(
|
|
132
|
+
*sorted_content_id_score_similarity
|
|
133
|
+
)
|
|
134
|
+
return list(content_result), list(id_result), list(score_result)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from typing import List, Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from autorag.embedding.base import EmbeddingModel
|
|
7
|
+
from autorag.evaluation.metric.util import calculate_cosine_similarity
|
|
8
|
+
from autorag.nodes.passagefilter.base import BasePassageFilter
|
|
9
|
+
from autorag.utils.util import (
|
|
10
|
+
embedding_query_content,
|
|
11
|
+
empty_cuda_cache,
|
|
12
|
+
result_to_dataframe,
|
|
13
|
+
pop_params,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SimilarityThresholdCutoff(BasePassageFilter):
|
|
18
|
+
def __init__(self, project_dir: str, *args, **kwargs):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the SimilarityThresholdCutoff module
|
|
21
|
+
|
|
22
|
+
:param project_dir: The project directory to use for initializing the module
|
|
23
|
+
:param embedding_model: The embedding model string to use for calculating similarity
|
|
24
|
+
Default is "openai" which is OpenAI text-embedding-ada-002 embedding model.
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(project_dir, *args, **kwargs)
|
|
27
|
+
embedding_model = kwargs.get("embedding_model", "openai")
|
|
28
|
+
self.embedding_model = EmbeddingModel.load(embedding_model)()
|
|
29
|
+
|
|
30
|
+
def __del__(self):
|
|
31
|
+
del self.embedding_model
|
|
32
|
+
empty_cuda_cache()
|
|
33
|
+
super().__del__()
|
|
34
|
+
|
|
35
|
+
@result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
|
|
36
|
+
def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
|
|
37
|
+
kwargs = pop_params(self._pure, kwargs)
|
|
38
|
+
queries, contents, scores, ids = self.cast_to_run(previous_result)
|
|
39
|
+
return self._pure(queries, contents, scores, ids, *args, **kwargs)
|
|
40
|
+
|
|
41
|
+
def _pure(
|
|
42
|
+
self,
|
|
43
|
+
queries: List[str],
|
|
44
|
+
contents_list: List[List[str]],
|
|
45
|
+
scores_list: List[List[float]],
|
|
46
|
+
ids_list: List[List[str]],
|
|
47
|
+
threshold: float,
|
|
48
|
+
batch: int = 128,
|
|
49
|
+
) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
|
|
50
|
+
"""
|
|
51
|
+
Re-calculate each content's similarity with the query and filter out the contents that are below the threshold.
|
|
52
|
+
If all contents are filtered, keep the only one highest similarity content.
|
|
53
|
+
This is a filter and does not override scores.
|
|
54
|
+
The output of scores is not coming from query-content similarity.
|
|
55
|
+
|
|
56
|
+
:param queries: The list of queries to use for filtering
|
|
57
|
+
:param contents_list: The list of lists of contents to filter
|
|
58
|
+
:param scores_list: The list of lists of scores retrieved
|
|
59
|
+
:param ids_list: The list of lists of ids retrieved
|
|
60
|
+
:param threshold: The threshold to cut off
|
|
61
|
+
:param batch: The number of queries to be processed in a batch
|
|
62
|
+
Default is 128.
|
|
63
|
+
:return: Tuple of lists containing the filtered contents, ids, and scores
|
|
64
|
+
"""
|
|
65
|
+
query_embeddings, content_embeddings = embedding_query_content(
|
|
66
|
+
queries, contents_list, self.embedding_model, batch
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
remain_indices = list(
|
|
70
|
+
map(
|
|
71
|
+
lambda x: self.__row_pure(x[0], x[1], threshold),
|
|
72
|
+
zip(query_embeddings, content_embeddings),
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
remain_content_list = list(
|
|
77
|
+
map(lambda c, idx: [c[i] for i in idx], contents_list, remain_indices)
|
|
78
|
+
)
|
|
79
|
+
remain_scores_list = list(
|
|
80
|
+
map(lambda s, idx: [s[i] for i in idx], scores_list, remain_indices)
|
|
81
|
+
)
|
|
82
|
+
remain_ids_list = list(
|
|
83
|
+
map(lambda _id, idx: [_id[i] for i in idx], ids_list, remain_indices)
|
|
84
|
+
)
|
|
85
|
+
return remain_content_list, remain_ids_list, remain_scores_list
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def __row_pure(
|
|
89
|
+
query_embedding: str, content_embeddings: List[List[float]], threshold: float
|
|
90
|
+
) -> List[int]:
|
|
91
|
+
"""
|
|
92
|
+
Return indices that have to remain.
|
|
93
|
+
Return at least one index if there is nothing to remain.
|
|
94
|
+
|
|
95
|
+
:param query_embedding: Query embedding
|
|
96
|
+
:param content_embeddings: Each content embedding
|
|
97
|
+
:param threshold: The threshold to cut off
|
|
98
|
+
:return: Indices to remain at the contents
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
similarities = np.array(
|
|
102
|
+
list(
|
|
103
|
+
map(
|
|
104
|
+
lambda x: calculate_cosine_similarity(query_embedding, x),
|
|
105
|
+
content_embeddings,
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
result = np.where(similarities >= threshold)[0].tolist()
|
|
110
|
+
if len(result) > 0:
|
|
111
|
+
return result
|
|
112
|
+
return [np.argmax(similarities)]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from typing import List, Tuple
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from autorag.nodes.passagefilter.base import BasePassageFilter
|
|
6
|
+
from autorag.utils.util import convert_inputs_to_list, result_to_dataframe
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ThresholdCutoff(BasePassageFilter):
|
|
10
|
+
@result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
|
|
11
|
+
def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
|
|
12
|
+
_, contents, scores, ids = self.cast_to_run(previous_result)
|
|
13
|
+
return self._pure(contents, scores, ids, *args, **kwargs)
|
|
14
|
+
|
|
15
|
+
def _pure(
|
|
16
|
+
self,
|
|
17
|
+
contents_list: List[List[str]],
|
|
18
|
+
scores_list: List[List[float]],
|
|
19
|
+
ids_list: List[List[str]],
|
|
20
|
+
threshold: float,
|
|
21
|
+
reverse: bool = False,
|
|
22
|
+
) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
|
|
23
|
+
"""
|
|
24
|
+
Filters the contents, scores, and ids based on a previous result's score.
|
|
25
|
+
Keeps at least one item per query if all scores are below the threshold.
|
|
26
|
+
|
|
27
|
+
:param contents_list: List of content strings for each query.
|
|
28
|
+
:param scores_list: List of scores for each content.
|
|
29
|
+
:param ids_list: List of ids for each content.
|
|
30
|
+
:param threshold: The minimum score to keep an item.
|
|
31
|
+
:param reverse: If True, the lower the score, the better.
|
|
32
|
+
Default is False.
|
|
33
|
+
:return: Filtered lists of contents, ids, and scores.
|
|
34
|
+
"""
|
|
35
|
+
remain_indices = list(
|
|
36
|
+
map(lambda x: self.__row_pure(x, threshold, reverse), scores_list)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
remain_content_list = list(
|
|
40
|
+
map(lambda c, idx: [c[i] for i in idx], contents_list, remain_indices)
|
|
41
|
+
)
|
|
42
|
+
remain_scores_list = list(
|
|
43
|
+
map(lambda s, idx: [s[i] for i in idx], scores_list, remain_indices)
|
|
44
|
+
)
|
|
45
|
+
remain_ids_list = list(
|
|
46
|
+
map(lambda _id, idx: [_id[i] for i in idx], ids_list, remain_indices)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return remain_content_list, remain_ids_list, remain_scores_list
|
|
50
|
+
|
|
51
|
+
@convert_inputs_to_list
|
|
52
|
+
def __row_pure(
|
|
53
|
+
self, scores_list: List[float], threshold: float, reverse: bool = False
|
|
54
|
+
) -> List[int]:
|
|
55
|
+
"""
|
|
56
|
+
Return indices that have to remain.
|
|
57
|
+
Return at least one index if there is nothing to remain.
|
|
58
|
+
|
|
59
|
+
:param scores_list: Each score
|
|
60
|
+
:param threshold: The threshold to cut off
|
|
61
|
+
:param reverse: If True, the lower the score, the better
|
|
62
|
+
Default is False.
|
|
63
|
+
:return: Indices to remain at the contents
|
|
64
|
+
"""
|
|
65
|
+
assert isinstance(scores_list, list), "scores_list must be a list."
|
|
66
|
+
|
|
67
|
+
if reverse:
|
|
68
|
+
remain_indices = [
|
|
69
|
+
i for i, score in enumerate(scores_list) if score <= threshold
|
|
70
|
+
]
|
|
71
|
+
default_index = scores_list.index(min(scores_list))
|
|
72
|
+
else:
|
|
73
|
+
remain_indices = [
|
|
74
|
+
i for i, score in enumerate(scores_list) if score >= threshold
|
|
75
|
+
]
|
|
76
|
+
default_index = scores_list.index(max(scores_list))
|
|
77
|
+
|
|
78
|
+
return remain_indices if remain_indices else [default_index]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .cohere import CohereReranker
|
|
2
|
+
from .colbert import ColbertReranker
|
|
3
|
+
from .flag_embedding import FlagEmbeddingReranker
|
|
4
|
+
from .flag_embedding_llm import FlagEmbeddingLLMReranker
|
|
5
|
+
from .jina import JinaReranker
|
|
6
|
+
from .koreranker import KoReranker
|
|
7
|
+
from .monot5 import MonoT5
|
|
8
|
+
from .pass_reranker import PassReranker
|
|
9
|
+
from .rankgpt import RankGPT
|
|
10
|
+
from .sentence_transformer import SentenceTransformerReranker
|
|
11
|
+
from .time_reranker import TimeReranker
|
|
12
|
+
from .upr import Upr
|
|
13
|
+
from .openvino import OpenVINOReranker
|
|
14
|
+
from .voyageai import VoyageAIReranker
|
|
15
|
+
from .mixedbreadai import MixedbreadAIReranker
|
|
16
|
+
from .flashrank import FlashRankReranker
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from autorag.schema import BaseModule
|
|
9
|
+
from autorag.utils import validate_qa_dataset
|
|
10
|
+
from autorag.utils.cast import cast_retrieve_infos
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("AutoRAG")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BasePassageReranker(BaseModule, metaclass=abc.ABCMeta):
|
|
16
|
+
def __init__(self, project_dir: Union[str, Path], *args, **kwargs):
|
|
17
|
+
logger.info(
|
|
18
|
+
f"Initialize passage reranker node - {self.__class__.__name__} module..."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def __del__(self):
|
|
22
|
+
logger.info(
|
|
23
|
+
f"Deleting passage reranker node - {self.__class__.__name__} module..."
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def cast_to_run(self, previous_result: pd.DataFrame, *args, **kwargs):
|
|
27
|
+
logger.info(
|
|
28
|
+
f"Running passage reranker node - {self.__class__.__name__} module..."
|
|
29
|
+
)
|
|
30
|
+
validate_qa_dataset(previous_result)
|
|
31
|
+
|
|
32
|
+
# find queries columns
|
|
33
|
+
assert "query" in previous_result.columns, (
|
|
34
|
+
"previous_result must have query column."
|
|
35
|
+
)
|
|
36
|
+
queries = previous_result["query"].tolist()
|
|
37
|
+
|
|
38
|
+
retrieve_infos = cast_retrieve_infos(previous_result)
|
|
39
|
+
return (
|
|
40
|
+
queries,
|
|
41
|
+
retrieve_infos["retrieved_contents"],
|
|
42
|
+
retrieve_infos["retrieve_scores"],
|
|
43
|
+
retrieve_infos["retrieved_ids"],
|
|
44
|
+
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List, Tuple
|
|
3
|
+
|
|
4
|
+
import cohere
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from cohere import RerankResponseResultsItem
|
|
7
|
+
|
|
8
|
+
from autorag.nodes.passagereranker.base import BasePassageReranker
|
|
9
|
+
from autorag.utils.util import get_event_loop, process_batch, result_to_dataframe
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CohereReranker(BasePassageReranker):
|
|
13
|
+
def __init__(self, project_dir: str, *args, **kwargs):
|
|
14
|
+
"""
|
|
15
|
+
Initialize Cohere rerank node.
|
|
16
|
+
|
|
17
|
+
:param project_dir: The project directory path.
|
|
18
|
+
:param api_key: The API key for Cohere rerank.
|
|
19
|
+
You can set it in the environment variable COHERE_API_KEY.
|
|
20
|
+
Or, you can directly set it on the config YAML file using this parameter.
|
|
21
|
+
Default is env variable "COHERE_API_KEY".
|
|
22
|
+
:param kwargs: Extra arguments that are not affected
|
|
23
|
+
"""
|
|
24
|
+
super().__init__(project_dir)
|
|
25
|
+
api_key = kwargs.pop("api_key", None)
|
|
26
|
+
api_key = os.getenv("COHERE_API_KEY", None) if api_key is None else api_key
|
|
27
|
+
if api_key is None:
|
|
28
|
+
api_key = os.getenv("CO_API_KEY", None)
|
|
29
|
+
if api_key is None:
|
|
30
|
+
raise KeyError(
|
|
31
|
+
"Please set the API key for Cohere rerank in the environment variable COHERE_API_KEY "
|
|
32
|
+
"or directly set it on the config YAML file."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
self.cohere_client = cohere.AsyncClientV2(api_key=api_key)
|
|
36
|
+
|
|
37
|
+
def __del__(self):
|
|
38
|
+
del self.cohere_client
|
|
39
|
+
super().__del__()
|
|
40
|
+
|
|
41
|
+
@result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
|
|
42
|
+
def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
|
|
43
|
+
queries, contents, scores, ids = self.cast_to_run(previous_result)
|
|
44
|
+
top_k = kwargs.pop("top_k")
|
|
45
|
+
batch = kwargs.pop("batch", 64)
|
|
46
|
+
model = kwargs.pop("model", "rerank-v3.5")
|
|
47
|
+
return self._pure(queries, contents, scores, ids, top_k, batch, model)
|
|
48
|
+
|
|
49
|
+
def _pure(
|
|
50
|
+
self,
|
|
51
|
+
queries: List[str],
|
|
52
|
+
contents_list: List[List[str]],
|
|
53
|
+
scores_list: List[List[float]],
|
|
54
|
+
ids_list: List[List[str]],
|
|
55
|
+
top_k: int,
|
|
56
|
+
batch: int = 64,
|
|
57
|
+
model: str = "rerank-v3.5",
|
|
58
|
+
) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
|
|
59
|
+
"""
|
|
60
|
+
Rerank a list of contents with Cohere rerank models.
|
|
61
|
+
You can get the API key from https://cohere.com/rerank and set it in the environment variable COHERE_API_KEY.
|
|
62
|
+
|
|
63
|
+
:param queries: The list of queries to use for reranking
|
|
64
|
+
:param contents_list: The list of lists of contents to rerank
|
|
65
|
+
:param scores_list: The list of lists of scores retrieved from the initial ranking
|
|
66
|
+
:param ids_list: The list of lists of ids retrieved from the initial ranking
|
|
67
|
+
:param top_k: The number of passages to be retrieved
|
|
68
|
+
:param batch: The number of queries to be processed in a batch
|
|
69
|
+
:param model: The model name for Cohere rerank.
|
|
70
|
+
You can choose between "rerank-v3.5", "rerank-english-v3.0", and "rerank-multilingual-v3.0".
|
|
71
|
+
Default is "rerank-v3.5".
|
|
72
|
+
:return: Tuple of lists containing the reranked contents, ids, and scores
|
|
73
|
+
"""
|
|
74
|
+
# Run async cohere_rerank_pure function
|
|
75
|
+
tasks = [
|
|
76
|
+
cohere_rerank_pure(self.cohere_client, model, query, document, ids, top_k)
|
|
77
|
+
for query, document, ids in zip(queries, contents_list, ids_list)
|
|
78
|
+
]
|
|
79
|
+
loop = get_event_loop()
|
|
80
|
+
results = loop.run_until_complete(process_batch(tasks, batch_size=batch))
|
|
81
|
+
content_result = list(map(lambda x: x[0], results))
|
|
82
|
+
id_result = list(map(lambda x: x[1], results))
|
|
83
|
+
score_result = list(map(lambda x: x[2], results))
|
|
84
|
+
|
|
85
|
+
return content_result, id_result, score_result
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
async def cohere_rerank_pure(
|
|
89
|
+
cohere_client: cohere.AsyncClient,
|
|
90
|
+
model: str,
|
|
91
|
+
query: str,
|
|
92
|
+
documents: List[str],
|
|
93
|
+
ids: List[str],
|
|
94
|
+
top_k: int,
|
|
95
|
+
) -> Tuple[List[str], List[str], List[float]]:
|
|
96
|
+
"""
|
|
97
|
+
Rerank a list of contents with Cohere rerank models.
|
|
98
|
+
|
|
99
|
+
:param cohere_client: The Cohere AsyncClient to use for reranking
|
|
100
|
+
:param model: The model name for Cohere rerank
|
|
101
|
+
:param query: The query to use for reranking
|
|
102
|
+
:param documents: The list of contents to rerank
|
|
103
|
+
:param ids: The list of ids corresponding to the documents
|
|
104
|
+
:param top_k: The number of passages to be retrieved
|
|
105
|
+
:return: Tuple of lists containing the reranked contents, ids, and scores
|
|
106
|
+
"""
|
|
107
|
+
rerank_results = await cohere_client.rerank(
|
|
108
|
+
model=model,
|
|
109
|
+
query=query,
|
|
110
|
+
documents=documents,
|
|
111
|
+
top_n=top_k,
|
|
112
|
+
)
|
|
113
|
+
results: List[RerankResponseResultsItem] = rerank_results.results
|
|
114
|
+
reranked_scores: List[float] = list(map(lambda x: x.relevance_score, results))
|
|
115
|
+
indices = list(map(lambda x: x.index, results))
|
|
116
|
+
reranked_contents: List[str] = list(map(lambda i: documents[i], indices))
|
|
117
|
+
reranked_ids: List[str] = list(map(lambda i: ids[i], indices))
|
|
118
|
+
return reranked_contents, reranked_ids, reranked_scores
|