tassid commited on
Commit
26bb094
·
verified ·
1 Parent(s): a17f21d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -121
app.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
- Sistema Avançado de Análise de Sentimentos com Moderação de Conteúdo
3
- Ensemble de 12 modelos + Detecção de discurso de ódio
4
  """
5
 
6
  import gradio as gr
@@ -11,55 +11,76 @@ from collections import Counter
11
  import warnings
12
  warnings.filterwarnings('ignore')
13
 
14
- # Modelos de moderação de conteúdo (verificam ANTES da análise)
15
  MODERATION_MODELS = [
16
- "citizenlab/distilbert-base-multilingual-cased-toxicity", # Toxicidade multilíngue
17
- "unitary/toxic-bert", # Detecção de toxicidade
18
- "martin-ha/toxic-comment-model", # Comentários tóxicos
 
 
19
  ]
20
 
21
- print("Carregando sistema de moderação de conteúdo...")
22
  moderators = []
 
23
 
24
  for model_name in MODERATION_MODELS:
25
  try:
26
- print(f"Carregando moderador: {model_name.split('/')[-1]}...", end=" ")
27
- moderator = pipeline(
28
- "text-classification",
29
- model=model_name,
30
- device=0 if torch.cuda.is_available() else -1
31
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  moderators.append(moderator)
 
33
  print("OK")
 
34
  except Exception as e:
35
- print(f"FALHA")
36
  continue
37
 
38
  print(f"Moderadores ativos: {len(moderators)}")
39
 
40
  # Modelos de análise de sentimentos
41
  SENTIMENT_MODELS = [
42
- # XLM-RoBERTa variants
 
 
 
 
43
  "cardiffnlp/twitter-xlm-roberta-base-sentiment",
44
  "cardiffnlp/twitter-xlm-roberta-base-sentiment-multilingual",
45
  "citizenlab/twitter-xlm-roberta-base-sentiment-finetunned",
46
 
47
- # DistilBERT variants
48
  "lxyuan/distilbert-base-multilingual-cased-sentiments-student",
49
-
50
- # BERT multilingual
51
  "nlptown/bert-base-multilingual-uncased-sentiment",
52
 
53
- # Portuguese-specific (BERTimbau)
54
- "neuralmind/bert-base-portuguese-cased",
55
- "neuralmind/bert-large-portuguese-cased",
56
-
57
- # Additional specialized
58
  "finiteautomata/bertweet-base-sentiment-analysis",
59
  "siebert/sentiment-roberta-large-english",
60
  "distilbert-base-uncased-finetuned-sst-2-english",
61
- "cardiffnlp/twitter-roberta-base-sentiment-latest",
62
- "j-hartmann/emotion-english-distilroberta-base",
63
  ]
64
 
65
  print("\nCarregando modelos de análise de sentimentos...")
@@ -69,7 +90,7 @@ for idx, model_name in enumerate(SENTIMENT_MODELS, 1):
69
  try:
70
  print(f"[{idx}/{len(SENTIMENT_MODELS)}] {model_name.split('/')[-1]}...", end=" ")
71
 
72
- if "neuralmind" in model_name or "emotion" in model_name:
73
  tokenizer = AutoTokenizer.from_pretrained(model_name)
74
  model = AutoModelForSequenceClassification.from_pretrained(model_name)
75
  classifier = pipeline(
@@ -98,8 +119,34 @@ print(f"- Moderadores: {len(moderators)}")
98
  print(f"- Analisadores: {len(classifiers)}")
99
  print(f"{'='*60}\n")
100
 
101
- # Limiar para detecção de conteúdo problemático
102
- TOXICITY_THRESHOLD = 0.6 # Ajustar se necessário (0.0 a 1.0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  # Mapeamento de labels
105
  LABEL_MAPPING = {
@@ -109,77 +156,97 @@ LABEL_MAPPING = {
109
  'LABEL_0': 'Negativo', 'LABEL_1': 'Neutro', 'LABEL_2': 'Positivo',
110
  '1 star': 'Negativo', '2 stars': 'Negativo', '3 stars': 'Neutro',
111
  '4 stars': 'Positivo', '5 stars': 'Positivo',
112
- 'anger': 'Negativo', 'disgust': 'Negativo', 'fear': 'Negativo',
113
- 'sadness': 'Negativo', 'joy': 'Positivo', 'surprise': 'Neutro',
114
- 'neg': 'Negativo', 'neu': 'Neutro', 'pos': 'Positivo',
115
  }
116
 
117
  def verificar_conteudo(texto):
118
  """
