def _execute_logical_form_on_table(logical_form: str, table: str): """ The parameters are written out to files which the jar file reads and then executes the logical form. """ logical_form_filename = os.path.join(SEMPRE_DIR, 'logical_forms.txt') with open(logical_form_filename, 'w') as temp_file: temp_file.write(logical_form + '\n') table_dir = os.path.join(SEMPRE_DIR, 'tsv/') os.makedirs(table_dir, exist_ok=True) # The .tsv file extension is important here since the table string parameter is in tsv format. # If this file was named with suffix .csv then Sempre would interpret it as comma separated # and return the wrong denotation. table_filename = 'context.tsv' with open(os.path.join(table_dir, table_filename), 'w', encoding='utf-8') as temp_file: temp_file.write(table) # The id, target, and utterance are ignored, we just need to get the # table filename into sempre's lisp format. test_record = ( '(example (id nt-0) (utterance none) (context (graph tables.TableKnowledgeGraph %s))' '(targetValue (list (description "6"))))' % (table_filename)) test_data_filename = os.path.join(SEMPRE_DIR, 'data.examples') with open(test_data_filename, 'w') as temp_file: temp_file.write(test_record) # TODO(matt): The jar that we have isn't optimal for this use case - we're using a # script designed for computing accuracy, and just pulling out a piece of it. Writing # a new entry point to the jar that's tailored for this use would be cleaner. if not check_for_java(): raise RuntimeError('Java is not installed properly.') command = ' '.join([ 'java', '-jar', cached_path(DEFAULT_EXECUTOR_JAR), test_data_filename, logical_form_filename, table_dir ]) run(command, shell=True) denotations_file = os.path.join(SEMPRE_DIR, 'logical_forms_denotations.tsv') with open(denotations_file) as temp_file: line = temp_file.readline().split('\t') # Clean up all the temp files generated from this function. # Take care to not remove the auxiliary sempre files os.remove(logical_form_filename) shutil.rmtree(table_dir) os.remove(denotations_file) os.remove(test_data_filename) return line[1] if len(line) > 1 else line[0]
def _create_sempre_executor(self) -> None: """ Creates a server running SEMPRE that we can send logical forms to for evaluation. This uses inter-process communication, because SEMPRE is java code. We also need to be careful to clean up the process when our program exits. """ if self._executor_process: return # It'd be much nicer to just use `cached_path` for these files. However, the SEMPRE jar # that we're using expects to find these files in a particular location, so we need to make # sure we put the files in that location. os.makedirs(SEMPRE_DIR, exist_ok=True) abbreviations_path = os.path.join(SEMPRE_DIR, 'abbreviations.tsv') grammar_path = os.path.join(SEMPRE_DIR, 'grow.grammar') with session_with_backoff() as session: if not os.path.exists(abbreviations_path): result = session.get(ABBREVIATIONS_FILE) with open(abbreviations_path, 'wb') as downloaded_file: downloaded_file.write(result.content) if not os.path.exists(grammar_path): result = session.get(GROW_FILE) with open(grammar_path, 'wb') as downloaded_file: downloaded_file.write(result.content) if not check_for_java(): raise RuntimeError('Java is not installed properly.') args = [ 'java', '-jar', cached_path(SEMPRE_EXECUTOR_JAR), 'serve', self._table_directory ] self._executor_process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1) lines = [] for _ in range(6): # SEMPRE outputs six lines of stuff when it loads that I can't disable. So, we clear # that here. lines.append(str(self._executor_process.stdout.readline())) assert 'Parser' in lines[ -1], "SEMPRE server output unexpected; the server may have changed" logger.info("Started SEMPRE server for evaluating logical forms") # This is supposed to ensure that the subprocess gets killed when python exits. atexit.register(self._stop_sempre_executor)
def _create_sempre_executor(self) -> None: """ Creates a server running SEMPRE that we can send logical forms to for evaluation. This uses inter-process communication, because SEMPRE is java code. We also need to be careful to clean up the process when our program exits. """ if self._executor_process: return # It'd be much nicer to just use `cached_path` for these files. However, the SEMPRE jar # that we're using expects to find these files in a particular location, so we need to make # sure we put the files in that location. os.makedirs(SEMPRE_DIR, exist_ok=True) abbreviations_path = os.path.join(SEMPRE_DIR, 'abbreviations.tsv') if not os.path.exists(abbreviations_path): result = requests.get(ABBREVIATIONS_FILE) with open(abbreviations_path, 'wb') as downloaded_file: downloaded_file.write(result.content) grammar_path = os.path.join(SEMPRE_DIR, 'grow.grammar') if not os.path.exists(grammar_path): result = requests.get(GROW_FILE) with open(grammar_path, 'wb') as downloaded_file: downloaded_file.write(result.content) if not check_for_java(): raise RuntimeError('Java is not installed properly.') args = ['java', '-jar', cached_path(SEMPRE_EXECUTOR_JAR), 'serve', self._table_directory] self._executor_process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1) lines = [] for _ in range(6): # SEMPRE outputs six lines of stuff when it loads that I can't disable. So, we clear # that here. lines.append(str(self._executor_process.stdout.readline())) assert 'Parser' in lines[-1], "SEMPRE server output unexpected; the server may have changed" logger.info("Started SEMPRE server for evaluating logical forms") # This is supposed to ensure that the subprocess gets killed when python exits. atexit.register(self._stop_sempre_executor)