diff --git a/app/main/check_packs/pack_config.py b/app/main/check_packs/pack_config.py
index 407d212d..dea098c2 100644
--- a/app/main/check_packs/pack_config.py
+++ b/app/main/check_packs/pack_config.py
@@ -45,6 +45,7 @@
["max_abstract_size_check"],
["theme_in_report_check"],
["empty_task_page_check"],
+ ["water_in_the_text_check"],
]
DEFAULT_TYPE = 'pres'
diff --git a/app/main/checks/report_checks/__init__.py b/app/main/checks/report_checks/__init__.py
index e8e58aad..a8b11c0e 100644
--- a/app/main/checks/report_checks/__init__.py
+++ b/app/main/checks/report_checks/__init__.py
@@ -25,6 +25,7 @@
from .max_abstract_size_check import ReportMaxSizeOfAbstractCheck
from .template_name import ReportTemplateNameCheck
from .empty_task_page_check import EmptyTaskPageCheck
+from .water_in_the_text_check import WaterInTheTextCheck
from .sw_section_banned_words import SWSectionBannedWordsCheck
from .sw_section_lit_reference import SWSectionLiteratureReferenceCheck
from .sw_tasks import SWTasksCheck
diff --git a/app/main/checks/report_checks/water_in_the_text_check.py b/app/main/checks/report_checks/water_in_the_text_check.py
new file mode 100644
index 00000000..a92a4c73
--- /dev/null
+++ b/app/main/checks/report_checks/water_in_the_text_check.py
@@ -0,0 +1,87 @@
+import re
+from collections import Counter
+from ..base_check import BaseReportCriterion, answer, morph
+from .watery_phrase_settings import WateryPhrase
+
+class WaterInTheTextCheck(BaseReportCriterion):
+ label = "Проверка объема воды в тексте"
+ description = ''
+ id = 'water_in_the_text_check'
+ # необходимо подобрать watery_phrase_threshold, long_sentence_threshold, meaningful_word_threshold, long_sentence_word_limit
+ def __init__(self, file_info, watery_phrase_threshold=0.3, long_sentence_threshold=0.3, meaningful_word_threshold=0.6, long_sentence_word_limit=20):
+ super().__init__(file_info)
+ self.chapters = []
+ self.watery_phrase = None
+ self.watery_words = None
+ self.watery_phrase_threshold = watery_phrase_threshold
+ self.long_sentence_threshold = long_sentence_threshold
+ self.meaningful_word_threshold = meaningful_word_threshold
+ self.long_sentence_word_limit = long_sentence_word_limit
+
+ def late_init(self):
+ self.chapters = self.file.make_chapters(self.file_type['report_type'])
+
+ def check(self):
+ self.watery_phrase = WateryPhrase.INTRODUCTORY_PHRASE
+ self.watery_words = WateryPhrase.SERVICE_WORDS + WateryPhrase.ABSTRACT_WORDS
+ if self.file.page_counter() < 4:
+ return answer(False, "В отчете недостаточно страниц. Нечего проверять.")
+ self.late_init()
+ result_str = ""
+ for chapter in self.chapters:
+ if 'список использованных источников' in chapter['text'].lower():
+ break
+ text = self.get_chapter_text(chapter)
+ words = self.get_words(text)
+ if self.watery_phrase_density(text, words) > self.watery_phrase_threshold:
+ result_str += f"В разделе '{chapter['text']}' содержится более {self.watery_phrase_threshold*100}% 'водянистых' фраз. Попробуйте уменьшить количество водянистых слов и фраз.
"
+
+ if self.long_sentences_density(text) > self.long_sentence_threshold:
+ result_str += f"В разделе '{chapter['text']}' более {self.long_sentence_threshold*100}% предложений длиннее {self.long_sentence_word_limit} слов. Используйте более короткие предложения.
"
+
+ if self.meaningful_word_density(words) < self.meaningful_word_threshold:
+ result_str += f"В разделе '{chapter['text']}' доля значимых слов составляет менее {self.meaningful_word_threshold*100}% от общего количества слов. Уменьшите количество вспомогательных частей речи.
"
+ if not result_str:
+ return answer(True, "Пройдена!")
+ result_str = f'''Значимыми словами в рамках критерия считаются существительные, прилагательные/краткие прилагательные и глаголы.
+ Водянистыми словами и фразами являются:
+ Служебные слова: {WateryPhrase.SERVICE_WORDS}
+ Вводные конструкции: { WateryPhrase.INTRODUCTORY_PHRASE}
+ Абстрактные слова: {WateryPhrase.ABSTRACT_WORDS}
+ ''' + result_str
+
+ return answer(False, result_str)
+
+ def get_chapter_text(self, chapter):
+ chapter_text = ""
+ for child in chapter['child']:
+ chapter_text += " " + child['text']
+ return chapter_text
+
+ def get_words(self, text):
+ cleaned_text = re.sub(r'\s+', ' ', text)
+ return re.findall(r'\b\w+(?:-\w+)*\b', re.sub(r'[^а-яА-ЯёЁ\s-]', '', cleaned_text.lower()))
+
+ def watery_phrase_density(self, text, words):
+ watery_phrase_count = sum(text.lower().count(phrase) for phrase in self.watery_phrase)
+ watery_phrase_count += sum(word in self.watery_words for word in words)
+ if len(words) == 0:
+ return 0
+ return watery_phrase_count / len(words)
+
+ def long_sentences_density(self, text):
+ sentences = re.split(r'[.!?]', text)
+ long_sentences_count = sum(len(sentence.split()) > self.long_sentence_word_limit for sentence in sentences)
+ total_sentences = len(sentences)
+ if total_sentences <= 3 :
+ return 0
+ return long_sentences_count / total_sentences
+
+ def meaningful_word_density(self, words):
+ meaningful_words = [
+ word for word in words
+ if morph.parse(word)[0].tag.POS in {'NOUN', 'VERB', 'ADJF', 'ADJS','INFN'}
+ ]
+ if len(words) == 0:
+ return 1
+ return len(meaningful_words) / len(words)
\ No newline at end of file
diff --git a/app/main/checks/report_checks/watery_phrase_settings.py b/app/main/checks/report_checks/watery_phrase_settings.py
new file mode 100644
index 00000000..fb9481e6
--- /dev/null
+++ b/app/main/checks/report_checks/watery_phrase_settings.py
@@ -0,0 +1,20 @@
+class WateryPhrase:
+ SERVICE_WORDS = [
+ "а", "бы", "был", "была", "были", "будет", "будешь", "буду", "вот", "всё", "вся",
+ "в", "для", "до", "его", "её", "ей", "если", "же", "за", "из", "и", "как", "когда", "кого",
+ "ли", "лишь", "многие", "на", "не", "ни", "о", "об", "или", "он", "она", "они", "это",
+ "к", "кто", "между", "над", "ну", "от", "по", "под", "при", "через", "с", "так", "та",
+ "те", "то", "ты", "уж", "чтобы", "ещё"
+ ]
+
+ INTRODUCTORY_PHRASE = [
+ "например", "так сказать", "кстати", "в общем", "по сути", "вроде", "между прочим", "короче",
+ "если честно", "во-первых", "во-вторых", "итак", "значит", "другими словами", "с другой стороны",
+ "по-моему", "по идее", "к слову", "собственно", "в принципе", "не удивлюсь", "естественно",
+ "по правде говоря", "безусловно", "пожалуй", "как правило", "почему-то", "честно говоря",
+ "вдобавок", "кроме того", "вдруг", "если так", "в общем-то", "скажем так"
+ ]
+
+ ABSTRACT_WORDS = [
+ "некоторый", "какой-то", "некто", "некоторые", "несколько", "некий", "такой-то"
+ ]