119
- Verifica se o texto contém discurso de ódio, racismo, homofobia ou outros conteúdos inadequados.
120
- Retorna: (is_toxic, confidence)
121
  """
122
  if not moderators:
123
- return False, 0.0
 
 
 
 
124
 
125
  scores_toxicos = []
 
126
 
127
- for moderator in moderators:
128
  try:
129
  resultado = moderator(texto[:512])[0]
130
-
131
- # Diferentes modelos usam diferentes labels
132
  label = resultado['label'].lower()
133
  score = resultado['score']
134
 
135
- # Verificar se é tóxico
136
- if 'toxic' in label or 'hate' in label or 'offensive' in label:
137
- scores_toxicos.append(score)
138
- elif 'not' in label or 'neutral' in label:
139
- scores_toxicos.append(1 - score)
140
  else:
141
- # Label inesperado, usar score direto
142
- scores_toxicos.append(score)
143
-
144
- except Exception as e:
 
 
145
  continue
146
 
147
  if not scores_toxicos:
148
- return False, 0.0
 
 
 
 
149
 
150
- # Média dos scores de toxicidade
151
  toxicity_score = np.mean(scores_toxicos)
 
 
 
 
 
 
152
  is_toxic = toxicity_score > TOXICITY_THRESHOLD
153
 
154
- return is_toxic, toxicity_score
155
 
156
  def normalizar_label(label):
157
- """Normaliza diferentes formatos de labels"""
158
  label_upper = label.upper() if isinstance(label, str) else str(label)
159
  return LABEL_MAPPING.get(label, LABEL_MAPPING.get(label_upper, 'Neutro'))
160
 
161
  def analisar_texto(texto):
162
  """
163
- Análise com moderação de conteúdo.
164
- Verifica discurso de ódio ANTES de analisar sentimento.
165
  """
166
 
167
  if not texto or len(texto.strip()) < 3:
168
- return "Aguardando entrada válida", {}, "-", "-", "-"
169
 
170
- # PASSO 1: MODERAÇÃO DE CONTEÚDO
171
- is_toxic, toxicity_score = verificar_conteudo(texto)
172
 
173
  if is_toxic:
174
- mensagem_recusa = (
175
- "**Conteúdo Inadequado Detectado**\n\n"
176
- "Este sistema não processa textos que contenham:\n"
177
- "- Discurso de ódio\n"
178
- "- Racismo\n"
179
- "- Homofobia\n"
180
- "- Conteúdo ofensivo ou discriminatório\n\n"
181
- "Por favor, revise o texto e tente novamente com conteúdo respeitoso."
182
- )
 
 
 
 
 
 
183
 
184
  info_moderacao = {
185
  'Inadequado': toxicity_score,
@@ -188,7 +255,7 @@ def analisar_texto(texto):
188
 
189
  return mensagem_recusa, info_moderacao, f"{toxicity_score:.1%}", "Bloqueado", "Moderação"
190
 
191
- # PASSO 2: ANÁLISE DE SENTIMENTO (só se passar na moderação)
192
  texto_processado = texto[:512]
193
  predicoes = []
194
  scores_por_classe = {
@@ -208,7 +275,6 @@ def analisar_texto(texto):
208
  predicoes.append(label_norm)
209
  modelos_usados += 1
210
 
211
- # Distribuir probabilidades
212
  if label_norm == 'Negativo':
213
  scores_por_classe['Negativo'].append(score)
214
  scores_por_classe['Neutro'].append((1-score) * 0.3)
@@ -228,7 +294,7 @@ def analisar_texto(texto):
228
  if not predicoes or modelos_usados == 0:
229
  return "Erro no processamento", {}, "-", "-", "-"
230
 
231
- # Voting majoritário
232
  contagem = Counter(predicoes)
233
  classificacao = contagem.most_common(1)[0][0]
234
  votos = contagem[classificacao]
@@ -245,40 +311,37 @@ def analisar_texto(texto):
245
  scores_final = scores_por_classe[classificacao]
246
  if len(scores_final) > 1:
247
  desvio = np.std(scores_final)
248
- consistencia = 1 - desvio
249
- nivel = "Alta" if consistencia > 0.8 else "Média" if consistencia > 0.6 else "Baixa"
250
  else:
251
  desvio = 0
252
  nivel = "N/A"
253
 
254
- # Outputs
255
  resultado_texto = f"{classificacao}"
256
  confianca_texto = f"{confianca:.1%}"
257
- consenso_texto = f"{votos}/{modelos_usados} ({(votos/modelos_usados)*100:.0f}%)"
258
  consistencia_texto = f"{nivel} (σ={desvio:.3f})" if desvio > 0 else "N/A"
259
 
260
  return resultado_texto, probs, confianca_texto, consenso_texto, consistencia_texto
261
 
262
  # Casos de teste
263
  casos_teste = [
264
- ["Produto excepcional. Qualidade superior e entrega dentro do prazo."],
265
- ["Experiência negativa. Produto defeituoso e atendimento inadequado."],
266
- ["Atende as especificações básicas. Desempenho dentro do esperado."],
267
- ["Recomendo fortemente. Excelente relação custo-benefício."],
268
- ["Performance satisfatória. Funcionalidades adequadas ao uso proposto."],
269
  ]
270
 
271
  # Interface
272
- with gr.Blocks(title="Sistema de Análise com Moderação") as demo:
273
 
274
  gr.Markdown(
275
  f"""
