Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| from huggingface_hub import InferenceClient | |
| from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader | |
| from langchain_text_splitters import RecursiveCharacterTextSplitter | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_community.vectorstores import Chroma | |
| # --- CONFIGURAÇÕES --- | |
| HF_TOKEN = os.getenv("Circulo_bot") | |
| MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct" | |
| DB_DIR = "./chroma_db" | |
| client = InferenceClient(MODEL_ID, token=HF_TOKEN) | |
| os.environ["USER_AGENT"] = "SRF_Marilia_Bot/1.0" | |
| # --- 1. CARREGAMENTO E VETORIZAÇÃO (RAG) --- | |
| def inicializar_base_conhecimento(): | |
| embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") | |
| # Se o banco já existe localmente, carrega ele em vez de reprocessar tudo | |
| if os.path.exists(DB_DIR) and os.listdir(DB_DIR): | |
| print("Carregando base de dados existente...") | |
| return Chroma(persist_directory=DB_DIR, embedding_function=embeddings) | |
| print("Criando nova base de dados...") | |
| urls = ["https://www.srf-marilia.com/atividades.html", "https://srf-marilia.com/index.html", "https://srf-marilia.com/srf.html", | |
| "https://srf-marilia.com/yogananda.html", "https://srf-marilia.com/meditacao.html", "https://srf-marilia.com/livraria.html", | |
| "https://srf-marilia.com/links.html", "https://www.instagram.com/srf.marilia", "https://yogananda.org/pt/perguntas-frequentes"] | |
| pdf_files = ["Autobiografia.pdf", "Circulo.pdf", "SRF.pdf", "FAQ.pdf", "Livros.pdf"] | |
| docs = [] | |
| # Carregar URLs | |
| for url in urls: | |
| try: | |
| loader = WebBaseLoader(url) | |
| docs.extend(loader.load()) | |
| except Exception as e: | |
| print(f"Erro URL {url}: {e}") | |
| # Carregar PDFs | |
| for pdf in pdf_files: | |
| if os.path.exists(pdf): | |
| try: | |
| loader = PyPDFLoader(pdf) | |
| docs.extend(loader.load()) | |
| except Exception as e: | |
| print(f"Erro PDF {pdf}: {e}") | |
| # Processamento de texto | |
| text_splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100) | |
| splits = text_splitter.split_documents(docs) | |
| # Criar e persistir o banco | |
| vectorstore = Chroma.from_documents( | |
| documents=splits, | |
| embedding=embeddings, | |
| persist_directory=DB_DIR | |
| ) | |
| return vectorstore | |
| # Inicializa o banco globalmente | |
| vectorstore = inicializar_base_conhecimento() | |
| # --- 2. LÓGICA DO CHAT --- | |
| def bot_response(message, history): | |
| # 1. Busca por similaridade no banco de dados | |
| relevant_docs = vectorstore.similarity_search(message, k=3) | |
| context = "\n\n".join([doc.page_content for doc in relevant_docs]) | |
| # 2. Prompt do Sistema | |
| system_message = ( | |
| "Você é o Assistente Virtual do Círculo de Meditação de Marília da SRF. " | |
| "Seu tom deve ser sempre calmo, gentil, acolhedor e espiritualizado, " | |
| "refletindo a paz dos ensinamentos de Paramahansa Yogananda.\n\n" | |
| "DIRETRIZES DE RESPOSTA:\n" | |
| "1. Se a resposta estiver presente no CONTEXTO abaixo, sinta-se à vontade para ser " | |
| "atencioso e explicar com clareza e beleza, usando o máximo de detalhes que o contexto permitir.\n" | |
| "2. Se a informação NÃO estiver no contexto, não tente adivinhar. Nesse caso específico, " | |
| "seja breve e peça desculpas, orientando o usuário a enviar um e-mail para srf.marilia@yahoo.com.\n" | |
| "3. Nunca mencione que está lendo um texto ou que tem um 'contexto fornecido'. Fale de forma natural.\n\n" | |
| f"CONTEXTO RELEVANTE:\n{context}" | |
| ) | |
| # 3. Construção do histórico de mensagens (Versão Segura) | |
| messages = [{"role": "system", "content": system_message}] | |
| for entry in history: | |
| # Se o histórico vier como dicionário (Gradio 5+) | |
| if isinstance(entry, dict): | |
| messages.append({"role": entry["role"], "content": entry["content"]}) | |
| # Se o histórico vier como lista/tupla (Gradio 4-) | |
| elif isinstance(entry, (list, tuple)) and len(entry) == 2: | |
| user_part, bot_part = entry | |
| if user_part: messages.append({"role": "user", "content": user_part}) | |
| if bot_part: messages.append({"role": "assistant", "content": bot_part}) | |
| # Adiciona a pergunta atual do usuário | |
| messages.append({"role": "user", "content": message}) | |
| # 4. GERAÇÃO via Stream (Versão ultra-segura) | |
| partial_text = "" | |
| try: | |
| for chunk in client.chat_completion( | |
| messages, | |
| max_tokens=600, | |
| stream=True, | |
| temperature=0.10, # Quase determinístico | |
| top_p=0.90 # Filtra respostas muito "fora da caixa" | |
| ): | |
| # Verificamos cuidadosamente se o chunk tem os dados antes de acessar o índice [0] | |
| if hasattr(chunk, 'choices') and len(chunk.choices) > 0: | |
| token = chunk.choices[0].delta.content | |
| if token: | |
| partial_text += token | |
| yield partial_text | |
| except Exception as e: | |
| yield f"Houve um erro na comunicação com o modelo: {str(e)}" | |
| # --- 3. INTERFACE --- | |
| # Removendo o argumento 'theme' que causou o erro | |
| demo = gr.ChatInterface( | |
| fn=bot_response, | |
| title="🧘 Assistente SRF Marília", | |
| description="Tire suas dúvidas sobre meditação e os ensinamentos de Paramahansa Yogananda.", | |
| examples=["Como começar a meditar?", "Quais os horários das atividades?", "Quem foi Yogananda?"], | |
| cache_examples=False | |
| ) | |
| if __name__ == "__main__": | |
| # Removendo server_name e server_port para o Hugging Face gerenciar sozinho | |
| demo.launch() | |