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.
Files changed (184) hide show
  1. autorag/__init__.py +82 -0
  2. autorag/chunker.py +51 -0
  3. autorag/cli.py +209 -0
  4. autorag/dashboard.py +199 -0
  5. autorag/data/__init__.py +109 -0
  6. autorag/data/chunk/__init__.py +2 -0
  7. autorag/data/chunk/base.py +128 -0
  8. autorag/data/chunk/langchain_chunk.py +76 -0
  9. autorag/data/chunk/llama_index_chunk.py +96 -0
  10. autorag/data/chunk/run.py +38 -0
  11. autorag/data/legacy/__init__.py +0 -0
  12. autorag/data/legacy/corpus/__init__.py +2 -0
  13. autorag/data/legacy/corpus/langchain.py +47 -0
  14. autorag/data/legacy/corpus/llama_index.py +93 -0
  15. autorag/data/legacy/qacreation/__init__.py +6 -0
  16. autorag/data/legacy/qacreation/base.py +239 -0
  17. autorag/data/legacy/qacreation/llama_index.py +253 -0
  18. autorag/data/legacy/qacreation/llama_index_default_prompt.txt +54 -0
  19. autorag/data/legacy/qacreation/ragas.py +75 -0
  20. autorag/data/legacy/qacreation/simple.py +99 -0
  21. autorag/data/parse/__init__.py +1 -0
  22. autorag/data/parse/base.py +79 -0
  23. autorag/data/parse/clova.py +194 -0
  24. autorag/data/parse/langchain_parse.py +87 -0
  25. autorag/data/parse/llamaparse.py +126 -0
  26. autorag/data/parse/run.py +141 -0
  27. autorag/data/parse/table_hybrid_parse.py +134 -0
  28. autorag/data/qa/__init__.py +3 -0
  29. autorag/data/qa/evolve/__init__.py +0 -0
  30. autorag/data/qa/evolve/llama_index_query_evolve.py +64 -0
  31. autorag/data/qa/evolve/openai_query_evolve.py +81 -0
  32. autorag/data/qa/evolve/prompt.py +288 -0
  33. autorag/data/qa/extract_evidence.py +1 -0
  34. autorag/data/qa/filter/__init__.py +0 -0
  35. autorag/data/qa/filter/dontknow.py +117 -0
  36. autorag/data/qa/filter/passage_dependency.py +88 -0
  37. autorag/data/qa/filter/prompt.py +73 -0
  38. autorag/data/qa/generation_gt/__init__.py +0 -0
  39. autorag/data/qa/generation_gt/base.py +16 -0
  40. autorag/data/qa/generation_gt/llama_index_gen_gt.py +41 -0
  41. autorag/data/qa/generation_gt/openai_gen_gt.py +84 -0
  42. autorag/data/qa/generation_gt/prompt.py +27 -0
  43. autorag/data/qa/query/__init__.py +0 -0
  44. autorag/data/qa/query/llama_gen_query.py +82 -0
  45. autorag/data/qa/query/openai_gen_query.py +95 -0
  46. autorag/data/qa/query/prompt.py +201 -0
  47. autorag/data/qa/sample.py +26 -0
  48. autorag/data/qa/schema.py +322 -0
  49. autorag/data/utils/__init__.py +0 -0
  50. autorag/data/utils/util.py +103 -0
  51. autorag/deploy/__init__.py +9 -0
  52. autorag/deploy/api.py +303 -0
  53. autorag/deploy/base.py +235 -0
  54. autorag/deploy/gradio.py +74 -0
  55. autorag/deploy/swagger.yml +202 -0
  56. autorag/embedding/__init__.py +0 -0
  57. autorag/embedding/base.py +144 -0
  58. autorag/embedding/vllm.py +256 -0
  59. autorag/evaluation/__init__.py +3 -0
  60. autorag/evaluation/generation.py +88 -0
  61. autorag/evaluation/metric/__init__.py +22 -0
  62. autorag/evaluation/metric/deepeval_prompt.py +322 -0
  63. autorag/evaluation/metric/g_eval_prompts/coh_detailed.txt +32 -0
  64. autorag/evaluation/metric/g_eval_prompts/con_detailed.txt +33 -0
  65. autorag/evaluation/metric/g_eval_prompts/flu_detailed.txt +26 -0
  66. autorag/evaluation/metric/g_eval_prompts/rel_detailed.txt +33 -0
  67. autorag/evaluation/metric/generation.py +504 -0
  68. autorag/evaluation/metric/retrieval.py +115 -0
  69. autorag/evaluation/metric/retrieval_contents.py +65 -0
  70. autorag/evaluation/metric/util.py +88 -0
  71. autorag/evaluation/retrieval.py +83 -0
  72. autorag/evaluation/retrieval_contents.py +65 -0
  73. autorag/evaluation/util.py +43 -0
  74. autorag/evaluator.py +559 -0
  75. autorag/node_line.py +65 -0
  76. autorag/nodes/__init__.py +0 -0
  77. autorag/nodes/generator/__init__.py +4 -0
  78. autorag/nodes/generator/base.py +103 -0
  79. autorag/nodes/generator/llama_index_llm.py +169 -0
  80. autorag/nodes/generator/openai_llm.py +329 -0
  81. autorag/nodes/generator/run.py +148 -0
  82. autorag/nodes/generator/vllm.py +147 -0
  83. autorag/nodes/generator/vllm_api.py +191 -0
  84. autorag/nodes/hybridretrieval/__init__.py +2 -0
  85. autorag/nodes/hybridretrieval/base.py +58 -0
  86. autorag/nodes/hybridretrieval/hybrid_cc.py +227 -0
  87. autorag/nodes/hybridretrieval/hybrid_rrf.py +149 -0
  88. autorag/nodes/hybridretrieval/run.py +137 -0
  89. autorag/nodes/lexicalretrieval/__init__.py +1 -0
  90. autorag/nodes/lexicalretrieval/bm25.py +381 -0
  91. autorag/nodes/lexicalretrieval/run.py +148 -0
  92. autorag/nodes/passageaugmenter/__init__.py +2 -0
  93. autorag/nodes/passageaugmenter/base.py +76 -0
  94. autorag/nodes/passageaugmenter/pass_passage_augmenter.py +43 -0
  95. autorag/nodes/passageaugmenter/prev_next_augmenter.py +155 -0
  96. autorag/nodes/passageaugmenter/run.py +131 -0
  97. autorag/nodes/passagecompressor/__init__.py +4 -0
  98. autorag/nodes/passagecompressor/base.py +78 -0
  99. autorag/nodes/passagecompressor/longllmlingua.py +115 -0
  100. autorag/nodes/passagecompressor/pass_compressor.py +16 -0
  101. autorag/nodes/passagecompressor/refine.py +54 -0
  102. autorag/nodes/passagecompressor/run.py +186 -0
  103. autorag/nodes/passagecompressor/tree_summarize.py +56 -0
  104. autorag/nodes/passagefilter/__init__.py +6 -0
  105. autorag/nodes/passagefilter/base.py +40 -0
  106. autorag/nodes/passagefilter/pass_passage_filter.py +14 -0
  107. autorag/nodes/passagefilter/percentile_cutoff.py +58 -0
  108. autorag/nodes/passagefilter/recency.py +105 -0
  109. autorag/nodes/passagefilter/run.py +138 -0
  110. autorag/nodes/passagefilter/similarity_percentile_cutoff.py +134 -0
  111. autorag/nodes/passagefilter/similarity_threshold_cutoff.py +112 -0
  112. autorag/nodes/passagefilter/threshold_cutoff.py +78 -0
  113. autorag/nodes/passagereranker/__init__.py +16 -0
  114. autorag/nodes/passagereranker/base.py +44 -0
  115. autorag/nodes/passagereranker/cohere.py +118 -0
  116. autorag/nodes/passagereranker/colbert.py +213 -0
  117. autorag/nodes/passagereranker/flag_embedding.py +112 -0
  118. autorag/nodes/passagereranker/flag_embedding_llm.py +101 -0
  119. autorag/nodes/passagereranker/flashrank.py +245 -0
  120. autorag/nodes/passagereranker/jina.py +115 -0
  121. autorag/nodes/passagereranker/koreranker.py +136 -0
  122. autorag/nodes/passagereranker/mixedbreadai.py +126 -0
  123. autorag/nodes/passagereranker/monot5.py +190 -0
  124. autorag/nodes/passagereranker/openvino.py +191 -0
  125. autorag/nodes/passagereranker/pass_reranker.py +31 -0
  126. autorag/nodes/passagereranker/rankgpt.py +170 -0
  127. autorag/nodes/passagereranker/run.py +145 -0
  128. autorag/nodes/passagereranker/sentence_transformer.py +129 -0
  129. autorag/nodes/passagereranker/tart/__init__.py +1 -0
  130. autorag/nodes/passagereranker/tart/modeling_enc_t5.py +152 -0
  131. autorag/nodes/passagereranker/tart/tart.py +139 -0
  132. autorag/nodes/passagereranker/tart/tokenization_enc_t5.py +112 -0
  133. autorag/nodes/passagereranker/time_reranker.py +72 -0
  134. autorag/nodes/passagereranker/upr.py +160 -0
  135. autorag/nodes/passagereranker/voyageai.py +109 -0
  136. autorag/nodes/promptmaker/__init__.py +12 -0
  137. autorag/nodes/promptmaker/base.py +32 -0
  138. autorag/nodes/promptmaker/chat_fstring.py +73 -0
  139. autorag/nodes/promptmaker/fstring.py +49 -0
  140. autorag/nodes/promptmaker/long_context_reorder.py +83 -0
  141. autorag/nodes/promptmaker/run.py +283 -0
  142. autorag/nodes/promptmaker/window_replacement.py +85 -0
  143. autorag/nodes/queryexpansion/__init__.py +4 -0
  144. autorag/nodes/queryexpansion/base.py +62 -0
  145. autorag/nodes/queryexpansion/hyde.py +43 -0
  146. autorag/nodes/queryexpansion/multi_query_expansion.py +57 -0
  147. autorag/nodes/queryexpansion/pass_query_expansion.py +22 -0
  148. autorag/nodes/queryexpansion/query_decompose.py +111 -0
  149. autorag/nodes/queryexpansion/run.py +308 -0
  150. autorag/nodes/retrieval/__init__.py +0 -0
  151. autorag/nodes/retrieval/base.py +127 -0
  152. autorag/nodes/retrieval/run_util.py +152 -0
  153. autorag/nodes/semanticretrieval/__init__.py +1 -0
  154. autorag/nodes/semanticretrieval/run.py +148 -0
  155. autorag/nodes/semanticretrieval/vectordb.py +339 -0
  156. autorag/nodes/util.py +16 -0
  157. autorag/parser.py +37 -0
  158. autorag/schema/__init__.py +3 -0
  159. autorag/schema/base.py +35 -0
  160. autorag/schema/metricinput.py +99 -0
  161. autorag/schema/module.py +24 -0
  162. autorag/schema/node.py +144 -0
  163. autorag/strategy.py +165 -0
  164. autorag/support.py +235 -0
  165. autorag/utils/__init__.py +8 -0
  166. autorag/utils/cast.py +45 -0
  167. autorag/utils/preprocess.py +149 -0
  168. autorag/utils/util.py +759 -0
  169. autorag/validator.py +98 -0
  170. autorag/vectordb/__init__.py +75 -0
  171. autorag/vectordb/base.py +73 -0
  172. autorag/vectordb/chroma.py +118 -0
  173. autorag/vectordb/couchbase.py +239 -0
  174. autorag/vectordb/milvus.py +169 -0
  175. autorag/vectordb/pinecone.py +121 -0
  176. autorag/vectordb/qdrant.py +155 -0
  177. autorag/vectordb/weaviate.py +184 -0
  178. autorag/web.py +81 -0
  179. autorag-0.0.0.dist-info/METADATA +780 -0
  180. autorag-0.0.0.dist-info/RECORD +184 -0
  181. autorag-0.0.0.dist-info/WHEEL +5 -0
  182. autorag-0.0.0.dist-info/entry_points.txt +2 -0
  183. autorag-0.0.0.dist-info/licenses/LICENSE +201 -0
  184. autorag-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,115 @@
