from natasha import (
    Segmenter,
    MorphVocab,
    
    NewsEmbedding,
    NewsMorphTagger,
    NewsSyntaxParser,
    NewsNERTagger,
    
    PER,
    NamesExtractor,
    DatesExtractor,
    MoneyExtractor,
    AddrExtractor,

    Doc
)

segmenter = Segmenter()
morph_vocab = MorphVocab()

emb = NewsEmbedding()
morph_tagger = NewsMorphTagger(emb)
syntax_parser = NewsSyntaxParser(emb)
ner_tagger = NewsNERTagger(emb)

names_extractor = NamesExtractor(morph_vocab)
dates_extractor = DatesExtractor(morph_vocab)
money_extractor = MoneyExtractor(morph_vocab)
addr_extractor = AddrExtractor(morph_vocab)

"""
Explanation: Natasha
Natasha solves basic NLP tasks for Russian language: tokenization, sentence segmentatoin, word embedding, morphology tagging, lemmatization, phrase normalization, syntax parsing, NER tagging, fact extraction.
Library is just a wrapper for lower level tools from <a href="https://github.com/natasha">Natasha project</a>:

<a href="https://github.com/natasha/razdel">Razdel</a> — token, sentence segmentation for Russian
<a href="https://github.com/natasha/navec">Navec</a> — compact Russian embeddings
<a href="https://github.com/natasha/slovnet">Slovnet</a> — modern deep-learning techniques for Russian NLP, compact models for Russian morphology, syntax, NER.
<a href="https://github.com/natasha/yargy">Yargy</a> — rule-based fact extraction similar to Tomita parser.
<a href="https://github.com/natasha/ipymarkup">Ipymarkup</a> — NLP visualizations for NER and syntax markups.

Consider using these lower level tools for realword tasks. Natasha models are optimized for news articles, on other domains quality may be worse.
End of explanation
"""


text = 'Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав о решении властей Львовской области объявить 2019 год годом лидера запрещенной в России Организации украинских националистов (ОУН) Степана Бандеры. Свое заявление он разместил в Twitter. «Я не могу понять, как прославление тех, кто непосредственно принимал участие в ужасных антисемитских преступлениях, помогает бороться с антисемитизмом и ксенофобией. Украина не должна забывать о преступлениях, совершенных против украинских евреев, и никоим образом не отмечать их через почитание их исполнителей», — написал дипломат. 11 декабря Львовский областной совет принял решение провозгласить 2019 год в регионе годом Степана Бандеры в связи с празднованием 110-летия со дня рождения лидера ОУН (Бандера родился 1 января 1909 года). В июле аналогичное решение принял Житомирский областной совет. В начале месяца с предложением к президенту страны Петру Порошенко вернуть Бандере звание Героя Украины обратились депутаты Верховной Рады. Парламентарии уверены, что признание Бандеры национальным героем поможет в борьбе с подрывной деятельностью против Украины в информационном поле, а также остановит «распространение мифов, созданных российской пропагандой». Степан Бандера (1909-1959) был одним из лидеров Организации украинских националистов, выступающей за создание независимого государства на территориях с украиноязычным населением. В 2010 году в период президентства Виктора Ющенко Бандера был посмертно признан Героем Украины, однако впоследствии это решение было отменено судом. '
doc = Doc(text)
doc

"""
Explanation: Getting started
Doc
Doc aggregates annotators, initially it has just text field defined:
End of explanation
"""


doc.segment(segmenter)
display(doc)
display(doc.sents[:2])
display(doc.tokens[:5])

"""
Explanation: After applying segmenter two new fields appear sents and tokens:
End of explanation
"""


doc.tag_morph(morph_tagger)
doc.parse_syntax(syntax_parser)
display(doc.tokens[:5])

"""
Explanation: After applying morph_tagger and syntax_parser, tokens get 5 new fields id, pos, feats, head_id, rel — annotation in <a href="https://universaldependencies.org/">Universal Dependencies format</a>:
End of explanation
"""


doc.tag_ner(ner_tagger)
display(doc.spans[:5])

"""
Explanation: After applying ner_tagger doc gets spans field with PER, LOC, ORG annotation:
End of explanation
"""


doc.ner.print()

sent = doc.sents[0]
sent.morph.print()

sent.syntax.print()

"""
Explanation: Visualizations
Natasha wraps <a href="https://github.com/natasha/ipymarkup">Ipymarkup</a> to provide ASCII visualizations for morphology, syntax and NER annotations. doc and sents have 3 methods: morph.print(), syntax.print() and ner.print():
End of explanation
"""


for token in doc.tokens:
    token.lemmatize(morph_vocab)
    
{_.text: _.lemma for _ in doc.tokens[:10]}

"""
Explanation: Lemmatization
Tokens have lemmatize method, it uses pos and feats assigned by morph_tagger to get word normal form. morph_vocab is just a wrapper for <a href="https://pymorphy2.readthedocs.io/en/latest/">Pymorphy2</a>:
End of explanation
"""


for span in doc.spans:
    span.normalize(morph_vocab)
    
{_.text: _.normal for _ in doc.spans}

