circulo_bot / app.py
h1bertto's picture
Update app.py
15e18fd verified
Raw
History Blame Contribute Delete
5.73 kB
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()