tassid commited on
Commit
fc1df2d
·
verified ·
1 Parent(s): bf12cf9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -135
app.py CHANGED
@@ -1,178 +1,158 @@
1
  """
2
- Versão Gradio para Hugging Face Spaces
 
3
  """
4
 
5
  import gradio as gr
6
  import torch
7
- from transformers import AutoTokenizer, AutoModelForSequenceClassification
8
  import numpy as np
 
9
 
10
- # Configuração
11
- MODEL_NAME = "lxyuan/distilbert-base-multilingual-cased-sentiments-student"
 
 
 
 
 
 
12
 
13
- # Carregar modelo
14
- print("Carregando modelo...")
15
- tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
16
- model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
17
- model.eval()
18
- print("Modelo carregado com sucesso!")
19
 
20
- # Labels
21
- LABEL_MAP = {
22
- 0: "NEGATIVO",
23
- 1: "NEUTRO",
24
- 2: "POSITIVO"
25
- }
 
 
 
26
 
27
- EMOJI_MAP = {
28
- "NEGATIVO": "😢",
29
- "NEUTRO": "😐",
30
- "POSITIVO": "😊"
 
 
 
 
31
  }
32
 
33
- def classificar_sentimento(texto):
34
- """
35
- Classifica o sentimento do texto.
36
- """
37
  if not texto or len(texto.strip()) < 3:
38
- return "Por favor, digite um texto válido.", {}, 0.0
39
 
40
- # Tokenizar
41
- inputs = tokenizer(
42
- texto,
43
- padding=True,
44
- truncation=True,
45
- max_length=512,
46
- return_tensors='pt'
47
- )
48
 
49
- # Predição
50
- with torch.no_grad():
51
- outputs = model(**inputs)
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- # Probabilidades
54
- probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
55
- probs = probs.numpy()[0]
56
 
57
- # Resultado
58
- pred_class = int(np.argmax(probs))
59
- sentimento = LABEL_MAP[pred_class]
60
- confianca = float(np.max(probs))
61
 
62
- # Criar dicionário de probabilidades para o Label
63
- prob_dict = {
64
- f"{EMOJI_MAP[LABEL_MAP[i]]} {LABEL_MAP[i]}": float(probs[i])
65
- for i in range(len(probs))
66
- }
67
 
68
- # Resultado principal
69
- resultado = f"{EMOJI_MAP[sentimento]} **{sentimento}**"
70
 
71
- return resultado, prob_dict, confianca
72
 
73
- # Exemplos
74
- exemplos = [
75
- ["Adorei o produto! Superou minhas expectativas."],
76
- ["Péssimo atendimento, nunca mais volto."],
77
- ["Ok, nada de especial."],
78
- ["O filme é sensacional! Recomendo muito!"],
79
- ["Horrível! Pior experiência da minha vida."],
80
- ["Satisfeito com a compra, chegou rápido."],
81
  ]
82
 
83
- # Interface Gradio
84
- with gr.Blocks(title="Análise de Sentimentos") as demo:
85
- gr.Markdown(
86
- """
87
- # 🤖 Análise de Sentimentos com IA
88
-
89
- Descubra o sentimento por trás do texto usando modelos Transformer!
90
-
91
- Digite ou cole um texto e descubra se é **positivo**, **negativo** ou **neutro**.
92
- """
93
- )
94
 
95
  with gr.Row():
96
- with gr.Column(scale=2):
97
- texto_input = gr.Textbox(
98
- label="📝 Digite seu texto aqui",
99
- placeholder="Ex: Adorei o produto! Superou todas as minhas expectativas...",
100
- lines=5,
101
- max_lines=10
102
- )
103
-
104
- with gr.Row():
105
- btn_analisar = gr.Button("🔍 Analisar Sentimento", variant="primary")
106
- btn_limpar = gr.Button("🗑️ Limpar")
107
 
108
  with gr.Row():
109
- with gr.Column(scale=1):
110
- resultado_output = gr.Markdown(
111
- label="Resultado",
112
- value=""
113
- )
114
-
115
- confianca_output = gr.Number(
116
- label="📊 Confiança"
117
- )
118
 
119
- with gr.Column(scale=1):
120
- probs_output = gr.Label(
121
- label="📈 Distribuição de Probabilidades",
122
- num_top_classes=3
123
- )
124
 