"""
Explanation: Phrase normalization
Consider phrase "Организации украинских националистов", one can not just inflect every word independently to get normal form: "Организация украинский националист". Spans have method normalize that uses syntax annotation by syntax_parser to inflect phrases:
End of explanation
"""


for span in doc.spans:
    if span.type == PER:
        span.extract_fact(names_extractor)
    
{_.normal: _.fact.as_dict for _ in doc.spans if _.fact}

"""
Explanation: Fact extraction
To split names like "Виктор Ющенко", "Бандера" and "Йоэль Лион" into parts use names_extractor and spans method extract_fact:
End of explanation
"""


tokens = list(segmenter.tokenize('Кружка-термос на 0.5л (50/64 см³, 516;...)'))
for token in tokens[:5]:
    print(token)

text = '''
- "Так в чем же дело?" - "Не ра-ду-ют".
 И т. д. и т. п. В общем, вся газета
'''
sents = list(segmenter.sentenize(text))
for sent in sents:
    print(sent)

"""
Explanation: Reference
One may use Natasha components independently. It is not mandatory to construct Doc object.
Segmenter
Segmenter is just a wrapper for <a href="https://github.com/natasha/razdel">Razdel</a>, it has two methods tokenize and sentenize:
End of explanation
"""


forms = morph_vocab('стали')
forms

morph_vocab.__call__.cache_info()

"""
Explanation: MorphVocab
MorphVocab is a wrapper for <a href="pymorphy2.readthedocs.io/en/latest/">Pymorphy2</a>. MorphVocab adds cache and adapts grammems to Universal Dependencies format:
End of explanation
"""


morph_vocab.lemmatize('стали', 'VERB', {})

morph_vocab.lemmatize('стали', 'X', {'Case': 'Gen'})

"""
Explanation: Also MorphVocab adds method lemmatize. Given pos and feats it selects the most suitable morph form and returns its normal field:
End of explanation
"""


print('Words in vocab + 2 for pad and unk: %d' % len(emb.vocab.words) )

emb['навек'][:10]

"""
Explanation: Embedding
Embedding is a wrapper for <a href="https://github.com/natasha/navec/">Navec</a> — compact pretrained word embeddings for Russian language:
End of explanation
"""


words = ['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей']
markup = morph_tagger(words)
markup.print()

"""
Explanation: MorphTagger
MorphTagger wraps <a href="https://github.com/natasha/slovnet">Slovnet morphology tagger</a>. Tagger has list of words as input and returns markup object. Markup has print method that outputs morph tags ASCII visualization:
End of explanation
"""


words = ['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей']
markup = syntax_parser(words)
markup.print()

"""
Explanation: SyntaxParser
SyntaxParser wraps <a href="https://github.com/natasha/slovnet">Slovnet syntax parser</a>. Interface is similar to MorphTagger:
End of explanation
"""


text = 'Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав о решении властей Львовской области объявить 2019 год годом лидера запрещенной в России Организации украинских националистов (ОУН) Степана Бандеры. Свое заявление он разместил в Twitter. 11 декабря Львовский областной совет принял решение провозгласить 2019 год в регионе годом Степана Бандеры в связи с празднованием 110-летия со дня рождения лидера ОУН (Бандера родился 1 января 1909 года).'
markup = ner_tagger(text)
markup.print()

"""
Explanation: NERTagger
NERTagger wraps <a href="https://github.com/natasha/slovnet">Slovnet NER tagger</a>. Interface is similar to MorphTagger but has untokenized text as input:
End of explanation
"""


text = '24.01.2017, 2015 год, 2014 г, 1 апреля, май 2017 г., 9 мая 2017 года'
list(dates_extractor(text))

"""
Explanation: Extractor
In addition to names_extractor Natasha bundles several other extractors: dates_extractor, money_extractor and addr_extractor. All extractors are based on <a href="https://github.com/natasha/yargy">Yargy-parser</a>, meaning that they work correctly only on small predefined set of texts. For realword tasks consider writing your own grammar, see <a href="https://github.com/natasha/yargy#documentation">Yargy docs</a> for more.
DatesExtractor
End of explanation
"""


text = '1 599 059, 38 Евро, 420 долларов, 20 млн руб, 20 т. р., 881 913 (Восемьсот восемьдесят одна тысяча девятьсот тринадцать) руб. 98 коп.'
list(money_extractor(text))

"""
Explanation: MoneyExtractor
End of explanation
"""


lines = [
    'Мустафа Джемилев',
    'О. Дерипаска',
    'Фёдор Иванович Шаляпин',
    'Янукович'
]
for line in lines:
    display(names_extractor.find(line))

"""
Explanation: NamesExtractor
names_extractor should be applied only to spans of text. To extract single fact use method find:
End of explanation
"""


lines = [
    'Россия, Вологодская обл. г. Череповец, пр.Победы 93 б',
    '692909, РФ, Приморский край, г. Находка, ул. Добролюбова, 18',
    'ул. Народного Ополчения д. 9к.3'
]
for line in lines:
    display(addr_extractor.find(line))

"""
Explanation: AddrExtractor
End of explanation
"""


