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,249 @@
1
+ # Source: https://github.com/IntelLabs/fastRAG/blob/main/fastrag/generators/replug.py
2
+ # The release is licensed under the Apache License 2.0
3
+
4
+ import warnings
5
+ from typing import List, Optional, Union
6
+ import transformers
7
+ from transformers import (
8
+ MODEL_FOR_CAUSAL_LM_MAPPING,
9
+ AutoConfig,
10
+ GenerationMixin,
11
+ LogitsProcessor,
12
+ LogitsProcessorList,
13
+ StoppingCriteriaList,
14
+ )
15
+ import torch
16
+ import torch.nn as nn
17
+ import torch.distributed as dist
18
+ from transformers.generation.stopping_criteria import validate_stopping_criteria
19
+ from transformers.generation.utils import (
20
+ SampleDecoderOnlyOutput,
21
+ SampleEncoderDecoderOutput,
22
+ SampleOutput,
23
+ )
24
+
25
+
26
+ class REPLUG_Generation(GenerationMixin):
27
+ """Implementing REPLUG-based sampling text generation."""
28
+
29
+ def sample(
30
+ self,
31
+ input_ids: torch.LongTensor,
32
+ logits_processor: Optional[LogitsProcessorList] = None,
33
+ stopping_criteria: Optional[StoppingCriteriaList] = None,
34
+ logits_warper: Optional[LogitsProcessorList] = None,
35
+ max_length: Optional[int] = None,
36
+ pad_token_id: Optional[int] = None,
37
+ eos_token_id: Optional[Union[int, List[int]]] = None,
38
+ output_attentions: Optional[bool] = None,
39
+ output_hidden_states: Optional[bool] = None,
40
+ output_scores: Optional[bool] = None,
41
+ return_dict_in_generate: Optional[bool] = None,
42
+ synced_gpus: bool = False,
43
+ streamer: Optional["BaseStreamer"] = None,
44
+ **model_kwargs,
45
+ ) -> Union[SampleOutput, torch.LongTensor]:
46
+ # init values
47
+ logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()
48
+ stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()
49
+ if max_length is not None:
50
+ warnings.warn(
51
+ "`max_length` is deprecated in this function, use"
52
+ " `stopping_criteria=StoppingCriteriaList(MaxLengthCriteria(max_length=max_length))` instead.",
53
+ UserWarning,
54
+ )
55
+ stopping_criteria = validate_stopping_criteria(stopping_criteria, max_length)
56
+ logits_warper = logits_warper if logits_warper is not None else LogitsProcessorList()
57
+ pad_token_id = pad_token_id if pad_token_id is not None else self.generation_config.pad_token_id
58
+ eos_token_id = eos_token_id if eos_token_id is not None else self.generation_config.eos_token_id
59
+ if isinstance(eos_token_id, int):
60
+ eos_token_id = [eos_token_id]
61
+ eos_token_id_tensor = torch.tensor(eos_token_id).to(input_ids.device) if eos_token_id is not None else None
62
+ output_scores = output_scores if output_scores is not None else self.generation_config.output_scores
63
+ output_attentions = (
64
+ output_attentions if output_attentions is not None else self.generation_config.output_attentions
65
+ )
66
+ output_hidden_states = (
67
+ output_hidden_states if output_hidden_states is not None else self.generation_config.output_hidden_states
68
+ )
69
+ return_dict_in_generate = (
70
+ return_dict_in_generate
71
+ if return_dict_in_generate is not None
72
+ else self.generation_config.return_dict_in_generate
73
+ )
74
+
75
+ # init attention / hidden states / scores tuples
76
+ scores = () if (return_dict_in_generate and output_scores) else None
77
+ decoder_attentions = () if (return_dict_in_generate and output_attentions) else None
78
+ cross_attentions = () if (return_dict_in_generate and output_attentions) else None
79
+ decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None
80
+
81
+ # if model is an encoder-decoder, retrieve encoder attention weights and hidden states
82
+ if return_dict_in_generate and self.config.is_encoder_decoder:
83
+ encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None
84
+ encoder_hidden_states = (
85
+ model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None
86
+ )
87
+
88
+ # keep track of which sequences are already finished
89
+ unfinished_sequences = torch.ones(input_ids.shape[0], dtype=torch.long, device=input_ids.device)
90
+
91
+ this_peer_finished = False # used by synced_gpus only
92
+ # auto-regressive generation
93
+ while True:
94
+ if synced_gpus:
95
+ # Under synced_gpus the `forward` call must continue until all gpus complete their sequence.
96
+ # The following logic allows an early break if all peers finished generating their sequence
97
+ this_peer_finished_flag = torch.tensor(0.0 if this_peer_finished else 1.0).to(input_ids.device)
98
+ # send 0.0 if we finished, 1.0 otherwise
99
+ dist.all_reduce(this_peer_finished_flag, op=dist.ReduceOp.SUM)
100
+ # did all peers finish? the reduced sum will be 0.0 then
101
+ if this_peer_finished_flag.item() == 0.0:
102
+ break
103
+
104
+ # prepare model inputs
105
+ model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs)
106
+
107
+ # forward pass to get next token
108
+ outputs = self(
109
+ **model_inputs,
110
+ return_dict=True,
111
+ output_attentions=output_attentions,
112
+ output_hidden_states=output_hidden_states,
113
+ )
114
+
115
+ if synced_gpus and this_peer_finished:
116
+ continue # don't waste resources running the code we don't need
117
+
118
+ next_token_logits = outputs.logits[:, -1, :]
119
+
120
+ # pre-process distribution
121
+ ### REPLUG - document weighting is done via REPLUGLogitsProcessor
122
+ next_token_scores = logits_processor(input_ids, next_token_logits)
123
+ next_token_scores = logits_warper(input_ids, next_token_scores)
124
+
125
+ # Store scores, attentions and hidden_states when required
126
+ if return_dict_in_generate:
127
+ if output_scores:
128
+ scores += (next_token_scores,)
129
+ if output_attentions:
130
+ decoder_attentions += (
131
+ (outputs.decoder_attentions,) if self.config.is_encoder_decoder else (outputs.attentions,)
132
+ )
133
+ if self.config.is_encoder_decoder:
134
+ cross_attentions += (outputs.cross_attentions,)
135
+
136
+ if output_hidden_states:
137
+ decoder_hidden_states += (
138
+ (outputs.decoder_hidden_states,) if self.config.is_encoder_decoder else (outputs.hidden_states,)
139
+ )
140
+
141
+ ### REPLUG
142
+ # Sample from the normalized "logits", assuming the REPLUG processor was used!
143
+ probs = nn.functional.softmax(next_token_scores, dim=-1)
144
+ next_tokens = torch.multinomial(probs, num_samples=1).squeeze(-1)
145
+ # Lock same next-token for all examples in batch
146
+ next_tokens[:] = next_tokens[0]
147
+
148
+ # finished sentences should have their next token be a padding token
149
+ if eos_token_id is not None:
150
+ if pad_token_id is None:
151
+ raise ValueError("If `eos_token_id` is defined, make sure that `pad_token_id` is defined.")
152
+ next_tokens = next_tokens * unfinished_sequences + pad_token_id * (1 - unfinished_sequences)
153
+
154
+ # update generated ids, model inputs, and length for next step
155
+ input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)
156
+ if streamer is not None:
157
+ streamer.put(next_tokens.cpu())
158
+ model_kwargs = self._update_model_kwargs_for_generation(
159
+ outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder
160
+ )
161
+
162
+ # if eos_token was found in one sentence, set sentence to finished
163
+ if eos_token_id_tensor is not None:
164
+ unfinished_sequences = unfinished_sequences.mul(
165
+ next_tokens.tile(eos_token_id_tensor.shape[0], 1).ne(eos_token_id_tensor.unsqueeze(1)).prod(dim=0)
166
+ )
167
+
168
+ # stop when each sentence is finished
169
+ if unfinished_sequences.max() == 0:
170
+ this_peer_finished = True
171
+
172
+ # stop if we exceed the maximum length
173
+ if stopping_criteria(input_ids, scores):
174
+ this_peer_finished = True
175
+
176
+ if this_peer_finished and not synced_gpus:
177
+ break
178
+
179
+ if streamer is not None:
180
+ streamer.end()
181
+
182
+ if return_dict_in_generate:
183
+ if self.config.is_encoder_decoder:
184
+ return SampleEncoderDecoderOutput(
185
+ sequences=input_ids,
186
+ scores=scores,
187
+ encoder_attentions=encoder_attentions,
188
+ encoder_hidden_states=encoder_hidden_states,
189
+ decoder_attentions=decoder_attentions,
190
+ cross_attentions=cross_attentions,
191
+ decoder_hidden_states=decoder_hidden_states,
192
+ )
193
+ else:
194
+ return SampleDecoderOnlyOutput(
195
+ sequences=input_ids,
196
+ scores=scores,
197
+ attentions=decoder_attentions,
198
+ hidden_states=decoder_hidden_states,
199
+ )
200
+ else:
201
+ return input_ids
202
+
203
+
204
+ class REPLUGLogitsProcessor(LogitsProcessor):
205
+ """
206
+ Merge logits of different docs in one batch.
207
+
208
+ Reference: fastRAG
209
+ """
210
+
211
+ def __init__(self, doc_scores: torch.FloatTensor):
212
+ self.num_docs = doc_scores.shape[0]
213
+ # normalize
214
+ doc_scores /= doc_scores.sum()
215
+ self.doc_scores = torch.unsqueeze(doc_scores, 1) # k*1
216
+
217
+ def __call__(self, input_ids, scores):
218
+ # doc_score: k*1, scores: k*vocab_size
219
+ replug_scores = self.doc_scores * scores
220
+ replug_scores = replug_scores.sum(dim=0) # 1*vocab_size
221
+ replug_scores = torch.tile(replug_scores, (self.num_docs, 1)) # k*vocab_size
222
+ return replug_scores
223
+
224
+
225
+ def load_replug_model(name_or_path):
226
+ class HF_REPLUG:
227
+ "Creates a HF model that inherits from REPLUG_Generation class"
228
+
229
+ def __new__(cls, name_or_path, **kwargs):
230
+ return factory(name_or_path).from_pretrained(name_or_path, **kwargs)
231
+
232
+ def factory(name_or_path):
233
+ loadedConfig = AutoConfig.from_pretrained(name_or_path)
234
+ try:
235
+ pretrained_class_object = getattr(transformers, loadedConfig.architectures[0])
236
+ if pretrained_class_object not in MODEL_FOR_CAUSAL_LM_MAPPING.values():
237
+ raise ValueError(f"Model {pretrained_class_object} is not used for causal LM generation.")
238
+ except AttributeError:
239
+ raise ValueError("Transformers architecture unknown.")
240
+
241
+ class HF(pretrained_class_object, REPLUG_Generation):
242
+ """Wrapper around HuggingFace transformers with REPLUG generation."""
243
+
244
+ _keys_to_ignore_on_load_unexpected = [r"cls"]
245
+ _tied_weights_keys = ["lm_head.weight"]
246
+
247
+ return HF
248
+
249
+ return HF_REPLUG(name_or_path)
@@ -0,0 +1 @@
1
+ from flashrag.prompt.base_prompt import *
@@ -0,0 +1,165 @@
1
+ from transformers import AutoTokenizer, AutoConfig
2
+
3
+
4
+ class PromptTemplate:
5
+ placeholders = ["reference", "question"]
6
+ base_system_prompt = (
7
+ "Answer the question based on the given document."
8
+ "Only give me the answer and do not output any other words."
9
+ "\nThe following are given documents.\n\n{reference}"
10
+ )
11
+ base_user_prompt = "Question: {question}"
12
+
13
+ def __init__(self, config, system_prompt="", user_prompt="", reference_template=None, enable_chat=True):
14
+
15
+ self.config = config
16
+ self.is_openai = config["framework"] == "openai"
17
+ if not self.is_openai:
18
+ self.generator_path = config["generator_model_path"]
19
+ model_config = AutoConfig.from_pretrained(self.generator_path, trust_remote_code=True)
20
+ model_name = model_config._name_or_path.lower()
21
+ self.is_chat = False
22
+ if "chat" in model_name or "instruct" in model_name:
23
+ self.is_chat = True
24
+ self.tokenizer = AutoTokenizer.from_pretrained(self.generator_path, trust_remote_code=True)
25
+ else:
26
+ self.is_chat = True
27
+ self.enable_chat = True
28
+
29
+ if len(system_prompt) == 0 and len(user_prompt) == 0:
30
+ system_prompt = self.base_system_prompt
31
+ user_prompt = self.base_user_prompt
32
+ self.system_prompt = system_prompt
33
+ self.user_prompt = user_prompt
34
+ self.enable_chat = enable_chat
35
+ self.reference_template = reference_template
36
+
37
+ # self._check_placeholder()
38
+
39
+ def _check_placeholder(self):
40
+ # check placeholder in prompt
41
+ for holder in self.placeholders:
42
+ flag = False
43
+ for prompt in [self.system_prompt, self.user_prompt]:
44
+ if f"{holder}" in prompt:
45
+ print(f"Find `{holder}` in template")
46
+ flag = True
47
+ break
48
+ if not flag and holder != "reference":
49
+ assert False
50
+
51
+ def get_string(self, question=None, retrieval_result=None, formatted_reference=None, previous_gen=None, messages=None, **params):
52
+ if messages is not None:
53
+ if isinstance(messages, str):
54
+ return messages
55
+ if self.is_chat and self.enable_chat:
56
+ if self.is_openai:
57
+ for item in input:
58
+ if item["role"] == "system":
59
+ item["role"] = "assistant"
60
+ return messages
61
+ else:
62
+ prompt = self.tokenizer.apply_chat_template(
63
+ messages, tokenize=False, add_generation_prompt=True
64
+ )
65
+ return prompt
66
+ else:
67
+ prompt = "\n\n".join(
68
+ [message['content'] for message in messages if message['content']]
69
+ )
70
+ return prompt
71
+
72
+ if formatted_reference is None:
73
+ if retrieval_result is not None:
74
+ formatted_reference = self.format_reference(retrieval_result)
75
+ else:
76
+ formatted_reference = ""
77
+
78
+ input_params = {"question": question, "reference": formatted_reference}
79
+ input_params.update(**params)
80
+
81
+ system_prompt = self.system_prompt.format(**input_params)
82
+ user_prompt = self.user_prompt.format(**input_params)
83
+
84
+ if self.is_chat and self.enable_chat:
85
+ input = []
86
+ if system_prompt != "":
87
+ input.append({"role": "system", "content": system_prompt})
88
+ if user_prompt != "":
89
+ input.append({"role": "user", "content": user_prompt})
90
+ if self.is_openai:
91
+ for item in input:
92
+ if item["role"] == "system":
93
+ item["role"] = "assistant"
94
+ else:
95
+ input = self.tokenizer.apply_chat_template(input, tokenize=False, add_generation_prompt=True)
96
+ else:
97
+ input = "\n\n".join([prompt for prompt in [system_prompt, user_prompt] if prompt != ""])
98
+
99
+ if previous_gen is not None and previous_gen not in ["", " "] and self.is_openai is False:
100
+ input += previous_gen
101
+
102
+ return input
103
+
104
+ def get_string_with_varying_examplars(
105
+ self,
106
+ question,
107
+ retrieval_result=None,
108
+ formatted_reference=None,
109
+ previous_gen=None,
110
+ examplars=[],
111
+ tokenizer=None,
112
+ max_length=2048,
113
+ **params,
114
+ ):
115
+ """
116
+ Select the maximum number of examplars that can be placed in the prompt
117
+ """
118
+
119
+ final_examplars = None
120
+ num = len(examplars)
121
+ while len(examplars) > 0:
122
+ for num in range(len(examplars), 0, -1):
123
+ possible_prompt = self.get_string(
124
+ question=question,
125
+ retrieval_result=retrieval_result,
126
+ formatted_reference=formatted_reference,
127
+ previous_gen=previous_gen,
128
+ examplars="\n\n".join(examplars[:num]),
129
+ **params,
130
+ )
131
+
132
+ possible_prompt_tokens = tokenizer.encode(possible_prompt)
133
+ if len(possible_prompt_tokens) <= max_length:
134
+ final_examplars = examplars[:num]
135
+ break
136
+ if final_examplars is None:
137
+ examplars = examplars[1:]
138
+ else:
139
+ break
140
+ if final_examplars is None:
141
+ final_examplars = []
142
+
143
+ final_prompt = self.get_string(
144
+ question=question,
145
+ retrieval_result=retrieval_result,
146
+ formatted_reference=formatted_reference,
147
+ previous_gen=previous_gen,
148
+ examplars="\n\n".join(final_examplars[:num]),
149
+ **params,
150
+ )
151
+
152
+ return final_prompt
153
+
154
+ def format_reference(self, retrieval_result):
155
+ format_reference = ""
156
+ for idx, doc_item in enumerate(retrieval_result):
157
+ content = doc_item["contents"]
158
+ title = content.split("\n")[0]
159
+ text = "\n".join(content.split("\n")[1:])
160
+ if self.reference_template is not None:
161
+ format_reference += self.reference_template.format(idx=idx, title=title, text=text)
162
+ else:
163
+ format_reference += f"Doc {idx+1}(Title: {title}) {text}\n"
164
+
165
+ return format_reference
@@ -0,0 +1,108 @@
1
+ SELF_ASK_PROMPT_SINGLE_HOP = """Given the following question, answer it by providing follow up questions and intermediate answers. If intermediate questions are not necessarry, answer the question directly. You are provided with evidence that can help you arrive at the answer before the question.
2
+ #
3
+ Context1: The Big Red One: Fuller was a World War II veteran and served with the 1st Infantry Division, which is nicknamed "The Big Red One" for the red numeral "1" on the division's shoulder patch. He received the Silver Star, Bronze Star, and Purple Heart during his service.
4
+ Question: how did the big red one get its name
5
+ Are follow up questions needed here: No.
6
+ So the final answer is: its shoulder patch
7
+ #
8
+ Context1: Module:Location map/data/Cayman Islands: Module:Location map/data/Cayman Islands is a location map definition used to overlay markers and labels on an equirectangular projection map of Cayman
9
+ Question: where are the cayman islands on the map
10
+ Are follow up questions needed here: No.
11
+ So the final answer is: western Caribbean Sea
12
+ #
13
+ Context1: Korean War | Combatants, Summary, Years, Map ... - Britannica: After more than a million combat casualties had been suffered on both sides, the fighting ended in July 1953 with Korea still divided into two hostile states. Negotiations in 1954 produced no further agreement, and the front line has been accepted ever since as the de facto boundary between North and South Korea.
14
+ Question: who won the war between north korea and south korea
15
+ Are follow up questions needed here: No.
16
+ So the final answer is: technically still at war
17
+ #
18
+ Context1: It's Always Sunny in Philadelphia (season 13): The thirteenth season of the American comedy television series It's Always Sunny in Philadelphia premiered on FXX on September 5, 2018.
19
+ Question: when does it's always sunny in philadelphia season 13 start
20
+ Are follow up questions needed here: No.
21
+ So the final answer is: September 5, 2018
22
+ #
23
+ Context1: You've Got a Friend in Me: "You've Got a Friend in Me" is a song by Randy Newman. Used as the theme song for the 1995 Disney/Pixar animated film Toy Story, it has since become a major ...
24
+ Question: who sang you got a friend in me from toy story
25
+ Are follow up questions needed here: No.
26
+ So the final answer is: Randy Newman
27
+ #
28
+ Context1: Timeline of space exploration: This is a timeline of space exploration which includes notable achievements, first accomplishments and milestones in humanity's exploration of outer space.
29
+ Question: when was the first person sent to space
30
+ Are follow up questions needed here: No.
31
+ So the final answer is: 12 April 1961
32
+ #"""
33
+
34
+
35
+ SELF_ASK_PROMPT_MULTI_HOP = """Given the following question, answer it by providing follow up questions and intermediate answers. If intermediate questions are not necessarry, answer the question directly. You are provided with evidence that can help you arrive at the answer before the question.
36
+ #
37
+ Context1: Xawery Żuławski: Polish-Russian War (Wojna polsko-ruska) is a 2009 Polish film directed by Xawery Żuławski based on the novel Polish-Russian War under the white-red flag by Dorota Masłowska. So the answer is Xawery Żuławski.
38
+ Context2: Xawery Żuławski: Xawery Żuławski ; National Film School in Łódź · 1995–present · Maria Strzelecka · 2.
39
+ Question: Who is the mother of the director of film Polish-Russian War (Film)?
40
+ Are follow up questions needed here: Yes.
41
+ Follow up: Who is the director of the film Polish-Russian War (Film)?
42
+ Intermediate answer: The director of the film Polish-Russian War is Xawery Żuławski.
43
+ Follow up: Who is the mother of Xawery Żuławski?
44
+ Intermediate answer: The mother of Xawery Żuławski is Małgorzata Braunek.
45
+ So the final answer is: Rick Scott Małgorzata Braunek.
46
+ #
47
+ Context1: 2003: Blind Shaft (Chinese: 盲井; pinyin: Mángjǐng) is a 2003 film about a pair of brutal con artists operating in the illegal coal mines of present-day northern China. So the answer is 2003.
48
+ Context2: December 2, 1932: Release and reception. The Mask of Fu Manchu opened in New York on December 2, 1932. The film cost a total of $338,000 and had worldwide rentals of $625,000. It had a profit of $62,000. So the answer is December 2, 1932.
49
+ Question: Which film came out first, Blind Shaft or The Mask Of Fu Manchu?
50
+ Are follow up questions needed here: Yes.
51
+ Follow up: When did Blind Shaft come out?
52
+ Intermediate answer: Blind Shaft came out in 2003.
53
+ Follow up: When did The Mask Of Fu Manchu come out?
54
+ Intermediate answer: The Mask Of Fu Manchu came out in 1932.
55
+ So the final answer is: The Mask Of Fu Manchu.
56
+ #
57
+ Context1: John V, Prince of Anhalt-Zerbst: John was the second (but eldest surviving) son of Ernest I, Prince of Anhalt-Dessau, by his wife Margarete, daughter of Henry I, Duke of Münsterberg-Oels, and granddaughter of George of Poděbrady, King of Bohemia.
58
+ Context2: 12 June 1516: Ernest I, Prince of Anhalt-Dessau (died Dessau, 12 June 1516), was a German prince of the House of Ascania and ruler of the principality of Anhalt-Dessau. So the answer is 12 June 1516.
59
+ Question: When did John V, Prince Of Anhalt-Zerbst's father die?
60
+ Are follow up questions needed here: Yes.
61
+ Follow up: Who is the father of John V, Prince Of Anhalt-Zerbst?
62
+ Intermediate answer: The father of John V, Prince Of Anhalt-Zerbst is Ernest I, Prince of Anhalt-Dessau.
63
+ Follow up: When did Ernest I, Prince of Anhalt-Dessau die?
64
+ Intermediate answer: Ernest I, Prince of Anhalt-Dessau died on 12 June 1516.
65
+ So the final answer is: 12 June 1516
66
+ #
67
+ Context1: El extraño viaje: El extraño viaje (English: The Strange Voyage) is a 1964 Spanish black drama film directed by Fernando Fernán Gómez.
68
+ Context2: Love in Pawn: Love in Pawn is a 1953 British comedy film directed by Charles Saunders and starring Bernard Braden, Barbara Kelly and Jeannie Carson.
69
+ Context3: 28 August 1921: Fernando Fernández Gómez (28 August 1921 – 21 November 2007) better known as Fernando Fernán Gómez was a Spanish actor, screenwriter, film director, theater director and member of the Royal Spanish Academy for seven years. So the answer is 28 August 1921.
70
+ Context4: Charles Saunders (director): Charles Joel Saunders (8 April 1904 – 20 April 1997) was an English film director and screenwriter who began in the industry as a film editor, and who also contributed to television.
71
+ Question: Which film has the director who was born later, El Extraño Viaje or Love In Pawn?
72
+ Are follow up questions needed here: Yes.
73
+ Follow up: Who is the director of El Extraño Viaje?
74
+ Intermediate answer: The director of El Extraño Viaje is Fernando Fernán Gómez.
75
+ Follow up: Who is the director of Love in Pawn?
76
+ Intermediate answer: The director of Love in Pawn is Charles Saunders.
77
+ Follow up: When was Fernando Fernán Gómez born?
78
+ Intermediate answer: Fernando Fernán Gómez was born on 28 August 1921.
79
+ Follow up: When was Charles Saunders (director) born?
80
+ Intermediate answer: Charles Saunders was born on 8 April 1904.
81
+ So the final answer is: El Extraño Viaje.
82
+ #
83
+ Context1: John, Count Palatine of Neumarkt: John (Johann von Pfalz-Neumarkt; 1383 – 14 March 1443) was the Count Palatine of Neumarkt from 1410 to his death. The son of Rupert III of the Palatinate, he married Catherine of Pomerania in 1407.
84
+ Context2: John, Count Palatine of Neumarkt: John (Johann von Pfalz-Neumarkt; 1383 – 14 March 1443) was the Count Palatine of Neumarkt from 1410 to his death. The son of Rupert III of the Palatinate, he married Catherine of Pomerania in 1407.
85
+ Question: Who is Catherine Of Pomerania, Countess Palatine Of Neumarkt's father-in-law?
86
+ Are follow up questions needed here: Yes.
87
+ Follow up: Who is the husband of Catherine of Pomerania, Countess Palatine of Neumarkt?
88
+ Intermediate answer: The husband of Catherine of Pomerania, Countess Palatine of Neumarkt is John, Count Palatine of Neumarkt.
89
+ Follow up: Who is the father of John, Count Palatine of Neumarkt?
90
+ Intermediate answer: The father of John, Count Palatine of Neumarkt is Rupert III of the Palatinate.
91
+ So the final answer is: Rupert III of the Palatinate.
92
+ #
93
+ Context1: Crimen a las tres: Crimen a las tres is a 1935 Argentine crime film directed and written by Luis Saslavsky. Crimen a las tres. Directed by, Luis Saslavsky.
94
+ Context2: Elio Petri: The Working Class Goes to Heaven (Italian: La classe operaia va in paradiso), released in the US as Lulu the Tool, is a 1971 political drama film directed by Elio Petri. So the answer is Elio Petri.
95
+ Context3: March 20, 1995: Luis Saslavsky (April 21, 1903 – March 20, 1995) was an Argentine film director, screenwriter and film producer, and one of the influential directors in the Cinema of Argentina of the classic era. So the answer is March 20, 1995.
96
+ Context4: Elio Petri: Final years. In 1981, Petri visited Geneva to direct Arthur Miller\'s new play The American Clock, with Marcello Mastroianni playing the lead role. Petri died of cancer on 10 November 1982. He was 53 years old.
97
+ Question: Which film has the director died first, Crimen A Las Tres or The Working Class Goes To Heaven?
98
+ Are follow up questions needed here: Yes.
99
+ Follow up: Who is the director of Crimen a las tres?
100
+ Intermediate answer: The director of Crimen a las tres is Luis Saslavsky.
101
+ Follow up: Who is the director of The Working Class Goes to Heaven?
102
+ Intermediate answer: The director of The Working Class Goes to Heaven is Elio Petri.
103
+ Follow up: When did Luis Saslavsky die?
104
+ Intermediate answer: Luis Saslavsky died on March 20, 1995.
105
+ Follow up: When did Elio Petri die?
106
+ Intermediate answer: Elio Petri died on 10 November 1982.
107
+ So the final answer is: The Working Class Goes to Heaven
108
+ #"""