""" app.py — Interface Gradio para o RAG didático (compatível com Gradio 5) Execute localmente: python app.py No HF Space: o Spaces detecta automaticamente o app.py com gr.Blocks() """ import gradio as gr from rag import SimpleRAG # --------------------------------------------------------------------------- # Texto de exemplo embutido # --------------------------------------------------------------------------- SAMPLE_TEXT = """ Inteligência Artificial (IA) é um campo da ciência da computação dedicado a criar sistemas capazes de realizar tarefas que normalmente exigiriam inteligência humana. Essas tarefas incluem reconhecimento de fala, visão computacional, tradução de idiomas, tomada de decisões e muito mais. A história da IA começa na década de 1950, quando Alan Turing propôs o famoso "Teste de Turing" para avaliar se uma máquina poderia exibir comportamento inteligente indistinguível do humano. Em 1956, John McCarthy cunhou o termo "Inteligência Artificial" na Conferência de Dartmouth, considerada o marco oficial do nascimento da área. O aprendizado de máquina (Machine Learning) é um subcampo da IA que permite que sistemas aprendam automaticamente a partir de dados, sem serem explicitamente programados. Os principais paradigmas são: aprendizado supervisionado, não supervisionado e por reforço. O aprendizado profundo (Deep Learning) utiliza redes neurais com múltiplas camadas (por isso "profundo") para aprender representações hierárquicas dos dados. Essa abordagem revolucionou áreas como visão computacional e processamento de linguagem natural a partir de 2012, com a vitória da rede AlexNet na competição ImageNet. Os Modelos de Linguagem de Grande Escala (LLMs) são treinados em enormes quantidades de texto e conseguem gerar, resumir e responder perguntas em linguagem natural. Exemplos incluem GPT-4 da OpenAI, Gemini do Google e Claude da Anthropic. Esses modelos funcionam prevendo o próximo token (pedaço de palavra) com base no contexto anterior. O RAG (Retrieval-Augmented Generation) combina a busca de informações relevantes em uma base de conhecimento com a capacidade de geração de texto dos LLMs. Em vez de depender apenas do conhecimento memorizado durante o treinamento, o modelo recebe trechos do documento como contexto adicional, tornando as respostas mais precisas e verificáveis. Aplicações práticas de IA incluem: assistentes virtuais (Siri, Alexa), carros autônomos, diagnóstico médico por imagem, recomendação de conteúdo em plataformas de streaming, detecção de fraudes em bancos e tradução automática de textos. Os desafios éticos da IA envolvem preocupações com vieses algorítmicos, privacidade de dados, desemprego tecnológico e o risco de sistemas autônomos tomarem decisões críticas sem supervisão humana adequada. A área de IA Responsável busca desenvolver frameworks e regulamentações para garantir que sistemas de IA sejam seguros, justos e transparentes. """ # --------------------------------------------------------------------------- # Estado global # --------------------------------------------------------------------------- rag_instance = None is_indexed = False def setup_rag(hf_token, document, chunk_size, overlap): global rag_instance, is_indexed if not hf_token.strip(): return "❌ Insira um token válido do Hugging Face.", gr.update(interactive=False) if not document.strip(): return "❌ O documento está vazio.", gr.update(interactive=False) try: rag_instance = SimpleRAG(hf_token=hf_token.strip()) n_chunks = rag_instance.index(document, chunk_size=chunk_size, overlap=overlap) is_indexed = True return ( f"✅ Documento indexado com sucesso!\n" f" • Chunks gerados : {n_chunks}\n" f" • Chunk size : {chunk_size} palavras\n" f" • Overlap : {overlap} palavras\n\n" f"Agora faça uma pergunta sobre o documento!", gr.update(interactive=True), ) except Exception as e: is_indexed = False return f"❌ Erro ao indexar: {str(e)}", gr.update(interactive=False) def answer_question(question, top_k, history): """Gradio 5: history é lista de dicts {role, content}.""" global rag_instance, is_indexed if not is_indexed or rag_instance is None: history = history or [] history.append({"role": "user", "content": question}) history.append({"role": "assistant", "content": "⚠️ Indexe um documento primeiro na aba **Configuração**."}) return history, "_Faça uma pergunta para ver os trechos recuperados._", "" if not question.strip(): return history or [], "_Faça uma pergunta para ver os trechos recuperados._", "" try: answer, retrieved = rag_instance.query(question, top_k=top_k) context_display = "" for i, (chunk, score) in enumerate(retrieved, 1): bar = "█" * int(score * 20) context_display += ( f"**Trecho {i}** — similaridade: `{score:.3f}` {bar}\n\n" f"```\n{chunk[:400]}{'...' if len(chunk) > 400 else ''}\n```\n\n---\n\n" ) history = history or [] history.append({"role": "user", "content": question}) history.append({"role": "assistant", "content": answer}) return history, context_display, "" except Exception as e: history = history or [] history.append({"role": "user", "content": question}) history.append({"role": "assistant", "content": f"❌ Erro: {str(e)}"}) return history, "", "" # --------------------------------------------------------------------------- # Interface # --------------------------------------------------------------------------- CSS = """ .gradio-container { max-width: 1100px !important; margin: auto; } #title-block { text-align: center; padding: 24px 0 8px; } #title-block h1 { font-size: 2rem; font-weight: 700; margin-bottom: 4px; } #title-block p { color: #9ca3af; font-size: 0.95rem; } #status-box textarea { font-family: monospace; font-size: 0.85rem; } """ with gr.Blocks(css=CSS, title="RAG Didático — HF Spaces") as demo: gr.HTML("""