125
- gr.Markdown("### 💡 Exemplos para testar:")
126
  gr.Examples(
127
- examples=exemplos,
128
- inputs=texto_input,
129
- outputs=[resultado_output, probs_output, confianca_output],
130
- fn=classificar_sentimento,
131
- cache_examples=False
132
  )
133
 
134
  gr.Markdown(
135
  """
136
  ---
137
- ### 📚 Sobre o Modelo
138
-
139
- Este sistema usa modelos **Transformer** treinados em milhares de textos em português.
140
 
141
- **Características:**
142
- - Análise em tempo real
143
- - Suporte para português brasileiro
144
- - Alta precisão
145
- - ✅ Múltiplas classes (Positivo, Neutro, Negativo)
146
 
147
- **Limitações:**
148
- - Textos muito longos são truncados
149
- - Sarcasmo pode ser difícil de detectar
150
- - Contexto cultural pode afetar resultados
151
-
152
- ---
153
- **Feito com ❤️ usando Transformers e Gradio**
154
  """
155
  )
156
 
157
- # Eventos
158
- btn_analisar.click(
159
- fn=classificar_sentimento,
160
- inputs=texto_input,
161
- outputs=[resultado_output, probs_output, confianca_output]
162
- )
163
-
164
- btn_limpar.click(
165
- fn=lambda: ("", "", {}, 0.0),
166
- inputs=None,
167
- outputs=[texto_input, resultado_output, probs_output, confianca_output]
168
- )
169
-
170
- texto_input.submit(
171
- fn=classificar_sentimento,
172
- inputs=texto_input,
173
- outputs=[resultado_output, probs_output, confianca_output]
174
- )
175
 
176
- # Iniciar
177
  if __name__ == "__main__":
178
  demo.launch()
 
1
  """
2
+ Sistema de Análise de Sentimentos - Ensemble de Modelos
3
+ Desenvolvido para classificação de textos em português
4
  """
5
 
6
  import gradio as gr
7
  import torch
8
+ from transformers import pipeline
9
  import numpy as np
10
+ from collections import Counter
11
 
12
+ # Modelos selecionados para português
13
+ MODELS = [
14
+ "cardiffnlp/twitter-xlm-roberta-base-sentiment",
15
+ "lxyuan/distilbert-base-multilingual-cased-sentiments-student",
16
+ "nlptown/bert-base-multilingual-uncased-sentiment",
17
+ "citizenlab/twitter-xlm-roberta-base-sentiment-finetunned",
18
+ "cardiffnlp/twitter-xlm-roberta-base-sentiment-multilingual"
19
+ ]
20
 
21
+ print("Inicializando modelos...")
22
+ classifiers = []
 
 
 
 
23
 
24
+ for model_name in MODELS:
25
+ try:
26
+ classifier = pipeline("sentiment-analysis", model=model_name, device=0 if torch.cuda.is_available() else -1)
27
+ classifiers.append(classifier)
28
+ print(f"OK: {model_name.split('/')[-1]}")
29
+ except:
30
+ print(f"Falha: {model_name.split('/')[-1]}")
31
+
32
+ print(f"{len(classifiers)} modelos ativos")
33
 
34
+ # Padronização de labels
35
+ LABEL_MAP = {
36
+ 'NEGATIVE': 'Negativo', 'negative': 'Negativo', 'NEG': 'Negativo',
37
+ 'NEUTRAL': 'Neutro', 'neutral': 'Neutro', 'NEU': 'Neutro',
38
+ 'POSITIVE': 'Positivo', 'positive': 'Positivo', 'POS': 'Positivo',
39
+ '1 star': 'Negativo', '2 stars': 'Negativo',
40
+ '3 stars': 'Neutro',
41
+ '4 stars': 'Positivo', '5 stars': 'Positivo',
42
  }
43
 
44
+ def processar(texto):
45
+ """Classifica texto usando ensemble de modelos"""
46
+
 
47
  if not texto or len(texto.strip()) < 3:
48
+ return "Aguardando entrada", {}, "-", "-"
49
 
50
+ texto = texto[:500]
51
+ predicoes = []
52
+ scores = {'Negativo': [], 'Neutro': [], 'Positivo': []}
 
 
 
 
 
