HenriqueBraz commited on
Commit
7302bef
·
verified ·
1 Parent(s): bbec95e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +204 -187
app.py CHANGED
@@ -2,6 +2,9 @@ import streamlit as st
2
  import streamlit_authenticator as stauth
3
  import sqlite3
4
  import os
 
 
 
5
  from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
6
  import torch
7
  from PIL import Image
@@ -12,6 +15,8 @@ import logging
12
  import tempfile
13
  from streamlit.runtime.uploaded_file_manager import UploadedFile
14
  from diffusers import StableDiffusionPipeline
 
 
15
 
16
  # Configurar página
17
  st.set_page_config(
@@ -20,43 +25,42 @@ st.set_page_config(
20
  layout="wide"
21
  )
22
 
23
- # Configurar logging
 
24
  logging.basicConfig(
25
- filename='app_errors.log',
26
  level=logging.ERROR,
27
  format='%(asctime)s - %(levelname)s - %(message)s'
28
  )
29
 
30
- # Configurar banco de dados SQLite
31
  def init_db():
32
  """Inicializa o banco de dados SQLite com tabela de usuários"""
33
- db_path = os.getenv('DB_PATH', 'users.db')
 
34
  conn = sqlite3.connect(db_path)
35
  cursor = conn.cursor()
36
 
37
- # Criar tabela de usuários se não existir
38
  cursor.execute('''
39
  CREATE TABLE IF NOT EXISTS users (
40
  username TEXT PRIMARY KEY,
41
  name TEXT NOT NULL,
42
- password TEXT NOT NULL
 
43
  )
44
  ''')
45
 
46
- # Adicionar usuários de exemplo (remover ou personalizar em produção)
47
  try:
48
- hashed_password = stauth.Hasher(['senha123']).generate()[0]
49
  cursor.execute('''
50
- INSERT OR IGNORE INTO users (username, name, password)
51
- VALUES (?, ?, ?)
52
- ''', ('cliente', 'Cliente', hashed_password))
53
- cursor.execute('''
54
- INSERT OR IGNORE INTO users (username, name, password)
55
- VALUES (?, ?, ?)
56
- ''', ('empresa1', 'Empresa Um', hashed_password))
57
  conn.commit()
58
  except Exception as e:
59
  logging.error(f"Erro ao inicializar banco de dados: {e}")
 
60
  st.error(f"Erro ao inicializar banco de dados: {str(e)}")
61
 
62
  conn.close()
@@ -64,11 +68,11 @@ def init_db():
64
  def load_users_from_db():
65
  """Carrega usuários do banco de dados SQLite"""
66
  try:
67
- db_path = os.getenv('DB_PATH', 'users.db')
68
  conn = sqlite3.connect(db_path)
69
  cursor = conn.cursor()
70
- cursor.execute("SELECT username, name, password FROM users")
71
- users = {row[0]: {'name': row[1], 'password': row[2]} for row in cursor.fetchall()}
72
  conn.close()
73
 
74
  config = {
@@ -78,130 +82,64 @@ def load_users_from_db():
78
  }
79
  return config
80
  except Exception as e:
81
- st.error(f"Erro ao carregar usuários do banco de dados: {str(e)}")
82
  logging.error(f"Erro ao carregar usuários: {e}")
 
83
  return None
84
 
85
- # Cache para evitar recarregar modelos a cada execução
86
  @st.cache_resource(show_spinner=False)
87
- def load_models():
88
- """Carrega todos os modelos com cache para melhor performance"""
89
- device = torch.device("cpu") # Use 'cuda' se GPU estiver disponível
90
- logging.info(f"Usando dispositivo: {device}")
91
- models = {}
 
92
 
93
  try:
94
- # Modelos de texto
95
- models['sentiment_analysis'] = pipeline(
96
- "sentiment-analysis",
97
- model="cardiffnlp/twitter-roberta-base-sentiment-latest",
98
- device=device
99
- )
100
-
101
- models['text_classification'] = pipeline(
102
- "text-classification",
103
- model="distilbert-base-uncased-finetuned-sst-2-english",
104
- device=device
105
- )
106
-
107
- models['summarization'] = pipeline(
108
- "summarization",
109
- model="facebook/bart-large-cnn",
110
- device=device,
111
- max_length=150,
112
- min_length=30
113
- )
114
-
115
- models['question_answering'] = pipeline(
116
- "question-answering",
117
- model="deepset/roberta-base-squad2",
118
- device=device
119
- )
120
-
121
- models['translation'] = pipeline(
122
- "translation",
123
- model="Helsinki-NLP/opus-mt-tc-big-en-pt",
124
- device=device
125
- )
126
-
127
- tokenizer_gpt2 = AutoTokenizer.from_pretrained("gpt2")
128
- model_gpt2 = AutoModelForCausalLM.from_pretrained("gpt2")
129
- model_gpt2.config.pad_token_id = model_gpt2.config.eos_token_id
130
-
131
- models['text_generation'] = pipeline(
132
- "text-generation",
133
- model=model_gpt2,
134
- tokenizer=tokenizer_gpt2,
135
- device=device
136
- )
137
-
138
- models['ner'] = pipeline(
139
- "ner",
140
- model="dbmdz/bert-large-cased-finetuned-conll03-english",
141
- device=device,
142
- aggregation_strategy="simple"
143
- )
144
-
145
- # Modelos de imagem
146
- models['image_classification'] = pipeline(
147
- "image-classification",
148
- model="google/vit-base-patch16-224",
149
- device=device
150
- )
151
-
152
- models['object_detection'] = pipeline(
153
- "object-detection",
154
- model="facebook/detr-resnet-50",
155
- device=device
156
- )
157
-
158
- models['image_segmentation'] = pipeline(
159
- "image-segmentation",
160
- model="facebook/detr-resnet-50-panoptic",
161
- device=device
162
- )
163
-
164
- models['facial_recognition'] = pipeline(
165
- "image-classification",
166
- model="mo-thecreator/vit-Facial-Expression-Recognition",
167
- device=device
168
- )
169
-
170
- # Modelos de áudio
171
- models['speech_to_text'] = pipeline(
172
- "automatic-speech-recognition",
173
- model="openai/whisper-base",
174
- device=device
175
- )
176
-
177
- models['audio_classification'] = pipeline(
178
- "audio-classification",
179
- model="superb/hubert-base-superb-er",
180
- device=device
181
- )
182
-
183
- # Modelos generativos
184
- models['text_to_image'] = StableDiffusionPipeline.from_pretrained(
185
- "runwayml/stable-diffusion-v1-5",
186
- torch_dtype=torch.float16,
187
- use_safetensors=True,
188
- safety_checker=None,
189
- variant="fp16"
190
- )
191
-
192
  except Exception as e:
193
- st.error(f"Erro crítico ao carregar modelos: {str(e)}")
194
- logging.exception("Erro ao carregar modelos")
195
- return {}
196
-
197
- return models
198
 
199
  def validate_audio_file(file: UploadedFile) -> bool:
200
  """Valida o arquivo de áudio"""
201
  valid_extensions = ['.wav', '.mp3', '.flac', '.m4a']
202
- if not any(file.name.lower().endswith(ext) for ext in valid_extensions):
203
- return False
204
- return True
205
 
206
  def validate_image_file(file: UploadedFile) -> bool:
207
  """Valida o arquivo de imagem"""
@@ -223,11 +161,11 @@ def process_audio_file(audio_file):
223
 
224
  audio_array, sample_rate = librosa.load(tmp_file_path, sr=16000)
225
  os.unlink(tmp_file_path)
226
-
227
  return audio_array
228
  except Exception as e:
229
  st.error(f"Erro ao processar áudio: {str(e)}")
230
  logging.error(f"Erro no processamento de áudio: {e}")
 
231
  return None
232
 
233
  def process_image_file(image_file):
@@ -240,6 +178,7 @@ def process_image_file(image_file):
240
  except Exception as e:
241
  st.error(f"Erro ao processar imagem: {str(e)}")
242
  logging.error(f"Erro no processamento de imagem: {e}")
 
243
  return None
244
 
245
  def display_results(result, model_key, input_text=None):
@@ -304,6 +243,61 @@ def display_results(result, model_key, input_text=None):
304
  st.subheader("🎨 Imagem Gerada")
305
  st.image(result[0], caption="Imagem gerada a partir do texto")
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  def get_use_cases():
308
  """Retorna os casos de uso para cada modelo"""
309
  return {
@@ -315,6 +309,7 @@ def get_use_cases():
315
  'demo_input': "A entrega foi super rápida, adorei!",
316
  'demo_type': 'text'
317
  },
 
318
  'text_classification': {
319
  'title': "Classificação de Texto",
320
  'description': "Classifica e-mails recebidos como positivos ou negativos para priorizar respostas ou identificar reclamações.",
@@ -432,13 +427,14 @@ def handle_use_case_demo(models, use_case_key, use_case):
432
 
433
  st.subheader("📊 Demonstração")
434
  try:
 
435
  if use_case['demo_type'] == 'text':
436
  with st.spinner("Processando demonstração..."):
437
- result = models[use_case_key](use_case['demo_input'])
438
  display_results(result, use_case_key, input_text=use_case['demo_input'])
439
  elif use_case['demo_type'] == 'qa':
440
  with st.spinner("Processando demonstração..."):
441
- result = models[use_case_key](
442
  question=use_case['demo_input']['question'],
443
  context=use_case['demo_input']['context']
444
  )
@@ -450,6 +446,7 @@ def handle_use_case_demo(models, use_case_key, use_case):
450
  except Exception as e:
451
  st.error(f"Erro ao executar demonstração: {str(e)}")
452
  logging.error(f"Erro na demonstração do caso de uso {use_case_key}: {e}")
 
453
 
454
  def main():
455
  # Inicializar banco de dados
@@ -473,51 +470,62 @@ def main():
473
  name, authentication_status, username = authenticator.login('Login', 'main')
474
 
475
  if authentication_status:
476
- st.write(f"Bem-vindo, {name}!")
 
 
 
 
 
 
 
 
 
 
477
  authenticator.logout('Logout', 'sidebar')
478
-
479
- st.title("🤖 Aplicação de IA Multi-Modal Avançada")
480
- st.markdown("---")
481
 
482
- # Carregar modelos
483
- with st.spinner("Carregando modelos de IA... (Isso pode levar alguns minutos na primeira execução)"):
484
- models = load_models()
 
 
 
 
485
 
486
- if not models:
487
- st.error("Falha crítica ao carregar os modelos. Verifique os logs para mais detalhes.")
488
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
 
490
  # Abas para navegação
491
  tab1, tab2 = st.tabs(["Explorar Modelos", "Casos de Uso"])
492
 
493
  with tab1:
494
- # Sidebar para seleção de modelo
495
  st.sidebar.title("⚙️ Configurações")
496
- model_categories = {
497
- "📝 Processamento de Texto": [
498
- ("Análise de Sentimento", "sentiment_analysis"),
499
- ("Classificação de Texto", "text_classification"),
500
- ("Resumo de Texto", "summarization"),
501
- ("Perguntas e Respostas", "question_answering"),
502
- ("Tradução (EN→PT)", "translation"),
503
- ("Reconhecimento de Entidades", "ner"),
504
- ("Geração de Texto", "text_generation")
505
- ],
506
- "🖼️ Processamento de Imagem": [
507
- ("Classificação de Imagem", "image_classification"),
508
- ("Detecção de Objetos", "object_detection"),
509
- ("Segmentação de Imagem", "image_segmentation"),
510
- ("Reconhecimento Facial", "facial_recognition")
511
- ],
512
- "🎵 Processamento de Áudio": [
513
- ("Transcrição de Áudio", "speech_to_text"),
514
- ("Classificação de Emoções", "audio_classification")
515
- ],
516
- "✨ Modelos Generativos": [
517
- ("Texto para Imagem", "text_to_image")
518
- ]
519
- }
520
-
521
  selected_category = st.sidebar.selectbox(
522
  "Categoria",
523
  list(model_categories.keys()),
@@ -531,13 +539,17 @@ def main():
531
  index=0
532
  )
533
 
534
- # Obter chave do modelo selecionado
535
  model_key = next(key for name, key in model_categories[selected_category] if name == selected_model)
536
 
537
- # Interface principal
 
 
 
 
 
 
538
  st.header(f"{selected_model}")
539
 
540
- # Accordion para informações do modelo
541
  with st.expander("ℹ️ Sobre este modelo"):
542
  model_info = {
543
  'sentiment_analysis': "Analisa o sentimento expresso em um texto (positivo/negativo/neutro).",
@@ -557,7 +569,6 @@ def main():
557
  }
558
  st.info(model_info.get(model_key, "Informações detalhadas sobre este modelo."))
559
 
560
- # Processamento baseado no tipo de modelo
561
  try:
562
  if model_key in ['sentiment_analysis', 'text_classification', 'summarization',
563
  'translation', 'text_generation', 'ner']:
@@ -578,7 +589,8 @@ def main():
578
 
579
  except Exception as e:
580
  st.error(f"Erro inesperado durante a execução: {str(e)}")
581
- logging.exception("Erro durante a execução do modelo")
 
582
 
583
  with tab2:
584
  st.header("Casos de Uso")
@@ -612,7 +624,6 @@ def handle_text_models(models, model_key, model_name):
612
  key=f"text_input_{model_key}"
613
  )
614
 
615
- # Parâmetros adicionais para alguns modelos
616
  advanced_params = {}
617
  if model_key == 'summarization':
618
  with st.expander("⚙️ Parâmetros Avançados"):
@@ -629,10 +640,11 @@ def handle_text_models(models, model_key, model_name):
629
  if input_text.strip():
630
  with st.spinner("Processando..."):
631
  try:
 
632
  if model_key == 'ner':
633
- result = models[model_key](input_text)
634
  elif model_key == 'text_generation':
635
- result = models[model_key](
636
  input_text,
637
  max_new_tokens=advanced_params.get('max_length', 100),
638
  do_sample=True,
@@ -642,13 +654,14 @@ def handle_text_models(models, model_key, model_name):
642
  num_return_sequences=advanced_params.get('num_return_sequences', 1)
643
  )
644
  else:
645
- result = models[model_key](input_text, **advanced_params)
646
 
647
  display_results(result, model_key, input_text=input_text)
648
 
649
  except Exception as e:
650
  st.error(f"Erro ao processar texto: {str(e)}")
651
  logging.error(f"Erro no modelo {model_key}: {e}")
 
652
  else:
653
  st.warning("⚠️ Por favor, insira um texto válido.")
654
 
@@ -679,7 +692,8 @@ def handle_qa_model(models, model_key):
679
  if context.strip() and question.strip():
680
  with st.spinner("Buscando resposta..."):
681
  try:
682
- result = models[model_key](question=question, context=context)
 
683
 
684
  if result['score'] < confidence_threshold:
685
  st.warning(f"⚠️ Confiança baixa na resposta ({result['score']:.2%})")
@@ -693,6 +707,7 @@ def handle_qa_model(models, model_key):
693
  except Exception as e:
694
  st.error(f"Erro ao processar Q&A: {str(e)}")
695
  logging.error(f"Erro no modelo Q&A: {e}")
 
696
  else:
697
  st.warning("⚠️ Por favor, forneça tanto o contexto quanto a pergunta.")
698
 
@@ -724,12 +739,13 @@ def handle_image_models(models, model_key, model_name):
724
  if image:
725
  with st.spinner("Analisando imagem..."):
726
  try:
727
- result = models[model_key](image)
 
728
  display_results(result, model_key)
729
-
730
  except Exception as e:
731
  st.error(f"Erro ao processar imagem: {str(e)}")
732
  logging.error(f"Erro no modelo {model_key}: {e}")
 
733
 
734
  def handle_audio_models(models, model_key):
735
  """Manipula modelos de áudio"""
@@ -753,16 +769,16 @@ def handle_audio_models(models, model_key):
753
  with st.spinner("Processando áudio..."):
754
  try:
755
  audio_array = process_audio_file(uploaded_file)
756
-
757
  if audio_array is not None:
758
- result = models[model_key](audio_array)
 
759
  display_results(result, model_key)
760
  else:
761
  st.error("Não foi possível processar o arquivo de áudio.")
762
-
763
  except Exception as e:
764
  st.error(f"Erro ao processar áudio: {str(e)}")
765
  logging.error(f"Erro no modelo {model_key}: {e}")
 
766
 
767
  def handle_generative_models(models, model_key):
768
  """Manipula modelos generativos"""
@@ -786,7 +802,8 @@ def handle_generative_models(models, model_key):
786
  if prompt.strip():
787
  with st.spinner("Criando imagem..."):
788
  try:
789
- result = models[model_key](
 
790
  prompt,
791
  height=height,
792
  width=width,
@@ -794,10 +811,10 @@ def handle_generative_models(models, model_key):
794
  guidance_scale=guidance_scale
795
  )
796
  display_results(result, model_key)
797
-
798
  except Exception as e:
799
  st.error(f"Erro ao gerar imagem: {str(e)}")
800
  logging.error(f"Erro no modelo text-to-image: {e}")
 
801
  else:
802
  st.warning("⚠️ Por favor, insira uma descrição para a imagem.")
803
 
 
2
  import streamlit_authenticator as stauth
3
  import sqlite3
4
  import os
5
+ import psycopg2
6
+ import jwt
7
+ from datetime import datetime, timedelta
8
  from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
9
  import torch
10
  from PIL import Image
 
15
  import tempfile
16
  from streamlit.runtime.uploaded_file_manager import UploadedFile
17
  from diffusers import StableDiffusionPipeline
18
+ import sentry_sdk
19
+ from streamlit_tour import st_tour
20
 
21
  # Configurar página
22
  st.set_page_config(
 
25
  layout="wide"
26
  )
27
 
28
+ # Configurar logging e Sentry
29
+ sentry_sdk.init(os.getenv('SENTRY_DSN', ''), traces_sample_rate=1.0)
30
  logging.basicConfig(
31
+ filename='/home/user/app/private/app_errors.log',
32
  level=logging.ERROR,
33
  format='%(asctime)s - %(levelname)s - %(message)s'
34
  )
35
 
36
+ # Configurar banco de dados
37
  def init_db():
38
  """Inicializa o banco de dados SQLite com tabela de usuários"""
39
+ db_path = os.getenv('DB_PATH', '/home/user/app/private/users.db')
40
+ os.makedirs(os.path.dirname(db_path), exist_ok=True)
41
  conn = sqlite3.connect(db_path)
42
  cursor = conn.cursor()
43
 
 
44
  cursor.execute('''
45
  CREATE TABLE IF NOT EXISTS users (
46
  username TEXT PRIMARY KEY,
47
  name TEXT NOT NULL,
48
+ password TEXT NOT NULL,
49
+ role TEXT NOT NULL DEFAULT 'user'
50
  )
51
  ''')
52
 
53
+ # Adicionar admin padrão (remover em produção)
54
  try:
55
+ hashed_password = stauth.Hasher(['admin123']).generate()[0]
56
  cursor.execute('''
57
+ INSERT OR IGNORE INTO users (username, name, password, role)
58
+ VALUES (?, ?, ?, ?)
59
+ ''', ('admin', 'Administrador', hashed_password, 'admin'))
 
 
 
 
60
  conn.commit()
61
  except Exception as e:
62
  logging.error(f"Erro ao inicializar banco de dados: {e}")
63
+ sentry_sdk.capture_exception(e)
64
  st.error(f"Erro ao inicializar banco de dados: {str(e)}")
65
 
66
  conn.close()
 
68
  def load_users_from_db():
69
  """Carrega usuários do banco de dados SQLite"""
70
  try:
71
+ db_path = os.getenv('DB_PATH', '/home/user/app/private/users.db')
72
  conn = sqlite3.connect(db_path)
73
  cursor = conn.cursor()
74
+ cursor.execute("SELECT username, name, password, role FROM users")
75
+ users = {row[0]: {'name': row[1], 'password': row[2], 'role': row[3]} for row in cursor.fetchall()}
76
  conn.close()
77
 
78
  config = {
 
82
  }
83
  return config
84
  except Exception as e:
85
+ st.error(f"Erro ao carregar usuários: {str(e)}")
86
  logging.error(f"Erro ao carregar usuários: {e}")
87
+ sentry_sdk.capture_exception(e)
88
  return None
89
 
90
+ # Cache para modelos
91
  @st.cache_resource(show_spinner=False)
92
+ def load_model(model_key):
93
+ """Carrega modelo específico com cache persistente"""
94
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
95
+ cache_dir = "/home/user/app/model_cache"
96
+ os.makedirs(cache_dir, exist_ok=True)
97
+ logging.info(f"Carregando modelo {model_key} em {device} com cache em {cache_dir}")
98
 
99
  try:
100
+ if model_key == 'sentiment_analysis':
101
+ return pipeline("sentiment-analysis", model="cardiffnlp/twitter-roberta-base-sentiment-latest", device=device, cache_dir=cache_dir)
102
+ elif model_key == 'text_classification':
103
+ return pipeline("text-classification", model="distilbert-base-uncased-finetuned-sst-2-english", device=device, cache_dir=cache_dir)
104
+ elif model_key == 'summarization':
105
+ return pipeline("summarization", model="facebook/bart-large-cnn", device=device, max_length=150, min_length=30, cache_dir=cache_dir)
106
+ elif model_key == 'question_answering':
107
+ return pipeline("question-answering", model="deepset/roberta-base-squad2", device=device, cache_dir=cache_dir)
108
+ elif model_key == 'translation':
109
+ return pipeline("translation", model="Helsinki-NLP/opus-mt-tc-big-en-pt", device=device, cache_dir=cache_dir)
110
+ elif model_key == 'text_generation':
111
+ tokenizer = AutoTokenizer.from_pretrained("gpt2", cache_dir=cache_dir)
112
+ model = AutoModelForCausalLM.from_pretrained("gpt2", cache_dir=cache_dir)
113
+ model.config.pad_token_id = model.config.eos_token_id
114
+ return pipeline("text-generation", model=model, tokenizer=tokenizer, device=device)
115
+ elif model_key == 'ner':
116
+ return pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english", device=device, aggregation_strategy="simple", cache_dir=cache_dir)
117
+ elif model_key == 'image_classification':
118
+ return pipeline("image-classification", model="google/vit-base-patch16-224", device=device, cache_dir=cache_dir)
119
+ elif model_key == 'object_detection':
120
+ return pipeline("object-detection", model="facebook/detr-resnet-50", device=device, cache_dir=cache_dir)
121
+ elif model_key == 'image_segmentation':
122
+ return pipeline("image-segmentation", model="facebook/detr-resnet-50-panoptic", device=device, cache_dir=cache_dir)
123
+ elif model_key == 'facial_recognition':
124
+ return pipeline("image-classification", model="mo-thecreator/vit-Facial-Expression-Recognition", device=device, cache_dir=cache_dir)
125
+ elif model_key == 'speech_to_text':
126
+ return pipeline("automatic-speech-recognition", model="openai/whisper-base", device=device, cache_dir=cache_dir)
127
+ elif model_key == 'audio_classification':
128
+ return pipeline("audio-classification", model="superb/hubert-base-superb-er", device=device, cache_dir=cache_dir)
129
+ elif model_key == 'text_to_image':
130
+ return StableDiffusionPipeline.from_pretrained(
131
+ "runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16, use_safetensors=True, safety_checker=None, variant="fp16", cache_dir=cache_dir
132
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  except Exception as e:
134
+ st.error(f"Erro ao carregar modelo {model_key}: {str(e)}")
135
+ logging.error(f"Erro ao carregar modelo {model_key}: {e}")
136
+ sentry_sdk.capture_exception(e)
137
+ return None
 
138
 
139
  def validate_audio_file(file: UploadedFile) -> bool:
140
  """Valida o arquivo de áudio"""
141
  valid_extensions = ['.wav', '.mp3', '.flac', '.m4a']
142
+ return any(file.name.lower().endswith(ext) for ext in valid_extensions)
 
 
143
 
144
  def validate_image_file(file: UploadedFile) -> bool:
145
  """Valida o arquivo de imagem"""
 
161
 
162
  audio_array, sample_rate = librosa.load(tmp_file_path, sr=16000)
163
  os.unlink(tmp_file_path)
 
164
  return audio_array
165
  except Exception as e:
166
  st.error(f"Erro ao processar áudio: {str(e)}")
167
  logging.error(f"Erro no processamento de áudio: {e}")
168
+ sentry_sdk.capture_exception(e)
169
  return None
170
 
171
  def process_image_file(image_file):
 
178
  except Exception as e:
179
  st.error(f"Erro ao processar imagem: {str(e)}")
180
  logging.error(f"Erro no processamento de imagem: {e}")
181
+ sentry_sdk.capture_exception(e)
182
  return None
183
 
184
  def display_results(result, model_key, input_text=None):
 
243
  st.subheader("🎨 Imagem Gerada")
244
  st.image(result[0], caption="Imagem gerada a partir do texto")
245
 
246
+ def load_branding(username):
247
+ """Carrega branding personalizado por usuário"""
248
+ branding = {
249
+ 'admin': {'logo': '/home/user/app/logos/admin_logo.png', 'title': 'Bem-vindo, Administrador!'},
250
+ 'cliente': {'logo': '/home/user/app/logos/cliente_logo.png', 'title': 'Bem-vindo, Cliente!'},
251
+ 'empresa1': {'logo': '/home/user/app/logos/empresa1_logo.png', 'title': 'Bem-vindo, Empresa Um!'}
252
+ }
253
+ return branding.get(username, {'logo': None, 'title': 'Bem-vindo!'})
254
+
255
+ def admin_panel(authenticator):
256
+ """Painel administrativo para gerenciar usuários"""
257
+ if st.session_state.get('role') == 'admin':
258
+ st.sidebar.subheader("Painel Admin")
259
+ with st.sidebar.form("add_user_form"):
260
+ username = st.text_input("Username")
261
+ name = st.text_input("Nome")
262
+ password = st.text_input("Senha", type="password")
263
+ role = st.selectbox("Role", ["user", "admin"])
264
+ if st.form_submit_button("Adicionar Usuário"):
265
+ hashed_password = stauth.Hasher([password]).generate()[0]
266
+ db_path = os.getenv('DB_PATH', '/home/user/app/private/users.db')
267
+ conn = sqlite3.connect(db_path)
268
+ cursor = conn.cursor()
269
+ try:
270
+ cursor.execute('INSERT INTO users (username, name, password, role) VALUES (?, ?, ?, ?)',
271
+ (username, name, hashed_password, role))
272
+ conn.commit()
273
+ st.success(f"Usuário {username} adicionado!")
274
+ except sqlite3.IntegrityError:
275
+ st.error("Usuário já existe.")
276
+ except Exception as e:
277
+ st.error(f"Erro ao adicionar usuário: {str(e)}")
278
+ logging.error(f"Erro ao adicionar usuário: {e}")
279
+ sentry_sdk.capture_exception(e)
280
+ conn.close()
281
+
282
+ with st.sidebar.form("remove_user_form"):
283
+ username_to_remove = st.text_input("Username para Remover")
284
+ if st.form_submit_button("Remover Usuário"):
285
+ db_path = os.getenv('DB_PATH', '/home/user/app/private/users.db')
286
+ conn = sqlite3.connect(db_path)
287
+ cursor = conn.cursor()
288
+ try:
289
+ cursor.execute('DELETE FROM users WHERE username = ?', (username_to_remove,))
290
+ conn.commit()
291
+ if cursor.rowcount > 0:
292
+ st.success(f"Usuário {username_to_remove} removido!")
293
+ else:
294
+ st.error("Usuário não encontrado.")
295
+ except Exception as e:
296
+ st.error(f"Erro ao remover usuário: {str(e)}")
297
+ logging.error(f"Erro ao remover usuário: {e}")
298
+ sentry_sdk.capture_exception(e)
299
+ conn.close()
300
+
301
  def get_use_cases():
302
  """Retorna os casos de uso para cada modelo"""
303
  return {
 
309
  'demo_input': "A entrega foi super rápida, adorei!",
310
  'demo_type': 'text'
311
  },
312
+ # Outros casos de uso mantidos idênticos ao original
313
  'text_classification': {
314
  'title': "Classificação de Texto",
315
  'description': "Classifica e-mails recebidos como positivos ou negativos para priorizar respostas ou identificar reclamações.",
 
427
 
428
  st.subheader("📊 Demonstração")
429
  try:
430
+ model = models.get(use_case_key) or load_model(use_case_key)
431
  if use_case['demo_type'] == 'text':
432
  with st.spinner("Processando demonstração..."):
433
+ result = model(use_case['demo_input'])
434
  display_results(result, use_case_key, input_text=use_case['demo_input'])
435
  elif use_case['demo_type'] == 'qa':
436
  with st.spinner("Processando demonstração..."):
437
+ result = model(
438
  question=use_case['demo_input']['question'],
439
  context=use_case['demo_input']['context']
440
  )
 
446
  except Exception as e:
447
  st.error(f"Erro ao executar demonstração: {str(e)}")
448
  logging.error(f"Erro na demonstração do caso de uso {use_case_key}: {e}")
449
+ sentry_sdk.capture_exception(e)
450
 
451
  def main():
452
  # Inicializar banco de dados
 
470
  name, authentication_status, username = authenticator.login('Login', 'main')
471
 
472
  if authentication_status:
473
+ # Gerenciar sessão
474
+ if "user_id" not in st.session_state:
475
+ st.session_state.user_id = username
476
+ st.session_state.role = config['credentials']['usernames'][username]['role']
477
+
478
+ # Carregar branding
479
+ branding = load_branding(username)
480
+ if branding['logo'] and os.path.exists(branding['logo']):
481
+ st.image(branding['logo'], width=150)
482
+ st.title(branding['title'])
483
+
484
  authenticator.logout('Logout', 'sidebar')
485
+ admin_panel(authenticator)
 
 
486
 
487
+ # Tour guiado
488
+ if st.sidebar.button("Iniciar Tour"):
489
+ st_tour([
490
+ {"element": "#login", "title": "Login", "description": "Faça login com suas credenciais."},
491
+ {"element": "#tab1", "title": "Explorar Modelos", "description": "Teste modelos de IA."},
492
+ {"element": "#tab2", "title": "Casos de Uso", "description": "Explore aplicações práticas."}
493
+ ])
494
 
495
+ st.markdown("---")
496
+
497
+ # Carregar modelos sob demanda
498
+ models = {}
499
+ model_categories = {
500
+ "📝 Processamento de Texto": [
501
+ ("Análise de Sentimento", "sentiment_analysis"),
502
+ ("Classificação de Texto", "text_classification"),
503
+ ("Resumo de Texto", "summarization"),
504
+ ("Perguntas e Respostas", "question_answering"),
505
+ ("Tradução (EN→PT)", "translation"),
506
+ ("Reconhecimento de Entidades", "ner"),
507
+ ("Geração de Texto", "text_generation")
508
+ ],
509
+ "🖼️ Processamento de Imagem": [
510
+ ("Classificação de Imagem", "image_classification"),
511
+ ("Detecção de Objetos", "object_detection"),
512
+ ("Segmentação de Imagem", "image_segmentation"),
513
+ ("Reconhecimento Facial", "facial_recognition")
514
+ ],
515
+ "🎵 Processamento de Áudio": [
516
+ ("Transcrição de Áudio", "speech_to_text"),
517
+ ("Classificação de Emoções", "audio_classification")
518
+ ],
519
+ "✨ Modelos Generativos": [
520
+ ("Texto para Imagem", "text_to_image")
521
+ ]
522
+ }
523
 
524
  # Abas para navegação
525
  tab1, tab2 = st.tabs(["Explorar Modelos", "Casos de Uso"])
526
 
527
  with tab1:
 
528
  st.sidebar.title("⚙️ Configurações")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  selected_category = st.sidebar.selectbox(
530
  "Categoria",
531
  list(model_categories.keys()),
 
539
  index=0
540
  )
541
 
 
542
  model_key = next(key for name, key in model_categories[selected_category] if name == selected_model)
543
 
544
+ # Carregar modelo com barra de progresso
545
+ if model_key not in models:
546
+ with st.spinner(f"Carregando modelo {selected_model}..."):
547
+ progress = st.progress(0)
548
+ models[model_key] = load_model(model_key)
549
+ progress.progress(100)
550
+
551
  st.header(f"{selected_model}")
552
 
 
553
  with st.expander("ℹ️ Sobre este modelo"):
554
  model_info = {
555
  'sentiment_analysis': "Analisa o sentimento expresso em um texto (positivo/negativo/neutro).",
 
569
  }
570
  st.info(model_info.get(model_key, "Informações detalhadas sobre este modelo."))
571
 
 
572
  try:
573
  if model_key in ['sentiment_analysis', 'text_classification', 'summarization',
574
  'translation', 'text_generation', 'ner']:
 
589
 
590
  except Exception as e:
591
  st.error(f"Erro inesperado durante a execução: {str(e)}")
592
+ logging.error(f"Erro durante a execução do modelo {model_key}: {e}")
593
+ sentry_sdk.capture_exception(e)
594
 
595
  with tab2:
596
  st.header("Casos de Uso")
 
624
  key=f"text_input_{model_key}"
625
  )
626
 
 
627
  advanced_params = {}
628
  if model_key == 'summarization':
629
  with st.expander("⚙️ Parâmetros Avançados"):
 
640
  if input_text.strip():
641
  with st.spinner("Processando..."):
642
  try:
643
+ model = models.get(model_key) or load_model(model_key)
644
  if model_key == 'ner':
645
+ result = model(input_text)
646
  elif model_key == 'text_generation':
647
+ result = model(
648
  input_text,
649
  max_new_tokens=advanced_params.get('max_length', 100),
650
  do_sample=True,
 
654
  num_return_sequences=advanced_params.get('num_return_sequences', 1)
655
  )
656
  else:
657
+ result = model(input_text, **advanced_params)
658
 
659
  display_results(result, model_key, input_text=input_text)
660
 
661
  except Exception as e:
662
  st.error(f"Erro ao processar texto: {str(e)}")
663
  logging.error(f"Erro no modelo {model_key}: {e}")
664
+ sentry_sdk.capture_exception(e)
665
  else:
666
  st.warning("⚠️ Por favor, insira um texto válido.")
667
 
 
692
  if context.strip() and question.strip():
693
  with st.spinner("Buscando resposta..."):
694
  try:
695
+ model = models.get(model_key) or load_model(model_key)
696
+ result = model(question=question, context=context)
697
 
698
  if result['score'] < confidence_threshold:
699
  st.warning(f"⚠️ Confiança baixa na resposta ({result['score']:.2%})")
 
707
  except Exception as e:
708
  st.error(f"Erro ao processar Q&A: {str(e)}")
709
  logging.error(f"Erro no modelo Q&A: {e}")
710
+ sentry_sdk.capture_exception(e)
711
  else:
712
  st.warning("⚠️ Por favor, forneça tanto o contexto quanto a pergunta.")
713
 
 
739
  if image:
740
  with st.spinner("Analisando imagem..."):
741
  try:
742
+ model = models.get(model_key) or load_model(model_key)
743
+ result = model(image)
744
  display_results(result, model_key)
 
745
  except Exception as e:
746
  st.error(f"Erro ao processar imagem: {str(e)}")
747
  logging.error(f"Erro no modelo {model_key}: {e}")
748
+ sentry_sdk.capture_exception(e)
749
 
750
  def handle_audio_models(models, model_key):
751
  """Manipula modelos de áudio"""
 
769
  with st.spinner("Processando áudio..."):
770
  try:
771
  audio_array = process_audio_file(uploaded_file)
 
772
  if audio_array is not None:
773
+ model = models.get(model_key) or load_model(model_key)
774
+ result = model(audio_array)
775
  display_results(result, model_key)
776
  else:
777
  st.error("Não foi possível processar o arquivo de áudio.")
 
778
  except Exception as e:
779
  st.error(f"Erro ao processar áudio: {str(e)}")
780
  logging.error(f"Erro no modelo {model_key}: {e}")
781
+ sentry_sdk.capture_exception(e)
782
 
783
  def handle_generative_models(models, model_key):
784
  """Manipula modelos generativos"""
 
802
  if prompt.strip():
803
  with st.spinner("Criando imagem..."):
804
  try:
805
+ model = models.get(model_key) or load_model(model_key)
806
+ result = model(
807
  prompt,
808
  height=height,
809
  width=width,
 
811
  guidance_scale=guidance_scale
812
  )
813
  display_results(result, model_key)
 
814
  except Exception as e:
815
  st.error(f"Erro ao gerar imagem: {str(e)}")
816
  logging.error(f"Erro no modelo text-to-image: {e}")
817
+ sentry_sdk.capture_exception(e)
818
  else:
819
  st.warning("⚠️ Por favor, insira uma descrição para a imagem.")
820