flashrag-dev 0.1.4.dev20250410__tar.gz → 0.1.4.dev20250424__tar.gz

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 (62) hide show
  1. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/PKG-INFO +1 -1
  2. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/openai_generator.py +39 -14
  3. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/active_pipeline.py +9 -5
  4. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/prompt/base_prompt.py +32 -19
  5. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/encoder.py +16 -13
  6. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/retriever.py +6 -5
  7. flashrag_dev-0.1.4.dev20250424/flashrag/version.py +1 -0
  8. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag_dev.egg-info/PKG-INFO +1 -1
  9. flashrag_dev-0.1.4.dev20250410/flashrag/version.py +0 -1
  10. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/LICENSE +0 -0
  11. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/README.md +0 -0
  12. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/__init__.py +0 -0
  13. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/config/__init__.py +0 -0
  14. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/config/basic_config.yaml +0 -0
  15. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/config/config.py +0 -0
  16. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/dataset/__init__.py +0 -0
  17. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/dataset/dataset.py +0 -0
  18. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/dataset/utils.py +0 -0
  19. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/evaluator/__init__.py +0 -0
  20. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/evaluator/_bleu.py +0 -0
  21. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/evaluator/evaluator.py +0 -0
  22. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/evaluator/metrics.py +0 -0
  23. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/evaluator/utils.py +0 -0
  24. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/__init__.py +0 -0
  25. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/fid.py +0 -0
  26. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/generator.py +0 -0
  27. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/multimodal_generator.py +0 -0
  28. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/stop_word_criteria.py +0 -0
  29. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/generator/utils.py +0 -0
  30. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/judger/__init__.py +0 -0
  31. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/judger/judger.py +0 -0
  32. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/__init__.py +0 -0
  33. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/branching_pipeline.py +0 -0
  34. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/mm_pipeline.py +0 -0
  35. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/pipeline.py +0 -0
  36. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/reasoning_pipeline.py +0 -0
  37. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/pipeline/replug_utils.py +0 -0
  38. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/prompt/__init__.py +0 -0
  39. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/prompt/mm_prompt.py +0 -0
  40. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/prompt/selfask_examplars.py +0 -0
  41. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/prompt/trace_examplars.py +0 -0
  42. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/refiner/__init__.py +0 -0
  43. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/refiner/kg_refiner.py +0 -0
  44. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/refiner/llmlingua_compressor.py +0 -0
  45. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/refiner/refiner.py +0 -0
  46. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/refiner/selective_context_compressor.py +0 -0
  47. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/__init__.py +0 -0
  48. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/__main__.py +0 -0
  49. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/index_builder.py +0 -0
  50. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/reranker.py +0 -0
  51. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/retriever/utils.py +0 -0
  52. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/utils/__init__.py +0 -0
  53. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/utils/constants.py +0 -0
  54. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/utils/pred_parse.py +0 -0
  55. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag/utils/utils.py +0 -0
  56. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag_dev.egg-info/SOURCES.txt +0 -0
  57. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag_dev.egg-info/dependency_links.txt +0 -0
  58. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag_dev.egg-info/requires.txt +0 -0
  59. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/flashrag_dev.egg-info/top_level.txt +0 -0
  60. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/pyproject.toml +0 -0
  61. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/setup.cfg +0 -0
  62. {flashrag_dev-0.1.4.dev20250410 → flashrag_dev-0.1.4.dev20250424}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flashrag_dev
3
- Version: 0.1.4.dev20250410
3
+ Version: 0.1.4.dev20250424
4
4
  Summary: A library for efficient Retrieval-Augmented Generation research
5
5
  Home-page: https://github.com/RUC-NLPIR/FlashRAG
6
6
  Author: Jiajie Jin, Yutao Zhu, Chenghao Zhang, Xinyu Yang, Zhicheng Dou
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import List
2
+ from typing import List, Union
3
3
  from copy import deepcopy
4
4
  import warnings
5
5
  from tqdm import tqdm