276
- # Sistema de Análise de Sentimentos com Moderação de Conteúdo
277
 
278
- Ensemble de {len(classifiers)} modelos de análise com {len(moderators)} moderadores de conteúdo.
279
 
280
- **Sistema de proteção:** Detecta e bloqueia automaticamente conteúdo com discurso de ódio,
281
- racismo, homofobia e outros tipos de discriminação.
282
  """
283
  )
284
 
@@ -286,20 +349,20 @@ with gr.Blocks(title="Sistema de Análise com Moderação") as demo:
286
  with gr.Column():
287
  texto_input = gr.Textbox(
288
  label="Texto para Análise",
289
- placeholder="Insira o texto (até 512 caracteres)...",
290
  lines=5,
291
  max_lines=10
292
  )
293
 
294
  with gr.Row():
295
- btn_analisar = gr.Button("Processar", variant="primary", size="lg")
296
  btn_limpar = gr.Button("Limpar", size="lg")
297
 
298
  with gr.Row():
299
  with gr.Column(scale=1):
300
- resultado_output = gr.Markdown(label="Resultado")
301
- confianca_output = gr.Textbox(label="Confiança", interactive=False)
302
- consenso_output = gr.Textbox(label="Consenso", interactive=False)
303
  consistencia_output = gr.Textbox(label="Consistência", interactive=False)
304
 
305
  with gr.Column(scale=1):
@@ -321,63 +384,66 @@ with gr.Blocks(title="Sistema de Análise com Moderação") as demo:
321
  gr.Markdown(
322
  f"""
323
  ---
324
- ## Especificações do Sistema
325
 
326
  ### Moderação de Conteúdo
327
 
328
- O sistema verifica automaticamente:
329
- - Discurso de ódio
330
- - Racismo e discriminação racial
331
- - Homofobia e LGBTfobia
332
- - Sexismo e misoginia
333
- - Xenofobia
334
- - Outros conteúdos ofensivos ou discriminatórios
335
 
336
- **Ação:** Textos detectados como inadequados são bloqueados e não passam pela análise de sentimentos.
337
 
338
- **Limiar de Detecção:** {TOXICITY_THRESHOLD*100:.0f}% (ajustável)
339
 
340
  ### Análise de Sentimentos
341
 
342
- **Modelos Ativos:** {len(classifiers)} / {len(SENTIMENT_MODELS)}
343
- **Moderadores Ativos:** {len(moderators)} / {len(MODERATION_MODELS)}
344
- **Arquitetura:** Ensemble com voting majoritário
345
  **Classes:** Negativo, Neutro, Positivo
346
- **Limite:** 512 caracteres
347
 
348
  ### Fluxo de Processamento
349
 
350
- 1. **Recebimento:** Sistema recebe o texto
351
- 2. **Moderação:** Verificação de conteúdo inadequado
352
- 3. **Bloqueio:** Se inadequado, interrompe e informa
353
- 4. **Análise:** Se adequado, processa com ensemble
354
- 5. **Resultado:** Retorna classificação e métricas
355
 
