Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import streamlit_authenticator as stauth | |
| import sqlite3 | |
| import os | |
| import psycopg2 | |
| import jwt | |
| from datetime import datetime, timedelta | |
| from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer | |
| import torch | |
| from PIL import Image | |
| import io | |
| import librosa | |
| import numpy as np | |
| import logging | |
| import tempfile | |
| from streamlit.runtime.uploaded_file_manager import UploadedFile | |
| from diffusers import StableDiffusionPipeline | |
| import sentry_sdk | |
| from streamlit_tour import st_tour | |
| # Configurar página | |
| st.set_page_config( | |
| page_title="Aplicação de IA Multi-Modal", | |
| page_icon="🤖", | |
| layout="wide" | |
| ) | |
| # Configurar logging e Sentry | |
| sentry_sdk.init(os.getenv('SENTRY_DSN', ''), traces_sample_rate=1.0) | |
| logging.basicConfig( | |
| filename='private/app_errors.log', | |
| level=logging.ERROR, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| # Configurar banco de dados | |
| def init_db(): | |
| """Inicializa o banco de dados SQLite com tabela de usuários""" | |
| db_path = os.getenv('DB_PATH', 'private/users.db') | |
| os.makedirs(os.path.dirname(db_path), exist_ok=True) | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS users ( | |
| username TEXT PRIMARY KEY, | |
| name TEXT NOT NULL, | |
| password TEXT NOT NULL, | |
| role TEXT NOT NULL DEFAULT 'user' | |
| ) | |
| ''') | |
| # Adicionar admin padrão (remover em produção) | |
| try: | |
| hashed_password = stauth.Hasher(['admin123']).generate()[0] | |
| cursor.execute(''' | |
| INSERT OR IGNORE INTO users (username, name, password, role) | |
| VALUES (?, ?, ?, ?) | |
| ''', ('admin', 'Administrador', hashed_password, 'admin')) | |
| conn.commit() | |
| except Exception as e: | |
| logging.error(f"Erro ao inicializar banco de dados: {e}") | |
| sentry_sdk.capture_exception(e) | |
| st.error(f"Erro ao inicializar banco de dados: {str(e)}") | |
| conn.close() | |
| def load_users_from_db(): | |
| """Carrega usuários do banco de dados SQLite""" | |
| try: | |
| db_path = os.getenv('DB_PATH', 'private/users.db') | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT username, name, password, role FROM users") | |
| users = {row[0]: {'name': row[1], 'password': row[2], 'role': row[3]} for row in cursor.fetchall()} | |
| conn.close() | |
| config = { | |
| 'credentials': {'usernames': users}, | |
| 'cookie': {'name': 'ai_app_cookie', 'key': 'random_key_123', 'expiry_days': 30}, | |
| 'preauthorized': {'emails': []} | |
| } | |
| return config | |
| except Exception as e: | |
| st.error(f"Erro ao carregar usuários: {str(e)}") | |
| logging.error(f"Erro ao carregar usuários: {e}") | |
| sentry_sdk.capture_exception(e) | |
| return None | |
| # Cache para modelos | |
| def load_model(model_key): | |
| """Carrega modelo específico com cache persistente""" | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| cache_dir = "model_cache" | |
| os.makedirs(cache_dir, exist_ok=True) | |
| logging.info(f"Carregando modelo {model_key} em {device} com cache em {cache_dir}") | |
| try: | |
| if model_key == 'sentiment_analysis': | |
| return pipeline("sentiment-analysis", model="cardiffnlp/twitter-roberta-base-sentiment-latest", device=device, cache_dir=cache_dir) | |
| elif model_key == 'text_classification': | |
| return pipeline("text-classification", model="distilbert-base-uncased-finetuned-sst-2-english", device=device, cache_dir=cache_dir) | |
| elif model_key == 'summarization': | |
| return pipeline("summarization", model="facebook/bart-large-cnn", device=device, max_length=150, min_length=30, cache_dir=cache_dir) | |
| elif model_key == 'question_answering': | |
| return pipeline("question-answering", model="deepset/roberta-base-squad2", device=device, cache_dir=cache_dir) | |
| elif model_key == 'translation': | |
| return pipeline("translation", model="Helsinki-NLP/opus-mt-tc-big-en-pt", device=device, cache_dir=cache_dir) | |
| elif model_key == 'text_generation': | |
| tokenizer = AutoTokenizer.from_pretrained("gpt2", cache_dir=cache_dir) | |
| model = AutoModelForCausalLM.from_pretrained("gpt2", cache_dir=cache_dir) | |
| model.config.pad_token_id = model.config.eos_token_id | |
| return pipeline("text-generation", model=model, tokenizer=tokenizer, device=device) | |
| elif model_key == 'ner': | |
| return pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english", device=device, aggregation_strategy="simple", cache_dir=cache_dir) | |
| elif model_key == 'image_classification': | |
| return pipeline("image-classification", model="google/vit-base-patch16-224", device=device, cache_dir=cache_dir) | |
| elif model_key == 'object_detection': | |
| return pipeline("object-detection", model="facebook/detr-resnet-50", device=device, cache_dir=cache_dir) | |
| elif model_key == 'image_segmentation': | |
| return pipeline("image-segmentation", model="facebook/detr-resnet-50-panoptic", device=device, cache_dir=cache_dir) | |
| elif model_key == 'facial_recognition': | |
| return pipeline("image-classification", model="mo-thecreator/vit-Facial-Expression-Recognition", device=device, cache_dir=cache_dir) | |
| elif model_key == 'speech_to_text': | |
| return pipeline("automatic-speech-recognition", model="openai/whisper-base", device=device, cache_dir=cache_dir) | |
| elif model_key == 'audio_classification': | |
| return pipeline("audio-classification", model="superb/hubert-base-superb-er", device=device, cache_dir=cache_dir) | |
| elif model_key == 'text_to_image': | |
| return StableDiffusionPipeline.from_pretrained( | |
| "runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16, use_safetensors=True, safety_checker=None, variant="fp16", cache_dir=cache_dir | |
| ) | |
| except Exception as e: | |
| st.error(f"Erro ao carregar modelo {model_key}: {str(e)}") | |
| logging.error(f"Erro ao carregar modelo {model_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| return None | |
| def validate_audio_file(file: UploadedFile) -> bool: | |
| """Valida o arquivo de áudio""" | |
| valid_extensions = ['.wav', '.mp3', '.flac', '.m4a'] | |
| return any(file.name.lower().endswith(ext) for ext in valid_extensions) | |
| def validate_image_file(file: UploadedFile) -> bool: | |
| """Valida o arquivo de imagem""" | |
| valid_extensions = ['.jpg', '.jpeg', '.png', '.bmp'] | |
| if not any(file.name.lower().endswith(ext) for ext in valid_extensions): | |
| return False | |
| try: | |
| Image.open(file).verify() | |
| return True | |
| except Exception: | |
| return False | |
| def process_audio_file(audio_file): | |
| """Processa arquivo de áudio para o formato correto""" | |
| try: | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(audio_file.name)[1]) as tmp_file: | |
| tmp_file.write(audio_file.read()) | |
| tmp_file_path = tmp_file.name | |
| audio_array, sample_rate = librosa.load(tmp_file_path, sr=16000) | |
| os.unlink(tmp_file_path) | |
| return audio_array | |
| except Exception as e: | |
| st.error(f"Erro ao processar áudio: {str(e)}") | |
| logging.error(f"Erro no processamento de áudio: {e}") | |
| sentry_sdk.capture_exception(e) | |
| return None | |
| def process_image_file(image_file): | |
| """Processa arquivo de imagem""" | |
| try: | |
| image = Image.open(image_file) | |
| if image.mode != 'RGB': | |
| image = image.convert('RGB') | |
| return image | |
| except Exception as e: | |
| st.error(f"Erro ao processar imagem: {str(e)}") | |
| logging.error(f"Erro no processamento de imagem: {e}") | |
| sentry_sdk.capture_exception(e) | |
| return None | |
| def display_results(result, model_key, input_text=None): | |
| """Exibe resultados formatados de acordo com o tipo de modelo""" | |
| if model_key == 'summarization': | |
| st.subheader("📝 Resumo Gerado") | |
| if input_text: | |
| st.markdown("**Texto Original:**") | |
| st.write(input_text) | |
| st.markdown("**Resumo:**") | |
| st.info(result[0]['summary_text']) | |
| elif model_key == 'translation': | |
| st.subheader("🌍 Tradução") | |
| st.success(result[0]['translation_text']) | |
| elif model_key in ['sentiment_analysis', 'text_classification']: | |
| st.subheader("📊 Resultados") | |
| for res in result: | |
| label = res['label'] | |
| score = res['score'] | |
| st.progress(float(score), text=f"{label} ({score:.2%})") | |
| elif model_key == 'ner': | |
| st.subheader("🔍 Entidades Reconhecidas") | |
| for entity in result: | |
| st.write(f"- **{entity['word']}**: {entity['entity_group']} (confiança: {entity['score']:.2%})") | |
| elif model_key == 'text_generation': | |
| st.subheader("🧠 Texto Gerado") | |
| st.write(result[0]['generated_text']) | |
| elif model_key == 'image_classification': | |
| st.subheader("🏷️ Classificação") | |
| for res in result[:5]: | |
| st.write(f"- **{res['label']}**: {res['score']:.2%}") | |
| elif model_key == 'object_detection': | |
| st.subheader("📦 Objetos Detectados") | |
| for obj in result: | |
| st.write(f"- {obj['label']} (confiança: {obj['score']:.2%})") | |
| elif model_key == 'image_segmentation': | |
| st.subheader("🧩 Segmentação") | |
| st.image(result[0]['mask'], caption="Máscara de segmentação") | |
| elif model_key == 'facial_recognition': | |
| st.subheader("😊 Reconhecimento Facial") | |
| top_result = result[0] | |
| st.write(f"**Emoção predominante**: {top_result['label']} (confiança: {top_result['score']:.2%})") | |
| elif model_key == 'speech_to_text': | |
| st.subheader("🔈 Transcrição") | |
| st.success(result['text']) | |
| elif model_key == 'audio_classification': | |
| st.subheader("🎧 Classificação de Áudio") | |
| top_emotion = result[0] | |
| st.write(f"**Emoção detectada**: {top_emotion['label']} (confiança: {top_emotion['score']:.2%})") | |
| elif model_key == 'text_to_image': | |
| st.subheader("🎨 Imagem Gerada") | |
| st.image(result[0], caption="Imagem gerada a partir do texto") | |
| def load_branding(username): | |
| """Carrega branding personalizado por usuário""" | |
| branding = { | |
| 'admin': {'logo': 'logos/admin_logo.png', 'title': 'Bem-vindo, Administrador!'}, | |
| 'cliente': {'logo': 'logos/cliente_logo.png', 'title': 'Bem-vindo, Cliente!'}, | |
| 'empresa1': {'logo': 'logos/empresa1_logo.png', 'title': 'Bem-vindo, Empresa Um!'} | |
| } | |
| return branding.get(username, {'logo': None, 'title': 'Bem-vindo!'}) | |
| def admin_panel(authenticator): | |
| """Painel administrativo para gerenciar usuários""" | |
| if st.session_state.get('role') == 'admin': | |
| st.sidebar.subheader("Painel Admin") | |
| with st.sidebar.form("add_user_form"): | |
| username = st.text_input("Username") | |
| name = st.text_input("Nome") | |
| password = st.text_input("Senha", type="password") | |
| role = st.selectbox("Role", ["user", "admin"]) | |
| if st.form_submit_button("Adicionar Usuário"): | |
| hashed_password = stauth.Hasher([password]).generate()[0] | |
| db_path = os.getenv('DB_PATH', 'private/users.db') | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| try: | |
| cursor.execute('INSERT INTO users (username, name, password, role) VALUES (?, ?, ?, ?)', | |
| (username, name, hashed_password, role)) | |
| conn.commit() | |
| st.success(f"Usuário {username} adicionado!") | |
| except sqlite3.IntegrityError: | |
| st.error("Usuário já existe.") | |
| except Exception as e: | |
| st.error(f"Erro ao adicionar usuário: {str(e)}") | |
| logging.error(f"Erro ao adicionar usuário: {e}") | |
| sentry_sdk.capture_exception(e) | |
| conn.close() | |
| with st.sidebar.form("remove_user_form"): | |
| username_to_remove = st.text_input("Username para Remover") | |
| if st.form_submit_button("Remover Usuário"): | |
| db_path = os.getenv('DB_PATH', 'private/users.db') | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| try: | |
| cursor.execute('DELETE FROM users WHERE username = ?', (username_to_remove,)) | |
| conn.commit() | |
| if cursor.rowcount > 0: | |
| st.success(f"Usuário {username_to_remove} removido!") | |
| else: | |
| st.error("Usuário não encontrado.") | |
| except Exception as e: | |
| st.error(f"Erro ao remover usuário: {str(e)}") | |
| logging.error(f"Erro ao remover usuário: {e}") | |
| sentry_sdk.capture_exception(e) | |
| conn.close() | |
| def get_use_cases(): | |
| """Retorna os casos de uso para cada modelo""" | |
| return { | |
| 'sentiment_analysis': { | |
| 'title': "Análise de Sentimento", | |
| 'description': "Analisa o sentimento (positivo, negativo, neutro) em comentários, avaliações ou postagens de clientes em redes sociais.", | |
| 'example': "Uma empresa de varejo monitora menções da marca no Twitter/X, identificando feedback negativo para responder proativamente ou destacando comentários positivos em campanhas de marketing.", | |
| 'benefit': "Melhoria na gestão de reputação online e resposta rápida a crises de imagem.", | |
| 'demo_input': "A entrega foi super rápida, adorei!", | |
| 'demo_type': 'text' | |
| }, | |
| # Outros casos de uso mantidos idênticos ao original | |
| 'text_classification': { | |
| 'title': "Classificação de Texto", | |
| 'description': "Classifica e-mails recebidos como positivos ou negativos para priorizar respostas ou identificar reclamações.", | |
| 'example': "Um call center categoriza e-mails de clientes, direcionando mensagens negativas para equipes de suporte prioritário.", | |
| 'benefit': "Otimização do tempo da equipe de atendimento e melhoria na experiência do cliente.", | |
| 'demo_input': "Estou insatisfeito com o produto", | |
| 'demo_type': 'text' | |
| }, | |
| 'summarization': { | |
| 'title': "Resumo de Texto", | |
| 'description': "Gera resumos concisos de documentos longos, como relatórios financeiros ou atas de reuniões.", | |
| 'example': "Uma consultoria financeira resume relatórios anuais de empresas em poucos parágrafos para facilitar a análise de investidores.", | |
| 'benefit': "Economia de tempo na leitura de documentos extensos e tomada de decisão mais rápida.", | |
| 'demo_input': "A empresa XYZ reportou um crescimento de 15% no último trimestre, impulsionado por novas parcerias estratégicas e expansão no mercado asiático. No entanto, desafios logísticos aumentaram os custos operacionais em 5%. A diretoria planeja investir em automação para mitigar esses custos no próximo ano.", | |
| 'demo_type': 'text' | |
| }, | |
| 'question_answering': { | |
| 'title': "Perguntas e Respostas", | |
| 'description': "Responde perguntas específicas com base em manuais, FAQs ou documentos internos.", | |
| 'example': "Um chatbot de suporte técnico responde perguntas como 'Como configurar o produto X?' extraindo respostas diretamente do manual do produto.", | |
| 'benefit': "Redução do tempo de suporte e maior autonomia para os usuários finais.", | |
| 'demo_input': { | |
| 'context': "O produto X tem garantia de 2 anos e pode ser configurado via aplicativo móvel em 5 minutos.", | |
| 'question': "Qual é o tempo de garantia do produto X?" | |
| }, | |
| 'demo_type': 'qa' | |
| }, | |
| 'translation': { | |
| 'title': "Tradução (EN→PT)", | |
| 'description': "Traduz conteúdo de marketing, manuais ou comunicações de inglês para português.", | |
| 'example': "Uma empresa de software traduz descrições de produtos para lançar no mercado brasileiro.", | |
| 'benefit': "Expansão de mercado com conteúdo adaptado e redução de custos com tradutores humanos.", | |
| 'demo_input': "Our product ensures high performance", | |
| 'demo_type': 'text' | |
| }, | |
| 'ner': { | |
| 'title': "Reconhecimento de Entidades", | |
| 'description': "Identifica entidades como nomes de pessoas, organizações e locais em contratos ou documentos legais.", | |
| 'example': "Um escritório de advocacia extrai automaticamente nomes de partes envolvidas em contratos, agilizando revisões.", | |
| 'benefit': "Redução de erros manuais e maior eficiência na análise de documentos.", | |
| 'demo_input': "Microsoft assinou um contrato com a empresa XYZ em Nova York.", | |
| 'demo_type': 'text' | |
| }, | |
| 'text_generation': { | |
| 'title': "Geração de Texto", | |
| 'description': "Gera textos criativos para campanhas de marketing, postagens em redes sociais ou roteiros.", | |
| 'example': "Uma agência de publicidade cria slogans ou descrições de produtos a partir de prompts iniciais.", | |
| 'benefit': "Aceleração do processo criativo e geração de ideias inovadoras.", | |
| 'demo_input': "Um futuro onde a tecnologia conecta todos", | |
| 'demo_type': 'text' | |
| }, | |
| 'image_classification': { | |
| 'title': "Classificação de Imagem", | |
| 'description': "Identifica defeitos ou classifica produtos em linhas de produção com base em imagens.", | |
| 'example': "Uma fábrica de eletrônicos classifica imagens de circuitos como 'Defeituoso' ou 'Aprovado' para controle de qualidade.", | |
| 'benefit': "Redução de erros humanos e aumento da eficiência na inspeção.", | |
| 'demo_input': None, | |
| 'demo_type': 'image' | |
| }, | |
| 'object_detection': { | |
| 'title': "Detecção de Objetos", | |
| 'description': "Detecta objetos como pessoas, veículos ou itens em imagens de câmeras de segurança.", | |
| 'example': "Um sistema de segurança identifica veículos em um estacionamento para monitoramento automático.", | |
| 'benefit': "Maior segurança e automação de processos de monitoramento.", | |
| 'demo_input': None, | |
| 'demo_type': 'image' | |
| }, | |
| 'image_segmentation': { | |
| 'title': "Segmentação de Imagem", | |
| 'description': "Segmenta diferentes partes de uma imagem, como órgãos em exames médicos.", | |
| 'example': "Um hospital segmenta tumores em imagens de ressonância magnética, facilitando diagnósticos.", | |
| 'benefit': "Apoio a diagnósticos médicos com maior precisão e rapidez.", | |
| 'demo_input': None, | |
| 'demo_type': 'image' | |
| }, | |
| 'facial_recognition': { | |
| 'title': "Reconhecimento Facial", | |
| 'description': "Identifica emoções faciais em vídeos ou fotos de clientes em lojas ou eventos.", | |
| 'example': "Uma loja de varejo analisa expressões faciais de clientes para avaliar a satisfação durante interações com produtos.", | |
| 'benefit': "Melhoria na experiência do cliente com base em dados emocionais.", | |
| 'demo_input': None, | |
| 'demo_type': 'image' | |
| }, | |
| 'speech_to_text': { | |
| 'title': "Transcrição de Áudio", | |
| 'description': "Converte gravações de reuniões ou entrevistas em texto para documentação.", | |
| 'example': "Uma empresa transcreve automaticamente reuniões para criar atas ou resumos.", | |
| 'benefit': "Economia de tempo na documentação e maior acessibilidade de conteúdo.", | |
| 'demo_input': None, | |
| 'demo_type': 'audio' | |
| }, | |
| 'audio_classification': { | |
| 'title': "Classificação de Áudio", | |
| 'description': "Classifica emoções em chamadas de suporte para avaliar a qualidade do atendimento.", | |
| 'example': "Um call center analisa chamadas para identificar emoções como 'Frustração' ou 'Satisfação' dos clientes.", | |
| 'benefit': "Melhoria na formação de equipes e na experiência do cliente.", | |
| 'demo_input': None, | |
| 'demo_type': 'audio' | |
| }, | |
| 'text_to_image': { | |
| 'title': "Texto para Imagem", | |
| 'description': "Gera imagens personalizadas a partir de descrições textuais para campanhas publicitárias ou design de produtos.", | |
| 'example': "Uma agência de design cria mockups de produtos com base em prompts como 'Um smartphone futurista em um fundo azul neon'.", | |
| 'benefit': "Redução de custos com designers gráficos e maior agilidade na criação de conteúdo visual.", | |
| 'demo_input': "Uma paisagem tropical ao pôr do sol", | |
| 'demo_type': 'text' | |
| } | |
| } | |
| def handle_use_case_demo(models, use_case_key, use_case): | |
| """Executa a demonstração de um caso de uso com entrada pré-definida""" | |
| if use_case['demo_input'] is None: | |
| st.warning("⚠️ Demonstração não disponível. Este modelo requer upload de imagem ou áudio.") | |
| return | |
| st.subheader("📊 Demonstração") | |
| try: | |
| model = models.get(use_case_key) or load_model(use_case_key) | |
| if use_case['demo_type'] == 'text': | |
| with st.spinner("Processando demonstração..."): | |
| result = model(use_case['demo_input']) | |
| display_results(result, use_case_key, input_text=use_case['demo_input']) | |
| elif use_case['demo_type'] == 'qa': | |
| with st.spinner("Processando demonstração..."): | |
| result = model( | |
| question=use_case['demo_input']['question'], | |
| context=use_case['demo_input']['context'] | |
| ) | |
| st.success("🔍 Resposta encontrada:") | |
| st.markdown(f"**Contexto:** {use_case['demo_input']['context']}") | |
| st.markdown(f"**Pergunta:** {use_case['demo_input']['question']}") | |
| st.markdown(f"**Resposta:** {result['answer']}") | |
| st.markdown(f"**Confiança:** {result['score']:.2%}") | |
| except Exception as e: | |
| st.error(f"Erro ao executar demonstração: {str(e)}") | |
| logging.error(f"Erro na demonstração do caso de uso {use_case_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| def main(): | |
| # Inicializar banco de dados | |
| init_db() | |
| # Carregar configuração de autenticação | |
| config = load_users_from_db() | |
| if not config: | |
| st.error("Falha ao carregar autenticação. Contate o administrador.") | |
| return | |
| authenticator = stauth.Authenticate( | |
| config['credentials'], | |
| config['cookie']['name'], | |
| config['cookie']['key'], | |
| config['cookie']['expiry_days'], | |
| config['preauthorized'] | |
| ) | |
| # Tela de login | |
| name, authentication_status, username = authenticator.login('Login', 'main') | |
| if authentication_status: | |
| # Gerenciar sessão | |
| if "user_id" not in st.session_state: | |
| st.session_state.user_id = username | |
| st.session_state.role = config['credentials']['usernames'][username]['role'] | |
| # Carregar branding | |
| branding = load_branding(username) | |
| if branding['logo'] and os.path.exists(branding['logo']): | |
| st.image(branding['logo'], width=150) | |
| st.title(branding['title']) | |
| authenticator.logout('Logout', 'sidebar') | |
| admin_panel(authenticator) | |
| # Tour guiado | |
| if st.sidebar.button("Iniciar Tour"): | |
| st_tour([ | |
| {"element": "#login", "title": "Login", "description": "Faça login com suas credenciais."}, | |
| {"element": "#tab1", "title": "Explorar Modelos", "description": "Teste modelos de IA."}, | |
| {"element": "#tab2", "title": "Casos de Uso", "description": "Explore aplicações práticas."} | |
| ]) | |
| st.markdown("---") | |
| # Carregar modelos sob demanda | |
| models = {} | |
| model_categories = { | |
| "📝 Processamento de Texto": [ | |
| ("Análise de Sentimento", "sentiment_analysis"), | |
| ("Classificação de Texto", "text_classification"), | |
| ("Resumo de Texto", "summarization"), | |
| ("Perguntas e Respostas", "question_answering"), | |
| ("Tradução (EN→PT)", "translation"), | |
| ("Reconhecimento de Entidades", "ner"), | |
| ("Geração de Texto", "text_generation") | |
| ], | |
| "🖼️ Processamento de Imagem": [ | |
| ("Classificação de Imagem", "image_classification"), | |
| ("Detecção de Objetos", "object_detection"), | |
| ("Segmentação de Imagem", "image_segmentation"), | |
| ("Reconhecimento Facial", "facial_recognition") | |
| ], | |
| "🎵 Processamento de Áudio": [ | |
| ("Transcrição de Áudio", "speech_to_text"), | |
| ("Classificação de Emoções", "audio_classification") | |
| ], | |
| "✨ Modelos Generativos": [ | |
| ("Texto para Imagem", "text_to_image") | |
| ] | |
| } | |
| # Abas para navegação | |
| tab1, tab2 = st.tabs(["Explorar Modelos", "Casos de Uso"]) | |
| with tab1: | |
| st.sidebar.title("⚙️ Configurações") | |
| selected_category = st.sidebar.selectbox( | |
| "Categoria", | |
| list(model_categories.keys()), | |
| index=0 | |
| ) | |
| selected_model = st.sidebar.selectbox( | |
| "Modelo", | |
| [name for name, key in model_categories[selected_category]], | |
| format_func=lambda x: x, | |
| index=0 | |
| ) | |
| model_key = next(key for name, key in model_categories[selected_category] if name == selected_model) | |
| # Carregar modelo com barra de progresso | |
| if model_key not in models: | |
| with st.spinner(f"Carregando modelo {selected_model}..."): | |
| progress = st.progress(0) | |
| models[model_key] = load_model(model_key) | |
| progress.progress(100) | |
| st.header(f"{selected_model}") | |
| with st.expander("ℹ️ Sobre este modelo"): | |
| model_info = { | |
| 'sentiment_analysis': "Analisa o sentimento expresso em um texto (positivo/negativo/neutro).", | |
| 'text_classification': "Classifica textos em categorias pré-definidas.", | |
| 'summarization': "Gera um resumo conciso de um texto longo.", | |
| 'question_answering': "Responde perguntas baseadas em um contexto fornecido.", | |
| 'translation': "Traduz texto de inglês para português.", | |
| 'ner': "Identifica e classifica entidades nomeadas (pessoas, lugares, organizações).", | |
| 'text_generation': "Gera texto criativo continuando a partir de um prompt.", | |
| 'image_classification': "Identifica objetos e cenas em imagens.", | |
| 'object_detection': "Detecta e localiza múltiplos objetos em uma imagem.", | |
| 'image_segmentation': "Segmenta diferentes elementos em uma imagem.", | |
| 'facial_recognition': "Reconhece características faciais e emoções.", | |
| 'speech_to_text': "Transcreve fala em texto.", | |
| 'audio_classification': "Classifica emoções em arquivos de áudio.", | |
| 'text_to_image': "Gera imagens a partir de descrições textuais." | |
| } | |
| st.info(model_info.get(model_key, "Informações detalhadas sobre este modelo.")) | |
| try: | |
| if model_key in ['sentiment_analysis', 'text_classification', 'summarization', | |
| 'translation', 'text_generation', 'ner']: | |
| handle_text_models(models, model_key, selected_model) | |
| elif model_key == 'question_answering': | |
| handle_qa_model(models, model_key) | |
| elif model_key in ['image_classification', 'object_detection', | |
| 'image_segmentation', 'facial_recognition']: | |
| handle_image_models(models, model_key, selected_model) | |
| elif model_key in ['speech_to_text', 'audio_classification']: | |
| handle_audio_models(models, model_key) | |
| elif model_key == 'text_to_image': | |
| handle_generative_models(models, model_key) | |
| except Exception as e: | |
| st.error(f"Erro inesperado durante a execução: {str(e)}") | |
| logging.error(f"Erro durante a execução do modelo {model_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| with tab2: | |
| st.header("Casos de Uso") | |
| st.markdown("Explore casos práticos de aplicação dos modelos para resolver problemas reais.") | |
| use_cases = get_use_cases() | |
| selected_use_case = st.selectbox( | |
| "Selecione um caso de uso", | |
| list(use_cases.keys()), | |
| format_func=lambda x: use_cases[x]['title'] | |
| ) | |
| use_case = use_cases[selected_use_case] | |
| st.subheader(use_case['title']) | |
| with st.expander("ℹ️ Detalhes do Caso de Uso"): | |
| st.markdown(f"**Descrição**: {use_case['description']}") | |
| st.markdown(f"**Exemplo Prático**: {use_case['example']}") | |
| st.markdown(f"**Benefício**: {use_case['benefit']}") | |
| if use_case['demo_input'] is not None: | |
| if st.button("🚀 Executar Demonstração", key=f"demo_{selected_use_case}"): | |
| handle_use_case_demo(models, selected_use_case, use_case) | |
| def handle_text_models(models, model_key, model_name): | |
| """Manipula modelos de texto""" | |
| input_text = st.text_area( | |
| f"Digite o texto para {model_name.lower()}:", | |
| height=200, | |
| placeholder="Cole ou digite seu texto aqui...", | |
| key=f"text_input_{model_key}" | |
| ) | |
| advanced_params = {} | |
| if model_key == 'summarization': | |
| with st.expander("⚙️ Parâmetros Avançados"): | |
| advanced_params['max_length'] = st.slider("Comprimento máximo", 50, 300, 150) | |
| advanced_params['min_length'] = st.slider("Comprimento mínimo", 10, 100, 30) | |
| if model_key == 'text_generation': | |
| with st.expander("⚙️ Parâmetros Avançados"): | |
| advanced_params['max_length'] = st.slider("Comprimento do texto", 50, 500, 100) | |
| advanced_params['temperature'] = st.slider("Criatividade", 0.1, 1.0, 0.7) | |
| advanced_params['num_return_sequences'] = st.slider("Número de resultados", 1, 5, 1) | |
| if st.button(f"🚀 Executar {model_name}", type="primary", key=f"btn_{model_key}"): | |
| if input_text.strip(): | |
| with st.spinner("Processando..."): | |
| try: | |
| model = models.get(model_key) or load_model(model_key) | |
| if model_key == 'ner': | |
| result = model(input_text) | |
| elif model_key == 'text_generation': | |
| result = model( | |
| input_text, | |
| max_new_tokens=advanced_params.get('max_length', 100), | |
| do_sample=True, | |
| temperature=advanced_params.get('temperature', 0.7), | |
| top_k=50, | |
| top_p=0.95, | |
| num_return_sequences=advanced_params.get('num_return_sequences', 1) | |
| ) | |
| else: | |
| result = model(input_text, **advanced_params) | |
| display_results(result, model_key, input_text=input_text) | |
| except Exception as e: | |
| st.error(f"Erro ao processar texto: {str(e)}") | |
| logging.error(f"Erro no modelo {model_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| else: | |
| st.warning("⚠️ Por favor, insira um texto válido.") | |
| def handle_qa_model(models, model_key): | |
| """Manipula modelo de Q&A""" | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| context = st.text_area( | |
| "Contexto:", | |
| height=200, | |
| placeholder="Cole o texto que contém a informação...", | |
| key="qa_context" | |
| ) | |
| with col2: | |
| question = st.text_area( | |
| "Pergunta:", | |
| height=150, | |
| placeholder="Faça sua pergunta sobre o contexto...", | |
| key="qa_question" | |
| ) | |
| with st.expander("⚙️ Parâmetros Avançados"): | |
| confidence_threshold = st.slider("Limite de confiança", 0.0, 1.0, 0.5, 0.01) | |
| if st.button("🚀 Executar Pergunta e Resposta", type="primary", key="btn_qa"): | |
| if context.strip() and question.strip(): | |
| with st.spinner("Buscando resposta..."): | |
| try: | |
| model = models.get(model_key) or load_model(model_key) | |
| result = model(question=question, context=context) | |
| if result['score'] < confidence_threshold: | |
| st.warning(f"⚠️ Confiança baixa na resposta ({result['score']:.2%})") | |
| st.success("🔍 Resposta encontrada:") | |
| st.markdown(f"**Contexto:** {context}") | |
| st.markdown(f"**Pergunta:** {question}") | |
| st.markdown(f"**Resposta:** {result['answer']}") | |
| st.markdown(f"**Confiança:** {result['score']:.2%}") | |
| except Exception as e: | |
| st.error(f"Erro ao processar Q&A: {str(e)}") | |
| logging.error(f"Erro no modelo Q&A: {e}") | |
| sentry_sdk.capture_exception(e) | |
| else: | |
| st.warning("⚠️ Por favor, forneça tanto o contexto quanto a pergunta.") | |
| def handle_image_models(models, model_key, model_name): | |
| """Manipula modelos de imagem""" | |
| uploaded_file = st.file_uploader( | |
| "Carregue uma imagem", | |
| type=["jpg", "png", "jpeg", "bmp"], | |
| help="Formatos suportados: JPG, PNG, JPEG, BMP", | |
| key=f"img_upload_{model_key}" | |
| ) | |
| if uploaded_file is not None: | |
| if not validate_image_file(uploaded_file): | |
| st.error("⚠️ Formato de arquivo inválido ou arquivo corrompido.") | |
| return | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("🖼️ Imagem Original") | |
| image = process_image_file(uploaded_file) | |
| if image: | |
| st.image(image) | |
| with col2: | |
| st.subheader("📊 Resultados") | |
| if st.button(f"🚀 Executar {model_name}", type="primary", key=f"btn_img_{model_key}"): | |
| if image: | |
| with st.spinner("Analisando imagem..."): | |
| try: | |
| model = models.get(model_key) or load_model(model_key) | |
| result = model(image) | |
| display_results(result, model_key) | |
| except Exception as e: | |
| st.error(f"Erro ao processar imagem: {str(e)}") | |
| logging.error(f"Erro no modelo {model_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| def handle_audio_models(models, model_key): | |
| """Manipula modelos de áudio""" | |
| model_name = "Transcrição de Áudio" if model_key == 'speech_to_text' else "Classificação de Áudio" | |
| uploaded_file = st.file_uploader( | |
| f"Carregue um arquivo de áudio para {model_name}", | |
| type=["wav", "mp3", "flac", "m4a"], | |
| help="Formatos suportados: WAV, MP3, FLAC, M4A", | |
| key=f"audio_upload_{model_key}" | |
| ) | |
| if uploaded_file is not None: | |
| if not validate_audio_file(uploaded_file): | |
| st.error("⚠️ Formato de arquivo inválido ou não suportado.") | |
| return | |
| st.audio(uploaded_file, format="audio/wav") | |
| if st.button(f"🚀 Executar {model_name}", type="primary", key=f"btn_audio_{model_key}"): | |
| with st.spinner("Processando áudio..."): | |
| try: | |
| audio_array = process_audio_file(uploaded_file) | |
| if audio_array is not None: | |
| model = models.get(model_key) or load_model(model_key) | |
| result = model(audio_array) | |
| display_results(result, model_key) | |
| else: | |
| st.error("Não foi possível processar o arquivo de áudio.") | |
| except Exception as e: | |
| st.error(f"Erro ao processar áudio: {str(e)}") | |
| logging.error(f"Erro no modelo {model_key}: {e}") | |
| sentry_sdk.capture_exception(e) | |
| def handle_generative_models(models, model_key): | |
| """Manipula modelos generativos""" | |
| prompt = st.text_area( | |
| "Descrição da imagem:", | |
| height=150, | |
| placeholder="Descreva a imagem que deseja gerar...", | |
| key="text_to_image_prompt" | |
| ) | |
| with st.expander("⚙️ Parâmetros Avançados"): | |
| cols = st.columns(2) | |
| with cols[0]: | |
| width = st.slider("Largura", 256, 1024, 512, 64) | |
| with cols[1]: | |
| height = st.slider("Altura", 256, 1024, 512, 64) | |
| num_images = st.slider("Número de imagens", 1, 4, 1) | |
| guidance_scale = st.slider("Escala de orientação", 1.0, 20.0, 7.5) | |
| if st.button("🚀 Gerar Imagem", type="primary", key="btn_text_to_image"): | |
| if prompt.strip(): | |
| with st.spinner("Criando imagem..."): | |
| try: | |
| model = models.get(model_key) or load_model(model_key) | |
| result = model( | |
| prompt, | |
| height=height, | |
| width=width, | |
| num_images_per_prompt=num_images, | |
| guidance_scale=guidance_scale | |
| ) | |
| display_results(result, model_key) | |
| except Exception as e: | |
| st.error(f"Erro ao gerar imagem: {str(e)}") | |
| logging.error(f"Erro no modelo text-to-image: {e}") | |
| sentry_sdk.capture_exception(e) | |
| else: | |
| st.warning("⚠️ Por favor, insira uma descrição para a imagem.") | |
| if __name__ == "__main__": | |
| main() |