File size: 9,722 Bytes
982cda3
eab29b2
d43ee70
 
eab29b2
 
 
d43ee70
eab29b2
 
 
 
 
 
 
 
 
d43ee70
 
 
 
 
eab29b2
 
 
 
afb4867
 
 
eab29b2
 
 
 
 
57f5b08
 
 
 
eab29b2
 
57f5b08
eab29b2
 
d43ee70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eab29b2
 
d43ee70
 
 
eab29b2
 
 
 
d43ee70
eab29b2
afb4867
 
 
 
 
 
 
 
 
 
 
 
 
 
eab29b2
d43ee70
eab29b2
 
d43ee70
 
eab29b2
 
 
 
 
 
d43ee70
 
 
 
 
 
 
 
 
 
 
 
eab29b2
d43ee70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eab29b2
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import os
import gradio as gr
import wget
from ftlangdetect import detect
from cleantext import clean
from keybert import KeyBERT
from keyphrase_vectorizers import KeyphraseCountVectorizer
from functools import partial

# models sentence-bert multilingual
# fonte SBERT: https://www.sbert.net/docs/pretrained_models.html#multi-lingual-models
# models na Hugging Face model hub (https://huggingface.co/sentence-transformers/...)
model_id = ["paraphrase-multilingual-MiniLM-L12-v2", "sentence-transformers/LaBSE", "distiluse-base-multilingual-cased-v1"]
model_name = ["SBERT multilingual", "LaBSE", "DistilBERT mltilingual (v1)"]
kw_model_0 = KeyBERT(model=model_id[0])
kw_model_1 = KeyBERT(model=model_id[1])
kw_model_2 = KeyBERT(model=model_id[2])
kw_model = {
    0: kw_model_0,
    1: kw_model_1,
    2: kw_model_2
    }

## KeyphraseVectorizers
# source: https://github.com/TimSchopf/KeyphraseVectorizers#keyphrasevectorizers