356
- ### Modelos de Moderação
357
 
358
- - DistilBERT Toxicity (CitizenLab) - Multilíngue
359
- - Toxic-BERT (Unitary)
360
- - Toxic Comment Model (Martin-HA)
 
 
361
 
362
- ### Modelos de Análise
 
 
 
 
363
 
364
- - XLM-RoBERTa (3 variantes)
365
- - BERTimbau (2 variantes - PT-BR)
366
- - DistilBERT Multilingual
367
- - BERT Multilingual
368
- - RoBERTa (4 variantes)
369
- - Outros especializados
370
 
371
- ### Política de Uso
 
372
 
373
- Este sistema foi desenvolvido para análise de sentimentos em conteúdos respeitosos.
374
- Não tolera e não processa conteúdo que promova ódio, discriminação ou violência.
 
375
 
376
- **Compromisso:** Promover análise técnica mantendo respeito e dignidade humana.
 
377
  """
378
  )
379
 
380
- # Eventos
381
  btn_analisar.click(
382
  fn=analisar_texto,
383
  inputs=texto_input,
 
1
  """
2
+ Sistema Avançado de Análise de Sentimentos com Moderação em Português
3
+ Ensemble de modelos + Detecção de discurso de ódio em PT-BR
4
  """
5
 
6
  import gradio as gr
 
11
  import warnings
12
  warnings.filterwarnings('ignore')
13
 
14
+ # Modelos de moderação ESPECÍFICOS para PORTUGUÊS
15
  MODERATION_MODELS = [
16
+ # Modelos brasileiros de detecção de ódio
17
+ "citizenlab/distilbert-base-multilingual-cased-toxicity", # Multilíngue mas funciona bem em PT
18
+ "francisco-perez-sorrosal/distilbert-base-uncased-finetuned-with-hateoffensive",
19
+ "Hate-speech-CNERG/dehatebert-mono-portuguese", # Específico PT!
20
+ "neuralmind/bert-base-portuguese-cased", # BERTimbau adaptado
21
  ]
22
 
23
+ print("Carregando sistema de moderação em português...")
24
  moderators = []
25
+ moderator_names = []
26
 
27
  for model_name in MODERATION_MODELS:
28
  try:
29
+ print(f"Carregando: {model_name.split('/')[-1]}...", end=" ")
30
+
31
+ # Carregar com configuração específica
32
+ if "dehatebert" in model_name:
33
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
34
+ model = AutoModelForSequenceClassification.from_pretrained(model_name)
35
+ moderator = pipeline(
36
+ "text-classification",
37
+ model=model,
38
+ tokenizer=tokenizer,
39
+ device=0 if torch.cuda.is_available() else -1
40
+ )
41
+ elif "neuralmind" in model_name:
42
+ # BERTimbau precisa ser adaptado para classificação
43
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
44
+ # Usar modelo base e adaptar
45
+ moderator = None # Pular por enquanto, precisa fine-tuning específico
46
+ print("PULADO (precisa adaptação)")
47
+ continue
48
+ else:
49
+ moderator = pipeline(
50
+ "text-classification",
51
+ model=model_name,
52
+ device=0 if torch.cuda.is_available() else -1
53
+ )
54
+
55
  moderators.append(moderator)
56
+ moderator_names.append(model_name.split('/')[-1])
57
  print("OK")
58
+
59
  except Exception as e:
60
+ print(f"FALHA ({str(e)[:40]}...)")
61
  continue
62
 
63
  print(f"Moderadores ativos: {len(moderators)}")
64
 
65
  # Modelos de análise de sentimentos
66
  SENTIMENT_MODELS = [
67
+ # Modelos em português prioritários
68
+ "neuralmind/bert-base-portuguese-cased",
69
+ "neuralmind/bert-large-portuguese-cased",
70
+
71
+ # XLM-RoBERTa (excelentes para PT)
72
  "cardiffnlp/twitter-xlm-roberta-base-sentiment",
73
  "cardiffnlp/twitter-xlm-roberta-base-sentiment-multilingual",
74
  "citizenlab/twitter-xlm-roberta-base-sentiment-finetunned",
75
 
76
+ # Multilíngues
77
  "lxyuan/distilbert-base-multilingual-cased-sentiments-student",
 
 
78
  "nlptown/bert-base-multilingual-uncased-sentiment",
79
 
80
+ # Modelos adicionais
 
 
 
 
81
  "finiteautomata/bertweet-base-sentiment-analysis",
82
  "siebert/sentiment-roberta-large-english",
83
  "distilbert-base-uncased-finetuned-sst-2-english",
 
 
84
  ]
85
 
86
  print("\nCarregando modelos de análise de sentimentos...")
 
90
  try:
91
  print(f"[{idx}/{len(SENTIMENT_MODELS)}] {model_name.split('/')[-1]}...", end=" ")
92
 
93
+ if "neuralmind" in model_name:
94
  tokenizer = AutoTokenizer.from_pretrained(model_name)
95
  model = AutoModelForSequenceClassification.from_pretrained(model_name)
96
  classifier = pipeline(
 
119
  print(f"- Analisadores: {len(classifiers)}")
120
  print(f"{'='*60}\n")
121
 
122
+ # Limiar para detecção
123
+ TOXICITY_THRESHOLD = 0.65
124
+
125
+ # Palavras-chave de alerta (backup em português)
126
+ PALAVRAS_ALERTA = [
127
+ # Racismo
128
+ 'preto', 'negro', 'macaco', 'escuro',
129
+ # Homofobia
130
+ 'gay', 'viado', 'bicha', 'sapatao',
131
+ # Sexismo
132
+ 'vadia', 'puta', 'vagabunda',
133
+ # Xenofobia
134
+ 'nordestino', 'baiano', 'paraiba',
135
+ # Outros
136
+ 'lixo', 'merda', 'idiota', 'burro'
137
+ ]
138
+
139
+ def verificar_palavras_suspeitas(texto):
140
+ """
141
+ Verificação adicional por palavras-chave (backup)
142
+ Retorna número de palavras suspeitas encontradas
143
+ """
144
+ texto_lower = texto.lower()
145
+ count = 0
146
+ for palavra in PALAVRAS_ALERTA:
147
+ if palavra in texto_lower:
148
+ count += 1
149
+ return count
150
 
151
  # Mapeamento de labels
152
  LABEL_MAPPING = {
 
156
  'LABEL_0': 'Negativo', 'LABEL_1': 'Neutro', 'LABEL_2': 'Positivo',
157
  '1 star': 'Negativo', '2 stars': 'Negativo', '3 stars': 'Neutro',
158
  '4 stars': 'Positivo', '5 stars': 'Positivo',
159
+ # Labels específicos de hate speech
160
+ 'hate': 'Tóxico', 'offensive': 'Tóxico', 'toxic': 'Tóxico',
161
+ 'NOT': 'Normal', 'normal': 'Normal', 'neutral': 'Normal',
162
  }
163
 
164
  def verificar_conteudo(texto):
165
  """