53
 
54
+ for clf in classifiers:
55
+ try:
56
+ result = clf(texto)[0]
57
+ label = LABEL_MAP.get(result['label'], result['label'])
58
+ score = result['score']
59
+
60
+ predicoes.append(label)
61
+
62
+ # Distribuição de scores
63
+ for classe in scores.keys():
64
+ if classe == label:
65
+ scores[classe].append(score)
66
+ else:
67
+ scores[classe].append((1-score)/(len(scores)-1))
68
+ except:
69
+ continue
70
 
71
+ if not predicoes:
72
+ return "Erro no processamento", {}, "-", "-"
 
73
 
74
+ # Resultado por voting
75
+ contagem = Counter(predicoes)
76
+ resultado = contagem.most_common(1)[0][0]
77
+ votos = contagem[resultado]
78
 
79
+ # Probabilidades
80
+ probs = {k: np.mean(v) if v else 0 for k, v in scores.items()}
81
+ total = sum(probs.values())
82
+ if total > 0:
83
+ probs = {k: v/total for k, v in probs.items()}
84
 
85
+ confianca = probs[resultado]
86
+ info = f"{votos}/{len(predicoes)} modelos"
87
 
88
+ return resultado, probs, f"{confianca:.2%}", info
89
 
90
+ # Casos de teste
91
+ casos = [
92
+ ["Produto de qualidade superior. Recomendo para uso profissional."],
93
+ ["Apresenta defeitos graves. Não atende especificações mínimas."],
94
+ ["Desempenho adequado. Corresponde à descrição do fabricante."],
95
+ ["Excelente custo-benefício. Entrega conforme prometido."],
96
+ ["Qualidade inferior ao esperado. Necessita melhorias significativas."],
 
97
  ]
98
 
99
+ # Interface
100
+ demo = gr.Blocks(title="Análise de Sentimentos")
101
+
102
+ with demo:
103
+ gr.Markdown("# Sistema de Análise de Sentimentos")
104
+ gr.Markdown("Classificação automática usando ensemble de modelos Transformer")
 
 
 
 
 
105
 
106
  with gr.Row():
107
+ entrada = gr.Textbox(
108
+ label="Texto",
109
+ placeholder="Insira o texto para análise",
110
+ lines=4
111
+ )
 
 
 
 
 
 
112
 
113
  with gr.Row():
114
+ btn_proc = gr.Button("Processar", variant="primary")
115
+ btn_limp = gr.Button("Limpar")
116
+
117
+ with gr.Row():
118
+ with gr.Column():
119
+ resultado = gr.Textbox(label="Classificação")
120
+ confianca = gr.Textbox(label="Confiança")
121
+ info = gr.Textbox(label="Consenso")
 
122
 
123
+ with gr.Column():
124
+ probs = gr.Label(label="Probabilidades")
 
 
 
125
 
126
+ gr.Markdown("### Casos de Teste")
127
  gr.Examples(
128
+ examples=casos,
129
+ inputs=entrada,
130
+ outputs=[resultado, probs, confianca, info],
131
+ fn=processar
 
132
  )
133
 
134
  gr.Markdown(
135
  """
136
  ---
137
+ **Especificações Técnicas**
 
 
138
 
139
+ Método: Ensemble voting com 5 modelos Transformer
140
+ Idioma: Português (BR/PT)
141
+ Classes: Negativo, Neutro, Positivo
142
+ Limite: 500 caracteres por texto
 
143
 
144
+ Modelos utilizados:
145
+ - XLM-RoBERTa (Cardiff NLP)
146
+ - DistilBERT Multilingual
147
+ - BERT Multilingual (NLP Town)
148
+ - XLM-RoBERTa Fine-tuned (CitizenLab)
149
+ - XLM-RoBERTa Multilingual (Cardiff NLP)
 
150
  """
151
  )
152
 
153
+ btn_proc.click(fn=processar, inputs=entrada, outputs=[resultado, probs, confianca, info])
154
+ btn_limp.click(fn=lambda: ("", "", "", "", {}), outputs=[entrada, resultado, confianca, info, probs])
155
+ entrada.submit(fn=processar, inputs=entrada, outputs=[resultado, probs, confianca, info])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
 
157
  if __name__ == "__main__":
158
  demo.launch()