#--- START OF FILE app (23).py --- import streamlit as st import time import os import tempfile # Para criar diretórios temporários seguros # --- IMPORTS GROQ --- from groq import Groq # --- IMPORTS LANGCHAIN / RAG --- from langchain_community.document_loaders import TextLoader from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS from langchain.chains import RetrievalQA from langchain_groq import ChatGroq # -------------------------- # 1. Título da Página e Configuração de Layout st.set_page_config(page_title="Iza - Assistente Groq RAG", layout="wide") # --- CSS CORRIGIDO E ATUALIZADO (REMOÇÃO DO AVATAR E ESPAÇO) --- st.markdown(""" """, unsafe_allow_html=True) st.title("Iza - Assistente com Groq RAG 🚀") st.caption("Um chatbot com memória, upload de arquivos, LangChain RAG e controle de velocidade.") # 3. Configuração do Cliente Groq print("DEBUG: Inicializando clientes Groq.") # Log de depuração client = Groq() groq_llm = ChatGroq(model_name="mixtral-8x7b-32768", temperature=0.7) # 2. Barra Lateral e Lógica de Upload/Processamento RAG with st.sidebar: st.header("Opções") if 'retriever' not in st.session_state: st.session_state.retriever = None st.session_state.retriever_source = None print("DEBUG: Estado inicial: retriever=None.") # Log de depuração uploaded_file = st.file_uploader( "Anexe um arquivo para pesquisa RAG (opcional)", type=["txt", "md", "pdf"], help="O arquivo será processado e a IA poderá responder perguntas sobre seu conteúdo." ) # Lógica de Processamento do Arquivo if uploaded_file: # Apenas processa se o arquivo for novo if st.session_state.retriever_source != uploaded_file.name: file_path = f"./temp_file_{uploaded_file.name.replace('/', '_')}" try: # --- USO DO DIRETÓRIO TEMPORÁRIO --- st.info("Passo 1/5: Salvando arquivo temporariamente. Aguarde...") print(f"DEBUG: Tentando salvar arquivo: {uploaded_file.name}") # Log de depuração with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{uploaded_file.name}") as tmp_file: tmp_file.write(uploaded_file.read()) file_path = tmp_file.name print(f"DEBUG: Arquivo salvo em: {file_path}") # Log de depuração # 2. CONFIGURAÇÃO RAG (Processo de Embedding) with st.spinner(f"Processando '{uploaded_file.name}' com LangChain..."): # Carregamento do Documento if uploaded_file.type == 'application/pdf': loader = PyPDFLoader(file_path) elif uploaded_file.type in ['text/markdown', 'text/plain']: loader = TextLoader(file_path) else: raise ValueError("Tipo de arquivo não suportado após o upload.") documents = loader.load() st.info(f"Passo 2/5: Carregamento concluído. Documentos carregados: {len(documents)}.") # Fragmentação do Texto text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) texts = text_splitter.split_documents(documents) st.info(f"Passo 3/5: Texto fragmentado em {len(texts)} pedaços.") # HuggingFace Embeddings (Roda na CPU) st.info("Passo 4/5: Criando Embeddings (vetores) com HuggingFace. Isso pode levar alguns segundos.") embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") # Criar o Vector Store (FAISS) st.info("Passo 5/5: Criando o Vector Store (FAISS) para busca rápida.") vectorstore = FAISS.from_documents(texts, embeddings) # Armazenar na sessão st.session_state.retriever = vectorstore.as_retriever() st.session_state.retriever_source = uploaded_file.name st.success(f"Arquivo '{uploaded_file.name}' processado! Pergunte sobre ele.") print("DEBUG: Processo RAG concluído e retriever armazenado.") # Log de depuração except Exception as e: # Tratamento de erro 403 e outros if "403" in str(e): st.error("Erro no upload (403 Forbidden). O servidor de deploy está rejeitando a requisição.") print(f"ERRO CRÍTICO (403): {e}") # Log de depuração else: st.error(f"Erro ao processar o arquivo: {e}") print(f"ERRO DE PROCESSAMENTO: {e}") # Log de depuração st.session_state.retriever = None st.session_state.retriever_source = None finally: # Garante que o arquivo temporário seja removido if os.path.exists(file_path): os.remove(file_path) print(f"DEBUG: Arquivo temporário removido: {file_path}") # Log de depuração else: st.info(f"O arquivo '{st.session_state.retriever_source}' já foi processado e está ativo.") elif st.session_state.retriever_source is not None: st.warning("O arquivo processado foi removido. A IA voltará a usar pesquisa web.") st.session_state.retriever = None st.session_state.retriever_source = None # 4. Inicialização do Histórico da Conversa if "messages" not in st.session_state: print("DEBUG: Inicializando histórico de mensagens.") # Log de depuração system_prompt = ( "Você é um assistente de pesquisa avançado chamado Iza. " "Se houver um documento anexo, use-o como primeira fonte de conhecimento. " "Caso contrário, use as ferramentas 'visit_website' ou 'web_search' para obter informações. " "Sua tarefa é fornecer um resumo completo, bem estruturado e detalhado em markdown. " "IMPORTANTE: Ao criar tabelas, elas devem ter no máximo 3 colunas, e de preferência apenas 2, " "para garantir a legibilidade em todas as telas." ) st.session_state.messages = [{"role": "system", "content": system_prompt}] # 5. Exibição das Mensagens Anteriores (Log de quantas mensagens) if len(st.session_state.messages) > 1: print(f"DEBUG: Exibindo {len(st.session_state.messages) - 1} mensagens anteriores.") # Log de depuração for message in st.session_state.messages: if message["role"] != "system": with st.chat_message(message["role"]): st.markdown(message["content"]) # 6. Lógica de Interação do Chat if prompt := st.chat_input("Pergunte algo sobre o documento ou faça uma pesquisa na web..."): # 6a. Adiciona a mensagem do usuário e exibe st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) print(f"DEBUG: Prompt do usuário: '{prompt}'") # Log de depuração # 6b. Obtém a resposta do assistente (RAG ou Streaming com Tool Use) with st.chat_message("assistant"): placeholder = st.empty() full_response = "" try: # --- LÓGICA DE DECISÃO RAG vs GROQ DIRETO --- if st.session_state.retriever is not None: # RAG: Caso haja um arquivo anexado. print("DEBUG: Modo RAG (Documento anexado) ativado.") # Log de depuração qa_chain = RetrievalQA.from_chain_type( llm=groq_llm, chain_type="stuff", retriever=st.session_state.retriever, return_source_documents=False ) # Resposta RAG with st.spinner("Buscando no documento e gerando resposta..."): result = qa_chain.invoke({"query": prompt}) full_response = result['result'] else: # GROQ DIRETO: Caso NÃO haja arquivo (usa Tool Use para pesquisa web). print("DEBUG: Modo Groq Direto (Web Search) ativado.") # Log de depuração stream = client.chat.completions.create( model="groq/compound", messages=[ {"role": m["role"], "content": m["content"]} for m in st.session_state.messages ], temperature=0.7, max_tokens=4096, stream=True, compound_custom={"tools": {"enabled_tools": ["web_search", "visit_website"]}} ) # Streaming da resposta for chunk in stream: full_response += chunk.choices[0].delta.content or "" placeholder.markdown(full_response + "▌") time.sleep(0.005) # Exibe a resposta completa placeholder.markdown(full_response) print("DEBUG: Resposta completa enviada ao chat.") # Log de depuração # 6c. Adiciona a resposta completa ao histórico st.session_state.messages.append({"role": "assistant", "content": full_response}) except Exception as e: st.error(f"Ocorreu um erro na interação: {e}") print(f"ERRO DE INTERAÇÃO: {e}") # Log de depuração # --- END OF FILE app (23).py ---