1
+ import os
2
+ from typing import List, Tuple
3
+
4
+ import aiohttp
5
+ import pandas as pd
6
+
7
+ from autorag.nodes.passagereranker.base import BasePassageReranker
8
+ from autorag.utils.util import get_event_loop, process_batch, result_to_dataframe
9
+
10
+ JINA_API_URL = "https://api.jina.ai/v1/rerank"
11
+
12
+
13
+ class JinaReranker(BasePassageReranker):
14
+ def __init__(self, project_dir: str, api_key: str = None, *args, **kwargs):
15
+ """
16
+ Initialize Jina rerank node.
17
+
18
+ :param project_dir: The project directory path.
19
+ :param api_key: The API key for Jina rerank.
20
+ You can set it in the environment variable JINAAI_API_KEY.
21
+ Or, you can directly set it on the config YAML file using this parameter.
22
+ Default is env variable "JINAAI_API_KEY".
23
+ :param kwargs: Extra arguments that are not affected
24
+ """
25
+ super().__init__(project_dir)
26
+ if api_key is None:
27
+ api_key = os.getenv("JINAAI_API_KEY", None)
28
+ if api_key is None:
29
+ raise ValueError(
30
+ "API key is not provided."
31
+ "You can set it as an argument or as an environment variable 'JINAAI_API_KEY'"
32
+ )
33
+ self.session = aiohttp.ClientSession(loop=get_event_loop())
34
+ self.session.headers.update(
35
+ {"Authorization": f"Bearer {api_key}", "Accept-Encoding": "identity"}
36
+ )
37
+
38
+ def __del__(self):
39
+ self.session.close()
40
+ del self.session
41
+ super().__del__()
42
+
43
+ @result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
44
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
45
+ queries, contents, _, ids = self.cast_to_run(previous_result)
46
+ top_k = kwargs.pop("top_k")
47
+ batch = kwargs.pop("batch", 8)
48
+ model = kwargs.pop("model", "jina-reranker-v1-base-en")
49
+ return self._pure(queries, contents, ids, top_k, model, batch)
50
+
51
+ def _pure(
52
+ self,
53
+ queries: List[str],
54
+ contents_list: List[List[str]],
55
+ ids_list: List[List[str]],
56
+ top_k: int,
57
+ model: str = "jina-reranker-v1-base-en",
58
+ batch: int = 8,
59
+ ) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
60
+ """
61
+ Rerank a list of contents with Jina rerank models.
62
+ You can get the API key from https://jina.ai/reranker and set it in the environment variable JINAAI_API_KEY.
63
+
64
+ :param queries: The list of queries to use for reranking
65
+ :param contents_list: The list of lists of contents to rerank
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 model: The model name for Cohere rerank.
69
+ You can choose between "jina-reranker-v1-base-en" and "jina-colbert-v1-en".
70
+ Default is "jina-reranker-v1-base-en".
71
+ :param batch: The number of queries to be processed in a batch
72
+ :return: Tuple of lists containing the reranked contents, ids, and scores
73
+ """
74
+ tasks = [
75
+ jina_reranker_pure(
76
+ self.session, query, contents, ids, top_k=top_k, model=model
77
+ )
78
+ for query, contents, ids in zip(queries, contents_list, ids_list)
79
+ ]
80
+ loop = get_event_loop()
81
+ results = loop.run_until_complete(process_batch(tasks, batch))
82
+
83
+ content_result, id_result, score_result = zip(*results)
84
+
85
+ return list(content_result), list(id_result), list(score_result)
86
+
87
+
88
+ async def jina_reranker_pure(
89
+ session,
90
+ query: str,
91
+ contents: List[str],
92
+ ids: List[str],
93
+ top_k: int,
94
+ model: str = "jina-reranker-v1-base-en",
95
+ ) -> Tuple[List[str], List[str], List[float]]:
96
+ async with session.post(
97
+ JINA_API_URL,
98
+ json={
99
+ "query": query,
100
+ "documents": contents,
101
+ "model": model,
102
+ "top_n": top_k,
103
+ },
104
+ ) as resp:
105
+ resp_json = await resp.json()
106
+ if "results" not in resp_json:
107
+ raise RuntimeError(f"Invalid response from Jina API: {resp_json['detail']}")
108
+
109
+ results = resp_json["results"]
110
+ indices = list(map(lambda x: x["index"], results))
111
+ score_result = list(map(lambda x: x["relevance_score"], results))
112
+ id_result = list(map(lambda x: ids[x], indices))
113
+ content_result = list(map(lambda x: contents[x], indices))
114
+
115
+ return content_result, id_result, score_result
@@ -0,0 +1,136 @@
1
+ from typing import List, Tuple
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ from autorag.nodes.passagereranker.base import BasePassageReranker
7
+ from autorag.utils.util import (
8
+ make_batch,
9
+ sort_by_scores,
10
+ flatten_apply,
11
+ select_top_k,
12
+ result_to_dataframe,
13
+ empty_cuda_cache,
14
+ )
15
+
16
+
17
+ class KoReranker(BasePassageReranker):
18
+ def __init__(self, project_dir: str, *args, **kwargs):
19
+ super().__init__(project_dir)
20
+ try:
21
+ import torch
22
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
23
+ except ImportError:
24
+ raise ImportError("For using KoReranker, please install torch first.")
25
+
26
+ model_path = "Dongjin-kr/ko-reranker"
27
+ self.tokenizer = AutoTokenizer.from_pretrained(model_path)
28
+ self.model = AutoModelForSequenceClassification.from_pretrained(model_path)
29
+ self.model.eval()
30
+ # Determine the device to run the model on (GPU if available, otherwise CPU)
31
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
32
+ self.model.to(self.device)
33
+
34
+ def __del__(self):
35
+ del self.model
36
+ empty_cuda_cache()
37
+ super().__del__()
38
+
39
+ @result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
40
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
41
+ queries, contents, _, ids = self.cast_to_run(previous_result)
42
+ top_k = kwargs.pop("top_k")
43
+ batch = kwargs.pop("batch", 64)
44
+ return self._pure(queries, contents, ids, top_k, batch)
45
+
46
+ def _pure(
47
+ self,
48
+ queries: List[str],
49
+ contents_list: List[List[str]],
50
+ ids_list: List[List[str]],
51
+ top_k: int,
52
+ batch: int = 64,
53
+ ) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
54
+ """
55
+ Rerank a list of contents based on their relevance to a query using ko-reranker.
56
+ ko-reranker is a reranker based on korean (https://huggingface.co/Dongjin-kr/ko-reranker).
57
+
58
+ :param queries: The list of queries to use for reranking
59
+ :param contents_list: The list of lists of contents to rerank
60
+ :param ids_list: The list of lists of ids retrieved from the initial ranking
61
+ :param top_k: The number of passages to be retrieved
62
+ :param batch: The number of queries to be processed in a batch
63
+ Default is 64.
64
+ :return: Tuple of lists containing the reranked contents, ids, and scores
65
+ """
66
+ nested_list = [
67
+ list(map(lambda x: [query, x], content_list))
68
+ for query, content_list in zip(queries, contents_list)
69
+ ]
70
+ scores_nps = flatten_apply(
71
+ koreranker_run_model,
72
+ nested_list,
73
+ model=self.model,
74
+ batch_size=batch,
75
+ tokenizer=self.tokenizer,
76
+ device=self.device,
77
+ )
78
+
79
+ rerank_scores = list(
80
+ map(
81
+ lambda scores: exp_normalize(np.array(scores)).astype(float), scores_nps
82
+ )
83
+ )
84
+
85
+ df = pd.DataFrame(
86
+ {
87
+ "contents": contents_list,
88
+ "ids": ids_list,
89
+ "scores": rerank_scores,
90
+ }
91
+ )
92
+ df[["contents", "ids", "scores"]] = df.apply(
93
+ sort_by_scores, axis=1, result_type="expand"
94
+ )
95
+ results = select_top_k(df, ["contents", "ids", "scores"], top_k)
96
+
97
+ return (
98
+ results["contents"].tolist(),
99
+ results["ids"].tolist(),
100
+ results["scores"].tolist(),
101
+ )
102
+
103
+
104
+ def koreranker_run_model(input_texts, model, tokenizer, device, batch_size: int):
105
+ try:
106
+ import torch
107
+ except ImportError:
108
+ raise ImportError("For using KoReranker, please install torch first.")
109
+ batch_input_texts = make_batch(input_texts, batch_size)
110
+ results = []
111
+ for batch_texts in batch_input_texts:
112
+ inputs = tokenizer(
113
+ batch_texts,
114
+ padding=True,
115
+ truncation=True,
116
+ return_tensors="pt",
117
+ max_length=512,
118
+ )
119
+ inputs = inputs.to(device)
120
+ with torch.no_grad():
121
+ scores = (
122
+ model(**inputs, return_dict=True)
123
+ .logits.view(
124
+ -1,
125
+ )
126
+ .float()
127
+ )
128
+ scores_np = scores.cpu().numpy()
129
+ results.extend(scores_np)
130
+ return results
131
+
132
+
133
+ def exp_normalize(x):
134
+ b = x.max()
135
+ y = np.exp(x - b)
136
+ return y / y.sum()
@@ -0,0 +1,126 @@
1
+ import os
2
+ from typing import List, Tuple
3
+
4
+ import pandas as pd
5
+ from mixedbread_ai.client import AsyncMixedbreadAI
6
+
7
+ from autorag.nodes.passagereranker.base import BasePassageReranker
8
+ from autorag.utils.util import (
9
+ result_to_dataframe,
10
+ get_event_loop,
11
+ process_batch,
12
+ pop_params,
13
+ )
14
+
15
+
16
+ class MixedbreadAIReranker(BasePassageReranker):
17
+ def __init__(
18
+ self,
19
+ project_dir: str,
20
+ *args,
21
+ **kwargs,
22
+ ):
23
+ """
24
+ Initialize mixedbread-ai rerank node.
25
+
26
+ :param project_dir: The project directory path.
27
+ :param api_key: The API key for MixedbreadAI rerank.
28
+ You can set it in the environment variable MXBAI_API_KEY.
29
+ Or, you can directly set it on the config YAML file using this parameter.
30
+ Default is env variable "MXBAI_API_KEY".
31
+ :param kwargs: Extra arguments that are not affected
32
+ """
33
+ super().__init__(project_dir)
34
+ api_key = kwargs.pop("api_key", None)
35
+ api_key = os.getenv("MXBAI_API_KEY", None) if api_key is None else api_key
36
+ if api_key is None:
37
+ raise KeyError(
38
+ "Please set the API key for Mixedbread AI rerank in the environment variable MXBAI_API_KEY "
39
+ "or directly set it on the config YAML file."
40
+ )
41
+ self.client = AsyncMixedbreadAI(api_key=api_key)
42
+
43
+ def __del__(self):
44
+ del self.client
45
+ super().__del__()
46
+
47
+ @result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
48
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
49
+ queries, contents, scores, ids = self.cast_to_run(previous_result)
50
+ top_k = kwargs.pop("top_k")
51
+ batch = kwargs.pop("batch", 8)
52
+ model = kwargs.pop("model", "mixedbread-ai/mxbai-rerank-large-v1")
53
+ rerank_params = pop_params(self.client.reranking, kwargs)
54
+ return self._pure(queries, contents, ids, top_k, model, batch, **rerank_params)
55
+
56
+ def _pure(
57
+ self,
58
+ queries: List[str],
59
+ contents_list: List[List[str]],
60
+ ids_list: List[List[str]],
61
+ top_k: int,
62
+ model: str = "mixedbread-ai/mxbai-rerank-large-v1",
63
+ batch: int = 8,
64
+ ) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
65
+ """
66
+ Rerank a list of contents with mixedbread-ai rerank models.
67
+ You can get the API key from https://www.mixedbread.ai/api-reference#quick-start-guide and set it in the environment variable MXBAI_API_KEY.
68
+
69
+ :param queries: The list of queries to use for reranking
70
+ :param contents_list: The list of lists of contents to rerank
71
+ :param ids_list: The list of lists of ids retrieved from the initial ranking
72
+ :param top_k: The number of passages to be retrieved
73
+ :param model: The model name for mixedbread-ai rerank.
74
+ You can choose between "mixedbread-ai/mxbai-rerank-large-v1", "mixedbread-ai/mxbai-rerank-base-v1" and "mixedbread-ai/mxbai-rerank-xsmall-v1".
75
+ Default is "mixedbread-ai/mxbai-rerank-large-v1".
76
+ :param batch: The number of queries to be processed in a batch
77
+ :return: Tuple of lists containing the reranked contents, ids, and scores
78
+ """
79
+ tasks = [
80
+ mixedbreadai_rerank_pure(
81
+ self.client, query, contents, ids, top_k=top_k, model=model
82
+ )
83
+ for query, contents, ids in zip(queries, contents_list, ids_list)
84
+ ]
85
+ loop = get_event_loop()
86
+ results = loop.run_until_complete(process_batch(tasks, batch))
87
+
88
+ content_result, id_result, score_result = zip(*results)
89
+
90
+ return list(content_result), list(id_result), list(score_result)
91
+
92
+
93
+ async def mixedbreadai_rerank_pure(
94
+ client: AsyncMixedbreadAI,
95
+ query: str,
96
+ documents: List[str],
97
+ ids: List[str],
98
+ top_k: int,
99
+ model: str = "mixedbread-ai/mxbai-rerank-large-v1",
100
+ ) -> Tuple[List[str], List[str], List[float]]:
101
+ """
102
+ Rerank a list of contents with mixedbread-ai rerank models.
103
+
104
+ :param client: The mixedbread-ai client to use for reranking
105
+ :param query: The query to use for reranking
106
+ :param documents: The list of contents to rerank
107
+ :param ids: The list of ids corresponding to the documents
108
+ :param top_k: The number of passages to be retrieved
109
+ :param model: The model name for mixedbread-ai rerank.
110
+ You can choose between "mixedbread-ai/mxbai-rerank-large-v1" and "mixedbread-ai/mxbai-rerank-base-v1".
111
+ Default is "mixedbread-ai/mxbai-rerank-large-v1".
112
+ :return: Tuple of lists containing the reranked contents, ids, and scores
113
+ """
114
+
115
+ results = await client.reranking(
116
+ query=query,
117
+ input=documents,
118
+ top_k=top_k,
119
+ model=model,
120
+ )
121
+ reranked_scores: List[float] = list(map(lambda x: x.score, results.data))
122
+ reranked_scores_float = list(map(float, reranked_scores))
123
+ indices = list(map(lambda x: x.index, results.data))
124
+ reranked_contents = list(map(lambda x: documents[x], indices))
125
+ reranked_ids: List[str] = list(map(lambda i: ids[i], indices))
126
+ return reranked_contents, reranked_ids, reranked_scores_float
@@ -0,0 +1,190 @@
1
+ from itertools import chain
2
+ from typing import List, Tuple
3
+
4
+ import pandas as pd
5
+
6
+ from autorag.nodes.passagereranker.base import BasePassageReranker
7
+ from autorag.utils.util import (
8
+ make_batch,
9
+ sort_by_scores,
10
+ flatten_apply,
11
+ select_top_k,
12
+ result_to_dataframe,
13
+ pop_params,
14
+ empty_cuda_cache,
15
+ )
16
+
17
+ prediction_tokens = {
18
+ "castorini/monot5-base-msmarco": ["▁false", "▁true"],
19
+ "castorini/monot5-base-msmarco-10k": ["▁false", "▁true"],
20
+ "castorini/monot5-large-msmarco": ["▁false", "▁true"],
21
+ "castorini/monot5-large-msmarco-10k": ["▁false", "▁true"],
22
+ "castorini/monot5-base-med-msmarco": ["▁false", "▁true"],
23
+ "castorini/monot5-3b-med-msmarco": ["▁false", "▁true"],
24
+ "castorini/monot5-3b-msmarco-10k": ["▁false", "▁true"],
25
+ "unicamp-dl/mt5-base-en-msmarco": ["▁no", "▁yes"],
26
+ "unicamp-dl/ptt5-base-pt-msmarco-10k-v2": ["▁não", "▁sim"],
27
+ "unicamp-dl/ptt5-base-pt-msmarco-100k-v2": ["▁não", "▁sim"],
28
+ "unicamp-dl/ptt5-base-en-pt-msmarco-100k-v2": ["▁não", "▁sim"],
29
+ "unicamp-dl/mt5-base-en-pt-msmarco-v2": ["▁no", "▁yes"],
30
+ "unicamp-dl/mt5-base-mmarco-v2": ["▁no", "▁yes"],
31
+ "unicamp-dl/mt5-base-en-pt-msmarco-v1": ["▁no", "▁yes"],
32
+ "unicamp-dl/mt5-base-mmarco-v1": ["▁no", "▁yes"],
33
+ "unicamp-dl/ptt5-base-pt-msmarco-10k-v1": ["▁não", "▁sim"],
34
+ "unicamp-dl/ptt5-base-pt-msmarco-100k-v1": ["▁não", "▁sim"],
35
+ "unicamp-dl/ptt5-base-en-pt-msmarco-10k-v1": ["▁não", "▁sim"],
36
+ "unicamp-dl/mt5-3B-mmarco-en-pt": ["▁", "▁true"],
37
+ "unicamp-dl/mt5-13b-mmarco-100k": ["▁", "▁true"],
38
+ }
39
+
40
+
41
+ class MonoT5(BasePassageReranker):
42
+ def __init__(
43
+ self,
44
+ project_dir: str,
45
+ model_name: str = "castorini/monot5-3b-msmarco-10k",
46
+ *args,
47
+ **kwargs,
48
+ ):
49
+ """
50
+ Initialize the MonoT5 reranker.
51
+
52
+ :param project_dir: The project directory
53
+ :param model_name: The name of the MonoT5 model to use for reranking
54
+ Note: default model name is 'castorini/monot5-3b-msmarco-10k'
55
+ If there is a '/' in the model name parameter,
56
+ when we create the file to store the results, the path will be twisted because of the '/'.
57
+ Therefore, it will be received as '_' instead of '/'.
58
+ :param kwargs: The extra arguments for the MonoT5 reranker
59
+ """
60
+ super().__init__(project_dir)
61
+ try:
62
+ import torch
63
+ from transformers import T5Tokenizer, T5ForConditionalGeneration
64
+ except ImportError:
65
+ raise ImportError("For using MonoT5 Reranker, please install torch first.")
66
+ # replace '_' to '/'
67
+ if "_" in model_name:
68
+ model_name = model_name.replace("_", "/")
69
+ # Load the tokenizer and model from the pre-trained MonoT5 model
70
+ self.tokenizer = T5Tokenizer.from_pretrained(model_name)
71
+ model_params = pop_params(T5ForConditionalGeneration.from_pretrained, kwargs)
72
+ self.model = T5ForConditionalGeneration.from_pretrained(
73
+ model_name, **model_params
74
+ ).eval()
75
+
76
+ # Determine the device to run the model on (GPU if available, otherwise CPU)
77
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
78
+ self.model.to(self.device)
79
+
80
+ token_false, token_true = prediction_tokens[model_name]
81
+ self.token_false_id = self.tokenizer.convert_tokens_to_ids(token_false)
82
+ self.token_true_id = self.tokenizer.convert_tokens_to_ids(token_true)
83
+
84
+ def __del__(self):
85
+ del self.model
86
+ del self.tokenizer
87
+ empty_cuda_cache()
88
+ super().__del__()
89
+
90
+ @result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
91
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
92
+ queries, contents, _, ids = self.cast_to_run(previous_result)
93
+ top_k = kwargs.get("top_k", 3)
94
+ batch = kwargs.get("batch", 64)
95
+ return self._pure(queries, contents, ids, top_k, batch)
96
+
97
+ def _pure(
98
+ self,
99
+ queries: List[str],
100
+ contents_list: List[List[str]],
101
+ ids_list: List[List[str]],
102
+ top_k: int,
103
+ batch: int = 64,
104
+ ) -> Tuple[List[List[str]], List[List[str]], List[List[float]]]:
105
+ """
106
+ Rerank a list of contents based on their relevance to a query using MonoT5.
107
+
108
+ :param queries: The list of queries to use for reranking
109
+ :param contents_list: The list of lists of contents to rerank
110
+ :param ids_list: The list of lists of ids retrieved from the initial ranking
111
+ :param top_k: The number of passages to be retrieved
112
+
113
+ :param batch: The number of queries to be processed in a batch
114
+ :return: tuple of lists containing the reranked contents, ids, and scores
115
+ """
116
+ # Retrieve the tokens used by the model to represent false and true predictions
117
+
118
+ nested_list = [
119
+ list(map(lambda x: [f"Query: {query} Document: {x}"], content_list))
120
+ for query, content_list in zip(queries, contents_list)
121
+ ]
122
+
123
+ rerank_scores = flatten_apply(
124
+ monot5_run_model,
125
+ nested_list,
126
+ model=self.model,
127
+ batch_size=batch,
128
+ tokenizer=self.tokenizer,
129
+ device=self.device,
130
+ token_false_id=self.token_false_id,
131
+ token_true_id=self.token_true_id,
132
+ )
133
+
134
+ df = pd.DataFrame(
135
+ {
136
+ "contents": contents_list,
137
+ "ids": ids_list,
138
+ "scores": rerank_scores,
139
+ }
140
+ )
141
+ df[["contents", "ids", "scores"]] = df.apply(
142
+ sort_by_scores, axis=1, result_type="expand"
143
+ )
144
+ results = select_top_k(df, ["contents", "ids", "scores"], top_k)
145
+
146
+ return (
147
+ results["contents"].tolist(),
148
+ results["ids"].tolist(),
149
+ results["scores"].tolist(),
150
+ )
151
+
152
+
153
+ def monot5_run_model(
154
+ input_texts,
155
+ model,
156
+ batch_size: int,
157
+ tokenizer,
158
+ device,
159
+ token_false_id,
160
+ token_true_id,
161
+ ):
162
+ try:
163
+ import torch
164
+ except ImportError:
165
+ raise ImportError("For using MonoT5 Reranker, please install torch first.")
166
+ batch_input_texts = make_batch(input_texts, batch_size)
167
+ results = []
168
+ for batch_texts in batch_input_texts:
169
+ flattened_batch_texts = list(chain.from_iterable(batch_texts))
170
+ input_encodings = tokenizer(
171
+ flattened_batch_texts,
172
+ padding=True,
173
+ truncation=True,
174
+ max_length=512,
175
+ return_tensors="pt",
176
+ ).to(device)
177
+ with torch.no_grad():
178
+ outputs = model.generate(
179
+ input_ids=input_encodings["input_ids"],
180
+ attention_mask=input_encodings["attention_mask"],
181
+ output_scores=True,
182
+ return_dict_in_generate=True,
183
+ )
184
+
185
+ # Extract logits for the 'false' and 'true' tokens from the model's output
186
+ logits = outputs.scores[-1][:, [token_false_id, token_true_id]]
187
+ # Calculate the softmax probability of the 'true' token
188
+ probs = torch.nn.functional.softmax(logits, dim=-1)[:, 1]
189
+ results.extend(probs.tolist())
190
+ return results