166
+ Verifica conteúdo inadequado usando modelos + palavras-chave
167
+ Retorna: (is_toxic, confidence, details)
168
  """
169
  if not moderators:
170
+ # Fallback: verificação por palavras-chave
171
+ palavras_suspeitas = verificar_palavras_suspeitas(texto)
172
+ if palavras_suspeitas >= 2:
173
+ return True, 0.75, "Detecção por palavras-chave"
174
+ return False, 0.0, "Sem moderadores ativos"
175
 
176
  scores_toxicos = []
177
+ detalhes = []
178
 
179
+ for idx, moderator in enumerate(moderators):
180
  try:
181
  resultado = moderator(texto[:512])[0]
 
 
182
  label = resultado['label'].lower()
183
  score = resultado['score']
184
 
185
+ # Interpretar resultado
186
+ is_toxic_label = any(word in label for word in ['toxic', 'hate', 'offensive', 'negative'])
187
+
188
+ if is_toxic_label:
189
+ toxicity = score
190
  else:
191
+ toxicity = 1 - score
192
+
193
+ scores_toxicos.append(toxicity)
194
+ detalhes.append(f"Modelo {idx+1}: {toxicity:.1%}")
195
+
196
+ except:
197
  continue
198
 
199
  if not scores_toxicos:
200
+ # Fallback para palavras-chave
201
+ palavras_suspeitas = verificar_palavras_suspeitas(texto)
202
+ if palavras_suspeitas >= 2:
203
+ return True, 0.75, "Detecção por palavras-chave"
204
+ return False, 0.0, "Erro na moderação"
205
 
206
+ # Média dos scores
207
  toxicity_score = np.mean(scores_toxicos)
208
+
209
+ # Verificação adicional por palavras
210
+ palavras_suspeitas = verificar_palavras_suspeitas(texto)
211
+ if palavras_suspeitas >= 3:
212
+ toxicity_score = max(toxicity_score, 0.8)
213
+
214
  is_toxic = toxicity_score > TOXICITY_THRESHOLD
215
 
216
+ return is_toxic, toxicity_score, " | ".join(detalhes)
217
 
218
  def normalizar_label(label):
219
+ """Normaliza labels"""
220
  label_upper = label.upper() if isinstance(label, str) else str(label)
221
  return LABEL_MAPPING.get(label, LABEL_MAPPING.get(label_upper, 'Neutro'))
222
 
223
  def analisar_texto(texto):
224
  """
