AiiTServices / app.py
HenriqueBraz's picture
Update app.py
ec4b7be verified
raw
history blame
29.4 kB
import streamlit as st
import streamlit_authenticator as stauth
import sqlite3
import os
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
# Configurar página
st.set_page_config(
page_title="Aplicação de IA Multi-Modal",
page_icon="🤖",
layout="wide"
)
# Configurar logging
logging.basicConfig(
filename='app_errors.log',
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Configurar banco de dados SQLite
def init_db():
"""Inicializa o banco de dados SQLite com tabela de usuários"""
db_path = os.getenv('DB_PATH', 'users.db')
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Criar tabela de usuários se não existir
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
username TEXT PRIMARY KEY,
name TEXT NOT NULL,
password TEXT NOT NULL
)
''')
# Adicionar usuários de exemplo (remover ou personalizar em produção)
try:
hashed_password = stauth.Hasher(['senha123']).generate()[0]
cursor.execute('''
INSERT OR IGNORE INTO users (username, name, password)
VALUES (?, ?, ?)
''', ('cliente', 'Cliente', hashed_password))
cursor.execute('''
INSERT OR IGNORE INTO users (username, name, password)
VALUES (?, ?, ?)
''', ('empresa1', 'Empresa Um', hashed_password))
conn.commit()
except Exception as e:
logging.error(f"Erro ao inicializar banco de dados: {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', 'users.db')
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute("SELECT username, name, password FROM users")
users = {row[0]: {'name': row[1], 'password': row[2]} 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 do banco de dados: {str(e)}")
logging.error(f"Erro ao carregar usuários: {e}")
return None
# Cache para evitar recarregar modelos a cada execução
@st.cache_resource(show_spinner=False)
def load_models():
"""Carrega todos os modelos com cache para melhor performance"""
device = torch.device("cpu") # Use 'cuda' se GPU estiver disponível
logging.info(f"Usando dispositivo: {device}")
models = {}
try:
# Modelos de texto
models['sentiment_analysis'] = pipeline(
"sentiment-analysis",
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
device=device
)
models['text_classification'] = pipeline(
"text-classification",
model="distilbert-base-uncased-finetuned-sst-2-english",
device=device
)
models['summarization'] = pipeline(
"summarization",
model="facebook/bart-large-cnn",
device=device,
max_length=150,
min_length=30
)
models['question_answering'] = pipeline(
"question-answering",
model="deepset/roberta-base-squad2",
device=device
)
models['translation'] = pipeline(
"translation",
model="Helsinki-NLP/opus-mt-tc-big-en-pt",
device=device
)
tokenizer_gpt2 = AutoTokenizer.from_pretrained("gpt2")
model_gpt2 = AutoModelForCausalLM.from_pretrained("gpt2")
model_gpt2.config.pad_token_id = model_gpt2.config.eos_token_id
models['text_generation'] = pipeline(
"text-generation",
model=model_gpt2,
tokenizer=tokenizer_gpt2,
device=device
)
models['ner'] = pipeline(
"ner",
model="dbmdz/bert-large-cased-finetuned-conll03-english",
device=device,
aggregation_strategy="simple"
)
# Modelos de imagem
models['image_classification'] = pipeline(
"image-classification",
model="google/vit-base-patch16-224",
device=device
)
models['object_detection'] = pipeline(
"object-detection",
model="facebook/detr-resnet-50",
device=device
)
models['image_segmentation'] = pipeline(
"image-segmentation",
model="facebook/detr-resnet-50-panoptic",
device=device
)
models['facial_recognition'] = pipeline(
"image-classification",
model="mo-thecreator/vit-Facial-Expression-Recognition",
device=device
)
# Modelos de áudio
models['speech_to_text'] = pipeline(
"automatic-speech-recognition",
model="openai/whisper-base",
device=device
)
models['audio_classification'] = pipeline(
"audio-classification",
model="superb/hubert-base-superb-er",
device=device
)
# Modelos generativos
models['text_to_image'] = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16,
use_safetensors=True,
safety_checker=None,
variant="fp16"
)
except Exception as e:
st.error(f"Erro crítico ao carregar modelos: {str(e)}")
logging.exception("Erro ao carregar modelos")
return {}
return models
def validate_audio_file(file: UploadedFile) -> bool:
"""Valida o arquivo de áudio"""
valid_extensions = ['.wav', '.mp3', '.flac', '.m4a']
if not any(file.name.lower().endswith(ext) for ext in valid_extensions):
return False
return True
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}")
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}")
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 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'
},
'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:
if use_case['demo_type'] == 'text':
with st.spinner("Processando demonstração..."):
result = models[use_case_key](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 = models[use_case_key](
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}")
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:
st.write(f"Bem-vindo, {name}!")
authenticator.logout('Logout', 'sidebar')
st.title("🤖 Aplicação de IA Multi-Modal Avançada")
st.markdown("---")
# Carregar modelos
with st.spinner("Carregando modelos de IA... (Isso pode levar alguns minutos na primeira execução)"):
models = load_models()
if not models:
st.error("Falha crítica ao carregar os modelos. Verifique os logs para mais detalhes.")
return
# Abas para navegação
tab1, tab2 = st.tabs(["Explorar Modelos", "Casos de Uso"])
with tab1:
# Sidebar para seleção de modelo
st.sidebar.title("⚙️ Configurações")
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")
]
}
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
)
# Obter chave do modelo selecionado
model_key = next(key for name, key in model_categories[selected_category] if name == selected_model)
# Interface principal
st.header(f"{selected_model}")
# Accordion para informações do modelo
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."))
# Processamento baseado no tipo de 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.exception("Erro durante a execução do modelo")
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}"
)
# Parâmetros adicionais para alguns modelos
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:
if model_key == 'ner':
result = models[model_key](input_text)
elif model_key == 'text_generation':
result = models[model_key](
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 = models[model_key](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}")
else:
st.warning("⚠️ Por favor, insira um texto válido.")
def handle