|
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 |
|
|
|
|
|
|
|
|
|
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 |
|
} |
|
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
pos_pattern='<CONJ.*>*<ADP.*>*<ADV.*>*<NUM.*>*<ADJ.*>*<N.*>+' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vectorizer = KeyphraseCountVectorizer(spacy_pipeline='pt_core_news_lg', pos_pattern=pos_pattern, stop_words=None, lowercase=False) |
|
|
|
|
|
def get_kw_html(model_id, doc, top_n, diversity): |
|
|
|
|
|
res = detect(text=doc, low_memory=False) |
|
lang = res["lang"] |
|
score = res["score"] |
|
|
|
if len(doc) == 0: |
|
|
|
|
|
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: |
|
|
|
|
|
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: |
|
|
|
|
|
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 |
|
|
|
|
|
def get_html(keywords, doc=doc): |
|
|
|
|
|
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] |
|
|
|
|
|
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 |
|
|
|
|
|
doc = clean(doc, |
|
fix_unicode=True, |
|
to_ascii=False, |
|
lower=False, |
|
no_line_breaks=True, |
|
no_urls=False, |
|
no_emails=False, |
|
no_phone_numbers=False, |
|
no_numbers=False, |
|
no_digits=False, |
|
no_currency_symbols=False, |
|
no_punct=False, |
|
replace_with_punct="", |
|
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" |
|
) |
|
|
|
|
|
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() |