From 1e2928ed46fb4a7506f23dcb799c552137ddd6e5 Mon Sep 17 00:00:00 2001 From: Toropigeon <71664787+TheAnton1@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:45:23 +0300 Subject: [PATCH 01/19] create-preprocessor --- app/main/check_packs/pack_config.py | 3 +- app/main/checks/__init__.py | 3 +- app/main/checks/report_checks/__init__.py | 2 +- .../report_checks/compare_goal_and_content.py | 11 ++++++ playground/nlp/preprocessing.py | 37 +++++++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 app/main/checks/report_checks/compare_goal_and_content.py create mode 100644 playground/nlp/preprocessing.py diff --git a/app/main/check_packs/pack_config.py b/app/main/check_packs/pack_config.py index 0639689b..a4d8e0ac 100644 --- a/app/main/check_packs/pack_config.py +++ b/app/main/check_packs/pack_config.py @@ -39,7 +39,8 @@ ["header_check"], ["report_section_component"], ["main_text_check"], - ["spelling_check"] + ["spelling_check"], + ["compare_goal_and_content_check"] ] DEFAULT_TYPE = 'pres' diff --git a/app/main/checks/__init__.py b/app/main/checks/__init__.py index 8e643b62..c2c9fd4f 100644 --- a/app/main/checks/__init__.py +++ b/app/main/checks/__init__.py @@ -37,6 +37,7 @@ ReportChapters.id: ReportChapters, ReportSectionComponent.id: ReportSectionComponent, ReportMainTextCheck.id: ReportMainTextCheck, - SpellingCheck.id: SpellingCheck + SpellingCheck.id: SpellingCheck, + CompareGoalAndContentCheck.id: CompareGoalAndContentCheck, } } diff --git a/app/main/checks/report_checks/__init__.py b/app/main/checks/report_checks/__init__.py index 61a4f8a2..c6e50c48 100644 --- a/app/main/checks/report_checks/__init__.py +++ b/app/main/checks/report_checks/__init__.py @@ -21,4 +21,4 @@ from .sections_check import LRReportSectionCheck from .style_check import ReportStyleCheck from .spelling_check import SpellingCheck - +from .compare_goal_and_content import CompareGoalAndContentCheck diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py new file mode 100644 index 00000000..752dbfd0 --- /dev/null +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -0,0 +1,11 @@ +from ..base_check import BaseReportCriterion, answer + +class CompareGoalAndContentCheck(BaseReportCriterion): + description = "Проверка соответствия цели, задач и содержания" + id = 'compare_goal_and_content_check' + + def __init__(self, file_info): + super().__init__(file_info) + + def check(self): + return answer(True, "Проверка") \ No newline at end of file diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py new file mode 100644 index 00000000..37a6eaad --- /dev/null +++ b/playground/nlp/preprocessing.py @@ -0,0 +1,37 @@ +import nltk +from nltk import word_tokenize +from nltk.stem import SnowballStemmer +from nltk.util import ngrams +import string + + +class NLPPreprocessor: + def __init__(self, language='russian'): + nltk.download('punkt') + self.stemmer = SnowballStemmer(language) + + def preprocessing(self, text): + text = text.translate(str.maketrans('', '', string.punctuation)) + return text + + def stemming(self, text): + tokens = word_tokenize(text) + stemmed_words = [self.stemmer.stem(word) for word in tokens] + return stemmed_words + + def get_ngrams(self, tokens, n=2): + result = [] + for i in range(n): + n_grams = ngrams(tokens, i+1) + result.extend([' '.join(grams) for grams in n_grams]) + return result + + def tokenization(self, stemmed_words): + token_count = {} + for word in stemmed_words: + if word in token_count: + token_count[word] += 1 + else: + token_count[word] = 1 + return token_count + From b551e3cd0639950b72ea05966c02a9e46551442a Mon Sep 17 00:00:00 2001 From: Toropigeon <71664787+TheAnton1@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:42:13 +0300 Subject: [PATCH 02/19] remove-stopwords --- playground/nlp/preprocessing.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index 37a6eaad..a4e0e23d 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -1,21 +1,25 @@ import nltk from nltk import word_tokenize +from nltk.corpus import stopwords from nltk.stem import SnowballStemmer from nltk.util import ngrams import string -class NLPPreprocessor: +class NLPProcessor: def __init__(self, language='russian'): nltk.download('punkt') + nltk.download('stopwords') + self.stop_words = set(stopwords.words(language)) self.stemmer = SnowballStemmer(language) def preprocessing(self, text): text = text.translate(str.maketrans('', '', string.punctuation)) - return text - - def stemming(self, text): tokens = word_tokenize(text) + tokens = [word for word in tokens if word.lower() not in self.stop_words] + return tokens + + def stemming(self, tokens): stemmed_words = [self.stemmer.stem(word) for word in tokens] return stemmed_words @@ -26,12 +30,16 @@ def get_ngrams(self, tokens, n=2): result.extend([' '.join(grams) for grams in n_grams]) return result - def tokenization(self, stemmed_words): - token_count = {} - for word in stemmed_words: - if word in token_count: - token_count[word] += 1 - else: - token_count[word] = 1 - return token_count +# # Пример использования +# nlp_processor = NLPProcessor() +# +# text = "Пример текста для стемминга и токенизации. Текст содержит повторяющиеся слова для создания n-грамм." +# tokens = nlp_processor.preprocessing(text) +# stemmed_words = nlp_processor.stemming(tokens) +# n_grams = nlp_processor.get_ngrams(stemmed_words) +# +# print("Текст:", text) +# print("Стеммированные слова:", stemmed_words) +# print("N-граммы:", n_grams) +# print("Матрица n-грамм:") From 652927503c8beb5144f6060ce867088df1129ce5 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 15 Mar 2024 13:08:31 +0300 Subject: [PATCH 03/19] cosine-similarity-added --- .../report_checks/compare_goal_and_content.py | 21 +++++- playground/nlp/preprocessing.py | 69 ++++++++++++++----- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index 752dbfd0..0340af51 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -1,4 +1,7 @@ -from ..base_check import BaseReportCriterion, answer +import re + +from ..base_check import BaseReportCriterion, answer, morph + class CompareGoalAndContentCheck(BaseReportCriterion): description = "Проверка соответствия цели, задач и содержания" @@ -6,6 +9,20 @@ class CompareGoalAndContentCheck(BaseReportCriterion): def __init__(self, file_info): super().__init__(file_info) + self.headers = [] + self.goal = "" + self.problems = [] + self.main_text = [] + + def late_init(self): + self.headers = self.file.make_headers(self.file_type['report_type']) def check(self): - return answer(True, "Проверка") \ No newline at end of file + self.late_init() + if self.file.page_counter() < 4: + return answer(False, "В отчете недостаточно страниц. Нечего проверять.") + result = [] + for header in self.headers: + result.append(header["text"][0:10]) + + return answer(True, " ".join(result)) \ No newline at end of file diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index a4e0e23d..ec2931d6 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -1,4 +1,7 @@ +from collections import Counter, defaultdict + import nltk +import numpy as np from nltk import word_tokenize from nltk.corpus import stopwords from nltk.stem import SnowballStemmer @@ -17,11 +20,7 @@ def preprocessing(self, text): text = text.translate(str.maketrans('', '', string.punctuation)) tokens = word_tokenize(text) tokens = [word for word in tokens if word.lower() not in self.stop_words] - return tokens - - def stemming(self, tokens): - stemmed_words = [self.stemmer.stem(word) for word in tokens] - return stemmed_words + return [self.stemmer.stem(token) for token in tokens] def get_ngrams(self, tokens, n=2): result = [] @@ -30,16 +29,52 @@ def get_ngrams(self, tokens, n=2): result.extend([' '.join(grams) for grams in n_grams]) return result + def get_bag_of_n_gramms(self, corpus): + new_corpus = [] + for item in corpus: + for n_gramm in item: + new_corpus.append(n_gramm) + index_word = {} + i = 0 + for word in new_corpus: + if word in index_word.keys(): + continue + index_word[word] = i + i += 1 + return index_word + + def get_vector_by_BOW(self, bag_of_ngramms, doc): + count_dict = defaultdict(int) + vec = np.zeros(len(bag_of_ngramms)) + for item in doc: + count_dict[item] += 1 + for key, item in count_dict.items(): + vec[bag_of_ngramms[key]] = item + return vec + + def cosine_similarity(self, vector1, vector2): + text1_norm = float(len(vector1)) ** 0.5 + text2_norm = float(len(vector2)) ** 0.5 + dot_product = sum(gram_a * gram_b for gram_a, gram_b in zip(vector1, vector2)) + cosine_sim = dot_product / (text1_norm * text2_norm) + + return cosine_sim + + +# Пример использования +nlp_processor = NLPProcessor() + +text1 = "Реализация алгоритма поиска и отслеживания точек интереса для измерения пульса по видео" +text2 = "Проанализировать существующие решения для определения видимых областей лица человека и для определения перекрытий объектов, На основе анализа существующих решений сформулировать требования к реализации алгоритма, Реализовать алгоритм поиска и отслеживания точек интереса, Исследовать свойства реализованного алгоритма" + +tokens1 = nlp_processor.preprocessing(text1) +n_grams1 = nlp_processor.get_ngrams(tokens1) + +tokens2 = nlp_processor.preprocessing(text2) +n_grams2 = nlp_processor.get_ngrams(tokens2) -# # Пример использования -# nlp_processor = NLPProcessor() -# -# text = "Пример текста для стемминга и токенизации. Текст содержит повторяющиеся слова для создания n-грамм." -# tokens = nlp_processor.preprocessing(text) -# stemmed_words = nlp_processor.stemming(tokens) -# n_grams = nlp_processor.get_ngrams(stemmed_words) -# -# print("Текст:", text) -# print("Стеммированные слова:", stemmed_words) -# print("N-граммы:", n_grams) -# print("Матрица n-грамм:") +docs = [n_grams1, n_grams2] +bag_of_ngrams = nlp_processor.get_bag_of_n_gramms(docs) +vector1 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams1) +vector2 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams2) +print(f"Согласно косиносному сходству, веторы похожи на {nlp_processor.cosine_similarity(vector1, vector2)}") \ No newline at end of file From 7ff30c52514f3a9c500d1787c81dd346377e1a2b Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 15 Mar 2024 14:01:57 +0300 Subject: [PATCH 04/19] cosine-similarity-added --- playground/nlp/preprocessing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index ec2931d6..434e5ce3 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -77,4 +77,6 @@ def cosine_similarity(self, vector1, vector2): bag_of_ngrams = nlp_processor.get_bag_of_n_gramms(docs) vector1 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams1) vector2 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams2) -print(f"Согласно косиносному сходству, веторы похожи на {nlp_processor.cosine_similarity(vector1, vector2)}") \ No newline at end of file +print(f"Согласно косиносному сходству, векторы похожи на {nlp_processor.cosine_similarity(vector1, vector2)}") + +# Согласно косиносному сходству, векторы похожи на 0.23636363636363636 (для данного примера) \ No newline at end of file From 7a62a3f93017f1ed7b066f1c22358fa2ce86cf9c Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 29 Mar 2024 13:41:00 +0300 Subject: [PATCH 05/19] tf-idf-added --- playground/nlp/goal_1 | 1 + playground/nlp/goal_2 | 1 + playground/nlp/preprocessing.py | 103 ++++++++++++++++++++++---------- playground/nlp/text_1 | 41 +++++++++++++ playground/nlp/text_2 | 26 ++++++++ 5 files changed, 140 insertions(+), 32 deletions(-) create mode 100644 playground/nlp/goal_1 create mode 100644 playground/nlp/goal_2 create mode 100644 playground/nlp/text_1 create mode 100644 playground/nlp/text_2 diff --git a/playground/nlp/goal_1 b/playground/nlp/goal_1 new file mode 100644 index 00000000..f4e62fcc --- /dev/null +++ b/playground/nlp/goal_1 @@ -0,0 +1 @@ +Изучение иерархических списков и способов работы с ними. diff --git a/playground/nlp/goal_2 b/playground/nlp/goal_2 new file mode 100644 index 00000000..c70d7e99 --- /dev/null +++ b/playground/nlp/goal_2 @@ -0,0 +1 @@ +изучение феномена последовательного цветового контраста (возникновения последовательных образов) – изменения процесса цветоощущения после предварительной адаптации к излучению определенного спектрального состава diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index 434e5ce3..6895a547 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -1,4 +1,4 @@ -from collections import Counter, defaultdict +from collections import defaultdict import nltk import numpy as np @@ -22,10 +22,10 @@ def preprocessing(self, text): tokens = [word for word in tokens if word.lower() not in self.stop_words] return [self.stemmer.stem(token) for token in tokens] - def get_ngrams(self, tokens, n=2): + def get_ngrams(self, tokens, n=1): result = [] for i in range(n): - n_grams = ngrams(tokens, i+1) + n_grams = ngrams(tokens, i + 1) result.extend([' '.join(grams) for grams in n_grams]) return result @@ -43,40 +43,79 @@ def get_bag_of_n_gramms(self, corpus): i += 1 return index_word - def get_vector_by_BOW(self, bag_of_ngramms, doc): + def get_vector_by_BOW(self, bag_of_ngramms, doc, docs): + def tf(word, doc): + return doc.count(word) / len(doc) + + def idf(word, docs): + word_in_docs = 0 + for item in docs: + if word in item: + word_in_docs += 1 + return np.log10((len(docs) + 1) / (word_in_docs + 1)) + + def tf_idf(word, doc, docs): + return tf(word, doc) * idf(word, docs) + count_dict = defaultdict(int) vec = np.zeros(len(bag_of_ngramms)) - for item in doc: - count_dict[item] += 1 + for word in doc: + count_dict[word] += tf_idf(word, doc, docs) + for key, item in count_dict.items(): vec[bag_of_ngramms[key]] = item return vec def cosine_similarity(self, vector1, vector2): - text1_norm = float(len(vector1)) ** 0.5 - text2_norm = float(len(vector2)) ** 0.5 - dot_product = sum(gram_a * gram_b for gram_a, gram_b in zip(vector1, vector2)) - cosine_sim = dot_product / (text1_norm * text2_norm) - - return cosine_sim - - -# Пример использования -nlp_processor = NLPProcessor() - -text1 = "Реализация алгоритма поиска и отслеживания точек интереса для измерения пульса по видео" -text2 = "Проанализировать существующие решения для определения видимых областей лица человека и для определения перекрытий объектов, На основе анализа существующих решений сформулировать требования к реализации алгоритма, Реализовать алгоритм поиска и отслеживания точек интереса, Исследовать свойства реализованного алгоритма" - -tokens1 = nlp_processor.preprocessing(text1) -n_grams1 = nlp_processor.get_ngrams(tokens1) - -tokens2 = nlp_processor.preprocessing(text2) -n_grams2 = nlp_processor.get_ngrams(tokens2) - -docs = [n_grams1, n_grams2] -bag_of_ngrams = nlp_processor.get_bag_of_n_gramms(docs) -vector1 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams1) -vector2 = nlp_processor.get_vector_by_BOW(bag_of_ngrams, n_grams2) -print(f"Согласно косиносному сходству, векторы похожи на {nlp_processor.cosine_similarity(vector1, vector2)}") -# Согласно косиносному сходству, векторы похожи на 0.23636363636363636 (для данного примера) \ No newline at end of file + norm1 = np.linalg.norm(vector1) + norm2 = np.linalg.norm(vector2) + dot_product = np.dot(vector1, vector2) + cosine_sim = dot_product / (norm1 * norm2) + return cosine_sim + + def example(self, goal, text): + corpus = [] + goal_n_grams = [] + for paragraph in goal: + if paragraph: + tokens1 = self.preprocessing(paragraph) + n_grams1 = self.get_ngrams(tokens1) + goal_n_grams.append(n_grams1) + + text_n_grams = [] + for paragraph in text: + if paragraph: + tokens2 = self.preprocessing(paragraph) + n_grams2 = self.get_ngrams(tokens2) + text_n_grams.append(n_grams2) + + corpus.extend(goal_n_grams) + corpus.extend(text_n_grams) + bag_of_n_grams = self.get_bag_of_n_gramms(corpus) + goal_vector = self.get_vector_by_BOW(bag_of_n_grams, goal_n_grams[0], corpus) + text_vectors = [] + for paragraph in text_n_grams: + text_vectors.append(self.get_vector_by_BOW(bag_of_n_grams, paragraph, corpus)) + results = [] + for i, text_vector in enumerate(text_vectors): + result = self.cosine_similarity(goal_vector, text_vector) + results.append(result) + for index, value in enumerate(results): + print(f"Абзац {index + 1} схож с целью на {results[index]}") + print(f"В среднем: {sum(results) / len(results)}") + + print('\n') + + +if __name__ == '__main__': + nlp_processor = NLPProcessor() + + text1 = open("text_1").read().split('\n') + text2 = open("text_2").read().split('\n') + goal1 = open("goal_1").read().split('\n') + goal2 = open("goal_2").read().split('\n') + nlp_processor.example(goal1, text1) + nlp_processor.example(goal1, text2) + nlp_processor.example(goal2, text1) + nlp_processor.example(goal2, text2) diff --git a/playground/nlp/text_1 b/playground/nlp/text_1 new file mode 100644 index 00000000..20943b9a --- /dev/null +++ b/playground/nlp/text_1 @@ -0,0 +1,41 @@ +В файле hierarchical_list.h описаны структуры s_expr и two_ptr, которые вместе описывают структуру элементов списка: первая из них описывает структуру узла списка (union), вторая же хранит пару указателей на начало и конец данного списка. Также с помощью директивы typedef был задан синоним lisp для (s_expr *). + +Затем были описаны функции работы со списком: + + функция удаления списка destroy (lisp s); + + функция head( const lisp s), возвращающая указатель на начало списка; + + функция tail( const lisp s), возвращающая указатель на конец списка; + + функция isNull(const lisp s), проверяющая, является ли список пустым; + + функция cons(const lisp h, const lisp t), создающая точечную пару элементов (новый список из «головы» и «хвоста»). + +Также были описаны функции работы с элементами списка: + + функция make_atom(const char * x), создающая элемент списка, хранящий переданную в функцию строку; + + функция isAtom(const lisp s), проверяющая, является ли элемент списка обычным узлом, а не началом другого списка. + + функция concat(const lisp y, const lisp z), объединяющая два списка; + + функции equal_lisp(const lisp x,const lisp y) и equal_seq(const lisp x,const lisp y) сравнивающие 2 списка; + + функции read_seq( lisp & y, istringstream & streamIn ), read_s_expr(char * prev, lisp& y, istringstream & streamIn), read_lisp(lisp& y, istringstream & streamIn) для считывания списка в скобочной записи с входного потока. + +Далее были описаны слоты – функции, вызываемые при нажатии определённых пунктов меню: + + слот on_actionInfo_triggered() – вызывается при выборе в меню пункта «Info» и вызывает справку по программе; + + слот on_actionAbout_Authour_triggered() – вызывается при выборе в меню пункта «Author» и вызвает справку об авторе; + + слоты on_file_button_1_clicked и on_file_button_2_clicked – вызываются при нажатии на кнопку «файл» и загружают данные из заданного файла в текстовые поля; + + слот on_equationButton_clicked – вызывается при нажатии на кнопку «Сравнить» и выполняет считывание списков из текстовых полей и производит их сравнение с последующим выводом. + +Все вышеописанные функции являются методами или слотами базового класса главного окна QMainWindow и имеют свои прототипы в файле mainwindow.h. + +Далее был описан класс HelpBrowser в файле helpbrowser.h, в котором содержится лишь описание конструктора, который в переданном по указателю виджете располагает кнопки для переключения между html страницами, и «соединяет» соответствующие сигналы со слотами. + +Далее были созданы 5 html файлов, описывающих страницы для виджета HelpBrowser. diff --git a/playground/nlp/text_2 b/playground/nlp/text_2 new file mode 100644 index 00000000..621f1f70 --- /dev/null +++ b/playground/nlp/text_2 @@ -0,0 +1,26 @@ +В ходе опыта было установлено, что кажущаяся величина образа пропорциональна расстоянию до поверхности наблюдения – на листе бумаги изображение казалось меньше, чем на стене, расположенной дальше от наблюдателя. + +Последовательный образ неподвижен относительно сетчатки. Угловая величина такого образа постоянна, поэтому его кажущаяся величина соответствует проекции этого угла на видимую поверхность. +Одновременный цветовой контраст + + Определить закон изменения цветовосприятия при одновременном цветовом контрасте ахроматических цветов + +Характеристики цвета эталона на черном фоне: 128, 128, 128 (серый) + +Характеристики цвета сравнения на белом фоне: 135,133,133 + +При рассмотрении ахроматических цветов наблюдается незначительный одновременный цветовой контраст. Светлые цвета выглядят светлее на темном фоне (на черном фоне эталона) и темнее на более светлом (на белом фоне сравнения), однако параметры цветов достаточно близки. + + Определить закон изменения цветовосприятия при одновременном цветовом контрасте хроматических цветов. + +Цвет стимула эталона: желтый (255, 0, 255) + +Цвет фона сравнения: белый + +При красном цвете фона эталона цвет объекта сравнения (255,0,241) можно заметить, что концентрация зеленого цвета уменьшилась. + +При синем цвете фона цвет объекта сравнения (255, 37, 232) наблюдаем увеличение концентрации синего цвета и уменьшение зеленого. + +При зеленом цвете фона параметры цвета сравнения (255, 0, 236) снова наблюдаем снижение концентрации зеленого цвета. Если цвет находится в окружении хроматических цветов, то к нему как бы примешивается (по закону оптического смешения) цвет, близкий к дополнительному цвету окружения. + +Вывод: в ходе работы было изучено явление последовательного цветового контраста - после исчезновения стимула наблюдались дополнительные цвета. Проведена проверка закона изменения времени ощущения послесвечения - для всех цветов время послесвечения увеличивалось с увеличением времени предъявления стимула, дольше всего изображение сохранялось для красного цвета (23,72 с). Была проведена проверка закона Эммерта - неподвижности последовательного образа относительно сетчатки. При рассмотрении ахроматических цветов наблюдается незначительный одновременный цветовой контраст. Светлые цвета выглядят светлее на темном фоне (на черном фоне эталона) и темнее на более светлом (на белом фоне сравнения). Если цвет находится в окружении хроматических цветов, то к нему как бы примешивается (по закону оптического смешения) цвет, близкий к дополнительному цвету окружения. From baff2eeed110aa310939d9505a1094f02de030c0 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 29 Mar 2024 14:00:13 +0300 Subject: [PATCH 06/19] data-fix --- playground/nlp/goal_1 | 2 +- playground/nlp/preprocessing.py | 5 +++- playground/nlp/text_1 | 51 +++++++-------------------------- 3 files changed, 15 insertions(+), 43 deletions(-) diff --git a/playground/nlp/goal_1 b/playground/nlp/goal_1 index f4e62fcc..e2ce731b 100644 --- a/playground/nlp/goal_1 +++ b/playground/nlp/goal_1 @@ -1 +1 @@ -Изучение иерархических списков и способов работы с ними. +Создать программное средство, обеспечивающее извлечение наборов пар «имя атрибута — значение атрибута» из входной таблицы в одном из указанных форматов, с возможностью добавления новых форматов diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index 6895a547..7eeedd72 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -52,7 +52,7 @@ def idf(word, docs): for item in docs: if word in item: word_in_docs += 1 - return np.log10((len(docs) + 1) / (word_in_docs + 1)) + return np.log10(len(docs) / (word_in_docs + 1)) def tf_idf(word, doc, docs): return tf(word, doc) * idf(word, docs) @@ -101,7 +101,10 @@ def example(self, goal, text): for i, text_vector in enumerate(text_vectors): result = self.cosine_similarity(goal_vector, text_vector) results.append(result) + max_result = max(results) for index, value in enumerate(results): + if max_result != 0.0: + results[index] = value / max_result print(f"Абзац {index + 1} схож с целью на {results[index]}") print(f"В среднем: {sum(results) / len(results)}") diff --git a/playground/nlp/text_1 b/playground/nlp/text_1 index 20943b9a..7552ef72 100644 --- a/playground/nlp/text_1 +++ b/playground/nlp/text_1 @@ -1,41 +1,10 @@ -В файле hierarchical_list.h описаны структуры s_expr и two_ptr, которые вместе описывают структуру элементов списка: первая из них описывает структуру узла списка (union), вторая же хранит пару указателей на начало и конец данного списка. Также с помощью директивы typedef был задан синоним lisp для (s_expr *). - -Затем были описаны функции работы со списком: - - функция удаления списка destroy (lisp s); - - функция head( const lisp s), возвращающая указатель на начало списка; - - функция tail( const lisp s), возвращающая указатель на конец списка; - - функция isNull(const lisp s), проверяющая, является ли список пустым; - - функция cons(const lisp h, const lisp t), создающая точечную пару элементов (новый список из «головы» и «хвоста»). - -Также были описаны функции работы с элементами списка: - - функция make_atom(const char * x), создающая элемент списка, хранящий переданную в функцию строку; - - функция isAtom(const lisp s), проверяющая, является ли элемент списка обычным узлом, а не началом другого списка. - - функция concat(const lisp y, const lisp z), объединяющая два списка; - - функции equal_lisp(const lisp x,const lisp y) и equal_seq(const lisp x,const lisp y) сравнивающие 2 списка; - - функции read_seq( lisp & y, istringstream & streamIn ), read_s_expr(char * prev, lisp& y, istringstream & streamIn), read_lisp(lisp& y, istringstream & streamIn) для считывания списка в скобочной записи с входного потока. - -Далее были описаны слоты – функции, вызываемые при нажатии определённых пунктов меню: - - слот on_actionInfo_triggered() – вызывается при выборе в меню пункта «Info» и вызывает справку по программе; - - слот on_actionAbout_Authour_triggered() – вызывается при выборе в меню пункта «Author» и вызвает справку об авторе; - - слоты on_file_button_1_clicked и on_file_button_2_clicked – вызываются при нажатии на кнопку «файл» и загружают данные из заданного файла в текстовые поля; - - слот on_equationButton_clicked – вызывается при нажатии на кнопку «Сравнить» и выполняет считывание списков из текстовых полей и производит их сравнение с последующим выводом. - -Все вышеописанные функции являются методами или слотами базового класса главного окна QMainWindow и имеют свои прототипы в файле mainwindow.h. - -Далее был описан класс HelpBrowser в файле helpbrowser.h, в котором содержится лишь описание конструктора, который в переданном по указателю виджете располагает кнопки для переключения между html страницами, и «соединяет» соответствующие сигналы со слотами. - -Далее были созданы 5 html файлов, описывающих страницы для виджета HelpBrowser. +В качестве определения будет использоваться следующее: объектом в таблице называется сущность, значения атрибутов которой заданы в ячейках таблица, а имена атрибутов могут содержаться в заголовке таблицы. +В дальнейшей работе будет предполагаться, что любая таблица содержит объекты либо в строках (горизонтально ориентированная, или горизонтальная таблица), либо в столбцах (вертикально ориентированная, или вертикальная). +В данной задаче наиболее естественным способом задания входных данных является признаковое описание объекта, то есть задание набора характеристик, называемых признаками. +У всех признаков, характеризующих таблицу, можно выделить общую природу. Рассматриваются две ориентации одной и той же таблицы — горизонтальная и вертикальная, — над ними вычисляется одна и та же функция, после чего находится разница между двумя полученными значениями. +Мотивация использования данного признака следующая: атрибуты чаще, чем имена объектов, выстраиваются в иерархии, поэтому положительная разница в высоте заголовка свидетельствует о более высокой вероятности того, что горизонтальная ориентация таблицы является корректной. И наоборот, отрицательная разница свидетельствует о вертикальной ориентации. +Признак «Разница в максимальной похожести ячеек» основан на понятии похожести ячеек, которое, в свою очередь, основано на понятии строкового расстояния. Строковое расстояние — это величина, показывающая расстояние (или близость) между двумя текстовыми строками и предназначенная для сравнения или частичного сопоставления строк. +Чтобы получить значение признака в случае горизонтальной ориентации, на первом этапе вычисляется средняя похожесть ячеек для каждой строки, кроме первой (поскольку она содержит заголовок), то есть вычисляется похожесть каждых двух ячеек и полученное значение нормируется на общее число пар. После этого из полученных чисел выбирается максимальное — оно и будет значением признака для горизонтальной ориентации таблицы. +отивация использования данного признака следующая: значения одного и того же атрибута, как правило, представляют собой похожие текстовые строки, поскольку формат записи для разных значений одного атрибута один и тот же и зачастую у нескольких объектов значения атрибута в точности совпадают. Поэтому если в строках 20 похожесть ячеек меньше, чем в столбцах, то с большей вероятностью строка представляет собой набор значений разных атрибутов, а столбец — набор значений одного атрибута +Следовательно, положительная разница в максимальной похожести ячеек свидетельствует о более высокой вероятности того, что вертикальная ориентация таблицы является корректной. И наоборот, отрицательная разница свидетельствует о горизонтальной ориентации. +Признак «Разница в средней похожести ячеек» очень похож на предыдущий. Единственное отличие заключается в том, что после подсчета средней похожести для каждой строки не выбирается максимальное число, как это делается в признаке «Разница в максимальной согласованности ячеек», а подсчитывается среднее арифметическое. From 852b108cc9bdb79799e2c40f7a29a01cd478c9db Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 29 Mar 2024 14:04:26 +0300 Subject: [PATCH 07/19] data-fix --- playground/nlp/preprocessing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/nlp/preprocessing.py b/playground/nlp/preprocessing.py index 7eeedd72..40d1378f 100644 --- a/playground/nlp/preprocessing.py +++ b/playground/nlp/preprocessing.py @@ -22,7 +22,7 @@ def preprocessing(self, text): tokens = [word for word in tokens if word.lower() not in self.stop_words] return [self.stemmer.stem(token) for token in tokens] - def get_ngrams(self, tokens, n=1): + def get_ngrams(self, tokens, n=2): result = [] for i in range(n): n_grams = ngrams(tokens, i + 1) @@ -103,7 +103,7 @@ def example(self, goal, text): results.append(result) max_result = max(results) for index, value in enumerate(results): - if max_result != 0.0: + if results.count(0) / len(results) <= 0.6 and max_result != 0.0: results[index] = value / max_result print(f"Абзац {index + 1} схож с целью на {results[index]}") print(f"В среднем: {sum(results) / len(results)}") From 7393d6adf49ddee9fe4a31a144c69d14ae90e6fc Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 29 Mar 2024 14:13:15 +0300 Subject: [PATCH 08/19] readme-added --- playground/nlp/README.md | 22 ++++++++++++++++++++++ playground/nlp/img.png | Bin 0 -> 36599 bytes playground/nlp/img_1.png | Bin 0 -> 8542 bytes playground/nlp/img_2.png | Bin 0 -> 26466 bytes playground/nlp/img_3.png | Bin 0 -> 41928 bytes 5 files changed, 22 insertions(+) create mode 100644 playground/nlp/README.md create mode 100644 playground/nlp/img.png create mode 100644 playground/nlp/img_1.png create mode 100644 playground/nlp/img_2.png create mode 100644 playground/nlp/img_3.png diff --git a/playground/nlp/README.md b/playground/nlp/README.md new file mode 100644 index 00000000..f39b1831 --- /dev/null +++ b/playground/nlp/README.md @@ -0,0 +1,22 @@ +Были проведены эксперементы с текстами разной направленности, взятых из научных работ из открытых источников. В качестве +примера были взяты работы по физике и машинному обучению. Для удобства будем называть их работа №1 и работа №2. +В результате эксперимента с программой были получены следующие результаты: + +Для темы работы №1 и содержания работы № 1: + +![img.png](img.png) + +Для темы работы №1 и содержания работы № 2: + +![img_1.png](img_1.png) + +Для темы работы №2 и содержания работы № 1: + +![img_2.png](img_2.png) + +Для темы работы №2 и содержания работы № 2: + +![img_3.png](img_3.png) + +Можно заметить, что для содержания, которое соответствует теме, совпадение на 2-3 порядка больше, чем для +несоответстующих текстов. \ No newline at end of file diff --git a/playground/nlp/img.png b/playground/nlp/img.png new file mode 100644 index 0000000000000000000000000000000000000000..6b2173f40118a5ac85fdf5718d4040a3ef5b73b1 GIT binary patch literal 36599 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 literal 0 HcmV?d00001 diff --git a/playground/nlp/img_2.png b/playground/nlp/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..902a6db4c9f011199e145f27a05fca97140cbef2 GIT binary patch literal 26466 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 literal 0 HcmV?d00001 diff --git a/playground/nlp/img_3.png b/playground/nlp/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..224491eb4a4492204c2c9cf913844efd29834e67 GIT binary patch literal 41928 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 Date: Thu, 11 Apr 2024 19:40:09 +0300 Subject: [PATCH 09/19] remove-readme --- .../report_checks/compare_goal_and_content.py | 31 +++++++++++++----- playground/nlp/README.md | 22 ------------- playground/nlp/img.png | Bin 36599 -> 0 bytes playground/nlp/img_1.png | Bin 8542 -> 0 bytes playground/nlp/img_2.png | Bin 26466 -> 0 bytes playground/nlp/img_3.png | Bin 41928 -> 0 bytes 6 files changed, 22 insertions(+), 31 deletions(-) delete mode 100644 playground/nlp/README.md delete mode 100644 playground/nlp/img.png delete mode 100644 playground/nlp/img_1.png delete mode 100644 playground/nlp/img_2.png delete mode 100644 playground/nlp/img_3.png diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index 0340af51..6d6a783d 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -1,6 +1,4 @@ -import re - -from ..base_check import BaseReportCriterion, answer, morph +from ..base_check import BaseReportCriterion, answer class CompareGoalAndContentCheck(BaseReportCriterion): @@ -11,7 +9,7 @@ def __init__(self, file_info): super().__init__(file_info) self.headers = [] self.goal = "" - self.problems = [] + self.tasks = [] self.main_text = [] def late_init(self): @@ -21,8 +19,23 @@ def check(self): self.late_init() if self.file.page_counter() < 4: return answer(False, "В отчете недостаточно страниц. Нечего проверять.") - result = [] - for header in self.headers: - result.append(header["text"][0:10]) - - return answer(True, " ".join(result)) \ No newline at end of file + result = "" + for text_on_page in self.file.pdf_file.get_text_on_page().values(): + if text_on_page.split()[0].lower() != "введение": + continue + goal_index = text_on_page.find("Цель") + tasks_index = text_on_page.find("Задачи") + if goal_index != -1 and tasks_index != -1: + goal_start = goal_index + len("Цель") + 1 + goal_end = tasks_index + self.goal = text_on_page[goal_start:goal_end].strip() + tasks_start = tasks_index + len("Задачи") + 1 + tasks_end = text_on_page.find(".", tasks_start) + self.tasks = text_on_page[tasks_start:tasks_end].split('\n') + result = f"tasks equal {text_on_page[tasks_start:tasks_end]} {tasks_start} {tasks_end}" + elif goal_index == -1: + return answer(False, "В введении не написана цель работы") + elif tasks_index == -1: + return answer(False, "В введении не написаны задачи") + result = f"Цель: {self.goal}, задачи: {self.tasks}" + return answer(True, result) \ No newline at end of file diff --git a/playground/nlp/README.md b/playground/nlp/README.md deleted file mode 100644 index f39b1831..00000000 --- a/playground/nlp/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Были проведены эксперементы с текстами разной направленности, взятых из научных работ из открытых источников. В качестве -примера были взяты работы по физике и машинному обучению. Для удобства будем называть их работа №1 и работа №2. -В результате эксперимента с программой были получены следующие результаты: - -Для темы работы №1 и содержания работы № 1: - -![img.png](img.png) - -Для темы работы №1 и содержания работы № 2: - -![img_1.png](img_1.png) - -Для темы работы №2 и содержания работы № 1: - -![img_2.png](img_2.png) - -Для темы работы №2 и содержания работы № 2: - -![img_3.png](img_3.png) - -Можно заметить, что для содержания, которое соответствует теме, совпадение на 2-3 порядка больше, чем для -несоответстующих текстов. \ No newline at end of file diff --git a/playground/nlp/img.png b/playground/nlp/img.png deleted file mode 100644 index 6b2173f40118a5ac85fdf5718d4040a3ef5b73b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36599 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 diff --git a/playground/nlp/img_2.png b/playground/nlp/img_2.png deleted file mode 100644 index 902a6db4c9f011199e145f27a05fca97140cbef2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26466 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 diff --git a/playground/nlp/img_3.png b/playground/nlp/img_3.png deleted file mode 100644 index 224491eb4a4492204c2c9cf913844efd29834e67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41928 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 Date: Fri, 12 Apr 2024 01:21:47 +0300 Subject: [PATCH 10/19] goal-and-content-comparison --- .../report_checks/compare_goal_and_content.py | 46 +++++++++++++++++-- .../nlp/text_similarity.py | 43 ++++++++++------- 2 files changed, 67 insertions(+), 22 deletions(-) rename playground/nlp/preprocessing.py => app/nlp/text_similarity.py (75%) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index 6d6a783d..ba5aa1d6 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -1,5 +1,7 @@ from ..base_check import BaseReportCriterion, answer +import app.nlp.text_similarity as ts + class CompareGoalAndContentCheck(BaseReportCriterion): description = "Проверка соответствия цели, задач и содержания" @@ -11,9 +13,24 @@ def __init__(self, file_info): self.goal = "" self.tasks = [] self.main_text = [] + self.chapters = {} + self.weights = {} + self.to_pass = 0 + self.to_ignore = [] def late_init(self): - self.headers = self.file.make_headers(self.file_type['report_type']) + self.headers = self.file.make_chapters(self.file_type['report_type']) + self.weights = { + "ВВЕДЕНИЕ": 1, + "1": 1, + "2": 2, + "3": 5, + "4": 3, + "5": 1, + "ЗАКЛЮЧЕНИЕ": 1 + } + self.to_pass = 0.2 + self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ"] def check(self): self.late_init() @@ -31,11 +48,30 @@ def check(self): self.goal = text_on_page[goal_start:goal_end].strip() tasks_start = tasks_index + len("Задачи") + 1 tasks_end = text_on_page.find(".", tasks_start) - self.tasks = text_on_page[tasks_start:tasks_end].split('\n') - result = f"tasks equal {text_on_page[tasks_start:tasks_end]} {tasks_start} {tasks_end}" + self.tasks = text_on_page[tasks_start:tasks_end].split(';') elif goal_index == -1: return answer(False, "В введении не написана цель работы") elif tasks_index == -1: return answer(False, "В введении не написаны задачи") - result = f"Цель: {self.goal}, задачи: {self.tasks}" - return answer(True, result) \ No newline at end of file + for header in self.headers: + if header["text"] in self.to_ignore: + continue + text = "" + for child in header["child"]: + text += child['text'] + self.chapters[header["text"]] = text + self.chapters = {k: v for k, v in self.chapters.items() if v and v.strip()} + NLPProcessor = ts.NLPProcessor() + calculate_result = NLPProcessor.calculate_cosine_similarity(self.goal, self.chapters) + for k, v in calculate_result.items(): + for chapter, weight in self.weights.items(): + if 0 <= k.find(chapter) < 1: + calculate_result[k] = v * weight + break + avg = sum(calculate_result.values()) / len(calculate_result.values()) + result += f"
Средняя схожесть текста с темой: {avg}
" + for key, value in calculate_result.items(): + result += f"
Для главы \"{key}\" значение схожести с целью составило {value}
" + if avg < self.to_pass: + return answer(False, f"Цель недостаточно раскрыта в содержании (нужно {self.to_pass}, набрано {avg})") + return answer(True, result) diff --git a/playground/nlp/preprocessing.py b/app/nlp/text_similarity.py similarity index 75% rename from playground/nlp/preprocessing.py rename to app/nlp/text_similarity.py index 40d1378f..38bf87fa 100644 --- a/playground/nlp/preprocessing.py +++ b/app/nlp/text_similarity.py @@ -67,10 +67,11 @@ def tf_idf(word, doc, docs): return vec def cosine_similarity(self, vector1, vector2): - norm1 = np.linalg.norm(vector1) norm2 = np.linalg.norm(vector2) dot_product = np.dot(vector1, vector2) + if norm1 == 0.0 or norm2 == 0.0: + return 0 cosine_sim = dot_product / (norm1 * norm2) return cosine_sim @@ -103,22 +104,30 @@ def example(self, goal, text): results.append(result) max_result = max(results) for index, value in enumerate(results): - if results.count(0) / len(results) <= 0.6 and max_result != 0.0: - results[index] = value / max_result + results[index] = value / max_result print(f"Абзац {index + 1} схож с целью на {results[index]}") print(f"В среднем: {sum(results) / len(results)}") - print('\n') - - -if __name__ == '__main__': - nlp_processor = NLPProcessor() - - text1 = open("text_1").read().split('\n') - text2 = open("text_2").read().split('\n') - goal1 = open("goal_1").read().split('\n') - goal2 = open("goal_2").read().split('\n') - nlp_processor.example(goal1, text1) - nlp_processor.example(goal1, text2) - nlp_processor.example(goal2, text1) - nlp_processor.example(goal2, text2) + def calculate_cosine_similarity(self, goal, texts: dict): + if not (goal or texts): + return + corpus = [] + text1_n_grams = self.get_ngrams(self.preprocessing(goal)) + text2_n_grams = {} + for chapter in texts.keys(): + text2_n_grams[chapter] = self.get_ngrams(self.preprocessing(texts[chapter])) + corpus.append(text1_n_grams) + corpus.extend(text2_n_grams.values()) + bag_of_n_grams = self.get_bag_of_n_gramms(corpus) + goal_vector = self.get_vector_by_BOW(bag_of_n_grams, text1_n_grams, corpus) + text_vectors = {} + for chapter, text in text2_n_grams.items(): + text_vectors[chapter] = self.get_vector_by_BOW(bag_of_n_grams, text, corpus) + result = {} + for chapter in text_vectors.keys(): + text_vector = text_vectors[chapter] + result[chapter] = self.cosine_similarity(goal_vector, text_vector) + max_result = max(result.values()) + for key, value in result.items(): + result[key] = value / max_result + return result \ No newline at end of file From e041555b80143216e093f4b20af7058c43739b89 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 12 Apr 2024 01:22:31 +0300 Subject: [PATCH 11/19] remove-test-files --- playground/nlp/goal_1 | 1 - playground/nlp/goal_2 | 1 - playground/nlp/text_1 | 10 ---------- playground/nlp/text_2 | 26 -------------------------- 4 files changed, 38 deletions(-) delete mode 100644 playground/nlp/goal_1 delete mode 100644 playground/nlp/goal_2 delete mode 100644 playground/nlp/text_1 delete mode 100644 playground/nlp/text_2 diff --git a/playground/nlp/goal_1 b/playground/nlp/goal_1 deleted file mode 100644 index e2ce731b..00000000 --- a/playground/nlp/goal_1 +++ /dev/null @@ -1 +0,0 @@ -Создать программное средство, обеспечивающее извлечение наборов пар «имя атрибута — значение атрибута» из входной таблицы в одном из указанных форматов, с возможностью добавления новых форматов diff --git a/playground/nlp/goal_2 b/playground/nlp/goal_2 deleted file mode 100644 index c70d7e99..00000000 --- a/playground/nlp/goal_2 +++ /dev/null @@ -1 +0,0 @@ -изучение феномена последовательного цветового контраста (возникновения последовательных образов) – изменения процесса цветоощущения после предварительной адаптации к излучению определенного спектрального состава diff --git a/playground/nlp/text_1 b/playground/nlp/text_1 deleted file mode 100644 index 7552ef72..00000000 --- a/playground/nlp/text_1 +++ /dev/null @@ -1,10 +0,0 @@ -В качестве определения будет использоваться следующее: объектом в таблице называется сущность, значения атрибутов которой заданы в ячейках таблица, а имена атрибутов могут содержаться в заголовке таблицы. -В дальнейшей работе будет предполагаться, что любая таблица содержит объекты либо в строках (горизонтально ориентированная, или горизонтальная таблица), либо в столбцах (вертикально ориентированная, или вертикальная). -В данной задаче наиболее естественным способом задания входных данных является признаковое описание объекта, то есть задание набора характеристик, называемых признаками. -У всех признаков, характеризующих таблицу, можно выделить общую природу. Рассматриваются две ориентации одной и той же таблицы — горизонтальная и вертикальная, — над ними вычисляется одна и та же функция, после чего находится разница между двумя полученными значениями. -Мотивация использования данного признака следующая: атрибуты чаще, чем имена объектов, выстраиваются в иерархии, поэтому положительная разница в высоте заголовка свидетельствует о более высокой вероятности того, что горизонтальная ориентация таблицы является корректной. И наоборот, отрицательная разница свидетельствует о вертикальной ориентации. -Признак «Разница в максимальной похожести ячеек» основан на понятии похожести ячеек, которое, в свою очередь, основано на понятии строкового расстояния. Строковое расстояние — это величина, показывающая расстояние (или близость) между двумя текстовыми строками и предназначенная для сравнения или частичного сопоставления строк. -Чтобы получить значение признака в случае горизонтальной ориентации, на первом этапе вычисляется средняя похожесть ячеек для каждой строки, кроме первой (поскольку она содержит заголовок), то есть вычисляется похожесть каждых двух ячеек и полученное значение нормируется на общее число пар. После этого из полученных чисел выбирается максимальное — оно и будет значением признака для горизонтальной ориентации таблицы. -отивация использования данного признака следующая: значения одного и того же атрибута, как правило, представляют собой похожие текстовые строки, поскольку формат записи для разных значений одного атрибута один и тот же и зачастую у нескольких объектов значения атрибута в точности совпадают. Поэтому если в строках 20 похожесть ячеек меньше, чем в столбцах, то с большей вероятностью строка представляет собой набор значений разных атрибутов, а столбец — набор значений одного атрибута -Следовательно, положительная разница в максимальной похожести ячеек свидетельствует о более высокой вероятности того, что вертикальная ориентация таблицы является корректной. И наоборот, отрицательная разница свидетельствует о горизонтальной ориентации. -Признак «Разница в средней похожести ячеек» очень похож на предыдущий. Единственное отличие заключается в том, что после подсчета средней похожести для каждой строки не выбирается максимальное число, как это делается в признаке «Разница в максимальной согласованности ячеек», а подсчитывается среднее арифметическое. diff --git a/playground/nlp/text_2 b/playground/nlp/text_2 deleted file mode 100644 index 621f1f70..00000000 --- a/playground/nlp/text_2 +++ /dev/null @@ -1,26 +0,0 @@ -В ходе опыта было установлено, что кажущаяся величина образа пропорциональна расстоянию до поверхности наблюдения – на листе бумаги изображение казалось меньше, чем на стене, расположенной дальше от наблюдателя. - -Последовательный образ неподвижен относительно сетчатки. Угловая величина такого образа постоянна, поэтому его кажущаяся величина соответствует проекции этого угла на видимую поверхность. -Одновременный цветовой контраст - - Определить закон изменения цветовосприятия при одновременном цветовом контрасте ахроматических цветов - -Характеристики цвета эталона на черном фоне: 128, 128, 128 (серый) - -Характеристики цвета сравнения на белом фоне: 135,133,133 - -При рассмотрении ахроматических цветов наблюдается незначительный одновременный цветовой контраст. Светлые цвета выглядят светлее на темном фоне (на черном фоне эталона) и темнее на более светлом (на белом фоне сравнения), однако параметры цветов достаточно близки. - - Определить закон изменения цветовосприятия при одновременном цветовом контрасте хроматических цветов. - -Цвет стимула эталона: желтый (255, 0, 255) - -Цвет фона сравнения: белый - -При красном цвете фона эталона цвет объекта сравнения (255,0,241) можно заметить, что концентрация зеленого цвета уменьшилась. - -При синем цвете фона цвет объекта сравнения (255, 37, 232) наблюдаем увеличение концентрации синего цвета и уменьшение зеленого. - -При зеленом цвете фона параметры цвета сравнения (255, 0, 236) снова наблюдаем снижение концентрации зеленого цвета. Если цвет находится в окружении хроматических цветов, то к нему как бы примешивается (по закону оптического смешения) цвет, близкий к дополнительному цвету окружения. - -Вывод: в ходе работы было изучено явление последовательного цветового контраста - после исчезновения стимула наблюдались дополнительные цвета. Проведена проверка закона изменения времени ощущения послесвечения - для всех цветов время послесвечения увеличивалось с увеличением времени предъявления стимула, дольше всего изображение сохранялось для красного цвета (23,72 с). Была проведена проверка закона Эммерта - неподвижности последовательного образа относительно сетчатки. При рассмотрении ахроматических цветов наблюдается незначительный одновременный цветовой контраст. Светлые цвета выглядят светлее на темном фоне (на черном фоне эталона) и темнее на более светлом (на белом фоне сравнения). Если цвет находится в окружении хроматических цветов, то к нему как бы примешивается (по закону оптического смешения) цвет, близкий к дополнительному цвету окружения. From bb3519fec95d68fccd3abafbe44af3af84bda176 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Fri, 12 Apr 2024 01:24:00 +0300 Subject: [PATCH 12/19] remove-example --- app/nlp/text_similarity.py | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/app/nlp/text_similarity.py b/app/nlp/text_similarity.py index 38bf87fa..dae34418 100644 --- a/app/nlp/text_similarity.py +++ b/app/nlp/text_similarity.py @@ -75,39 +75,6 @@ def cosine_similarity(self, vector1, vector2): cosine_sim = dot_product / (norm1 * norm2) return cosine_sim - def example(self, goal, text): - corpus = [] - goal_n_grams = [] - for paragraph in goal: - if paragraph: - tokens1 = self.preprocessing(paragraph) - n_grams1 = self.get_ngrams(tokens1) - goal_n_grams.append(n_grams1) - - text_n_grams = [] - for paragraph in text: - if paragraph: - tokens2 = self.preprocessing(paragraph) - n_grams2 = self.get_ngrams(tokens2) - text_n_grams.append(n_grams2) - - corpus.extend(goal_n_grams) - corpus.extend(text_n_grams) - bag_of_n_grams = self.get_bag_of_n_gramms(corpus) - goal_vector = self.get_vector_by_BOW(bag_of_n_grams, goal_n_grams[0], corpus) - text_vectors = [] - for paragraph in text_n_grams: - text_vectors.append(self.get_vector_by_BOW(bag_of_n_grams, paragraph, corpus)) - results = [] - for i, text_vector in enumerate(text_vectors): - result = self.cosine_similarity(goal_vector, text_vector) - results.append(result) - max_result = max(results) - for index, value in enumerate(results): - results[index] = value / max_result - print(f"Абзац {index + 1} схож с целью на {results[index]}") - print(f"В среднем: {sum(results) / len(results)}") - def calculate_cosine_similarity(self, goal, texts: dict): if not (goal or texts): return From 0c75e0edb8af09f9f9a6cb1d176c02daeff38418 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 14 Apr 2024 12:26:18 +0300 Subject: [PATCH 13/19] pretty-output --- .../report_checks/compare_goal_and_content.py | 23 ++++++++++++++----- app/nlp/text_similarity.py | 3 --- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index ba5aa1d6..a3f07a7b 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -4,7 +4,7 @@ class CompareGoalAndContentCheck(BaseReportCriterion): - description = "Проверка соответствия цели, задач и содержания" + description = "Проверка соответствия цели и содержания" id = 'compare_goal_and_content_check' def __init__(self, file_info): @@ -22,14 +22,14 @@ def late_init(self): self.headers = self.file.make_chapters(self.file_type['report_type']) self.weights = { "ВВЕДЕНИЕ": 1, - "1": 1, + "1": 2, "2": 2, "3": 5, - "4": 3, + "4": 2, "5": 1, "ЗАКЛЮЧЕНИЕ": 1 } - self.to_pass = 0.2 + self.to_pass = 0.15 self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ"] def check(self): @@ -63,15 +63,26 @@ def check(self): self.chapters = {k: v for k, v in self.chapters.items() if v and v.strip()} NLPProcessor = ts.NLPProcessor() calculate_result = NLPProcessor.calculate_cosine_similarity(self.goal, self.chapters) + max_result = max(calculate_result.values()) for k, v in calculate_result.items(): for chapter, weight in self.weights.items(): if 0 <= k.find(chapter) < 1: calculate_result[k] = v * weight break + calculate_result[k] = calculate_result[k] / max_result avg = sum(calculate_result.values()) / len(calculate_result.values()) result += f"
Средняя схожесть текста с темой: {avg}
" - for key, value in calculate_result.items(): - result += f"
Для главы \"{key}\" значение схожести с целью составило {value}
" + sorted_chapters = dict(sorted(calculate_result.items(), key=lambda item: item[1], reverse=True)) + result += f"
7 глав, наиболее раскрывающих тему:
" + for i, key in enumerate(sorted_chapters.keys()): + if i >= 7: + break + result += f"
Для главы \"{key}\" схожесть составила {sorted_chapters[key]}
" + result += f"
7 глав, наименее раскрывающих тему:
" + for i, key in enumerate(sorted_chapters.keys()): + if i < len(sorted_chapters) - 7: + continue + result += f"
Для главы \"{key}\" схожесть составила {sorted_chapters[key]}
" if avg < self.to_pass: return answer(False, f"Цель недостаточно раскрыта в содержании (нужно {self.to_pass}, набрано {avg})") return answer(True, result) diff --git a/app/nlp/text_similarity.py b/app/nlp/text_similarity.py index dae34418..2565bbf8 100644 --- a/app/nlp/text_similarity.py +++ b/app/nlp/text_similarity.py @@ -94,7 +94,4 @@ def calculate_cosine_similarity(self, goal, texts: dict): for chapter in text_vectors.keys(): text_vector = text_vectors[chapter] result[chapter] = self.cosine_similarity(goal_vector, text_vector) - max_result = max(result.values()) - for key, value in result.items(): - result[key] = value / max_result return result \ No newline at end of file From 4c947a301f250f34425c75642bf39f6c8aa1e6fd Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 14 Apr 2024 20:57:35 +0300 Subject: [PATCH 14/19] compare-tasks-and-content-check-added --- app/main/check_packs/pack_config.py | 3 +- app/main/checks/__init__.py | 1 + app/main/checks/report_checks/__init__.py | 1 + .../report_checks/compare_goal_and_content.py | 58 +++++++++---------- app/nlp/text_similarity.py | 2 +- 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/app/main/check_packs/pack_config.py b/app/main/check_packs/pack_config.py index a4d8e0ac..31a458cb 100644 --- a/app/main/check_packs/pack_config.py +++ b/app/main/check_packs/pack_config.py @@ -40,7 +40,8 @@ ["report_section_component"], ["main_text_check"], ["spelling_check"], - ["compare_goal_and_content_check"] + ["compare_goal_and_content_check"], + ["compare_tasks_and_content_check"] ] DEFAULT_TYPE = 'pres' diff --git a/app/main/checks/__init__.py b/app/main/checks/__init__.py index c2c9fd4f..7cf3d717 100644 --- a/app/main/checks/__init__.py +++ b/app/main/checks/__init__.py @@ -39,5 +39,6 @@ ReportMainTextCheck.id: ReportMainTextCheck, SpellingCheck.id: SpellingCheck, CompareGoalAndContentCheck.id: CompareGoalAndContentCheck, + CompareTasksAndContentCheck.id: CompareTasksAndContentCheck } } diff --git a/app/main/checks/report_checks/__init__.py b/app/main/checks/report_checks/__init__.py index c6e50c48..53d8359c 100644 --- a/app/main/checks/report_checks/__init__.py +++ b/app/main/checks/report_checks/__init__.py @@ -22,3 +22,4 @@ from .style_check import ReportStyleCheck from .spelling_check import SpellingCheck from .compare_goal_and_content import CompareGoalAndContentCheck +from .compare_tasks_and_content import CompareTasksAndContentCheck \ No newline at end of file diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index a3f07a7b..b955af30 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -11,8 +11,6 @@ def __init__(self, file_info): super().__init__(file_info) self.headers = [] self.goal = "" - self.tasks = [] - self.main_text = [] self.chapters = {} self.weights = {} self.to_pass = 0 @@ -29,32 +27,28 @@ def late_init(self): "5": 1, "ЗАКЛЮЧЕНИЕ": 1 } - self.to_pass = 0.15 - self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ"] + self.to_pass = 0.1 + self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ", "ПРИЛОЖЕНИЕ"] def check(self): self.late_init() if self.file.page_counter() < 4: return answer(False, "В отчете недостаточно страниц. Нечего проверять.") result = "" - for text_on_page in self.file.pdf_file.get_text_on_page().values(): - if text_on_page.split()[0].lower() != "введение": - continue - goal_index = text_on_page.find("Цель") - tasks_index = text_on_page.find("Задачи") - if goal_index != -1 and tasks_index != -1: - goal_start = goal_index + len("Цель") + 1 - goal_end = tasks_index - self.goal = text_on_page[goal_start:goal_end].strip() - tasks_start = tasks_index + len("Задачи") + 1 - tasks_end = text_on_page.find(".", tasks_start) - self.tasks = text_on_page[tasks_start:tasks_end].split(';') - elif goal_index == -1: - return answer(False, "В введении не написана цель работы") - elif tasks_index == -1: - return answer(False, "В введении не написаны задачи") + intro_text = "" + for header in self.headers: + if header["text"] == "ВВЕДЕНИЕ": + for child in header["child"]: + intro_text += child["text"] + goal_index = intro_text.find("Цель") + if goal_index > 0: + goal_start = goal_index + len("Цель") + 1 + goal_end = intro_text.find(".", goal_start) + self.goal = intro_text[goal_start:goal_end] + else: + return answer(False, "В введении не найдена цель работы") for header in self.headers: - if header["text"] in self.to_ignore: + if any(ignore_phrase in header["text"] for ignore_phrase in self.to_ignore): continue text = "" for child in header["child"]: @@ -66,23 +60,27 @@ def check(self): max_result = max(calculate_result.values()) for k, v in calculate_result.items(): for chapter, weight in self.weights.items(): - if 0 <= k.find(chapter) < 1: + if k.find(chapter) == 0: calculate_result[k] = v * weight break calculate_result[k] = calculate_result[k] / max_result - avg = sum(calculate_result.values()) / len(calculate_result.values()) - result += f"
Средняя схожесть текста с темой: {avg}
" + avg = round(sum(calculate_result.values()) / len(calculate_result.values()), 3) + if avg < self.to_pass: + return answer(False, + f"Цель недостаточно раскрыта в содержании (нужно {self.to_pass * 100}%, набрано {avg * 100}%)") + result += f"
Тема раскрыта на {avg * 100}%
" sorted_chapters = dict(sorted(calculate_result.items(), key=lambda item: item[1], reverse=True)) - result += f"
7 глав, наиболее раскрывающих тему:
" + result += f"
7 разделов, наиболее раскрывающих тему:
" for i, key in enumerate(sorted_chapters.keys()): if i >= 7: break - result += f"
Для главы \"{key}\" схожесть составила {sorted_chapters[key]}
" - result += f"
7 глав, наименее раскрывающих тему:
" + result += f"
\"{key}\", {round(self.__output(sorted_chapters[key], sum(sorted_chapters.values())), 3)}% текста раскрывают тему
" + result += f"
7 разделов, наименее раскрывающих тему:
" for i, key in enumerate(sorted_chapters.keys()): if i < len(sorted_chapters) - 7: continue - result += f"
Для главы \"{key}\" схожесть составила {sorted_chapters[key]}
" - if avg < self.to_pass: - return answer(False, f"Цель недостаточно раскрыта в содержании (нужно {self.to_pass}, набрано {avg})") + result += f"
\"{key}\", {self.__output(sorted_chapters[key], sum(sorted_chapters.values()))}% текста раскрывают тему
" return answer(True, result) + + def __output(self, value, summ): + return round(value / summ, 3) * 100 diff --git a/app/nlp/text_similarity.py b/app/nlp/text_similarity.py index 2565bbf8..ce8be923 100644 --- a/app/nlp/text_similarity.py +++ b/app/nlp/text_similarity.py @@ -73,7 +73,7 @@ def cosine_similarity(self, vector1, vector2): if norm1 == 0.0 or norm2 == 0.0: return 0 cosine_sim = dot_product / (norm1 * norm2) - return cosine_sim + return round(cosine_sim, 3) def calculate_cosine_similarity(self, goal, texts: dict): if not (goal or texts): From cb7bf3d6b3e8653f13f169fe322622c7b97e3866 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 14 Apr 2024 20:59:14 +0300 Subject: [PATCH 15/19] compare-tasks-and-content-check-added --- .../compare_tasks_and_content.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 app/main/checks/report_checks/compare_tasks_and_content.py diff --git a/app/main/checks/report_checks/compare_tasks_and_content.py b/app/main/checks/report_checks/compare_tasks_and_content.py new file mode 100644 index 00000000..12b95094 --- /dev/null +++ b/app/main/checks/report_checks/compare_tasks_and_content.py @@ -0,0 +1,100 @@ +from ..base_check import BaseReportCriterion, answer + +import app.nlp.text_similarity as ts + + +class CompareTasksAndContentCheck(BaseReportCriterion): + description = "Проверка соответствия задач и содержания" + id = 'compare_tasks_and_content_check' + + def __init__(self, file_info): + super().__init__(file_info) + self.headers = [] + self.tasks = [] + self.chapters = {} + self.weights = {} + self.all_to_pass = 0 + self.specific_to_pass = 0 + self.to_ignore = [] + + def late_init(self): + self.headers = self.file.make_chapters(self.file_type['report_type']) + self.weights = { + "ВВЕДЕНИЕ": 1, + "1": 2, + "2": 2, + "3": 5, + "4": 2, + "5": 1, + "ЗАКЛЮЧЕНИЕ": 1 + } + self.all_to_pass = 0.15 + self.specific_to_pass = 0.05 + self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ", "ПРИЛОЖЕНИЕ"] + + def check(self): + self.late_init() + if self.file.page_counter() < 4: + return answer(False, "В отчете недостаточно страниц. Нечего проверять.") + result = "" + possible_tasks = [] + for header in self.headers: + if header["text"] == "ВВЕДЕНИЕ": + for i, child in enumerate(header["child"]): + if child["text"].lower().find("задачи") >= 0: + possible_tasks.append(i) + if child["text"].lower().find("объект") >= 0 and child["text"].lower().find("исследования") > 0: + if not possible_tasks: + return answer(False, "В введении не найдены задачи работы") + tasks = header["child"][max(possible_tasks) + 1:i] + self.tasks = [task["text"] for task in tasks] + break + if any(ignore_phrase in header["text"] for ignore_phrase in self.to_ignore): + continue + text = "" + for child in header["child"]: + text += child['text'] + self.chapters[header["text"]] = text + self.chapters = {k: v for k, v in self.chapters.items() if v and v.strip()} + NLPProcessor = ts.NLPProcessor() + all_tasks_result = NLPProcessor.calculate_cosine_similarity(" ".join(self.tasks), self.chapters) + max_result = max(all_tasks_result.values()) + for k, v in all_tasks_result.items(): + for chapter, weight in self.weights.items(): + if k.find(chapter) == 0: + all_tasks_result[k] = v * weight + break + all_tasks_result[k] = round(all_tasks_result[k] / max_result, 3) + avg = round(sum(all_tasks_result.values()) / len(all_tasks_result.values()), 3) + if avg < self.all_to_pass: + return answer(False, f"Задачи недостаточно раскрыты в содержании (нужно {self.all_to_pass * 100}%, набрано {avg * 100}%)") + result += f"
Задачи раскрыты на {avg * 100}%
" + for task in self.tasks: + cur_task = NLPProcessor.calculate_cosine_similarity(task, self.chapters) + max_result = max(cur_task.values()) + for k, v in cur_task.items(): + for chapter, weight in self.weights.items(): + if k.find(chapter) == 0: + cur_task[k] = v * weight + break + cur_task[k] = cur_task[k] / max_result + sorted_chapters = dict(sorted(cur_task.items(), key=lambda item: item[1], reverse=True)) + specific_avg = sum(sorted_chapters.values()) / len(sorted_chapters.values()) + specific_avg = round(specific_avg, 3) + if specific_avg < self.specific_to_pass: + return answer(False, f"
Задача \"{task}\" недостаточно раскрыта
") + result += f"
Задача \"{task}\" раскрыта на {round(specific_avg * 100, 2)}%