@@ -63,16 +63,26 @@ class OpenaiGenerator:
63
63
  def update_additional_setting(self):
64
64
  pass
65
65
 
66
- async def _get_response(self, messages: List, **params):
67
- response = await self.client.chat.completions.create(
68
- model=self.model_name, messages=messages, **params
69
- )
70
- if not response.choices:
71
- raise ValueError("No choices returned from API.")
72
- return response.choices[0]
66
+ async def _get_response(self, messages: Union[list, str], mode: str = 'chat', **params):
67
+ print(messages)
68
+ print("----asd-asd-a--------")
69
+ if mode == 'chat':
70
+ response = await self.client.chat.completions.create(
71
+ model=self.model_name, messages=messages, **params
72
+ )
73
+ if not response.choices:
74
+ raise ValueError("No choices returned from API.")
75
+ return response.choices[0]
76
+ else:
77
+ response = await self.client.completions.create(
78
+ model=self.model_name, prompt=messages, **params
79
+ )
80
+ if not response.choices:
81
+ raise ValueError("No choices returned from API.")
82
+ return response.choices[0]
73
83
 
74
- async def _get_batch_response(self, input_list: List[List], batch_size, **params):
75
- tasks = [self._get_response(messages, **params) for messages in input_list]
84
+ async def _get_batch_response(self, input_list: List[List], batch_size, mode, **params):
85
+ tasks = [self._get_response(messages, mode, **params) for messages in input_list]
76
86
  all_results = []
77
87
  for idx in tqdm(range(0, len(tasks), batch_size), desc="Generation process: "):
78
88
  batch_tasks = tasks[idx: idx + batch_size]
@@ -85,6 +95,10 @@ class OpenaiGenerator:
85
95
  input_list = [[input_list]]
86
96
  elif isinstance(input_list[0], dict):
87
97
  input_list = [input_list]
98
+ if isinstance(input_list[0], list):
99
+ mode = 'chat'
100
+ else:
101
+ mode = 'completion'
88
102
 
89
103
  if batch_size is None:
90
104
  batch_size = self.batch_size
@@ -107,15 +121,26 @@ class OpenaiGenerator:
107
121
  warnings.warn("Set logprobs to True to get generation scores.")
108
122
 
109
123
 
110
- results = await self._get_batch_response(input_list, batch_size, **generation_params)
124
+ results = await self._get_batch_response(input_list, batch_size, mode, **generation_params)
111
125
 
112
126
  response_texts = []
113
127
  scores = []
114
128
  for res in results:
115
- response_texts.append(res.message.content)
129
+ if mode == 'chat':
130
+ text = res.message.content
131
+ else:
132
+ text = res.text
133
+ if 'stop' in generation_params and not any([text.endswith(stop_str) for stop_str in generation_params['stop']]):
134
+ # current openai api not support including stop, so need to add the stop token
135
+ text += generation_params['stop'][0]
136
+ response_texts.append(text)
116
137
  if return_scores:
117
- score = np.exp([item.logprob for item in res.logprobs.content])
118
- scores.append(score)
138
+ try:
139
+ score = np.exp([item.logprob for item in res.logprobs.content])
140
+ scores.append(score)
141
+ except:
142
+ warnings.warn('Fail to get logprobs in openai generation!')
143
+ scores.append(None)
119
144
  return (response_texts, scores) if return_scores else response_texts
120
145
 
121
146
  # ----------------- 同步包装接口 -----------------
@@ -931,12 +931,17 @@ class IRCOTPipeline(BasicPipeline):
931
931
  ):
932
932
  # if not provide prompt template, use default template provided by IRCOT
933
933
  if prompt_template is None:
934
+ if config['framework'] == 'openai':
935
+ enable_chat = True
936
+ else:
937
+ enable_chat = False
938
+
934
939
  prompt_template = PromptTemplate(
935
940
  config=config,
936
941
  system_prompt=f"{self.IRCOT_INSTRUCTION}\n\n{self.IRCOT_EXAMPLE}",
937
942
  user_prompt="{reference}Question: {question}\nThought:",
938
943
  reference_template="Wikipedia Title: {title}\n{text}\n\n",
939
- enable_chat=False,
944
+ enable_chat=enable_chat,
940
945
  )
