Spaces:
Runtime error
Runtime error
| 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(""" | |
| <div style='background-color: #fff3cd; padding: 15px; border-radius: 10px; margin: 10px 0;'> | |
| ⚠️ <strong>Material protegido por direitos autorais</strong><br> | |
| Este conteúdo é de uso exclusivo dos alunos da disciplina. | |
| </div> | |
| """, 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 | |
| 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(""" | |
| <div style='text-align: center; padding: 20px;'> | |
| <h1>🦴 Assistente Virtual de Anatomia</h1> | |
| <p style='font-size: 18px;'>Tire suas dúvidas sobre o conteúdo das aulas</p> | |
| </div> | |
| """, 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(""" | |
| <div style='background-color: #e8f4f8; padding: 20px; border-radius: 10px; margin: 20px 0;'> | |
| <h3>🎓 Bem-vindo(a) ao Assistente de Anatomia!</h3> | |
| <p>Este assistente foi desenvolvido para ajudar você a estudar o conteúdo das aulas de Anatomia.</p> | |
| <p><strong>Como usar:</strong></p> | |
| <ul> | |
| <li>Faça perguntas específicas sobre os temas das aulas</li> | |
| <li>O assistente buscará respostas apenas no material oficial</li> | |
| <li>Seja claro e objetivo para obter melhores respostas</li> | |
| </ul> | |
| <p><strong>Exemplos de perguntas:</strong></p> | |
| <code>• Qual a função do osso esfenóide?</code><br> | |
| <code>• Explique a estrutura do coração</code><br> | |
| <code>• Quais são os músculos da respiração?</code> | |
| </div> | |
| """, 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(""" | |
| <div style='text-align: center; color: gray; font-size: 12px;'> | |
| <p>© Material didático protegido por direitos autorais - Uso exclusivo em sala de aula</p> | |
| <p>Em caso de problemas técnicos, contate o monitor da disciplina</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if __name__ == "__main__": | |
| main() |