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,155 @@
1
+ from typing import List, Union
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.passageaugmenter.base import BasePassageAugmenter
9
+ from autorag.utils.util import (
10
+ filter_dict_keys,
11
+ fetch_contents,
12
+ embedding_query_content,
13
+ result_to_dataframe,
14
+ empty_cuda_cache,
15
+ )
16
+
17
+
18
+ class PrevNextPassageAugmenter(BasePassageAugmenter):
19
+ def __init__(
20
+ self,
21
+ project_dir: str,
22
+ embedding_model: Union[str, dict] = "openai",
23
+ *args,
24
+ **kwargs,
25
+ ):
26
+ """
27
+ Initialize the PrevNextPassageAugmenter module.
28
+
29
+ :param project_dir:
30
+ :param embedding_model: The embedding model name to use for calculating cosine similarity
31
+ Default is openai (text-embedding-ada-002)
32
+ :param kwargs:
33
+ """
34
+ super().__init__(project_dir, *args, **kwargs)
35
+ slim_corpus_df = self.corpus_df[["doc_id", "metadata"]]
36
+ slim_corpus_df.loc[:, "metadata"] = slim_corpus_df["metadata"].apply(
37
+ filter_dict_keys, keys=["prev_id", "next_id"]
38
+ )
39
+ self.slim_corpus_df = slim_corpus_df
40
+
41
+ # init embedding model
42
+ self.embedding_model = EmbeddingModel.load(embedding_model)()
43
+
44
+ def __del__(self):
45
+ del self.embedding_model
46
+ empty_cuda_cache()
47
+ super().__del__()
48
+
49
+ @result_to_dataframe(["retrieved_contents", "retrieved_ids", "retrieve_scores"])
50
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
51
+ """
52
+ Run the passage augmenter node - PrevNextPassageAugmenter module.
53
+
54
+ :param previous_result: The previous result Dataframe.
55
+ :param top_k: You must input the top_k value to get the top k results.
56
+ :param kwargs: Not affected.
57
+ :return: DataFrame with retrieved_contents, retrieved_ids, and retrieve_scores columns
58
+ """
59
+ top_k = kwargs.pop("top_k")
60
+
61
+ ids = self.cast_to_run(previous_result)
62
+ # find queries columns
63
+ assert "query" in previous_result.columns, (
64
+ "previous_result must have query column."
65
+ )
66
+ queries = previous_result["query"].tolist()
67
+
68
+ mode = kwargs.pop("mode", "both")
69
+ num_passages = kwargs.pop("num_passages", 1)
70
+ augmented_ids = self._pure(ids, num_passages, mode)
71
+
72
+ # fetch contents from corpus to use augmented ids
73
+ augmented_contents = fetch_contents(self.corpus_df, augmented_ids)
74
+
75
+ query_embeddings, contents_embeddings = embedding_query_content(
76
+ queries, augmented_contents, self.embedding_model, batch=128
77
+ )
78
+
79
+ # get scores from calculated cosine similarity
80
+ augmented_scores = [
81
+ np.array(
82
+ [
83
+ calculate_cosine_similarity(query_embedding, x)
84
+ for x in content_embeddings
85
+ ]
86
+ ).tolist()
87
+ for query_embedding, content_embeddings in zip(
88
+ query_embeddings, contents_embeddings
89
+ )
90
+ ]
91
+ return self.sort_by_scores(
92
+ augmented_contents, augmented_ids, augmented_scores, top_k
93
+ )
94
+
95
+ def _pure(
96
+ self,
97
+ ids_list: List[List[str]],
98
+ num_passages: int = 1,
99
+ mode: str = "both",
100
+ ) -> List[List[str]]:
101
+ """
102
+ Add passages before and/or after the retrieved passage.
103
+ For more information, visit https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/PrevNextPostprocessorDemo/.
104
+
105
+ :param ids_list: The list of lists of ids retrieved
106
+ :param num_passages: The number of passages to add before and after the retrieved passage
107
+ Default is 1.
108
+ :param mode: The mode of augmentation
109
+ 'prev': add passages before the retrieved passage
110
+ 'next': add passages after the retrieved passage
111
+ 'both': add passages before and after the retrieved passage
112
+ Default is 'next'.
113
+ :return: The list of lists of augmented ids
114
+ """
115
+ if mode not in ["prev", "next", "both"]:
116
+ raise ValueError(f"mode must be 'prev', 'next', or 'both', but got {mode}")
117
+
118
+ augmented_ids = [
119
+ (
120
+ lambda ids: prev_next_augmenter_pure(
121
+ ids, self.slim_corpus_df, mode, num_passages
122
+ )
123
+ )(ids)
124
+ for ids in ids_list
125
+ ]
126
+
127
+ return augmented_ids
128
+
129
+
130
+ def prev_next_augmenter_pure(
131
+ ids: List[str], corpus_df: pd.DataFrame, mode: str, num_passages: int
132
+ ):
133
+ def fetch_id_sequence(start_id, key):
134
+ sequence = []
135
+ current_id = start_id
136
+ for _ in range(num_passages):
137
+ current_id = (
138
+ corpus_df.loc[corpus_df["doc_id"] == current_id]["metadata"]
139
+ .values[0]
140
+ .get(key)
141
+ )
142
+ if current_id is None:
143
+ break
144
+ sequence.append(current_id)
145
+ return sequence
146
+
147
+ augmented_group = []
148
+ for id_ in ids:
149
+ current_ids = [id_]
150
+ if mode in ["prev", "both"]:
151
+ current_ids = fetch_id_sequence(id_, "prev_id")[::-1] + current_ids
152
+ if mode in ["next", "both"]:
153
+ current_ids += fetch_id_sequence(id_, "next_id")
154
+ augmented_group.extend(current_ids)
155
+ return augmented_group
@@ -0,0 +1,131 @@
1
+ import logging
2
+ import os
3
+ import pathlib
4
+ from typing import List, Dict
5
+
6
+ import pandas as pd
7
+
8
+ from autorag.nodes.retrieval.run_util import evaluate_retrieval_node
9
+ from autorag.schema.metricinput import MetricInput
10
+ from autorag.strategy import measure_speed, filter_by_threshold, select_best
11
+ from autorag.utils.util import apply_recursive, to_list
12
+
13
+ logger = logging.getLogger("AutoRAG")
14
+
15
+
16
+ def run_passage_augmenter_node(
17
+ modules: List,
18
+ module_params: List[Dict],
19
+ previous_result: pd.DataFrame,
20
+ node_line_dir: str,
21
+ strategies: Dict,
22
+ ) -> pd.DataFrame:
23
+ if not os.path.exists(node_line_dir):
24
+ os.makedirs(node_line_dir)
25
+ project_dir = pathlib.PurePath(node_line_dir).parent.parent
26
+ qa_df = pd.read_parquet(
27
+ os.path.join(project_dir, "data", "qa.parquet"), engine="pyarrow"
28
+ )
29
+ retrieval_gt = qa_df["retrieval_gt"].tolist()
30
+ retrieval_gt = apply_recursive(lambda x: str(x), to_list(retrieval_gt))
31
+
32
+ results, execution_times = zip(
33
+ *map(
34
+ lambda task: measure_speed(
35
+ task[0].run_evaluator,
36
+ project_dir=project_dir,
37
+ previous_result=previous_result,
38
+ **task[1],
39
+ ),
40
+ zip(modules, module_params),
41
+ )
42
+ )
43
+ average_times = list(map(lambda x: x / len(results[0]), execution_times))
44
+ metric_inputs = [
45
+ MetricInput(retrieval_gt=ret_gt, query=query, generation_gt=gen_gt)
46
+ for ret_gt, query, gen_gt in zip(
47
+ retrieval_gt,
48
+ previous_result["query"].tolist(),
49
+ previous_result["generation_gt"].tolist(),
50
+ )
51
+ ]
52
+
53
+ # run metrics before filtering
54
+ if strategies.get("metrics") is None:
55
+ raise ValueError(
56
+ "You must at least one metrics for passage_augmenter evaluation."
57
+ )
58
+ results = list(
59
+ map(
60
+ lambda x: evaluate_retrieval_node(
61
+ x,
62
+ metric_inputs,
63
+ strategies.get("metrics"),
64
+ ),
65
+ results,
66
+ )
67
+ )
68
+
69
+ # save results to folder
70
+ save_dir = os.path.join(node_line_dir, "passage_augmenter") # node name
71
+ if not os.path.exists(save_dir):
72
+ os.makedirs(save_dir)
73
+ filepaths = list(
74
+ map(lambda x: os.path.join(save_dir, f"{x}.parquet"), range(len(modules)))
75
+ )
76
+ list(
77
+ map(lambda x: x[0].to_parquet(x[1], index=False), zip(results, filepaths))
78
+ ) # execute save to parquet
79
+ filenames = list(map(lambda x: os.path.basename(x), filepaths))
80
+
81
+ summary_df = pd.DataFrame(
82
+ {
83
+ "filename": filenames,
84
+ "module_name": list(map(lambda module: module.__name__, modules)),
85
+ "module_params": module_params,
86
+ "execution_time": average_times,
87
+ **{
88
+ f"passage_augmenter_{metric}": list(
89
+ map(lambda result: result[metric].mean(), results)
90
+ )
91
+ for metric in strategies.get("metrics")
92
+ },
93
+ }
94
+ )
95
+
96
+ # filter by strategies
97
+ if strategies.get("speed_threshold") is not None:
98
+ results, filenames = filter_by_threshold(
99
+ results, average_times, strategies["speed_threshold"], filenames
100
+ )
101
+ selected_result, selected_filename = select_best(
102
+ results,
103
+ strategies.get("metrics"),
104
+ filenames,
105
+ strategies.get("strategy", "mean"),
106
+ )
107
+ # change metric name columns to passage_augmenter_metric_name
108
+ selected_result = selected_result.rename(
109
+ columns={
110
+ metric_name: f"passage_augmenter_{metric_name}"
111
+ for metric_name in strategies["metrics"]
112
+ }
113
+ )
114
+ # drop retrieval result columns in previous_result
115
+ previous_result = previous_result.drop(
116
+ columns=["retrieved_contents", "retrieved_ids", "retrieve_scores"]
117
+ )
118
+ best_result = pd.concat([previous_result, selected_result], axis=1)
119
+
120
+ # add 'is_best' column to summary file
121
+ summary_df["is_best"] = summary_df["filename"] == selected_filename
122
+
123
+ # save files
124
+ summary_df.to_csv(os.path.join(save_dir, "summary.csv"), index=False)
125
+ best_result.to_parquet(
126
+ os.path.join(
127
+ save_dir, f"best_{os.path.splitext(selected_filename)[0]}.parquet"
128
+ ),
129
+ index=False,
130
+ )
131
+ return best_result
@@ -0,0 +1,4 @@
1
+ from .longllmlingua import LongLLMLingua
2
+ from .pass_compressor import PassCompressor
3
+ from .refine import Refine
4
+ from .tree_summarize import TreeSummarize
@@ -0,0 +1,78 @@
1
+ import abc
2
+ import logging
3
+ from typing import Dict
4
+
5
+ import pandas as pd
6
+ from llama_index.core.llms import LLM
7
+
8
+ from autorag import generator_models
9
+ from autorag.schema import BaseModule
10
+ from autorag.utils import result_to_dataframe
11
+ from autorag.utils.cast import cast_retrieved_contents
12
+
13
+ logger = logging.getLogger("AutoRAG")
14
+
15
+
16
+ class BasePassageCompressor(BaseModule, metaclass=abc.ABCMeta):
17
+ def __init__(self, project_dir: str, *args, **kwargs):
18
+ logger.info(
19
+ f"Initialize passage compressor node - {self.__class__.__name__} module..."
20
+ )
21
+
22
+ def __del__(self):
23
+ logger.info(
24
+ f"Deleting passage compressor node - {self.__class__.__name__} module..."
25
+ )
26
+
27
+ def cast_to_run(self, previous_result: pd.DataFrame, *args, **kwargs):
28
+ logger.info(
29
+ f"Running passage compressor node - {self.__class__.__name__} module..."
30
+ )
31
+ assert "query" in previous_result.columns, (
32
+ "previous_result must contain 'query' column."
33
+ )
34
+ assert len(previous_result) > 0, "previous_result must have at least one row."
35
+
36
+ queries = previous_result["query"].tolist()
37
+
38
+ return queries, cast_retrieved_contents(previous_result)
39
+
40
+
41
+ class LlamaIndexCompressor(BasePassageCompressor, metaclass=abc.ABCMeta):
42
+ param_list = ["prompt", "chat_prompt", "batch"]
43
+
44
+ def __init__(self, project_dir: str, **kwargs):
45
+ """
46
+ Initialize passage compressor module.
47
+
48
+ :param project_dir: The project directory
49
+ :param llm: The llm name that will be used to summarize.
50
+ The LlamaIndex LLM model can be used in here.
51
+ :param kwargs: Extra parameter for init llm
52
+ """
53
+ super().__init__(project_dir)
54
+ kwargs_dict = dict(
55
+ filter(lambda x: x[0] not in self.param_list, kwargs.items())
56
+ )
57
+ llm_name = kwargs_dict.pop("llm")
58
+ self.llm: LLM = make_llm(llm_name, kwargs_dict)
59
+
60
+ def __del__(self):
61
+ del self.llm
62
+ super().__del__()
63
+
64
+ @result_to_dataframe(["retrieved_contents"])
65
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
66
+ queries, retrieved_contents = self.cast_to_run(previous_result)
67
+ param_dict = dict(filter(lambda x: x[0] in self.param_list, kwargs.items()))
68
+ result = self._pure(queries, retrieved_contents, **param_dict)
69
+ return list(map(lambda x: [x], result))
70
+
71
+
72
+ def make_llm(llm_name: str, kwargs: Dict) -> LLM:
73
+ if llm_name not in generator_models:
74
+ raise KeyError(
75
+ f"{llm_name} is not supported. "
76
+ "You can add it manually by calling autorag.generator_models."
77
+ )
78
+ return generator_models[llm_name](**kwargs)
@@ -0,0 +1,115 @@
1
+ from typing import List, Optional
2
+
3
+ import pandas as pd
4
+
5
+ from autorag.nodes.passagecompressor.base import BasePassageCompressor
6
+ from autorag.utils.util import pop_params, result_to_dataframe, empty_cuda_cache
7
+
8
+
9
+ # TODO: Parallel Processing Refactoring at #460
10
+
11
+
12
+ class LongLLMLingua(BasePassageCompressor):
13
+ def __init__(
14
+ self, project_dir: str, model_name: str = "NousResearch/Llama-2-7b-hf", **kwargs
15
+ ):
16
+ try:
17
+ from llmlingua import PromptCompressor
18
+ except ImportError:
19
+ raise ImportError(
20
+ "LongLLMLingua is not installed. Please install it by running `pip install llmlingua`."
21
+ )
22
+
23
+ super().__init__(project_dir)
24
+ model_init_params = pop_params(PromptCompressor.__init__, kwargs)
25
+ self.llm_lingua = PromptCompressor(model_name=model_name, **model_init_params)
26
+
27
+ def __del__(self):
28
+ del self.llm_lingua
29
+ empty_cuda_cache()
30
+ super().__del__()
31
+
32
+ @result_to_dataframe(["retrieved_contents"])
33
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
34
+ queries, retrieved_contents = self.cast_to_run(previous_result)
35
+ results = self._pure(queries, retrieved_contents, **kwargs)
36
+ return list(map(lambda x: [x], results))
37
+
38
+ def _pure(
39
+ self,
40
+ queries: List[str],
41
+ contents: List[List[str]],
42
+ instructions: Optional[str] = None,
43
+ target_token: int = 300,
44
+ **kwargs,
45
+ ) -> List[str]:
46
+ """
47
+ Compresses the retrieved texts using LongLLMLingua.
48
+ For more information, visit https://github.com/microsoft/LLMLingua.
49
+
50
+ :param queries: The queries for retrieved passages.
51
+ :param contents: The contents of retrieved passages.
52
+ :param model_name: The model name to use for compression.
53
+ The default is "NousResearch/Llama-2-7b-hf".
54
+ :param instructions: The instructions for compression.
55
+ Default is None. When it is None, it will use default instructions.
56
+ :param target_token: The target token for compression.
57
+ Default is 300.
58
+ :param kwargs: Additional keyword arguments.
59
+ :return: The list of compressed texts.
60
+ """
61
+ if instructions is None:
62
+ instructions = "Given the context, please answer the final question"
63
+ results = [
64
+ llmlingua_pure(
65
+ query, contents_, self.llm_lingua, instructions, target_token, **kwargs
66
+ )
67
+ for query, contents_ in zip(queries, contents)
68
+ ]
69
+
70
+ return results
71
+
72
+
73
+ def llmlingua_pure(
74
+ query: str,
75
+ contents: List[str],
76
+ llm_lingua,
77
+ instructions: str,
78
+ target_token: int = 300,
79
+ **kwargs,
80
+ ) -> str:
81
+ """
82
+ Return the compressed text.
83
+
84
+ :param query: The query for retrieved passages.
85
+ :param contents: The contents of retrieved passages.
86
+ :param llm_lingua: The llm instance, that will be used to compress.
87
+ :param instructions: The instructions for compression.
88
+ :param target_token: The target token for compression.
89
+ Default is 300.
90
+ :param kwargs: Additional keyword arguments.
91
+ :return: The compressed text.
92
+ """
93
+ try:
94
+ from llmlingua import PromptCompressor
95
+ except ImportError:
96
+ raise ImportError(
97
+ "LongLLMLingua is not installed. Please install it by running `pip install llmlingua`."
98
+ )
99
+ # split by "\n\n" (recommended by LongLLMLingua authors)
100
+ new_context_texts = [c for context in contents for c in context.split("\n\n")]
101
+ compress_prompt_params = pop_params(PromptCompressor.compress_prompt, kwargs)
102
+ compressed_prompt = llm_lingua.compress_prompt(
103
+ new_context_texts,
104
+ question=query,
105
+ instruction=instructions,
106
+ rank_method="longllmlingua",
107
+ target_token=target_token,
108
+ **compress_prompt_params,
109
+ )
110
+ compressed_prompt_txt = compressed_prompt["compressed_prompt"]
111
+
112
+ # separate out the question and instruction
113
+ result = "\n\n".join(compressed_prompt_txt.split("\n\n")[1:-1])
114
+
115
+ return result
@@ -0,0 +1,16 @@
1
+ from typing import List
2
+
3
+ import pandas as pd
4
+
5
+ from autorag.nodes.passagecompressor.base import BasePassageCompressor
6
+ from autorag.utils import result_to_dataframe
7
+
8
+
9
+ class PassCompressor(BasePassageCompressor):
10
+ @result_to_dataframe(["retrieved_contents"])
11
+ def pure(self, previous_result: pd.DataFrame, *args, **kwargs):
12
+ _, contents = self.cast_to_run(previous_result)
13
+ return self._pure(contents)
14
+
15
+ def _pure(self, contents: List[List[str]]):
16
+ return contents
@@ -0,0 +1,54 @@
1
+ from typing import List, Optional
2
+
3
+ from llama_index.core import PromptTemplate
4
+ from llama_index.core.prompts import PromptType
5
+ from llama_index.core.prompts.utils import is_chat_model
6
+ from llama_index.core.response_synthesizers import Refine as rf
7
+
8
+ from autorag.nodes.passagecompressor.base import LlamaIndexCompressor
9
+ from autorag.utils.util import get_event_loop, process_batch
10
+
11
+
12
+ class Refine(LlamaIndexCompressor):
13
+ def _pure(
14
+ self,
15
+ queries: List[str],
16
+ contents: List[List[str]],
17
+ prompt: Optional[str] = None,
18
+ chat_prompt: Optional[str] = None,
19
+ batch: int = 16,
20
+ ) -> List[str]:
21
+ """
22
+ Refine a response to a query across text chunks.
23
+ This function is a wrapper for llama_index.response_synthesizers.Refine.
24
+ For more information, visit https://docs.llamaindex.ai/en/stable/examples/response_synthesizers/refine/.
25
+
26
+ :param queries: The queries for retrieved passages.
27
+ :param contents: The contents of retrieved passages.
28
+ :param prompt: The prompt template for refine.
29
+ If you want to use chat prompt, you should pass chat_prompt instead.
30
+ At prompt, you must specify where to put 'context_msg' and 'query_str'.
31
+ Default is None. When it is None, it will use llama index default prompt.
32
+ :param chat_prompt: The chat prompt template for refine.
33
+ If you want to use normal prompt, you should pass prompt instead.
34
+ At prompt, you must specify where to put 'context_msg' and 'query_str'.
35
+ Default is None. When it is None, it will use llama index default chat prompt.
36
+ :param batch: The batch size for llm.
37
+ Set low if you face some errors.
38
+ Default is 16.
39
+ :return: The list of compressed texts.
40
+ """
41
+ if prompt is not None and not is_chat_model(self.llm):
42
+ refine_template = PromptTemplate(prompt, prompt_type=PromptType.REFINE)
43
+ elif chat_prompt is not None and is_chat_model(self.llm):
44
+ refine_template = PromptTemplate(chat_prompt, prompt_type=PromptType.REFINE)
45
+ else:
46
+ refine_template = None
47
+ summarizer = rf(llm=self.llm, refine_template=refine_template, verbose=True)
48
+ tasks = [
49
+ summarizer.aget_response(query, content)
50
+ for query, content in zip(queries, contents)
51
+ ]
52
+ loop = get_event_loop()
53
+ results = loop.run_until_complete(process_batch(tasks, batch_size=batch))
54
+ return results