flashrag-dev 0.1.1__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 (48) hide show
  1. flashrag/__init__.py +0 -0
  2. flashrag/config/__init__.py +2 -0
  3. flashrag/config/config.py +219 -0
  4. flashrag/dataset/__init__.py +2 -0
  5. flashrag/dataset/dataset.py +160 -0
  6. flashrag/dataset/utils.py +60 -0
  7. flashrag/evaluator/__init__.py +2 -0
  8. flashrag/evaluator/_bleu.py +209 -0
  9. flashrag/evaluator/evaluator.py +82 -0
  10. flashrag/evaluator/metrics.py +508 -0
  11. flashrag/evaluator/utils.py +19 -0
  12. flashrag/generator/__init__.py +2 -0
  13. flashrag/generator/fid.py +247 -0
  14. flashrag/generator/generator.py +623 -0
  15. flashrag/generator/openai_generator.py +96 -0
  16. flashrag/generator/stop_word_criteria.py +105 -0
  17. flashrag/judger/__init__.py +1 -0
  18. flashrag/judger/judger.py +184 -0
  19. flashrag/pipeline/__init__.py +3 -0
  20. flashrag/pipeline/active_pipeline.py +980 -0
  21. flashrag/pipeline/branching_pipeline.py +250 -0
  22. flashrag/pipeline/pipeline.py +248 -0
  23. flashrag/pipeline/replug_utils.py +249 -0
  24. flashrag/prompt/__init__.py +1 -0
  25. flashrag/prompt/base_prompt.py +165 -0
  26. flashrag/prompt/selfask_examplars.py +108 -0
  27. flashrag/prompt/trace_examplars.py +4015 -0
  28. flashrag/refiner/__init__.py +2 -0
  29. flashrag/refiner/kg_refiner.py +612 -0
  30. flashrag/refiner/llmlingua_compressor.py +2360 -0
  31. flashrag/refiner/refiner.py +252 -0
  32. flashrag/refiner/selective_context_compressor.py +294 -0
  33. flashrag/retriever/__init__.py +3 -0
  34. flashrag/retriever/__main__.py +4 -0
  35. flashrag/retriever/encoder.py +120 -0
  36. flashrag/retriever/index_builder.py +334 -0
  37. flashrag/retriever/reranker.py +145 -0
  38. flashrag/retriever/retriever.py +346 -0
  39. flashrag/retriever/utils.py +49 -0
  40. flashrag/utils/__init__.py +2 -0
  41. flashrag/utils/constants.py +51 -0
  42. flashrag/utils/pred_parse.py +25 -0
  43. flashrag/utils/utils.py +135 -0
  44. flashrag_dev-0.1.1.dist-info/LICENSE +21 -0
  45. flashrag_dev-0.1.1.dist-info/METADATA +616 -0
  46. flashrag_dev-0.1.1.dist-info/RECORD +48 -0
  47. flashrag_dev-0.1.1.dist-info/WHEEL +5 -0
  48. flashrag_dev-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,346 @@