download spacy pipeline (https://spacy.io/models/pt)
source: https://melaniewalsh.github.io/Intro-Cultural-Analytics/05-Text-Analysis/Multilingual/Portuguese/03-POS-Keywords-Portuguese.html
os.system("python -m spacy download pt_core_news_lg")

# Part-of-Speech Tagging for Portuguese (https://melaniewalsh.github.io/Intro-Cultural-Analytics/05-Text-Analysis/Multilingual/Portuguese/03-POS-Keywords-Portuguese.html)
pos_pattern='<CONJ.*>*<ADP.*>*<ADV.*>*<NUM.*>*<ADJ.*>*<N.*>+'

# download stop words in Portuguese
#import nltk
#nltk.download('stopwords')
#from nltk.corpus import stopwords
#stop_words = set(stopwords.words('portuguese'))

# define o vectorizer
vectorizer = KeyphraseCountVectorizer(spacy_pipeline='pt_core_news_lg', pos_pattern=pos_pattern, stop_words=None, lowercase=False)

# function principal (keywords)
def get_kw_html(model_id, doc, top_n, diversity):

  # detect lang
  res = detect(text=doc, low_memory=False)
  lang = res["lang"]
  score = res["score"]

  if len(doc) == 0:

    # get keywords and highlighted text
    keywords, keywords_json = [("",0.)], {"":0.}
    html_doc = '<p style="font-size:150%; line-height:120%"></p>'
    label = "O texto do documento não pode estar vazio. Recomece, por favor."

  elif lang!="pt" or score<0.9:

    # get keywords and highlighted text
    keywords, keywords_json = [("",0.)], {"":0.}
    html_doc = '<p style="font-size:150%; line-height:120%"></p>'
    label = "O APP não tem certeza de que o texto do documento está em português. Recomece com um texto em português, por favor."
    
  else:

    # keywords
    def get_kw(kw_model=kw_model[model_id], doc=doc, top_n=top_n, diversity=diversity):
      keywords = kw_model.extract_keywords(doc, 
                                          vectorizer=vectorizer,                                     
                                          use_mmr=True, diversity=diversity,
                                          top_n=top_n,
                                          )
      keywords_json = {item[0]:item[1] for item in keywords}
      return keywords, keywords_json
    
    # highlight
    def get_html(keywords, doc=doc):

      # ordering of lists (from longest keywords to shortest ones)
      list3 = [keyword[0] for keyword in keywords]
      list2 = [len(item.split()) for item in list3]
      list1 = list(range(len(list2)))
      list2, list1 = (list(t) for t in zip(*sorted(zip(list2, list1))))
      list1 = list1[::-1]
      keywords_list = [list3[idx] for idx in list1]

      # converting doc to html format
      html_doc = doc
      for idx,keyword in enumerate(keywords_list):
        if sum([True if keyword in item else False for item in keywords_list[:idx]]) == 0:
          if keyword not in '<span style="color: black; background-color: yellow; padding:2px">' and keyword not in '</span>':
            html_doc = html_doc.replace(keyword, '<span style="color: black; background-color: yellow; padding:2px">' + keyword + '</span>')
      html_doc = '<p style="font-size:150%; line-height:120%">' + html_doc + '</p>'

      return html_doc

    # function to clean text of document
    doc = clean(doc,
        fix_unicode=True,               # fix various unicode errors
        to_ascii=False,                  # transliterate to closest ASCII representation
        lower=False,                    # lowercase text
        no_line_breaks=True,           # fully strip line breaks as opposed to only normalizing them
        no_urls=False,                  # replace all URLs with a special token
        no_emails=False,                # replace all email addresses with a special token
        no_phone_numbers=False,         # replace all phone numbers with a special token
        no_numbers=False,               # replace all numbers with a special token
        no_digits=False,                # replace all digits with a special token
        no_currency_symbols=False,      # replace all currency symbols with a special token
        no_punct=False,                 # remove punctuations
        replace_with_punct="",          # instead of removing punctuations you may replace them
        replace_with_url="<URL>",
        replace_with_email="<EMAIL>",
        replace_with_phone_number="<PHONE>",
        replace_with_number="<NUMBER>",
        replace_with_digit="0",
        replace_with_currency_symbol="<CUR>",
        lang="pt"                       # set to 'de' for German special handling
    )

    # get keywords and highlighted text
    keywords, keywords_json = get_kw()
    html_doc = get_html(keywords)
    label = f"A palavra/frase chave com a maior probabilidade é: {keywords[0]}"

  return label, keywords_json, html_doc

title = "Extração das key palavras/frases em português"
description = '<p>(17/12/2022) Forneça seu próprio documento em português e o APP vai fazer a extração das palavras/frases chave com as maiores probabilidades de similardide ao texto.\
<br />Segundo você, qual é o melhor modelo?</p>\
<p>Este aplicativo usa os modelos seguintes:\
<br />- <a href="https://huggingface.co/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2">SBERT multilingual</a>,\
<br />- <a href="https://huggingface.co/sentence-transformers/LaBSE">sentence-transformers/LaBSE</a>,\
<br />- <a href="https://huggingface.co/sentence-transformers/distiluse-base-multilingual-cased-v1>DistilBERT mltilingual (v1)</a>,\
<br />- <a href="https://github.com/TimSchopf/KeyphraseVectorizers#keyphrasevectorizers">KeyphraseVectorizers</a> para definir o vetorizador que extrai palavras/frases chave com padrões de parte do texto de um documento.\
<br />- <a href="https://maartengr.github.io/KeyBERT/index.html">KeyBERT</a> para calcular as similaridades entre as palavras/frases chave e o texto do documento.</p>'

doc_original = """
As contas de pelo menos seis jornalistas norte-americanos que cobrem tecnologia foram suspensas pelo Twitter na noite desta quinta-feira (15). Os profissionais escrevem sobre o tema para diversos veículos de comunicação dos Estados Unidos, como os jornais 'The New York Times' e 'Washington Post'.

A rede social afirmou apenas que suspende contas que violam as regras, mas não deu mais detalhes sobre os bloqueios.

Assim que comprou o Twitter, Elon Musk disse defender a liberdade de expressão, e reativou, inclusive, a conta do ex-presidente Donald Trump, suspensa desde o ataque ao Capitólio, em 2021.

Os jornalistas que tiveram as contas bloqueadas questionaram o compromisso de Musk com a liberdade de expressão.

Eles encararam o bloqueio como uma retaliação de Musk às críticas que o bilionário vem recebendo pela forma como está conduzindo a rede social: com demissões em massa e o desmonte de áreas, como o conselho de confiança e segurança da empresa.

Metade dos funcionários do Twitter foram demitidos desde que ele assumiu o comando da empresa e outros mil pediram demissão.
      """

examples = [
    [doc_original.strip()],
]

interface_0 = gr.Interface(
    fn=partial(get_kw_html, 0),
    inputs=[
        gr.Textbox(lines=15, label="Texto do documento"), 
        gr.Slider(1, 20, value=5, label="Número das palavras/frases chave a procurar (padrão: 5)"),
        gr.Slider(0, 1, value=0.2, label="Diversidade entre as palavras/frases chave encontrados (0: mínimo - 1: máximo - padrão: 0,2)")
        ],
    outputs=[
        gr.Textbox(label=f"{model_name[0]}"),
        gr.Label(show_label=False),
        gr.HTML(),
        ]
)

interface_1 = gr.Interface(
    fn=partial(get_kw_html, 1),
    inputs=[
        gr.Textbox(lines=15, label="Texto do documento"), 
        gr.Slider(1, 20, value=5, label="Número das palavras/frases chave a procurar (padrão: 5)"),
        gr.Slider(0, 1, value=0.2, label="Diversidade entre as palavras/frases chave encontrados (0: mínimo - 1: máximo - padrão: 0,2)")
        ],
    outputs=[
        gr.Textbox(label=f"{model_name[1]}"),
        gr.Label(show_label=False),
        gr.HTML(),
        ]
)

interface_2 = gr.Interface(
    fn=partial(get_kw_html, 2),
    inputs=[
        gr.Textbox(lines=15, label="Texto do documento"), 
        gr.Slider(1, 20, value=5, label="Número das palavras/frases chave a procurar (padrão: 5)"),
        gr.Slider(0, 1, value=0.2, label="Diversidade entre as palavras/frases chave encontrados (0: mínimo - 1: máximo - padrão: 0,2)")
        ],
    outputs=[
        gr.Textbox(label=f"{model_name[2]}"),
        gr.Label(show_label=False),
        gr.HTML(),
        ]
)

demo = gr.Parallel(interface_0, interface_1, interface_2,
                   title=title,
                   description=description,
                   examples=examples,
                   allow_flagging="never")

if __name__ == "__main__":
    demo.launch()