🔍 RAG Didático

Retrieval-Augmented Generation com Hugging Face Inference API

Embeddings: all-MiniLM-L6-v2  |  LLM: Llama-3.1-8B (Cerebras)  |  Busca: Similaridade Cosseno

""") with gr.Tabs(): with gr.Tab("⚙️ Configuração"): gr.Markdown( "### 1. Token do Hugging Face\n" "Crie um token gratuito em [hf.co/settings/tokens](https://huggingface.co/settings/tokens) " "(tipo **Read** é suficiente)." ) hf_token_input = gr.Textbox( label="HF Token", placeholder="hf_...", type="password", max_lines=1 ) gr.Markdown("### 2. Documento a ser indexado") document_input = gr.Textbox( label="Texto do documento", value=SAMPLE_TEXT, lines=12, placeholder="Cole aqui o texto que deseja consultar...", ) with gr.Row(): chunk_size_slider = gr.Slider( 50, 600, value=300, step=50, label="Tamanho do chunk (palavras)", info="Chunks menores = mais precisão; maiores = mais contexto", ) overlap_slider = gr.Slider( 0, 150, value=50, step=10, label="Overlap entre chunks (palavras)", info="Sobreposição evita cortar informações no meio", ) index_btn = gr.Button("🚀 Indexar Documento", variant="primary") status_output = gr.Textbox( label="Status da indexação", elem_id="status-box", lines=5, interactive=False, ) with gr.Tab("💬 Chat"): with gr.Row(): with gr.Column(scale=3): chatbot = gr.Chatbot( label="Conversa", height=420, type="messages", # formato Gradio 5 ) with gr.Row(): question_input = gr.Textbox( label="Pergunta", placeholder="Faça uma pergunta sobre o documento...", scale=5, interactive=False, ) ask_btn = gr.Button("Perguntar", variant="primary", scale=1) top_k_slider = gr.Slider( 1, 6, value=3, step=1, label="Número de trechos recuperados (top-k)", info="Quantos chunks serão enviados como contexto ao LLM", ) with gr.Column(scale=2): gr.Markdown("### 📄 Trechos Recuperados") gr.Markdown("*O coração do RAG — veja exatamente o que o modelo usa para responder!*") context_output = gr.Markdown( value="_Faça uma pergunta para ver os trechos recuperados._" ) with gr.Tab("📚 Como Funciona"): gr.Markdown(""" ## Pipeline RAG — Passo a Passo ``` INDEXAÇÃO (feita uma vez) ────────────────────────────────────────────── Documento → [Chunking] → [Embedding] → Índice CONSULTA (a cada pergunta) ────────────────────────────────────────────── Pergunta → [Embedding] → [Similaridade Cosseno] → Top-K chunks → [Prompt RAG] → LLM → Resposta ``` ## Por que RAG? | Problema do LLM puro | Solução com RAG | |---|---| | Conhecimento desatualizado | Contexto sempre atual | | Alucina fatos | Resposta baseada no documento | | Não conhece seus dados | Funciona com qualquer texto | | Caixa-preta | Trechos recuperados são visíveis | """) index_btn.click( fn=setup_rag, inputs=[hf_token_input, document_input, chunk_size_slider, overlap_slider], outputs=[status_output, question_input], ) ask_btn.click( fn=answer_question, inputs=[question_input, top_k_slider, chatbot], outputs=[chatbot, context_output, question_input], ) question_input.submit( fn=answer_question, inputs=[question_input, top_k_slider, chatbot], outputs=[chatbot, context_output, question_input], ) if __name__ == "__main__": demo.launch()