1
+ import json
2
+ import os
3
+
4
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
5
+ import warnings
6
+ from typing import List, Dict
7
+ import functools
8
+ from tqdm import tqdm
9
+ import faiss
10
+
11
+ from flashrag.utils import get_reranker
12
+ from flashrag.retriever.utils import load_corpus, load_docs
13
+ from flashrag.retriever.encoder import Encoder, STEncoder
14
+
15
+
16
+ def cache_manager(func):
17
+ """
18
+ Decorator used for retrieving document cache.
19
+ With the decorator, The retriever can store each retrieved document as a file and reuse it.
20
+ """
21
+
22
+ @functools.wraps(func)
23
+ def wrapper(self, query_list, num=None, return_score=False):
24
+ if num is None:
25
+ num = self.topk
26
+ if self.use_cache:
27
+ if isinstance(query_list, str):
28
+ new_query_list = [query_list]
29
+ else:
30
+ new_query_list = query_list
31
+
32
+ no_cache_query = []
33
+ cache_results = []
34
+ for query in new_query_list:
35
+ if query in self.cache:
36
+ cache_res = self.cache[query]
37
+ if len(cache_res) < num:
38
+ warnings.warn(f"The number of cached retrieval results is less than topk ({num})")
39
+ cache_res = cache_res[:num]
40
+ # separate the doc score
41
+ doc_scores = [item.pop("score") for item in cache_res]
42
+ cache_results.append((cache_res, doc_scores))
43
+ else:
44
+ cache_results.append(None)
45
+ no_cache_query.append(query)
46
+
47
+ if no_cache_query != []:
48
+ # use batch search without decorator
49
+ no_cache_results, no_cache_scores = self._batch_search_with_rerank(no_cache_query, num, True)
50
+ no_cache_idx = 0
51
+ for idx, res in enumerate(cache_results):
52
+ if res is None:
53
+ assert new_query_list[idx] == no_cache_query[no_cache_idx]
54
+ cache_results = (
55
+ no_cache_results[no_cache_idx],
56
+ no_cache_scores[no_cache_scores],
57
+ )
58
+ no_cache_idx += 1
59
+
60
+ results, scores = (
61
+ [t[0] for t in cache_results],
62
+ [t[1] for t in cache_results],
63
+ )
64
+
65
+ else:
66
+ results, scores = func(self, query_list, num, True)
67
+
68
+ if self.save_cache:
69
+ # merge result and score
70
+ save_results = results.copy()
71
+ save_scores = scores.copy()
72
+ if isinstance(query_list, str):
73
+ query_list = [query_list]
74
+ if "batch" not in func.__name__:
75
+ save_results = [save_results]
76
+ save_scores = [save_scores]
77
+ for query, doc_items, doc_scores in zip(query_list, save_results, save_scores):
78
+ for item, score in zip(doc_items, doc_scores):
79
+ item["score"] = score
80
+ self.cache[query] = doc_items
81
+
82
+ if return_score:
83
+ return results, scores
84
+ else:
85
+ return results
86
+
87
+ return wrapper
88
+
89
+
90
+ def rerank_manager(func):
91
+ """
92
+ Decorator used for reranking retrieved documents.
93
+ """
94
+
95
+ @functools.wraps(func)
96
+ def wrapper(self, query_list, num=None, return_score=False):
97
+ results, scores = func(self, query_list, num, True)
98
+ if self.use_reranker:
99
+ results, scores = self.reranker.rerank(query_list, results)
100
+ if "batch" not in func.__name__:
101
+ results = results[0]
102
+ scores = scores[0]
103
+ if return_score:
104
+ return results, scores
105
+ else:
106
+ return results
107
+
108
+ return wrapper
109
+
110
+
111
+ class BaseRetriever:
112
+ """Base object for all retrievers."""
113
+
114
+ def __init__(self, config):
115
+ self.config = config
116
+ self.retrieval_method = config["retrieval_method"]
117
+ self.topk = config["retrieval_topk"]
118
+
119
+ self.index_path = config["index_path"]
120
+ self.corpus_path = config["corpus_path"]
121
+
122
+ self.save_cache = config["save_retrieval_cache"]
123
+ self.use_cache = config["use_retrieval_cache"]
124
+ self.cache_path = config["retrieval_cache_path"]
125
+
126
+ self.use_reranker = config["use_reranker"]
127
+ if self.use_reranker:
128
+ self.reranker = get_reranker(config)
129
+
130
+ if self.save_cache:
131
+ self.cache_save_path = os.path.join(config["save_dir"], "retrieval_cache.json")
132
+ self.cache = {}
133
+ if self.use_cache:
134
+ assert self.cache_path is not None
135
+ with open(self.cache_path, "r") as f:
136
+ self.cache = json.load(f)
137
+
138
+ def _save_cache(self):
139
+ with open(self.cache_save_path, "w") as f:
140
+ json.dump(self.cache, f, indent=4)
141
+
142
+ def _search(self, query: str, num: int, return_score: bool) -> List[Dict[str, str]]:
143
+ r"""Retrieve topk relevant documents in corpus.
144
+
145
+ Return:
146
+ list: contains information related to the document, including:
147
+ contents: used for building index
148
+ title: (if provided)
149
+ text: (if provided)
150
+
151
+ """
152
+
153
+ pass
154
+
155
+ def _batch_search(self, query_list, num, return_score):
156
+ pass
157
+
158
+ @cache_manager
159
+ @rerank_manager
160
+ def search(self, *args, **kwargs):
161
+ return self._search(*args, **kwargs)
162
+
163
+ @cache_manager
164
+ @rerank_manager
165
+ def batch_search(self, *args, **kwargs):
166
+ return self._batch_search(*args, **kwargs)
167
+
168
+ @rerank_manager
169
+ def _batch_search_with_rerank(self, *args, **kwargs):
170
+ return self._batch_search(*args, **kwargs)
171
+
172
+ @rerank_manager
173
+ def _search_with_rerank(self, *args, **kwargs):
174
+ return self._search(*args, **kwargs)
175
+
176
+
177
+ class BM25Retriever(BaseRetriever):
178
+ r"""BM25 retriever based on pre-built pyserini index."""
179
+
180
+ def __init__(self, config):
181
+ super().__init__(config)
182
+ self.backend = config['bm25_backend']
183
+
184
+ if self.backend == 'pyserini':
185
+ # Warning: the method based on pyserini will be deprecated
186
+ from pyserini.search.lucene import LuceneSearcher
187
+
188
+ self.searcher = LuceneSearcher(self.index_path)
189
+ self.contain_doc = self._check_contain_doc()
190
+ if not self.contain_doc:
191
+ self.corpus = load_corpus(self.corpus_path)
192
+ self.max_process_num = 8
193
+ elif self.backend == 'bm25s':
194
+ import Stemmer
195
+ import bm25s
196
+
197
+ stemmer = Stemmer.Stemmer('english')
198
+ self.searcher = bm25s.BM25.load(self.index_path, mmap=True, load_corpus=True)
199
+ self.searcher.backend = 'numba'
200
+ self.tokenizer = bm25s.tokenization.Tokenizer(stemmer=stemmer)
201
+ else:
202
+ assert False, 'Invalid bm25 backend!'
203
+
204
+ def _check_contain_doc(self):
205
+ r"""Check if the index contains document content"""
206
+ return self.searcher.doc(0).raw() is not None
207
+
208
+ def _search(self, query: str, num: int = None, return_score=False) -> List[Dict[str, str]]:
209
+ if num is None:
210
+ num = self.topk
211
+ if self.backend == 'pyserini':
212
+ hits = self.searcher.search(query, num)
213
+ if len(hits) < 1:
214
+ if return_score:
215
+ return [], []
216
+ else:
217
+ return []
218
+
219
+ scores = [hit.score for hit in hits]
220
+ if len(hits) < num:
221
+ warnings.warn("Not enough documents retrieved!")
222
+ else:
223
+ hits = hits[:num]
224
+
225
+ if self.contain_doc:
226
+ all_contents = [json.loads(self.searcher.doc(hit.docid).raw())["contents"] for hit in hits]
227
+ results = [
228
+ {
229
+ "title": content.split("\n")[0].strip('"'),
230
+ "text": "\n".join(content.split("\n")[1:]),
231
+ "contents": content,
232
+ }
233
+ for content in all_contents
234
+ ]
235
+ else:
236
+ results = load_docs(self.corpus, [hit.docid for hit in hits])
237
+ elif self.backend == 'bm25s':
238
+ query_tokens = self.tokenizer.tokenize([query])
239
+ results, scores = self.searcher.retrieve(query_tokens, k=num)
240
+ results = results[0]
241
+ scores = scores[0]
242
+ else:
243
+ assert False, 'Invalid bm25 backend!'
244
+
245
+ if return_score:
246
+ return results, scores
247
+ else:
248
+ return results
249
+
250
+ def _batch_search(self, query_list, num: int = None, return_score=False):
251
+ if self.backend == 'pyserini':
252
+ # TODO: modify batch method
253
+ results = []
254
+ scores = []
255
+ for query in query_list:
256
+ item_result, item_score = self._search(query, num, True)
257
+ results.append(item_result)
258
+ scores.append(item_score)
259
+ elif self.backend == 'bm25s':
260
+ query_tokens = self.tokenizer.tokenize(query_list)
261
+ results, scores = self.searcher.retrieve(query_tokens, k=num)
262
+ else:
263
+ assert False, 'Invalid bm25 backend!'
264
+
265
+ if return_score:
266
+ return results, scores
267
+ else:
268
+ return results
269
+
270
+
271
+ class DenseRetriever(BaseRetriever):
272
+ r"""Dense retriever based on pre-built faiss index."""
273
+
274
+ def __init__(self, config: dict):
275
+ super().__init__(config)
276
+ self.index = faiss.read_index(self.index_path)
277
+ if config["faiss_gpu"]:
278
+ co = faiss.GpuMultipleClonerOptions()
279
+ co.useFloat16 = True
280
+ co.shard = True
281
+ self.index = faiss.index_cpu_to_all_gpus(self.index, co=co)
282
+
283
+ self.corpus = load_corpus(self.corpus_path)
284
+
285
+ if config["use_sentence_transformer"]:
286
+ self.encoder = STEncoder(
287
+ model_name=self.retrieval_method,
288
+ model_path=config["retrieval_model_path"],
289
+ max_length=config["retrieval_query_max_length"],
290
+ use_fp16=config["retrieval_use_fp16"],
291
+ )
292
+ else:
293
+ self.encoder = Encoder(
294
+ model_name=self.retrieval_method,
295
+ model_path=config["retrieval_model_path"],
296
+ pooling_method=config["retrieval_pooling_method"],
297
+ max_length=config["retrieval_query_max_length"],
298
+ use_fp16=config["retrieval_use_fp16"],
299
+ )
300
+ self.topk = config["retrieval_topk"]
301
+ self.batch_size = self.config["retrieval_batch_size"]
302
+
303
+ def _search(self, query: str, num: int = None, return_score=False):
304
+ if num is None:
305
+ num = self.topk
306
+ query_emb = self.encoder.encode(query)
307
+ scores, idxs = self.index.search(query_emb, k=num)
308
+ scores = scores.tolist()
309
+ idxs = idxs[0]
310
+ scores = scores[0]
311
+
312
+ results = load_docs(self.corpus, idxs)
313
+ if return_score:
314
+ return results, scores
315
+ else:
316
+ return results
317
+
318
+ def _batch_search(self, query_list: List[str], num: int = None, return_score=False):
319
+ if isinstance(query_list, str):
320
+ query_list = [query_list]
321
+ if num is None:
322
+ num = self.topk
323
+
324
+ batch_size = self.batch_size
325
+
326
+ results = []
327
+ scores = []
328
+
329
+ for start_idx in tqdm(range(0, len(query_list), batch_size), desc="Retrieval process: "):
330
+ query_batch = query_list[start_idx : start_idx + batch_size]
331
+ batch_emb = self.encoder.encode(query_batch)
332
+ batch_scores, batch_idxs = self.index.search(batch_emb, k=num)
333
+ batch_scores = batch_scores.tolist()
334
+ batch_idxs = batch_idxs.tolist()
335
+
336
+ flat_idxs = sum(batch_idxs, [])
337
+ batch_results = load_docs(self.corpus, flat_idxs)
338
+ batch_results = [batch_results[i * num : (i + 1) * num] for i in range(len(batch_idxs))]
339
+
340
+ scores.extend(batch_scores)
341
+ results.extend(batch_results)
342
+
343
+ if return_score:
344
+ return results, scores
345
+ else:
346
+ return results
@@ -0,0 +1,49 @@
1
+ import json
2
+ import datasets
3
+ from transformers import AutoTokenizer, AutoModel, AutoConfig
4
+
5
+
6
+ def load_model(model_path: str, use_fp16: bool = False):
7
+ model_config = AutoConfig.from_pretrained(model_path, trust_remote_code=True)
8
+ model = AutoModel.from_pretrained(model_path, trust_remote_code=True)
9
+ model.eval()
10
+ model.cuda()
11
+ if use_fp16:
12
+ model = model.half()
13
+ tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=True, trust_remote_code=True)
14
+
15
+ return model, tokenizer
16
+
17
+
18
+ def pooling(pooler_output, last_hidden_state, attention_mask=None, pooling_method="mean"):
19
+ if pooling_method == "mean":
20
+ last_hidden = last_hidden_state.masked_fill(~attention_mask[..., None].bool(), 0.0)
21
+ return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]
22
+ elif pooling_method == "cls":
23
+ return last_hidden_state[:, 0]
24
+ elif pooling_method == "pooler":
25
+ return pooler_output
26
+ else:
27
+ raise NotImplementedError("Pooling method not implemented!")
28
+
29
+
30
+ def load_corpus(corpus_path: str):
31
+ corpus = datasets.load_dataset("json", data_files=corpus_path, split="train")
32
+ return corpus
33
+
34
+
35
+ def read_jsonl(file_path):
36
+ with open(file_path, "r") as f:
37
+ while True:
38
+ new_line = f.readline()
39
+ if not new_line:
40
+ return
41
+ new_item = json.loads(new_line)
42
+
43
+ yield new_item
44
+
45
+
46
+ def load_docs(corpus, doc_idxs):
47
+ results = [corpus[int(idx)] for idx in doc_idxs]
48
+
49
+ return results
@@ -0,0 +1,2 @@
1
+ from flashrag.utils.utils import *
2
+ from flashrag.utils.pred_parse import *
@@ -0,0 +1,51 @@
1
+ OPENAI_MODEL_DICT = {
2
+ # chat
3
+ "gpt-4o": "o200k_base",
4
+ "gpt-4": "cl100k_base",
5
+ "gpt-3.5-turbo": "cl100k_base",
6
+ "gpt-3.5": "cl100k_base", # Common shorthand
7
+ "gpt-35-turbo": "cl100k_base", # Azure deployment name
8
+ # base
9
+ "davinci-002": "cl100k_base",
10
+ "babbage-002": "cl100k_base",
11
+ # embeddings
12
+ "text-embedding-ada-002": "cl100k_base",
13
+ "text-embedding-3-small": "cl100k_base",
14
+ "text-embedding-3-large": "cl100k_base",
15
+ # DEPRECATED MODELS
16
+ # text (DEPRECATED)
17
+ "text-davinci-003": "p50k_base",
18
+ "text-davinci-002": "p50k_base",
19
+ "text-davinci-001": "r50k_base",
20
+ "text-curie-001": "r50k_base",
21
+ "text-babbage-001": "r50k_base",
22
+ "text-ada-001": "r50k_base",
23
+ "davinci": "r50k_base",
24
+ "curie": "r50k_base",
25
+ "babbage": "r50k_base",
26
+ "ada": "r50k_base",
27
+ # code (DEPRECATED)
28
+ "code-davinci-002": "p50k_base",
29
+ "code-davinci-001": "p50k_base",
30
+ "code-cushman-002": "p50k_base",
31
+ "code-cushman-001": "p50k_base",
32
+ "davinci-codex": "p50k_base",
33
+ "cushman-codex": "p50k_base",
34
+ # edit (DEPRECATED)
35
+ "text-davinci-edit-001": "p50k_edit",
36
+ "code-davinci-edit-001": "p50k_edit",
37
+ # old embeddings (DEPRECATED)
38
+ "text-similarity-davinci-001": "r50k_base",
39
+ "text-similarity-curie-001": "r50k_base",
40
+ "text-similarity-babbage-001": "r50k_base",
41
+ "text-similarity-ada-001": "r50k_base",
42
+ "text-search-davinci-doc-001": "r50k_base",
43
+ "text-search-curie-doc-001": "r50k_base",
44
+ "text-search-babbage-doc-001": "r50k_base",
45
+ "text-search-ada-doc-001": "r50k_base",
46
+ "code-search-babbage-code-001": "r50k_base",
47
+ "code-search-ada-code-001": "r50k_base",
48
+ # open source
49
+ "gpt2": "gpt2",
50
+ "gpt-2": "gpt2", # Maintains consistency with gpt-4
51
+ }
@@ -0,0 +1,25 @@
1
+ def selfask_pred_parse(pred):
2
+ """Parsing the prediction results of self-ask format."""
3
+ FINAL_ANSWER_PREFIX = "So the final answer is: "
4
+
5
+ lines = pred.split("\n")
6
+ answer = ""
7
+ for line in lines:
8
+ if FINAL_ANSWER_PREFIX in line:
9
+ answer = line.split(FINAL_ANSWER_PREFIX)[1].strip()
10
+ break
11
+
12
+ return answer
13
+
14
+
15
+ def ircot_pred_parse(pred):
16
+ FINAL_ANSWER_PREFIX = "So the answer is:"
17
+ if FINAL_ANSWER_PREFIX in pred:
18
+ answer = pred.split(FINAL_ANSWER_PREFIX)[1].strip()
19
+ else:
20
+ answer = pred
21
+ return answer
22
+
23
+
24
+ def basic_pred_parse(pred):
25
+ return pred.split("\n")[0].strip()
@@ -0,0 +1,135 @@
1
+ import os
2
+ import importlib
3
+ from transformers import AutoConfig
4
+ from flashrag.dataset.dataset import Dataset
5
+
6
+
7
+ def get_dataset(config):
8
+ """Load dataset from config."""
9
+
10
+ dataset_path = config["dataset_path"]
11
+ all_split = config["split"]
12
+
13
+ split_dict = {split: None for split in all_split}
14
+
15
+ for split in all_split:
16
+ split_path = os.path.join(dataset_path, f"{split}.jsonl")
17
+ if not os.path.exists(split_path):
18
+ print(f"{split} file not exists!")
19
+ continue
20
+ if split in ["test", "val", "dev"]:
21
+ split_dict[split] = Dataset(
22
+ config, split_path, sample_num=config["test_sample_num"], random_sample=config["random_sample"]
23
+ )
24
+ else:
25
+ split_dict[split] = Dataset(config, split_path)
26
+
27
+ return split_dict
28
+
29
+
30
+ def get_generator(config, **params):
31
+ """Automatically select generator class based on config."""
32
+ if config["framework"] == "vllm":
33
+ return getattr(importlib.import_module("flashrag.generator"), "VLLMGenerator")(config, **params)
34
+ elif config["framework"] == "fschat":
35
+ return getattr(importlib.import_module("flashrag.generator"), "FastChatGenerator")(config, **params)
36
+ elif config["framework"] == "hf":
37
+ model_config = AutoConfig.from_pretrained(config["generator_model_path"])
38
+ arch = model_config.architectures[0]
39
+ if "t5" in arch.lower() or "bart" in arch.lower():
40
+ return getattr(importlib.import_module("flashrag.generator"), "EncoderDecoderGenerator")(config, **params)
41
+ else:
42
+ return getattr(importlib.import_module("flashrag.generator"), "HFCausalLMGenerator")(config, **params)
43
+ elif config["framework"] == "openai":
44
+ return getattr(importlib.import_module("flashrag.generator"), "OpenaiGenerator")(config, **params)
45
+ else:
46
+ raise NotImplementedError
47
+
48
+
49
+ def get_retriever(config):
50
+ r"""Automatically select retriever class based on config's retrieval method
51
+
52
+ Args:
53
+ config (dict): configuration with 'retrieval_method' key
54
+
55
+ Returns:
56
+ Retriever: retriever instance
57
+ """
58
+ if config["retrieval_method"] == "bm25":
59
+ return getattr(importlib.import_module("flashrag.retriever"), "BM25Retriever")(config)
60
+ else:
61
+ return getattr(importlib.import_module("flashrag.retriever"), "DenseRetriever")(config)
62
+
63
+
64
+ def get_reranker(config):
65
+ model_path = config["rerank_model_path"]
66
+ # get model config
67
+ model_config = AutoConfig.from_pretrained(model_path)
68
+ arch = model_config.architectures[0]
69
+ if "forsequenceclassification" in arch.lower():
70
+ return getattr(importlib.import_module("flashrag.retriever"), "CrossReranker")(config)
71
+ else:
72
+ return getattr(importlib.import_module("flashrag.retriever"), "BiReranker")(config)
73
+
74
+
75
+ def get_judger(config):
76
+ judger_name = config["judger_name"]
77
+ if "skr" in judger_name.lower():
78
+ return getattr(importlib.import_module("flashrag.judger"), "SKRJudger")(config)
79
+ elif "adaptive" in judger_name.lower():
80
+ return getattr(importlib.import_module("flashrag.judger"), "AdaptiveJudger")(config)
81
+ else:
82
+ assert False, "No implementation!"
83
+
84
+
85
+ def get_refiner(config, retriever=None, generator=None):
86
+ # 预定义默认路径字典
87
+ DEFAULT_PATH_DICT = {
88
+ "recomp_abstractive_nq": "fangyuan/nq_abstractive_compressor",
89
+ "recomp:abstractive_tqa": "fangyuan/tqa_abstractive_compressor",
90
+ "recomp:abstractive_hotpotqa": "fangyuan/hotpotqa_abstractive",
91
+ }
92
+ REFINER_MODULE = importlib.import_module("flashrag.refiner")
93
+
94
+ refiner_name = config["refiner_name"]
95
+ refiner_path = (
96
+ config["refiner_model_path"]
97
+ if config["refiner_model_path"] is not None
98
+ else DEFAULT_PATH_DICT.get(refiner_name, None)
99
+ )
100
+
101
+ try:
102
+ model_config = AutoConfig.from_pretrained(refiner_path)
103
+ arch = model_config.architectures[0].lower()
104
+ except:
105
+ model_config, arch = "", ""
106
+
107
+ if "recomp" in refiner_name or "bert" in arch:
108
+ if model_config.model_type == "t5":
109
+ refiner_class = "AbstractiveRecompRefiner"
110
+ else:
111
+ refiner_class = "ExtractiveRefiner"
112
+ elif "lingua" in refiner_name:
113
+ refiner_class = "LLMLinguaRefiner"
114
+ elif "selective-context" in refiner_name or "sc" in refiner_name:
115
+ refiner_class = "SelectiveContextRefiner"
116
+ elif "kg-trace" in refiner_name:
117
+ return getattr(REFINER_MODULE, "KGTraceRefiner")(config, retriever, generator)
118
+ else:
119
+ raise ValueError("No implementation!")
120
+
121
+ return getattr(REFINER_MODULE, refiner_class)(config)
122
+
123
+
124
+ def hash_object(o) -> str:
125
+ """Returns a character hash code of arbitrary Python objects."""
126
+ import hashlib
127
+ import io
128
+ import dill
129
+ import base58
130
+
131
+ m = hashlib.blake2b()
132
+ with io.BytesIO() as buffer:
133
+ dill.dump(o, buffer)
134
+ m.update(buffer.getbuffer())
135
+ return base58.b58encode(m.digest()).decode()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jiajie Jin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.