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
autorag/strategy.py ADDED
@@ -0,0 +1,165 @@
1
+ import functools
2
+ import time
3
+ from typing import List, Iterable, Tuple, Any, Optional, Callable
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+
9
+ def measure_speed(func, *args, **kwargs):
10
+ """
11
+ Method for measuring execution speed of the function.
12
+ """
13
+ start_time = time.time()
14
+ result = func(*args, **kwargs)
15
+ end_time = time.time()
16
+ return result, end_time - start_time
17
+
18
+
19
+ def avoid_empty_result(return_index: List[int]):
20
+ """
21
+ Decorator for avoiding empty results from the function.
22
+ When the func returns an empty result, it will return the origin results.
23
+ When the func returns a None, it will return the origin results.
24
+ When the return value is a tuple, it will check all the value or list is empty.
25
+ If so, it will return the origin results.
26
+ It keeps parameters at return_index of the function as the origin results.
27
+
28
+ :param return_index: The index of the result to be returned when there is no result.
29
+ :return: The origin results or the results from the function.
30
+ """
31
+
32
+ def decorator_avoid_empty_result(func: Callable):
33
+ @functools.wraps(func)
34
+ def wrapper(*args, **kwargs) -> List:
35
+ func_result = func(*args, **kwargs)
36
+ if isinstance(func_result, tuple):
37
+ # if all the results are empty, return the origin results.
38
+ if all([not bool(result) for result in func_result]):
39
+ return [args[index] for index in return_index]
40
+ if not bool(func_result):
41
+ return [args[index] for index in return_index]
42
+ else:
43
+ return func_result
44
+
45
+ return wrapper
46
+
47
+ return decorator_avoid_empty_result
48
+
49
+
50
+ @avoid_empty_result([0, 3])
51
+ def filter_by_threshold(results, value, threshold, metadatas=None) -> Tuple[List, List]:
52
+ """
53
+ Filter results by value's threshold.
54
+
55
+ :param results: The result list to be filtered.
56
+ :param value: The value list to be filtered.
57
+ It must have the same length with results.
58
+ :param threshold: The threshold value.
59
+ :param metadatas: The metadata of each result.
60
+ :return: Filtered list of results and filtered list of metadatas.
61
+ Metadatas will be returned even if you did not give input metadatas.
62
+ :rtype: Tuple[List, List]
63
+ """
64
+ if metadatas is None:
65
+ metadatas = [None] * len(results)
66
+ assert len(results) == len(value), "results and value must have the same length."
67
+ try:
68
+ filtered_results, _, filtered_metadatas = zip(
69
+ *filter(lambda x: x[1] <= threshold, zip(results, value, metadatas))
70
+ )
71
+ except ValueError:
72
+ return [], []
73
+ return list(filtered_results), list(filtered_metadatas)
74
+
75
+
76
+ def validate_strategy_inputs(
77
+ results: List[pd.DataFrame],
78
+ columns: Iterable[str],
79
+ metadatas: Optional[List[Any]] = None,
80
+ ):
81
+ if metadatas is None:
82
+ metadatas = [None] * len(results)
83
+ assert len(results) == len(metadatas), (
84
+ "results and module_filename must have the same length."
85
+ )
86
+ assert all([isinstance(result, pd.DataFrame) for result in results]), (
87
+ "results must be pd.DataFrame."
88
+ )
89
+ assert all(
90
+ [column in result.columns for result in results for column in columns]
91
+ ), "columns must be in the columns of results."
92
+ return results, columns, metadatas
93
+
94
+
95
+ def select_best(
96
+ results: List[pd.DataFrame],
97
+ columns: Iterable[str],
98
+ metadatas: Optional[List[Any]] = None,
99
+ strategy_name: str = "mean",
100
+ ) -> Tuple[pd.DataFrame, Any]:
101
+ strategy_func_dict = {
102
+ "mean": select_best_average,
103
+ "rank": select_best_rr,
104
+ "normalize_mean": select_normalize_mean,
105
+ }
106
+ if strategy_name not in strategy_func_dict:
107
+ raise ValueError(
108
+ f"Input strategy name {strategy_name} is not in {strategy_func_dict.keys()}"
109
+ )
110
+
111
+ return strategy_func_dict[strategy_name](results, columns, metadatas)
112
+
113
+
114
+ def select_best_average(
115
+ results: List[pd.DataFrame],
116
+ columns: Iterable[str],
117
+ metadatas: Optional[List[Any]] = None,
118
+ ) -> Tuple[pd.DataFrame, Any]:
119
+ """
120
+ Select the best result by average value among given columns.
121
+
122
+ :param results: The list of results.
123
+ Each result must be pd.DataFrame.
124
+ :param columns: Column names to be averaged.
125
+ Standard to select the best result.
126
+ :param metadatas: The metadata of each result.
127
+ It will select one metadata with the best result.
128
+ :return: The best result and the best metadata.
129
+ The metadata will be returned even if you did not give input 'metadatas' parameter.
130
+ :rtype: Tuple[pd.DataFrame, Any]
131
+ """
132
+ results, columns, metadatas = validate_strategy_inputs(results, columns, metadatas)
133
+ each_average = [df[columns].mean(axis=1).mean() for df in results]
134
+ best_index = each_average.index(max(each_average))
135
+ return results[best_index], metadatas[best_index]
136
+
137
+
138
+ def select_best_rr(
139
+ results: List[pd.DataFrame],
140
+ columns: Iterable[str],
141
+ metadatas: Optional[List[Any]] = None,
142
+ ) -> Tuple[pd.DataFrame, Any]:
143
+ results, columns, metadatas = validate_strategy_inputs(results, columns, metadatas)
144
+ each_average_df = pd.DataFrame(
145
+ [df[columns].mean(axis=0).to_dict() for df in results]
146
+ )
147
+ rank_df = each_average_df.rank(ascending=False)
148
+ rr_df = rank_df.map(lambda x: 1 / x)
149
+ best_index = np.array(rr_df.sum(axis=1)).argmax()
150
+ return results[best_index], metadatas[best_index]
151
+
152
+
153
+ def select_normalize_mean(
154
+ results: List[pd.DataFrame],
155
+ columns: Iterable[str],
156
+ metadatas: Optional[List[Any]] = None,
157
+ ) -> Tuple[pd.DataFrame, Any]:
158
+ results, columns, metadatas = validate_strategy_inputs(results, columns, metadatas)
159
+ each_mean_df = pd.DataFrame([df[columns].mean(axis=0).to_dict() for df in results])
160
+ normalized_means = (each_mean_df - each_mean_df.min()) / (
161
+ each_mean_df.max() - each_mean_df.min()
162
+ )
163
+ normalized_mean_sums = normalized_means.sum(axis=1)
164
+ best_index = normalized_mean_sums.argmax()
165
+ return results[best_index], metadatas[best_index]
autorag/support.py ADDED
@@ -0,0 +1,235 @@
1
+ import importlib
2
+ from typing import Callable, Dict
3
+
4
+
5
+ def dynamically_find_function(key: str, target_dict: Dict) -> Callable:
6
+ if key in target_dict:
7
+ module_path, func_name = target_dict[key]
8
+ module = importlib.import_module(module_path)
9
+ func = getattr(module, func_name)
10
+ return func
11
+ else:
12
+ raise KeyError(f"Input module or node {key} is not supported.")
13
+
14
+
15
+ def get_support_modules(module_name: str) -> Callable:
16
+ support_modules = {
17
+ # parse
18
+ "langchain_parse": ("autorag.data.parse", "langchain_parse"),
19
+ "clova": ("autorag.data.parse.clova", "clova_ocr"),
20
+ "llamaparse": ("autorag.data.parse.llamaparse", "llama_parse"),
21
+ "table_hybrid_parse": (
22
+ "autorag.data.parse.table_hybrid_parse",
23
+ "table_hybrid_parse",
24
+ ),
25
+ # chunk
26
+ "llama_index_chunk": ("autorag.data.chunk", "llama_index_chunk"),
27
+ "langchain_chunk": ("autorag.data.chunk", "langchain_chunk"),
28
+ # query_expansion
29
+ "query_decompose": ("autorag.nodes.queryexpansion", "QueryDecompose"),
30
+ "hyde": ("autorag.nodes.queryexpansion", "HyDE"),
31
+ "pass_query_expansion": (
32
+ "autorag.nodes.queryexpansion",
33
+ "PassQueryExpansion",
34
+ ),
35
+ "multi_query_expansion": (
36
+ "autorag.nodes.queryexpansion",
37
+ "MultiQueryExpansion",
38
+ ),
39
+ "QueryDecompose": ("autorag.nodes.queryexpansion", "QueryDecompose"),
40
+ "HyDE": ("autorag.nodes.queryexpansion", "HyDE"),
41
+ "PassQueryExpansion": (
42
+ "autorag.nodes.queryexpansion",
43
+ "PassQueryExpansion",
44
+ ),
45
+ "MultiQueryExpansion": (
46
+ "autorag.nodes.queryexpansion",
47
+ "MultiQueryExpansion",
48
+ ),
49
+ # retrieval
50
+ "bm25": ("autorag.nodes.lexicalretrieval", "BM25"),
51
+ "BM25": ("autorag.nodes.lexicalretrieval", "BM25"),
52
+ "vectordb": ("autorag.nodes.semanticretrieval", "VectorDB"),
53
+ "VectorDB": ("autorag.nodes.semanticretrieval", "VectorDB"),
54
+ "hybrid_rrf": ("autorag.nodes.hybridretrieval", "HybridRRF"),
55
+ "HybridRRF": ("autorag.nodes.hybridretrieval", "HybridRRF"),
56
+ "hybrid_cc": ("autorag.nodes.hybridretrieval", "HybridCC"),
57
+ "HybridCC": ("autorag.nodes.hybridretrieval", "HybridCC"),
58
+ # passage_augmenter
59
+ "prev_next_augmenter": (
60
+ "autorag.nodes.passageaugmenter",
61
+ "PrevNextPassageAugmenter",
62
+ ),
63
+ "PrevNextPassageAugmenter": (
64
+ "autorag.nodes.passageaugmenter",
65
+ "PrevNextPassageAugmenter",
66
+ ),
67
+ "pass_passage_augmenter": (
68
+ "autorag.nodes.passageaugmenter",
69
+ "PassPassageAugmenter",
70
+ ),
71
+ "PassPassageAugmenter": (
72
+ "autorag.nodes.passageaugmenter",
73
+ "PassPassageAugmenter",
74
+ ),
75
+ # passage_reranker
76
+ "monot5": ("autorag.nodes.passagereranker", "MonoT5"),
77
+ "MonoT5": ("autorag.nodes.passagereranker", "MonoT5"),
78
+ "tart": ("autorag.nodes.passagereranker.tart", "Tart"),
79
+ "Tart": ("autorag.nodes.passagereranker.tart", "Tart"),
80
+ "upr": ("autorag.nodes.passagereranker", "Upr"),
81
+ "Upr": ("autorag.nodes.passagereranker", "Upr"),
82
+ "koreranker": ("autorag.nodes.passagereranker", "KoReranker"),
83
+ "KoReranker": ("autorag.nodes.passagereranker", "KoReranker"),
84
+ "pass_reranker": ("autorag.nodes.passagereranker", "PassReranker"),
85
+ "PassReranker": ("autorag.nodes.passagereranker", "PassReranker"),
86
+ "cohere_reranker": ("autorag.nodes.passagereranker", "CohereReranker"),
87
+ "CohereReranker": ("autorag.nodes.passagereranker", "CohereReranker"),
88
+ "rankgpt": ("autorag.nodes.passagereranker", "RankGPT"),
89
+ "RankGPT": ("autorag.nodes.passagereranker", "RankGPT"),
90
+ "jina_reranker": ("autorag.nodes.passagereranker", "JinaReranker"),
91
+ "JinaReranker": ("autorag.nodes.passagereranker", "JinaReranker"),
92
+ "colbert_reranker": ("autorag.nodes.passagereranker", "ColbertReranker"),
93
+ "ColbertReranker": ("autorag.nodes.passagereranker", "ColbertReranker"),
94
+ "sentence_transformer_reranker": (
95
+ "autorag.nodes.passagereranker",
96
+ "SentenceTransformerReranker",
97
+ ),
98
+ "SentenceTransformerReranker": (
99
+ "autorag.nodes.passagereranker",
100
+ "SentenceTransformerReranker",
101
+ ),
102
+ "flag_embedding_reranker": (
103
+ "autorag.nodes.passagereranker",
104
+ "FlagEmbeddingReranker",
105
+ ),
106
+ "FlagEmbeddingReranker": (
107
+ "autorag.nodes.passagereranker",
108
+ "FlagEmbeddingReranker",
109
+ ),
110
+ "flag_embedding_llm_reranker": (
111
+ "autorag.nodes.passagereranker",
112
+ "FlagEmbeddingLLMReranker",
113
+ ),
114
+ "FlagEmbeddingLLMReranker": (
115
+ "autorag.nodes.passagereranker",
116
+ "FlagEmbeddingLLMReranker",
117
+ ),
118
+ "time_reranker": ("autorag.nodes.passagereranker", "TimeReranker"),
119
+ "TimeReranker": ("autorag.nodes.passagereranker", "TimeReranker"),
120
+ "openvino_reranker": ("autorag.nodes.passagereranker", "OpenVINOReranker"),
121
+ "OpenVINOReranker": ("autorag.nodes.passagereranker", "OpenVINOReranker"),
122
+ "voyageai_reranker": ("autorag.nodes.passagereranker", "VoyageAIReranker"),
123
+ "VoyageAIReranker": ("autorag.nodes.passagereranker", "VoyageAIReranker"),
124
+ "mixedbreadai_reranker": (
125
+ "autorag.nodes.passagereranker",
126
+ "MixedbreadAIReranker",
127
+ ),
128
+ "MixedbreadAIReranker": (
129
+ "autorag.nodes.passagereranker",
130
+ "MixedbreadAIReranker",
131
+ ),
132
+ "flashrank_reranker": ("autorag.nodes.passagereranker", "FlashRankReranker"),
133
+ "FlashRankReranker": ("autorag.nodes.passagereranker", "FlashRankReranker"),
134
+ # passage_filter
135
+ "pass_passage_filter": ("autorag.nodes.passagefilter", "PassPassageFilter"),
136
+ "similarity_threshold_cutoff": (
137
+ "autorag.nodes.passagefilter",
138
+ "SimilarityThresholdCutoff",
139
+ ),
140
+ "similarity_percentile_cutoff": (
141
+ "autorag.nodes.passagefilter",
142
+ "SimilarityPercentileCutoff",
143
+ ),
144
+ "recency_filter": ("autorag.nodes.passagefilter", "RecencyFilter"),
145
+ "threshold_cutoff": ("autorag.nodes.passagefilter", "ThresholdCutoff"),
146
+ "percentile_cutoff": ("autorag.nodes.passagefilter", "PercentileCutoff"),
147
+ "PassPassageFilter": ("autorag.nodes.passagefilter", "PassPassageFilter"),
148
+ "SimilarityThresholdCutoff": (
149
+ "autorag.nodes.passagefilter",
150
+ "SimilarityThresholdCutoff",
151
+ ),
152
+ "SimilarityPercentileCutoff": (
153
+ "autorag.nodes.passagefilter",
154
+ "SimilarityPercentileCutoff",
155
+ ),
156
+ "RecencyFilter": ("autorag.nodes.passagefilter", "RecencyFilter"),
157
+ "ThresholdCutoff": ("autorag.nodes.passagefilter", "ThresholdCutoff"),
158
+ "PercentileCutoff": ("autorag.nodes.passagefilter", "PercentileCutoff"),
159
+ # passage_compressor
160
+ "tree_summarize": ("autorag.nodes.passagecompressor", "TreeSummarize"),
161
+ "pass_compressor": ("autorag.nodes.passagecompressor", "PassCompressor"),
162
+ "refine": ("autorag.nodes.passagecompressor", "Refine"),
163
+ "longllmlingua": ("autorag.nodes.passagecompressor", "LongLLMLingua"),
164
+ "TreeSummarize": ("autorag.nodes.passagecompressor", "TreeSummarize"),
165
+ "Refine": ("autorag.nodes.passagecompressor", "Refine"),
166
+ "LongLLMLingua": ("autorag.nodes.passagecompressor", "LongLLMLingua"),
167
+ "PassCompressor": ("autorag.nodes.passagecompressor", "PassCompressor"),
168
+ # prompt_maker
169
+ "fstring": ("autorag.nodes.promptmaker", "Fstring"),
170
+ "long_context_reorder": ("autorag.nodes.promptmaker", "LongContextReorder"),
171
+ "window_replacement": ("autorag.nodes.promptmaker", "WindowReplacement"),
172
+ "Fstring": ("autorag.nodes.promptmaker", "Fstring"),
173
+ "LongContextReorder": ("autorag.nodes.promptmaker", "LongContextReorder"),
174
+ "WindowReplacement": ("autorag.nodes.promptmaker", "WindowReplacement"),
175
+ "chat_fstring": ("autorag.nodes.promptmaker", "ChatFstring"),
176
+ "ChatFstring": ("autorag.nodes.promptmaker", "ChatFstring"),
177
+ # generator
178
+ "llama_index_llm": ("autorag.nodes.generator", "LlamaIndexLLM"),
179
+ "vllm": ("autorag.nodes.generator", "Vllm"),
180
+ "openai_llm": ("autorag.nodes.generator", "OpenAILLM"),
181
+ "vllm_api": ("autorag.nodes.generator", "VllmAPI"),
182
+ "LlamaIndexLLM": ("autorag.nodes.generator", "LlamaIndexLLM"),
183
+ "Vllm": ("autorag.nodes.generator", "Vllm"),
184
+ "OpenAILLM": ("autorag.nodes.generator", "OpenAILLM"),
185
+ "VllmAPI": ("autorag.nodes.generator", "VllmAPI"),
186
+ }
187
+ return dynamically_find_function(module_name, support_modules)
188
+
189
+
190
+ def get_support_nodes(node_name: str) -> Callable:
191
+ support_nodes = {
192
+ "query_expansion": (
193
+ "autorag.nodes.queryexpansion.run",
194
+ "run_query_expansion_node",
195
+ ),
196
+ "semantic_retrieval": (
197
+ "autorag.nodes.semanticretrieval.run",
198
+ "run_semantic_retrieval_node",
199
+ ),
200
+ "dense_retrieval": (
201
+ "autorag.nodes.semanticretrieval.run",
202
+ "run_semantic_retrieval_node",
203
+ ),
204
+ "lexical_retrieval": (
205
+ "autorag.nodes.lexicalretrieval.run",
206
+ "run_lexical_retrieval_node",
207
+ ),
208
+ "sparse_retrieval": (
209
+ "autorag.nodes.lexicalretrieval.run",
210
+ "run_lexical_retrieval_node",
211
+ ),
212
+ "hybrid_retrieval": (
213
+ "autorag.nodes.hybridretrieval.run",
214
+ "run_hybrid_retrieval_node",
215
+ ),
216
+ "generator": ("autorag.nodes.generator.run", "run_generator_node"),
217
+ "prompt_maker": ("autorag.nodes.promptmaker.run", "run_prompt_maker_node"),
218
+ "passage_filter": (
219
+ "autorag.nodes.passagefilter.run",
220
+ "run_passage_filter_node",
221
+ ),
222
+ "passage_compressor": (
223
+ "autorag.nodes.passagecompressor.run",
224
+ "run_passage_compressor_node",
225
+ ),
226
+ "passage_reranker": (
227
+ "autorag.nodes.passagereranker.run",
228
+ "run_passage_reranker_node",
229
+ ),
230
+ "passage_augmenter": (
231
+ "autorag.nodes.passageaugmenter.run",
232
+ "run_passage_augmenter_node",
233
+ ),
234
+ }
235
+ return dynamically_find_function(node_name, support_nodes)
@@ -0,0 +1,8 @@
1
+ from .preprocess import (
2
+ validate_qa_dataset,
3
+ validate_corpus_dataset,
4
+ cast_qa_dataset,
5
+ cast_corpus_dataset,
6
+ validate_qa_from_corpus_dataset,
7
+ )
8
+ from .util import fetch_contents, result_to_dataframe, sort_by_scores
autorag/utils/cast.py ADDED
@@ -0,0 +1,45 @@
1
+ def cast_retrieve_infos(previous_result):
2
+ return {
3
+ "retrieved_contents": cast_retrieved_contents(previous_result),
4
+ "retrieved_ids": cast_retrieved_ids(previous_result),
5
+ "retrieve_scores": cast_retrieve_scores(previous_result),
6
+ }
7
+
8
+
9
+ def cast_retrieved_contents(previous_result):
10
+ if "retrieved_contents" in previous_result.columns:
11
+ return previous_result["retrieved_contents"].tolist()
12
+ elif "retrieved_contents_semantic" in previous_result.columns:
13
+ return previous_result["retrieved_contents_semantic"].tolist()
14
+ elif "retrieved_contents_lexical" in previous_result.columns:
15
+ return previous_result["retrieved_contents_lexical"].tolist()
16
+ else:
17
+ raise ValueError(
18
+ "previous_result must contain either 'retrieved_contents', 'retrieved_contents_semantic', or 'retrieved_contents_lexical' columns."
19
+ )
20
+
21
+
22
+ def cast_retrieved_ids(previous_result):
23
+ if "retrieved_ids" in previous_result.columns:
24
+ return previous_result["retrieved_ids"].tolist()
25
+ elif "retrieved_ids_semantic" in previous_result.columns:
26
+ return previous_result["retrieved_ids_semantic"].tolist()
27
+ elif "retrieved_ids_lexical" in previous_result.columns:
28
+ return previous_result["retrieved_ids_lexical"].tolist()
29
+ else:
30
+ raise ValueError(
31
+ "previous_result must contain either 'retrieved_ids', 'retrieved_ids_semantic', or 'retrieved_ids_lexical' columns."
32
+ )
33
+
34
+
35
+ def cast_retrieve_scores(previous_result):
36
+ if "retrieve_scores" in previous_result.columns:
37
+ return previous_result["retrieve_scores"].tolist()
38
+ elif "retrieve_scores_semantic" in previous_result.columns:
39
+ return previous_result["retrieve_scores_semantic"].tolist()
40
+ elif "retrieve_scores_lexical" in previous_result.columns:
41
+ return previous_result["retrieve_scores_lexical"].tolist()
42
+ else:
43
+ raise ValueError(
44
+ "previous_result must contain either 'retrieve_scores', 'retrieve_scores_semantic', or 'retrieve_scores_lexical' columns."
45
+ )
@@ -0,0 +1,149 @@
1
+ from datetime import datetime
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ from autorag.utils.util import preprocess_text
7
+
8
+
9
+ def validate_qa_dataset(df: pd.DataFrame):
10
+ columns = ["qid", "query", "retrieval_gt", "generation_gt"]
11
+ assert set(columns).issubset(df.columns), (
12
+ f"df must have columns {columns}, but got {df.columns}"
13
+ )
14
+
15
+
16
+ def validate_corpus_dataset(df: pd.DataFrame):
17
+ columns = ["doc_id", "contents", "metadata"]
18
+ assert set(columns).issubset(df.columns), (
19
+ f"df must have columns {columns}, but got {df.columns}"
20
+ )
21
+
22
+
23
+ def cast_qa_dataset(df: pd.DataFrame):
24
+ def cast_retrieval_gt(gt):
25
+ if isinstance(gt, str):
26
+ return [[gt]]
27
+ elif isinstance(gt, list):
28
+ if isinstance(gt[0], str):
29
+ return [gt]
30
+ elif isinstance(gt[0], list):
31
+ return gt
32
+ elif isinstance(gt[0], np.ndarray):
33
+ return cast_retrieval_gt(list(map(lambda x: x.tolist(), gt)))
34
+ else:
35
+ raise ValueError(
36
+ f"retrieval_gt must be str or list, but got {type(gt[0])}"
37
+ )
38
+ elif isinstance(gt, np.ndarray):
39
+ return cast_retrieval_gt(gt.tolist())
40
+ else:
41
+ raise ValueError(f"retrieval_gt must be str or list, but got {type(gt)}")
42
+
43
+ def cast_generation_gt(gt):
44
+ if isinstance(gt, str):
45
+ return [gt]
46
+ elif isinstance(gt, list):
47
+ return gt
48
+ elif isinstance(gt, np.ndarray):
49
+ return cast_generation_gt(gt.tolist())
50
+ else:
51
+ raise ValueError(f"generation_gt must be str or list, but got {type(gt)}")
52
+
53
+ df = df.reset_index(drop=True)
54
+ validate_qa_dataset(df)
55
+ assert df["qid"].apply(lambda x: isinstance(x, str)).sum() == len(df), (
56
+ "qid must be string type."
57
+ )
58
+ assert df["query"].apply(lambda x: isinstance(x, str)).sum() == len(df), (
59
+ "query must be string type."
60
+ )
61
+ df["retrieval_gt"] = df["retrieval_gt"].apply(cast_retrieval_gt)
62
+ df["generation_gt"] = df["generation_gt"].apply(cast_generation_gt)
63
+ df["query"] = df["query"].apply(preprocess_text)
64
+ df["generation_gt"] = df["generation_gt"].apply(
65
+ lambda x: list(map(preprocess_text, x))
66
+ )
67
+ return df
68
+
69
+
70
+ def cast_corpus_dataset(df: pd.DataFrame):
71
+ df = df.reset_index(drop=True)
72
+ validate_corpus_dataset(df)
73
+
74
+ # drop rows that have empty contents
75
+ df = df[~df["contents"].apply(lambda x: x is None or x.isspace())]
76
+
77
+ def make_datetime_metadata(x):
78
+ if x is None or x == {}:
79
+ return {"last_modified_datetime": datetime.now()}
80
+ elif x.get("last_modified_datetime") is None:
81
+ return {**x, "last_modified_datetime": datetime.now()}
82
+ else:
83
+ return x
84
+
85
+ df["metadata"] = df["metadata"].apply(make_datetime_metadata)
86
+
87
+ # check every metadata have a datetime key
88
+ assert sum(
89
+ df["metadata"].apply(lambda x: x.get("last_modified_datetime") is not None)
90
+ ) == len(df), "Every metadata must have a datetime key."
91
+
92
+ def make_prev_next_id_metadata(x, id_type: str):
93
+ if x is None or x == {}:
94
+ return {id_type: None}
95
+ elif x.get(id_type) is None:
96
+ return {**x, id_type: None}
97
+ else:
98
+ return x
99
+
100
+ df["metadata"] = df["metadata"].apply(
101
+ lambda x: make_prev_next_id_metadata(x, "prev_id")
102
+ )
103
+ df["metadata"] = df["metadata"].apply(
104
+ lambda x: make_prev_next_id_metadata(x, "next_id")
105
+ )
106
+
107
+ df["contents"] = df["contents"].apply(preprocess_text)
108
+
109
+ def normalize_unicode_metadata(metadata: dict):
110
+ result = {}
111
+ for key, value in metadata.items():
112
+ if isinstance(value, str):
113
+ result[key] = preprocess_text(value)
114
+ else:
115
+ result[key] = value
116
+ return result
117
+
118
+ df["metadata"] = df["metadata"].apply(normalize_unicode_metadata)
119
+
120
+ # check every metadata have a prev_id, next_id key
121
+ assert all("prev_id" in metadata for metadata in df["metadata"]), (
122
+ "Every metadata must have a prev_id key."
123
+ )
124
+ assert all("next_id" in metadata for metadata in df["metadata"]), (
125
+ "Every metadata must have a next_id key."
126
+ )
127
+
128
+ return df
129
+
130
+
131
+ def validate_qa_from_corpus_dataset(qa_df: pd.DataFrame, corpus_df: pd.DataFrame):
132
+ qa_ids = []
133
+ for retrieval_gt in qa_df["retrieval_gt"].tolist():
134
+ if isinstance(retrieval_gt, list) and (
135
+ retrieval_gt[0] != [] or any(bool(g) is True for g in retrieval_gt)
136
+ ):
137
+ for gt in retrieval_gt:
138
+ qa_ids.extend(gt)
139
+ elif isinstance(retrieval_gt, np.ndarray) and retrieval_gt[0].size > 0:
140
+ for gt in retrieval_gt:
141
+ qa_ids.extend(gt)
142
+
143
+ no_exist_ids = list(
144
+ filter(lambda qa_id: corpus_df[corpus_df["doc_id"] == qa_id].empty, qa_ids)
145
+ )
146
+
147
+ assert len(no_exist_ids) == 0, (
148
+ f"{len(no_exist_ids)} doc_ids in retrieval_gt do not exist in corpus_df."
149
+ )