Задачу \"{task}\" наиболее раскрывают разделы:
" + for i, key in enumerate(sorted_chapters.keys()): + if i >= 3: + break + result += f"
\"{key}\", {round(self.__output(sorted_chapters[key], sum(sorted_chapters.values())), 3)}% текста раскрывают задачу
" + all_tasks_result = dict(sorted(all_tasks_result.items(), key=lambda item: item[1], reverse=True)) + result += f"
Разделы, наименее раскрывающие задачи:
" + for i, key in enumerate(all_tasks_result.keys()): + if i < len(all_tasks_result.keys()) - 5: + continue + result += f"
{key}: {round(all_tasks_result[key], 3) * 100}%
" + return answer(True, result) + + def __output(self, value, summ): + return (value / summ) * 100 From 55a1777919158f30745af68fa5cde0e9fd4f2ed0 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 21 Apr 2024 12:30:36 +0300 Subject: [PATCH 16/19] compare-tasks-and-content-check-added --- app/main/checks/report_checks/compare_goal_and_content.py | 3 ++- app/main/checks/report_checks/compare_tasks_and_content.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index b955af30..1184841d 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -4,7 +4,8 @@ class CompareGoalAndContentCheck(BaseReportCriterion): - description = "Проверка соответствия цели и содержания" + label = "Проверка соответствия цели и содержания" + description = "Степень раскрытия цели в содержании" id = 'compare_goal_and_content_check' def __init__(self, file_info): diff --git a/app/main/checks/report_checks/compare_tasks_and_content.py b/app/main/checks/report_checks/compare_tasks_and_content.py index 12b95094..21c5d688 100644 --- a/app/main/checks/report_checks/compare_tasks_and_content.py +++ b/app/main/checks/report_checks/compare_tasks_and_content.py @@ -4,7 +4,8 @@ class CompareTasksAndContentCheck(BaseReportCriterion): - description = "Проверка соответствия задач и содержания" + label = "Проверка соответствия задач и содержания" + description = "Степень раскрытия задач в содержании" id = 'compare_tasks_and_content_check' def __init__(self, file_info): From 6321eb82b4c75f56a8ac4632069914aac0f7cd26 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 21 Apr 2024 12:44:28 +0300 Subject: [PATCH 17/19] fix-finding-intro --- .../checks/report_checks/compare_goal_and_content.py | 2 +- .../report_checks/compare_tasks_and_content.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index 1184841d..a5298f9f 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -38,7 +38,7 @@ def check(self): result = "" intro_text = "" for header in self.headers: - if header["text"] == "ВВЕДЕНИЕ": + if header["text"].find("ВВЕДЕНИЕ") >= 0: for child in header["child"]: intro_text += child["text"] goal_index = intro_text.find("Цель") diff --git a/app/main/checks/report_checks/compare_tasks_and_content.py b/app/main/checks/report_checks/compare_tasks_and_content.py index 21c5d688..229c3518 100644 --- a/app/main/checks/report_checks/compare_tasks_and_content.py +++ b/app/main/checks/report_checks/compare_tasks_and_content.py @@ -17,6 +17,7 @@ def __init__(self, file_info): self.all_to_pass = 0 self.specific_to_pass = 0 self.to_ignore = [] + self.minimum_tasks = 0 def late_init(self): self.headers = self.file.make_chapters(self.file_type['report_type']) @@ -32,6 +33,7 @@ def late_init(self): self.all_to_pass = 0.15 self.specific_to_pass = 0.05 self.to_ignore = ["СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ", "ПРИЛОЖЕНИЕ"] + self.minimum_tasks = 3 def check(self): self.late_init() @@ -40,7 +42,7 @@ def check(self): result = "" possible_tasks = [] for header in self.headers: - if header["text"] == "ВВЕДЕНИЕ": + if header["text"].find("ВВЕДЕНИЕ") >= 0: for i, child in enumerate(header["child"]): if child["text"].lower().find("задачи") >= 0: possible_tasks.append(i) @@ -48,6 +50,12 @@ def check(self): if not possible_tasks: return answer(False, "В введении не найдены задачи работы") tasks = header["child"][max(possible_tasks) + 1:i] + while len(tasks <= self.minimum_tasks): + try: + possible_tasks.remove(max(possible_tasks)) + tasks = header["child"][max(possible_tasks) + 1:i] + except: + return answer(False, f"В введении меньше {self.minimum_tasks} задач, что меньше необходимого минимума") self.tasks = [task["text"] for task in tasks] break if any(ignore_phrase in header["text"] for ignore_phrase in self.to_ignore): @@ -94,7 +102,7 @@ def check(self): for i, key in enumerate(all_tasks_result.keys()): if i < len(all_tasks_result.keys()) - 5: continue - result += f"
{key}: {round(all_tasks_result[key], 3) * 100}%
" + result += f"
{key}: {round(all_tasks_result[key] * 100, 3)}%
" return answer(True, result) def __output(self, value, summ): From 2bb80deadb122ca85933e2f1b1b74c10f4ae8c77 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 21 Apr 2024 12:52:01 +0300 Subject: [PATCH 18/19] hot-fixes --- app/main/checks/report_checks/compare_tasks_and_content.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/main/checks/report_checks/compare_tasks_and_content.py b/app/main/checks/report_checks/compare_tasks_and_content.py index 229c3518..0e374b74 100644 --- a/app/main/checks/report_checks/compare_tasks_and_content.py +++ b/app/main/checks/report_checks/compare_tasks_and_content.py @@ -50,7 +50,7 @@ def check(self): if not possible_tasks: return answer(False, "В введении не найдены задачи работы") tasks = header["child"][max(possible_tasks) + 1:i] - while len(tasks <= self.minimum_tasks): + while len(tasks) <= self.minimum_tasks: try: possible_tasks.remove(max(possible_tasks)) tasks = header["child"][max(possible_tasks) + 1:i] From e3bc13546088979711bd536424aa9c76a2f76915 Mon Sep 17 00:00:00 2001 From: TheAnton1 Date: Sun, 21 Apr 2024 13:12:58 +0300 Subject: [PATCH 19/19] fix-finding-intro --- app/main/checks/report_checks/compare_goal_and_content.py | 2 +- app/main/checks/report_checks/compare_tasks_and_content.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/main/checks/report_checks/compare_goal_and_content.py b/app/main/checks/report_checks/compare_goal_and_content.py index a5298f9f..263386a8 100644 --- a/app/main/checks/report_checks/compare_goal_and_content.py +++ b/app/main/checks/report_checks/compare_goal_and_content.py @@ -38,7 +38,7 @@ def check(self): result = "" intro_text = "" for header in self.headers: - if header["text"].find("ВВЕДЕНИЕ") >= 0: + if header["text"].lower().find("введение") >= 0: for child in header["child"]: intro_text += child["text"] goal_index = intro_text.find("Цель") diff --git a/app/main/checks/report_checks/compare_tasks_and_content.py b/app/main/checks/report_checks/compare_tasks_and_content.py index 0e374b74..06d757ad 100644 --- a/app/main/checks/report_checks/compare_tasks_and_content.py +++ b/app/main/checks/report_checks/compare_tasks_and_content.py @@ -42,7 +42,7 @@ def check(self): result = "" possible_tasks = [] for header in self.headers: - if header["text"].find("ВВЕДЕНИЕ") >= 0: + if header["text"].lower().find("введение") >= 0: for i, child in enumerate(header["child"]): if child["text"].lower().find("задачи") >= 0: possible_tasks.append(i)