225
+ Análise com moderação em português
 
226
  """
227
 
228
  if not texto or len(texto.strip()) < 3:
229
+ return "Aguardando texto para análise", {}, "-", "-", "-"
230
 
231
+ # MODERAÇÃO
232
+ is_toxic, toxicity_score, detalhes_mod = verificar_conteudo(texto)
233
 
234
  if is_toxic:
235
+ mensagem_recusa = f"""
236
+ **⚠️ Conteúdo Inadequado Detectado**
237
+
238
+ Este sistema não analisa textos que contenham:
239
+ Discurso de ódio
240
+ Racismo ou discriminação racial
241
+ Homofobia ou LGBTfobia
242
+ Sexismo ou misoginia
243
+ • Xenofobia
244
+ • Linguagem ofensiva ou discriminatória
245
+
246
+ **Por favor, reformule o texto de forma respeitosa.**
247
+
248
+ *Nível de inadequação detectado: {toxicity_score:.1%}*
249
+ """
250
 
251
  info_moderacao = {
252
  'Inadequado': toxicity_score,
 
255
 
256
  return mensagem_recusa, info_moderacao, f"{toxicity_score:.1%}", "Bloqueado", "Moderação"
257
 
258
+ # ANÁLISE DE SENTIMENTO
259
  texto_processado = texto[:512]
260
  predicoes = []
261
  scores_por_classe = {
 
275
  predicoes.append(label_norm)
276
  modelos_usados += 1
277
 
 
278
  if label_norm == 'Negativo':
279
  scores_por_classe['Negativo'].append(score)
280
  scores_por_classe['Neutro'].append((1-score) * 0.3)
 
294
  if not predicoes or modelos_usados == 0:
295
  return "Erro no processamento", {}, "-", "-", "-"
296
 
297
+ # Voting
298
  contagem = Counter(predicoes)
299
  classificacao = contagem.most_common(1)[0][0]
300
  votos = contagem[classificacao]
 
311
  scores_final = scores_por_classe[classificacao]
312
  if len(scores_final) > 1:
313
  desvio = np.std(scores_final)
314
+ nivel = "Alta" if desvio < 0.1 else "Média" if desvio < 0.2 else "Baixa"
 
315
  else:
316
  desvio = 0
317
  nivel = "N/A"
318
 
 
319
  resultado_texto = f"{classificacao}"
320
  confianca_texto = f"{confianca:.1%}"
321
+ consenso_texto = f"{votos}/{modelos_usados} modelos ({(votos/modelos_usados)*100:.0f}%)"
322
  consistencia_texto = f"{nivel} (σ={desvio:.3f})" if desvio > 0 else "N/A"
323
 
324
  return resultado_texto, probs, confianca_texto, consenso_texto, consistencia_texto
325
 
326
  # Casos de teste
327
  casos_teste = [
328
+ ["Este produto superou minhas expectativas. Qualidade excelente e entrega rápida."],
329
+ ["Experiência muito negativa. O produto apresentou defeitos e o atendimento foi inadequado."],
330
+ ["Produto atende o esperado. Funcionalidades básicas dentro do padrão da categoria."],
331
+ ["Recomendo fortemente. Excelente custo-benefício e durabilidade comprovada."],
332
+ ["Satisfatório. Cumpre o prometido sem grandes destaques."],
333
  ]
334
 
335
  # Interface
336
+ with gr.Blocks(title="Análise de Sentimentos") as demo:
337
 
338
  gr.Markdown(
339
  f"""
