diff --git a/app/main/check_packs/pack_config.py b/app/main/check_packs/pack_config.py index d2579f6d..4794e311 100644 --- a/app/main/check_packs/pack_config.py +++ b/app/main/check_packs/pack_config.py @@ -22,6 +22,7 @@ ['pres_image_capture'], ['task_tracker'], ['overview_in_tasks'], + ['pres_was_were_check'], ] BASE_REPORT_CRITERION = [ ["simple_check"], @@ -51,6 +52,7 @@ ["empty_task_page_check"], ["water_in_the_text_check"], ["report_task_tracker"], + ["report_was_were_check"], ] DEFAULT_TYPE = 'pres' diff --git a/app/main/checks/presentation_checks/__init__.py b/app/main/checks/presentation_checks/__init__.py index 8085b28f..3a68d562 100644 --- a/app/main/checks/presentation_checks/__init__.py +++ b/app/main/checks/presentation_checks/__init__.py @@ -6,4 +6,4 @@ module_globals=globals(), base_class=BaseCriterion, current_file=__file__ -) \ No newline at end of file +) diff --git a/app/main/checks/presentation_checks/was_were_check.py b/app/main/checks/presentation_checks/was_were_check.py new file mode 100644 index 00000000..acb39c60 --- /dev/null +++ b/app/main/checks/presentation_checks/was_were_check.py @@ -0,0 +1,18 @@ +from ..base_check import BasePresCriterion, answer +from app.utils.was_were_check import WasWereChecker + + +class PresWasWereCheck(BasePresCriterion): + label = "Проверка на пассивные конструкции, начинающиеся с Был/Была/Было/Были, которые можно убрать без потери смысла" + id = "pres_was_were_check" + + def __init__(self, file_info, threshold=3): + super().__init__(file_info) + self.threshold = threshold + self.checker = WasWereChecker(file_info, threshold) + + def check(self): + message, score = self.checker.get_result_msg_and_score( + self.file, self.format_page_link + ) + return answer(score, message) diff --git a/app/main/checks/report_checks/was_were_check.py b/app/main/checks/report_checks/was_were_check.py new file mode 100644 index 00000000..c4177343 --- /dev/null +++ b/app/main/checks/report_checks/was_were_check.py @@ -0,0 +1,18 @@ +from ..base_check import BaseReportCriterion, answer +from app.utils.was_were_check import WasWereChecker + + +class ReportWasWereCheck(BaseReportCriterion): + label = "Проверка на пассивные конструкции, начинающиеся с Был/Была/Было/Были, которые можно убрать без потери смысла" + _description = "Предложения начинающиеся с Был/Была/Было/Были, которые можно убрать без потери смысла" + id = "report_was_were_check" + + def __init__(self, file_info, threshold=3): + super().__init__(file_info) + self.checker = WasWereChecker(file_info, threshold) + + def check(self): + message, score = self.checker.get_result_msg_and_score( + self.file, self.format_page_link + ) + return answer(score, message) diff --git a/app/nlp/is_passive_was_were_sentence.py b/app/nlp/is_passive_was_were_sentence.py new file mode 100644 index 00000000..9878e5b4 --- /dev/null +++ b/app/nlp/is_passive_was_were_sentence.py @@ -0,0 +1,44 @@ +import re +import pymorphy3 +import string + +morph = pymorphy3.MorphAnalyzer() + + +def is_passive_was_were_sentece(sentence): + """ + Примеры плохих предложений (пассивные конструкции с "Был*" - можно убрать): + - Был проведен анализ данных + - Была выполнена работа по исследованию + - Было принято решение о внедрении + - Были получены следующие результаты + - Была создана база данных + + Примеры хороших предложений ("Был*" нельзя убрать): + - Было бы здорово получить новые данные + - Был сильный скачок напряжения + - Были времена, когда это казалось невозможным + - Был студентом университета три года назад + - Была программистом до выхода на пенсию + """ + first_words = re.split(r"\s+", sentence.strip(), maxsplit=2) + if len(first_words) < 2: + return False + + first_word = clean_word(first_words[0]) + second_word = clean_word(first_words[1]) + + parsed = morph.parse(first_word)[0] + if ( + parsed.normal_form == "быть" + and "past" in parsed.tag + and parsed.tag.POS == "VERB" + ): + second_word_parsed = morph.parse(second_word)[0] + return "PRTS" in second_word_parsed.tag and "pssv" in second_word_parsed.tag + return False + + +def clean_word(word): + punct = string.punctuation.replace("-", "") + return word.translate(str.maketrans("", "", punct)) diff --git a/app/utils/was_were_check.py b/app/utils/was_were_check.py new file mode 100644 index 00000000..8d810a1d --- /dev/null +++ b/app/utils/was_were_check.py @@ -0,0 +1,88 @@ +import re +from ..nlp.is_passive_was_were_sentence import is_passive_was_were_sentece + + +class WasWereChecker: + def __init__(self, file_info, threshold): + self.file_type = file_info["file_type"]["type"] + self.threshold = threshold + + def get_content_by_file(self, file): + if self.file_type == "report": + return file.pdf_file.get_text_on_page().items() + elif self.file_type == "pres": + return enumerate(file.get_text_from_slides()) + + def generate_output_text(self, detected_senteces, format_page_link_fn=None): + output = "Обнаружены конструкции (Был/Была/Было/Были), которые можно удалить без потери смысла:

" + offset_index = 0 + if self.file_type == "pres": + offset_index = 1 + + for index, messages in detected_senteces.items(): + display_index = index + offset_index + if format_page_link_fn: + output += ( + f"Страница {format_page_link_fn([display_index])}:
" + + "
".join(messages) + + "

" + ) + else: + output += ( + f"Страница №{display_index}:
" + + "
".join(messages) + + "

" + ) + return output + + def get_was_were_sentences(self, file): + detected = {} + total_sentences = 0 + for page_index, page_text in self.get_content_by_file(file): + lines = re.split(r"\n", page_text) + non_empty_line_counter = 0 + for line_index, line in enumerate(lines): + print(line_index, line) + line = line.strip() + if not line: + continue + + non_empty_line_counter += 1 + sentences = re.split(r"[.!?…]+\s*", line) + + for sentence in sentences: + sentence = sentence.strip() + if not sentence: + continue + + if is_passive_was_were_sentece(sentence): + total_sentences += 1 + if page_index not in detected: + detected[page_index] = [] + truncated_sentence = ( + sentence[:50] + "..." if len(sentence) > 50 else sentence + ) + if self.file_type == "pres": + err_str = ( + f"Строка {non_empty_line_counter}: {truncated_sentence}" + ) + elif self.file_type == "report": + err_str = f"Строка {line_index + 1}: {truncated_sentence}" + detected[page_index].append(err_str) + + return detected, total_sentences + + def get_result_msg_and_score(self, file, format_page_link): + detected, total_sentences = self.get_was_were_sentences(file) + result_msg = "" + result_score = 1 + if total_sentences == 0: + result_msg = "Пройдена!" + else: + result_msg = self.generate_output_text(detected, format_page_link) + if total_sentences > self.threshold: + result_msg = "Не пройдена!
" + result_msg + result_score = 0 + else: + result_msg = "Пройдена!
" + result_msg + return result_msg, result_score