import streamlit as st
import os
from pathlib import Path
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.gemini import Gemini
from llama_index.embeddings.google import GoogleEmbedding
import google.generativeai as genai
import hashlib
import hmac
from typing import Optional
# Configuração da página
st.set_page_config(
page_title="Anatomia - Material Didático",
page_icon="📚",
layout="wide"
)
# Configuração da API do Google
def setup_gemini():
"""Configura o Gemini com a API key"""
try:
# Pegar API key dos secrets do Streamlit
api_key = st.secrets.get("GOOGLE_API_KEY")
if not api_key:
st.error("❌ API Key do Google não encontrada! Configure nos secrets.")
return False
# Configurar o genai
genai.configure(api_key=api_key)
# Configurar o LLM Gemini
llm = Gemini(
model="models/gemini-1.5-flash", # Use gemini-1.5-pro para mais qualidade
api_key=api_key,
temperature=0.7,
max_tokens=1024,
)
# Configurar embeddings
embed_model = GoogleEmbedding(
model="models/embedding-001",
api_key=api_key,
)
# Configurar globalmente
Settings.llm = llm
Settings.embed_model = embed_model
Settings.chunk_size = 512
Settings.chunk_overlap = 50
return True
except Exception as e:
st.error(f"❌ Erro ao configurar Gemini: {str(e)}")
return False
# Função para verificar senha
def check_password():
"""Verifica se a senha está correta"""
def password_entered():
"""Verifica se a senha inserida corresponde à senha armazenada"""
if hmac.compare_digest(
st.session_state["password"],
st.secrets["PASSWORD"]
):
st.session_state["password_correct"] = True
del st.session_state["password"]
else:
st.session_state["password_correct"] = False
# Retorna True se a senha estiver correta
if st.session_state.get("password_correct", False):
return True
# Mostra o campo de senha
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.markdown("### 🔒 Acesso Restrito")
st.markdown("""
⚠️ Material protegido por direitos autorais
Este conteúdo é de uso exclusivo dos alunos da disciplina.
""", unsafe_allow_html=True)
st.text_input(
"Digite a senha de acesso:",
type="password",
on_change=password_entered,
key="password",
placeholder="Senha fornecida pelo monitor"
)
if st.session_state.get("password_correct", False) is False and st.session_state.get("password"):
st.error("❌ Senha incorreta! Acesso negado.")
return False
# Função para mostrar aviso de direitos autorais
def show_copyright_notice():
with st.sidebar:
st.image("https://cdn-icons-png.flaticon.com/512/2917/2917995.png", width=100)
st.markdown("## 📚 Anatomia")
st.markdown("---")
st.markdown("""
### ⚠️ **Aviso Legal**
**Este material é protegido por direitos autorais.**
#### É proibido:
- ❌ Compartilhar o link de acesso
- ❌ Baixar ou reproduzir o conteúdo
- ❌ Distribuir o material por qualquer meio
- ❌ Utilizar fora do contexto da disciplina
#### © Todos os direitos reservados ao professor.
""")
st.markdown("---")
st.markdown("### 📊 Estatísticas")
if "messages" in st.session_state:
st.metric("Perguntas realizadas", len(st.session_state.messages) // 2)
st.markdown("---")
st.markdown("### 💡 Dicas")
st.info("""
**Para melhores resultados:**
- Seja específico nas perguntas
- Mencione estruturas anatômicas claramente
- Pergunte sobre um tópico por vez
""")
# Função para carregar e processar os documentos
@st.cache_resource
def load_documents():
"""Carrega os documentos e cria o índice"""
try:
# Verificar se existe a pasta data
data_path = Path("data")
if not data_path.exists():
st.warning("⚠️ Pasta 'data' não encontrada. Criando pasta...")
data_path.mkdir(exist_ok=True)
st.info("📁 Por favor, adicione os arquivos das aulas na pasta 'data'")
return None
# Verificar se há arquivos
files = list(data_path.glob("*"))
if not files:
st.warning("⚠️ Nenhum arquivo encontrado na pasta 'data'")
st.info("📄 Adicione os arquivos .txt, .pdf ou .docx das aulas")
return None
# Carregar documentos
with st.spinner("📖 Carregando material didático..."):
documents = SimpleDirectoryReader("data").load_data()
if not documents:
st.warning("⚠️ Nenhum documento válido encontrado")
return None
st.success(f"✅ {len(documents)} documentos carregados com sucesso!")
# Criar índice
with st.spinner("🔨 Construindo índice de busca..."):
index = VectorStoreIndex.from_documents(documents)
# Criar query engine com configurações personalizadas
query_engine = index.as_query_engine(
similarity_top_k=3,
response_mode="compact",
)
return query_engine
except Exception as e:
st.error(f"❌ Erro ao carregar documentos: {str(e)}")
return None
# Função para formatar resposta
def format_response(response):
"""Formata a resposta para melhor visualização"""
return response
# Interface de chat
def chat_interface(query_engine):
"""Interface principal de chat"""
# Título principal
st.markdown("""
🦴 Assistente Virtual de Anatomia
Tire suas dúvidas sobre o conteúdo das aulas
""", unsafe_allow_html=True)
st.markdown("---")
# Inicializar histórico de chat
if "messages" not in st.session_state:
st.session_state.messages = []
# Mostrar histórico
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Input do usuário
if prompt := st.chat_input("Digite sua pergunta sobre anatomia..."):
# Adicionar mensagem do usuário
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# Gerar resposta
with st.chat_message("assistant"):
with st.spinner("🔍 Buscando no material didático..."):
try:
# Adicionar contexto de direitos autorais
response = query_engine.query(prompt)
# Exibir resposta
st.markdown(response.response)
# Adicionar fonte
with st.expander("📖 Ver fonte no material"):
st.info("Resposta baseada no material das aulas")
st.session_state.messages.append(
{"role": "assistant", "content": response.response}
)
except Exception as e:
st.error(f"❌ Erro ao processar pergunta: {str(e)}")
st.info("💡 Tente reformular sua pergunta ou seja mais específico")
# Função de boas-vindas
def welcome_message():
"""Mostra mensagem de boas-vindas"""
st.markdown("""
🎓 Bem-vindo(a) ao Assistente de Anatomia!
Este assistente foi desenvolvido para ajudar você a estudar o conteúdo das aulas de Anatomia.
Como usar:
- Faça perguntas específicas sobre os temas das aulas
- O assistente buscará respostas apenas no material oficial
- Seja claro e objetivo para obter melhores respostas
Exemplos de perguntas:
• Qual a função do osso esfenóide?
• Explique a estrutura do coração
• Quais são os músculos da respiração?
""", unsafe_allow_html=True)
# Função principal
def main():
# Verificar senha
if not check_password():
st.stop()
# Configurar Gemini
if not setup_gemini():
st.stop()
# Layout com sidebar
show_copyright_notice()
# Área principal
col1, col2, col3 = st.columns([1, 3, 1])
with col2:
# Carregar documentos
query_engine = load_documents()
if query_engine is None:
st.warning("""
### 📁 Adicione os arquivos das aulas
Para começar a usar o assistente, você precisa:
1. Criar uma pasta chamada `data` na raiz do projeto
2. Adicionar os arquivos das aulas (.txt, .pdf ou .docx)
3. Aguardar o processamento automático
Se você já adicionou os arquivos, aguarde alguns segundos.
""")
return
# Mostrar mensagem de boas-vindas se não houver histórico
if not st.session_state.get("messages", []):
welcome_message()
# Interface de chat
chat_interface(query_engine)
# Rodapé
st.markdown("---")
st.markdown("""
© Material didático protegido por direitos autorais - Uso exclusivo em sala de aula
Em caso de problemas técnicos, contate o monitor da disciplina
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()