340
+ # Sistema de Análise de Sentimentos com Moderação
341
 
342
+ Análise por ensemble de {len(classifiers)} modelos com moderação de conteúdo em português.
343
 
344
+ **Sistema de proteção:** Detecta automaticamente discurso de ódio, racismo, homofobia e conteúdo discriminatório.
 
345
  """
346
  )
347
 
 
349
  with gr.Column():
350
  texto_input = gr.Textbox(
351
  label="Texto para Análise",
352
+ placeholder="Digite ou cole o texto aqui (até 512 caracteres)...",
353
  lines=5,
354
  max_lines=10
355
  )
356
 
357
  with gr.Row():
358
+ btn_analisar = gr.Button("Analisar", variant="primary", size="lg")
359
  btn_limpar = gr.Button("Limpar", size="lg")
360
 
361
  with gr.Row():
362
  with gr.Column(scale=1):
363
+ resultado_output = gr.Markdown(label="Classificação")
364
+ confianca_output = gr.Textbox(label="Nível de Confiança", interactive=False)
365
+ consenso_output = gr.Textbox(label="Consenso entre Modelos", interactive=False)
366
  consistencia_output = gr.Textbox(label="Consistência", interactive=False)
367
 
368
  with gr.Column(scale=1):
 
384
  gr.Markdown(
385
  f"""
386
  ---
387
+ ## Sobre o Sistema
388
 
389
  ### Moderação de Conteúdo
390
 
391
+ O sistema verifica automaticamente e bloqueia:
392
+ Discurso de ódio e intolerância
393
+ Racismo e discriminação racial
394
+ Homofobia e LGBTfobia
395
+ Sexismo e misoginia
396
+ Xenofobia e regionalismo
397
+ Linguagem ofensiva ou discriminatória
398
 
399
+ **Método:** Ensemble de modelos especializados + verificação por palavras-chave
400
 
401
+ **Limiar:** {TOXICITY_THRESHOLD*100:.0f}% de confiança para bloqueio
402
 
403
  ### Análise de Sentimentos
404
 
405
+ **Modelos Ativos:** {len(classifiers)}
406
+ **Moderadores Ativos:** {len(moderators)}
407
+ **Método:** Voting majoritário com agregação probabilística
408
  **Classes:** Negativo, Neutro, Positivo
409
+ **Idioma Principal:** Português Brasileiro
410
 
411
  ### Fluxo de Processamento
412
 
413
+ 1. **Recepção** do texto
414
+ 2. **Moderação** por modelos especializados
415
+ 3. **Verificação adicional** por palavras-chave
416
+ 4. **Bloqueio** se inadequado ou **Análise** se adequado
417
+ 5. **Resultado** com métricas de qualidade
418
 
419
+ ### Modelos Utilizados
420
 
421
+ **Moderação em Português:**
422
+ - DistilBERT Toxicity Multilingual
423
+ - HateOffensive Detection
424
+ - DeHateBERT Portuguese
425
+ - Verificação por palavras-chave em PT-BR
426
 
427
+ **Análise de Sentimentos:**
428
+ - BERTimbau (2 variantes) - Português BR
429
+ - XLM-RoBERTa (3 variantes) - Multilíngue
430
+ - BERT e DistilBERT Multilingual
431
+ - Modelos especializados adicionais
432
 
433
+ ### Política de Uso Responsável
 
 
 
 
 
434
 
435
+ Este sistema foi desenvolvido para análise técnica de sentimentos em conteúdos respeitosos.
436
+ Não tolera e não processa qualquer forma de discriminação ou discurso de ódio.
437
 
438
+ **Compromisso:** Promover análise técnica mantendo respeito à dignidade humana e aos direitos fundamentais.
439
+
440
+ ---
441
 
442
+ **Nota Técnica:** O sistema utiliza múltiplas camadas de verificação para maximizar
443
+ a detecção de conteúdo inadequado, incluindo modelos de IA e verificação por padrões linguísticos.
444
  """
445
  )
446
 
 
447
  btn_analisar.click(
448
  fn=analisar_texto,
449
  inputs=texto_input,