941
946
 
942
947
  super().__init__(config, prompt_template)
@@ -957,7 +962,6 @@ class IRCOTPipeline(BasicPipeline):
957
962
  questions = [item.question for item in items]
958
963
  retrieval_results, scoress = self.retriever.batch_search(questions, return_score=True)
959
964
  for retrieval_result, scores in zip(retrieval_results,scoress):
960
-
961
965
  doc2score = {doc_item['id']: score for doc_item, score in zip(retrieval_result, scores)}
962
966
  id2doc = {doc_item['id']: doc_item for doc_item in retrieval_result}
963
967
  batch_retrieval_results.append(retrieval_result)
@@ -976,6 +980,7 @@ class IRCOTPipeline(BasicPipeline):
976
980
  )
977
981
  for item_id in active_item_ids
978
982
  ]
983
+
979
984
 
980
985
  # Batch generation for active items
981
986
  new_thoughts_batch = self.generator.generate(input_prompts, stop=['.', '\n'])
@@ -988,15 +993,14 @@ class IRCOTPipeline(BasicPipeline):
988
993
 
989
994
  # Check for termination condition
990
995
  # Store intermediate outputs
991
- if "So the answer is:" in new_thought:
992
- items[item_id].update_output(
996
+ items[item_id].update_output(
993
997
  f'intermediate_output_iter{iter_num}',
994
998
  {
995
999
  'input_prompt': input_prompts[idx],
996
1000
  'new_thought': new_thought,
997
1001
  },
998
1002
  )
999
- else:
1003
+ if "So the answer is:" not in new_thought:
1000
1004
  new_active_item_ids.append(item_id)
1001
1005
 
1002
1006
  # Update active item IDs for the next iteration
@@ -58,23 +58,29 @@ class PromptTemplate:
58
58
 
59
59
  def truncate_prompt(self, prompt):
60
60
  if self.is_openai:
61
- truncated_messages = []
62
- total_tokens = 0
63
- assert isinstance(prompt, list)
64
- for message in prompt:
65
- role_content = message['content']
66
- encoded_message = self.tokenizer.encode(role_content)
67
-
68
- if total_tokens + len(encoded_message) <= self.max_input_len:
69
- truncated_messages.append(message)
70
- total_tokens += len(encoded_message)
71
- else:
72
- print(f"The input text length is greater than the maximum length ({total_tokens + len(encoded_message)} > {self.max_input_len}) and has been truncated!")
73
- remaining_tokens = self.max_input_len - total_tokens
74
- truncated_message = self.encoding.decode(encoded_message[:remaining_tokens])
75
- message['content'] = truncated_message
76
- truncated_messages.append(message)
77
- break
61
+ if self.enable_chat:
62
+ truncated_messages = []
63
+ total_tokens = 0
64
+ assert isinstance(prompt, list)
65
+ for message in prompt:
66
+ role_content = message['content']
67
+ encoded_message = self.tokenizer.encode(role_content)
68
+
69
+ if total_tokens + len(encoded_message) <= self.max_input_len:
70
+ truncated_messages.append(message)
71
+ total_tokens += len(encoded_message)
72
+ else:
73
+ print(f"The input text length is greater than the maximum length ({total_tokens + len(encoded_message)} > {self.max_input_len}) and has been truncated!")
74
+ remaining_tokens = self.max_input_len - total_tokens
75
+ truncated_message = self.encoding.decode(encoded_message[:remaining_tokens])
76
+ message['content'] = truncated_message
77
+ truncated_messages.append(message)
78
+ break
79
+ else:
80
+ assert isinstance(prompt, str)
81
+ tokenized_prompt = self.tokenizer.encode(prompt,allowed_special={'<|endoftext|>'})
82
+ half = int(self.max_input_len / 2)
83
+ truncated_messages = self.tokenizer.decode(tokenized_prompt[:half]) + self.tokenizer.decode(tokenized_prompt[-half:])
78
84
 
79
85
  return truncated_messages
80
86
 
@@ -134,8 +140,15 @@ class PromptTemplate:
134
140
  else:
135
141
  input = "\n\n".join([prompt for prompt in [system_prompt, user_prompt] if prompt != ""])
136
142
 
137
- if previous_gen is not None and previous_gen not in ["", " "] and self.is_openai is False:
138
- input += previous_gen
143
+ if previous_gen is not None and previous_gen not in ["", " "]:
144
+ if self.is_openai:
145
+ if self.enable_chat:
146
+ input.append({"role": 'assistant', 'content': previous_gen})
147
+ else:
148
+ input += f'<|endoftext|>{previous_gen}'
149
+
150
+ else:
151
+ input += previous_gen
139
152
 
140
153
  return self.truncate_prompt(input)
141
154
 
@@ -24,7 +24,7 @@ class Encoder:
24
24
  Encodes a list of queries into embeddings.
25
25
  """
26
26
 
27
- def __init__(self, model_name, model_path, pooling_method, max_length, use_fp16, instruction, silent=False):
27
+ def __init__(self, model_name, model_path, pooling_method, max_length, use_fp16=True, instruction="", silent=False):
28
28
  self.model_name = model_name
29
29
  self.model_path = model_path
30
30
  self.pooling_method = pooling_method
@@ -44,7 +44,9 @@ class Encoder:
44
44
  )
45
45
  inputs = {k: v.cuda() for k, v in inputs.items()}
46
46
 
47
- if "T5" in type(self.model).__name__ or (isinstance(self.model, torch.nn.DataParallel) and "T5" in type(self.model.module).__name__):
47
+ if "T5" in type(self.model).__name__ or (
48
+ isinstance(self.model, torch.nn.DataParallel) and "T5" in type(self.model.module).__name__
49
+ ):
48
50
  # T5-based retrieval model
49
51
  decoder_input_ids = torch.zeros((inputs["input_ids"].shape[0], 1), dtype=torch.long).to(
50
52
  inputs["input_ids"].device
@@ -54,11 +56,9 @@ class Encoder:
54
56
 
55
57
  else:
56
58
  output = self.model(**inputs, return_dict=True)
57
- pooler_output = output.get('pooler_output', None)
58
- last_hidden_state = output.get('last_hidden_state', None)
59
- query_emb = pooling(
60
- pooler_output, last_hidden_state, inputs["attention_mask"], self.pooling_method
61
- )
59
+ pooler_output = output.get("pooler_output", None)
60
+ last_hidden_state = output.get("last_hidden_state", None)
61
+ query_emb = pooling(pooler_output, last_hidden_state, inputs["attention_mask"], self.pooling_method)
62
62
  if "dpr" not in self.model_name:
63
63
  query_emb = torch.nn.functional.normalize(query_emb, dim=-1)
64
64
  query_emb = query_emb.detach().cpu().numpy()
@@ -117,7 +117,11 @@ class STEncoder:
117
117
  def encode(self, query_list: Union[List[str], str], batch_size=64, is_query=True) -> np.ndarray:
118
118
  query_list = parse_query(self.model_name, query_list, self.instruction, is_query)
119
119
  query_emb = self.model.encode(
120
- query_list, batch_size=batch_size, convert_to_numpy=True, normalize_embeddings=True, show_progress_bar=not self.silent
120
+ query_list,
121
+ batch_size=batch_size,
122
+ convert_to_numpy=True,
123
+ normalize_embeddings=True,
124
+ show_progress_bar=not self.silent,
121
125
  )
122
126
  query_emb = query_emb.astype(np.float32, order="C")
123
127
 
@@ -173,11 +177,10 @@ class ClipEncoder:
173
177
  # set model max length for model that not specified in config.json
174
178
  if self.processor is not None and self.processor.tokenizer.model_max_length > 100000:
175
179
  try:
176
- model_max_length = config['text_config']['max_position_embeddings']
180
+ model_max_length = config["text_config"]["max_position_embeddings"]
177
181
  except:
178
182
  model_max_length = 512
179
- self.processor.tokenizer.model_max_length = model_max_length
180
-
183
+ self.processor.tokenizer.model_max_length = model_max_length
181
184
 
182
185
  @torch.inference_mode()
183
186
  def single_batch_encode(self, query_list: Union[List[str], str], modal="image") -> np.ndarray:
@@ -207,7 +210,7 @@ class ClipEncoder:
207
210
  @torch.inference_mode()
208
211
  def encode_image(self, image_list: List) -> np.ndarray:
209
212
  # Each item in image_list: PIL Image, local path, or URL
210
- if self.model_type == "CLIPModel" or self.model_type == 'ChineseCLIPModel':
213
+ if self.model_type == "CLIPModel" or self.model_type == "ChineseCLIPModel":
211
214
  # need handle image
212
215
  image_list = [parse_image(image) for image in image_list]
213
216
  inputs = self.processor(images=image_list, return_tensors="pt")
@@ -224,7 +227,7 @@ class ClipEncoder:
224
227
  @torch.inference_mode()
225
228
  def encode_text(self, text_list: List[str]) -> np.ndarray:
226
229
  # Each item in image_list: PIL Image, local path, or URL
227
- if self.model_type == "CLIPModel" or self.model_type == 'ChineseCLIPModel':
230
+ if self.model_type == "CLIPModel" or self.model_type == "ChineseCLIPModel":
228
231
  inputs = self.processor(
229
232
  text=text_list,
230
233
  padding=True,
@@ -242,10 +242,7 @@ class BM25Retriever(BaseTextRetriever):
242
242
  else:
243
243
  self.corpus = corpus
244
244
  self.max_process_num = 8
245
-
246
- is_zh = judge_zh(self.corpus[0]["contents"])
247
- if is_zh:
248
- self.searcher.set_language("zh")
245
+
249
246
  elif self.backend == "bm25s":
250
247
  import Stemmer
251
248
  import bm25s
@@ -278,6 +275,9 @@ class BM25Retriever(BaseTextRetriever):
278
275
  if num is None:
279
276
  num = self.topk
280
277
  if self.backend == "pyserini":
278
+ is_zh = judge_zh(query)
279
+ if is_zh:
280
+ self.searcher.set_language("zh")
281
281
  hits = self.searcher.search(query, num)
282
282
  if len(hits) < 1:
283
283
  if return_score:
@@ -295,11 +295,12 @@ class BM25Retriever(BaseTextRetriever):
295
295
  all_contents = [json.loads(self.searcher.doc(hit.docid).raw())["contents"] for hit in hits]
296
296
  results = [
297
297
  {
298
+ "id": hit.docid,
298
299
  "title": content.split("\n")[0].strip('"'),
299
300
  "text": "\n".join(content.split("\n")[1:]),
300
301
  "contents": content,
301
302
  }
302
- for content in all_contents
303
+ for content, hit in zip(all_contents, hits)
303
304
  ]
304
305
  else:
305
306
  results = load_docs(self.corpus, [hit.docid for hit in hits])
@@ -0,0 +1 @@
1
+ __version__ = "0.1.4dev20250424"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flashrag-dev
3
- Version: 0.1.4.dev20250410
3
+ Version: 0.1.4.dev20250424
4
4
  Summary: A library for efficient Retrieval-Augmented Generation research
5
5
  Home-page: https://github.com/RUC-NLPIR/FlashRAG
6
6
  Author: Jiajie Jin, Yutao Zhu, Chenghao Zhang, Xinyu Yang, Zhicheng Dou
@@ -1 +0,0 @@
1
- __version__ = "0.1.4dev20250410"