senyukhin commited on
Commit
eea4f3c
1 Parent(s): 7d61140

Upload 11 files

Browse files
Files changed (6) hide show
  1. app.py +21 -6
  2. diary.py +3 -3
  3. network_builder.py +56 -4
  4. sentiment_parser.py +0 -1
  5. test_1.txt +91 -0
  6. word_transformations.py +87 -0
app.py CHANGED
@@ -4,18 +4,29 @@ import sentiment_parser as sp
4
  import network_builder as nb
5
  from pyvis.network import Network
6
  import streamlit.components.v1 as components
7
- # import altair as alt
8
 
9
  st.title('Автоматический аннотатор')
10
 
11
- st.markdown("Скопируйте текст дневика в это поле или выберите для теста один из подготовленных отрывков.")
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
- with open('test.txt', 'r') as f:
15
- TEST = f.read()
16
  # diary = st.text_area('Текст дневника')
17
- if st.button('Быстрая обработка на тестовом тексте '):
18
- df = d.analyze(TEST)
19
  # st.dataframe(df)
20
  # for_chart = sp.data_for_sentiment_chart(df).set_index('n_date')
21
  # st.markdown('### График сентимента по записям дневника (тест)')
@@ -23,6 +34,10 @@ if st.button('Быстрая обработка на тестовом текст
23
  # st.experimental_memo.clear()
24
  graph = nb.build_graph(df)
25
 
 
 
 
 
26
  textnet = Network( height='400px',
27
  width='100%',
28
  bgcolor='white',
 
4
  import network_builder as nb
5
  from pyvis.network import Network
6
  import streamlit.components.v1 as components
7
+ import word_transformations as wt
8
 
9
  st.title('Автоматический аннотатор')
10
 
11
+ # st.markdown("Скопируйте текст дневика в это поле или выберите для теста один из подготовленных отрывков.")
12
+
13
+ txt = st.text_area('Скопируйте текст дневика в это поле', height=100)
14
+
15
+ option = st.selectbox(
16
+ 'Или выберите один из тестовых текстов дневников:',
17
+ ('Выбрать...', 'Анатолий Василивицкий', 'Мария Германова'))
18
+
19
+ if option == 'Анатолий Василивицкий':
20
+ with open('test_1.txt', 'r') as f:
21
+ txt = f.read()
22
+ elif option == 'Мария Германова':
23
+ with open('test.txt', 'r') as f:
24
+ txt = f.read()
25
 
26
 
 
 
27
  # diary = st.text_area('Текст дневника')
28
+ if st.button('Обработать') and txt != '':
29
+ df = d.analyze(txt)
30
  # st.dataframe(df)
31
  # for_chart = sp.data_for_sentiment_chart(df).set_index('n_date')
32
  # st.markdown('### График сентимента по записям дневника (тест)')
 
34
  # st.experimental_memo.clear()
35
  graph = nb.build_graph(df)
36
 
37
+ GENDER = wt.get_gender(df['tokens'])
38
+
39
+ st.markdown(f'**Аннотация этого дневника:** {nb.annotation(graph, GENDER)}')
40
+
41
  textnet = Network( height='400px',
42
  width='100%',
43
  bgcolor='white',
diary.py CHANGED
@@ -2,7 +2,8 @@ import date_parser as dp
2
  import preproc
3
  import category_parser as cp
4
  import sentiment_parser as sp
5
- import streamlit as st
 
6
 
7
  # def get_gender(tokens):
8
  # r = [token.feats['Gender'] for sent in tokenizing(text) for token in sent if (token.feats.get('Gender') and token.feats.get('Voice')) ]
@@ -19,8 +20,7 @@ def analyze(text):
19
  diary['tokens'] = diary['text'].apply(lambda text: preproc.tokenizing(text))
20
 
21
  # # Выделение фактов из текста
22
- diary['loc_facts'] = diary['tokens'].apply(lambda tokens: cp.get_facts(tokens, 'locations'))
23
- # diary['loc_words'] = diary['tokens'].apply(lambda tokens: cp.get_mentioned_words(tokens, 'locations'))
24
 
25
  # Определение сентимента по записям
26
  # diary['sent'] = diary['tokens'].apply(lambda tokens: sp.get_overall_sentiment(tokens))
 
2
  import preproc
3
  import category_parser as cp
4
  import sentiment_parser as sp
5
+ import word_transformations as wt
6
+
7
 
8
  # def get_gender(tokens):
9
  # r = [token.feats['Gender'] for sent in tokenizing(text) for token in sent if (token.feats.get('Gender') and token.feats.get('Voice')) ]
 
20
  diary['tokens'] = diary['text'].apply(lambda text: preproc.tokenizing(text))
21
 
22
  # # Выделение фактов из текста
23
+ diary['locations'] = diary['tokens'].apply(lambda tokens: cp.get_facts(tokens, 'locations'))
 
24
 
25
  # Определение сентимента по записям
26
  # diary['sent'] = diary['tokens'].apply(lambda tokens: sp.get_overall_sentiment(tokens))
network_builder.py CHANGED
@@ -1,8 +1,10 @@
1
  import networkx as nx
 
 
2
 
3
 
4
  def build_graph(df):
5
- G = nx.Graph()
6
 
7
  # Связывание дат
8
  for previous, current in zip(df['date_start'], df['date_start'][1:]):
@@ -11,11 +13,61 @@ def build_graph(df):
11
  G.add_edge(previous, current)
12
 
13
  # Добавление связей дат и фактов, фактов и слов
14
- for index, row in df[['date_start', 'loc_facts']].iterrows():
15
- for fact in row['loc_facts']:
16
  G.add_node(fact[0], group="Category_word", color = "green")
17
  G.add_node(fact[1], group="Fact", color = "red")
18
  G.add_edge(row['date_start'], fact[1])
19
  G.add_edge(fact[0], fact[1])
20
 
21
- return G
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import networkx as nx
2
+ from collections import Counter
3
+ import word_transformations as wt
4
 
5
 
6
  def build_graph(df):
7
+ G = nx.DiGraph()
8
 
9
  # Связывание дат
10
  for previous, current in zip(df['date_start'], df['date_start'][1:]):
 
13
  G.add_edge(previous, current)
14
 
15
  # Добавление связей дат и фактов, фактов и слов
16
+ for index, row in df[['date_start', 'locations']].iterrows():
17
+ for fact in row['locations']:
18
  G.add_node(fact[0], group="Category_word", color = "green")
19
  G.add_node(fact[1], group="Fact", color = "red")
20
  G.add_edge(row['date_start'], fact[1])
21
  G.add_edge(fact[0], fact[1])
22
 
23
+ return G
24
+
25
+
26
+ def dates_of_Diary_writing(G):
27
+ dates = [key for key, value in G.nodes.data() if value.get('group') == 'Date']
28
+ start = ''
29
+ stop = ''
30
+ for d in dates:
31
+ if not [i for i in G.predecessors(d)]:
32
+ start = d
33
+ elif not [i for i in G.successors(d) if G.nodes.data()[i]['group'] == 'Date']:
34
+ stop = d
35
+ return (start, stop)
36
+
37
+
38
+ def most_visited_places(G):
39
+ res = Counter()
40
+ for key, value in G.nodes.data():
41
+ if value.get('group') == 'Category_word':
42
+ res[key] = len(G[key])
43
+ return [i[0] for i in Counter(res).most_common(3)]
44
+
45
+
46
+ def facts_for_annotation(G, gender, most_places):
47
+ '''
48
+ Собирает лист из фактов и его даты упоминания
49
+ '''
50
+ res = Counter()
51
+ for key, value in G.nodes.data():
52
+ if value.get('group') == 'Category_word':
53
+ res[key] = len(G[key])
54
+ facts = [s for i in Counter(res).keys() for s in G.successors(i)]
55
+
56
+ res = []
57
+ for fact in facts:
58
+ if wt.get_fact_to_annotation(fact, gender, most_places):
59
+ date = [i for i in G.predecessors(fact) if G.nodes()[i].get('group') == 'Date'][0]
60
+ res.append((date, fact))
61
+ return res
62
+
63
+
64
+ def annotation(G, gender):
65
+ dates = dates_of_Diary_writing(G)
66
+ most_places = most_visited_places(G)
67
+ facts = facts_for_annotation(G, gender, most_places)
68
+
69
+ facts = ', '.join([f"{fact[1].lower()} ({fact[0]})" for fact in facts])
70
+
71
+ annotation = f'{wt.get_noun(gender).title()} этого дневника {wt.gender_transformer("вести", gender)} его с {dates[0]} по {dates[1]}. Наиболее часто {wt.get_pronoun(gender)} {wt.gender_transformer("описывал", gender)} {wt.inflector(most_places[0], "accs")}, {wt.inflector(most_places[1], "accs")} и {wt.inflector(most_places[2], "accs")}.\n\nВ дневнике упоминается, как {wt.get_noun(gender)} {facts}.'
72
+
73
+ return annotation
sentiment_parser.py CHANGED
@@ -67,7 +67,6 @@ def get_most_sentiment(sentiment_index):
67
  sentiments = Counter(sentiments)
68
  return sentiments.most_common(1)[0][0]
69
 
70
- @st.experimental_memo
71
  def data_for_sentiment_chart(df):
72
  df = df.copy()
73
  df['n_date'] = df.apply(lambda row:
 
67
  sentiments = Counter(sentiments)
68
  return sentiments.most_common(1)[0][0]
69
 
 
70
  def data_for_sentiment_chart(df):
71
  df = df.copy()
72
  df['n_date'] = df.apply(lambda row:
test_1.txt ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 1943
2
+
3
+ 24 марта. Челябинск
4
+
5
+ Сегодня кончается третья четверть. Потом каникулы до 1/IV — неделю. Говорили с Москвой. Папка может предет в апреле. Хорошо бы приехал.
6
+ Я немного болел. Теперь выздоровел. От класса отстал не намного. За каникулы догоню. Во дворе у нас несколько ребят уехало. Г.Л. обещала написать письмо. Посмотрим.
7
+ Сегодня мне сообщили что И[нна].Д[митриева]. в меня втрескалась[.] Чтоб ей лопнуть! Неужели без любви нельзя обойтись. У наших ребят какое-то странное понимание о дружбе. Если увидят что стоишь и разговариваешь с какой-нибудь девочкой. Сразу дразнить: влюбился, влюбился. А для того что-бы влюбиться по моему надо подрасти. А у нас во дворе нет таких что-бы не перелюбились. В половине этого случая не исключая и меня.
8
+ В школе то-же. Какие-то идиоты кругом. Как дикари. Ну, а я то-же не лучше. Я могу влюбиться сердцем, умом никогда.
9
+
10
+ 25 марта. «И в какой стороне я не буду по какой не пройду я тропе, друга я никогда незабуду если с ним подружился в Москве…»
11
+ Друга хорошего нельзя позыбыть не только если с ним подружишь в Москве.
12
+ «В какой точке Союза не буду, и где не встречу мой друг я тебя, я тебя никогда не забуду, если ты не забудешь меня».
13
+ «Я сейчас сижу в тюрьме и не светит
14
+ Солнце мне, Кашмари, кашмари, кашмари[»].
15
+ Эх! Не знаю что у меня на душе, что в животе я знаю там глисты, сегодня получил анализ кала.
16
+ Чорт меня побрал! Что это на меня нашло такое настроение влюбленного. Ну, ка пошлю вон. Быть тебе только другом но…
17
+ Опять!?
18
+ Последнее время я не знаю что со мной творится, но примерно догадываюсь, [запись обрывается]
19
+
20
+ 5 апреля. Началась последняя четверть. А там испытания. Кончу 6-й кл[асс]. наверно в Челябинске. В апреле в Москву конечно не поедем.
21
+ В выходной ходил стрелять в тир. Сдал на «Юный ворошиловский стрелок» .
22
+ Книга — лучший друг мой. Но такие книги что я читаю не могут заменить друга — человека. Друг. Как это слово звучит для меня непривычно. О нем я могу лишь мечтать. Дружба. Я так нуждаюсь в тебе.
23
+
24
+ 10 апреля. Утром говорили с Москвой. Едем в Москву после оконч[ания]. учебного года. Папка наверное в мае приедет к нам в гости. Завтра выходной. Жаль, он пройдет без пользы. Такая скука.
25
+ [Рисунок мушкетёра с бокалом]
26
+
27
+ 16 апреля. Дневник, я долгое время скрывал от тебя одну вещь. Я недоверял тебе. Думал ты можешь рассказать. Но сегодня я пишу. Я не могу скрывать. Я люблю А.Г. Раз я уж начал писать то буду продолжать. Это было давно. Однажды я сидел на тумбе. Ко мне подошла Г.З. и сказала что А.Г. меня любит. Во мне долго боролись два чувства: любовь и разум. И разум победил. Я сказал нет. Но это было бы хорошо. Однажды когда все были на улице я рассказал это. Да я это сделал! Теперь ты можешь понять дневник, как я раскаиваюсь в этом поступке.
28
+ Теперь же я люблю её. Люблю как только может любит мое бедное сердце. Но что я могу теперь делать: одно горько жалеть о прошедшем. Теперь же я ловлю её слова, я смотрю на нее. Но я скрываю все. Я был у Ж.А. А.Г. с ним в одной квартире. Она вошла к нам с Наталией. Ада показала мне свой альбом для стихов и свои собственные стихи. Один стих выражал ею чувства которые она переживала в те дни когда я над ней издевался. Я чувствовал что этот стих посвящен мне. Да я горько сожалею о зсделаном. Прошедшего не воротить.
29
+
30
+ 21 апреля.
31
+ >И в кого я такой уродился?
32
+ >Со своим характером таким.
33
+ >Стоит мне в девушку влюбиться,
34
+ >А она уже идет с другим.
35
+
36
+ 29 апреля. Я сделал в себе одно открытие. Любить я не могу. С А.Г. я бы хотел дружить. Да что говорить: «не все наши хотенья выполнять можно».
37
+
38
+ 2 мая. Ну вот и праздник прошел. Какая скука. Вчера вечерном я долго разговаривал с Н[аташа].П[люснина]. так у нас во дворе, а, вероятно, первый разговариваю с девочкой. Она мне многое рассказала о А.Г. и я понял как я виноват перед ней.
39
+
40
+ 6 мая. Через две недели испытания. Пора бы готовититься.
41
+
42
+ 8 мая. Мы вчера с Адой объяснились. Я ей проиграл «американку[»] . Она мне загодала «С кем ты хочешь дружить?» Я ответил чтобы она спросила у Н[аташа].П[люснина]. Она ответила правду.
43
+ Вчера Ж.А. подозвал меня и говорит что он видал дневник А[ды]., на последней страничке было написано: «Наконец, я узнала что меня любит Толя».
44
+
45
+ 16 мая. Последний выходной перед испытаниями. 20/V — алгебра. Папка приезжает 20/V. Я долгое время не понимал что такое любовь, теперь я это прекрасно понимаю.
46
+ [прикреплена фотография автора]
47
+
48
+ >Не все думают так как смотрят
49
+ >У них свой интерес впереди
50
+ >Тебе если будет горько
51
+ >Рукой от сердце зажми
52
+ >Отнимишь руку — прослушают
53
+ >Все мысли твои, всю печаль
54
+ >Потом головой покочают
55
+ >И расскажут друзьям невначай.
56
+
57
+ Дневник, милый мне так хочется иметь друга, хорошего друга. О, Зоя, ты была и вероятно будешь моим единственным другом. А сейчас я один совершенно один и некому мне излить души.
58
+
59
+ [на уголке страницы: «ПУСТЬ 1943 год ОСТАНЕТСЯ У МЕНЯ В ПАМЯТИ КАК ГОД СВЕ[Т]ЛЫХ ВОСПОМИНАНИЙ
60
+ 1943 г. БЫЛ ГОДОМ МОЕЙ ПЕРВОЙ ЛЮБВИ
61
+ 6/V—1943 г.»]
62
+
63
+ 19 мая. Завтра алгебра. Сегодня сижу и повторяю, в 3 ч. на консультацию. Всего 7 испыт[аний]. Завтра приезжает папка.
64
+
65
+ 20 мая. Сдал алгебру. На отлично. Папка еще не приехал
66
+
67
+ 25 мая. У А.Г. есть подруга Г.З. Очень хорошая девочка. Я с ней два дня назад долго разговаривал. Под конец я сказал, то что было того трудно воротить. Галя ответила два слова: «Да, охлождена».
68
+ Здал алгебру, географию и в/д на отлично, а русский письменный на хорошо.
69
+ Мне очень хочется написать о каждом(ой) из нашего двора.
70
+
71
+ Наташа Плюснина.
72
+ Приехала из Москвы. Очень хорошая девочка. Не воображает, не сплетничает. Простая и открытая. Мечтает иметь хорошего друга и поехать в Москву. С ней я часто разговаривал открыто и она знает все. Но несмотря на это не дразнится как это сделали бы другие. В общем я о ней самого хорошего мнения. [поздняя приписка — «Уехала в Москву. 3/VI—1943 г.»]
73
+
74
+ Инна Дми��риева. Приехала из Москвы. Инна и Наташа это две противоположности. Она считает себя красавицей и думает что в неё все влюбились. У меня с ней были частые ссоры (и будут). Если я кого нибудь ненавидел то это её. Однажды она при всех выказала опасение что из-за нее подеруться на финках. [поздняя приписка — «Уехала в Москву 2/VI—1943 г.»]
75
+ [оставлено место для других записей]
76
+
77
+ 2 июня. Сегодня исторический день.
78
+ И[нна].Д[митриева]. и Н[аташа].П[люснина]., а также другие уехали в Москву. Стало так скучно. Погоды поршивые. Тоска, скука. В дневнике я пишу сухими казенными словами. А как хочется его забросить к чорту на рога. А все таки жаль. Ада подорила мне свою фотографию. Я прямо радуюсь «как ребенок».
79
+ Я ехал на вокзал провожать ребят. Наташа много плакала, Ада немножко, плакала она из-за расставания с подругой и еще из-за какой-то тайны покрытой мраком.
80
+
81
+ 7 июня. Делать нечего. Скука. Лежу и читаю. Так хочется в Москву. Мама говорит что поедем в начале июля.
82
+
83
+ 16 июня. Дел за последнее время много. Образовали об[щест]во аТОС (тайная организ[ация] сороконожек).
84
+ Сегодня поднял шухер . Разбил стекло (4-е за неделю). Приходил мент. Я оторвался. Не знаю что будет. Завтра покажет. Я не боюсь и на все плюю.
85
+ Сороконожки действуют!
86
+
87
+ 20 июня. Сегодня ходил в театр. Смотрел «Чужой ребенок» . Комедия. Кончил читать Дж. Лондона . Замечательные рассказы. Последнее время я очень хочу в Москву. У меня такое настроение что я могу сделать глупость…
88
+
89
+ 26 июня. Вероятно скоро поеду в Москву.
90
+
91
+ 2 июля. Говорили с Зоей. Завтра высылает мой пропуск . Наконец я отсюда уеду С[лава]. Б[огу].!
word_transformations.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Методы преобразования слов для аннотаций
3
+ '''
4
+ import pymorphy2
5
+ from collections import Counter
6
+
7
+ morph = pymorphy2.MorphAnalyzer()
8
+
9
+ # Определение пола автора по тексту
10
+ def get_gender(tokens):
11
+ '''
12
+ Определение пола автора по тексту
13
+
14
+ Возвращает ``Fem`` — женский род, ``Masc`` — мужской род.
15
+ '''
16
+ gender = []
17
+ for i in [token for sent in tokens for token in sent]:
18
+ for token in i:
19
+ if token.feats.get('Gender') and token.pos == 'VERB':
20
+ gender.append(token.feats.get('Gender'))
21
+ return Counter(gender).most_common(1)[0][0]
22
+
23
+ def inflector(word, case):
24
+ '''
25
+ Склонение существительных по падежам.
26
+
27
+ word : существительное
28
+
29
+ case : падеж
30
+
31
+ `nomn` – именительный
32
+ `gent` — родительны
33
+ `datv` — дательный
34
+ `accs` — винительный
35
+ `ablt` — творительный
36
+ `loct` — предложный
37
+ '''
38
+ return morph.parse(word)[0].inflect({case}).word
39
+
40
+
41
+ def gender_transformer(verb, gender):
42
+ '''
43
+ Преобразование глагола в нужный род прошедшего времени
44
+ '''
45
+ # Преобразование формата рода Natasha к pymorphy2
46
+ if gender == 'Fem' : gender = 'femn'
47
+ else: gender = 'masc'
48
+
49
+ # Если автор пишет о себе в первом лице "Я пишу..."
50
+ # if {'1per'} in morph.parse(verb)[0].tag:
51
+ for w in morph.parse(verb)[0].lexeme:
52
+ if {gender, 'past', 'VERB'} in w.tag:
53
+ return w.word
54
+
55
+
56
+ def get_pronoun(gender):
57
+ if gender == 'Fem': return 'она'
58
+ else: return 'он'
59
+
60
+
61
+ def get_noun(gender):
62
+ if gender == 'Fem': return 'авторка'
63
+ else: return 'автор'
64
+
65
+
66
+ def get_fact_to_annotation(fact, gender, most_mentioned_word):
67
+ '''
68
+ Проверяет, нужно ли взять факт в аннотацию
69
+
70
+ Пока работает, если глагол в нужном лице и роде и не упоминается распространённое место.
71
+ '''
72
+ if gender == 'Fem' : gender = 'femn'
73
+ else: gender = 'masc'
74
+ flag = False
75
+ for word in fact.split(' '):
76
+ for form in morph.parse(word):
77
+ # Если глагол прошедшего времени
78
+ if {gender, 'VERB'} in form.tag:
79
+ flag = True
80
+ # Если глагол от "первого лица"
81
+ if {'1per', 'sing', 'VERB'} in form.tag:
82
+ flag = True
83
+ if form.normal_form in most_mentioned_word:
84
+ return False
85
+ if form.normal_form in ['она', 'он']:
86
+ return False
87
+ return flag