Como Replicar o Movimento

Este é um guia completo para você criar uma versão do "Facilita" na sua própria cidade e fortalecer a transparência local.

O "Movimento Facilita" é, em essência, um sistema composto por três grandes pilares. Este guia detalha cada um deles para que você possa entender a lógica por trás do projeto e adaptá-lo à realidade do seu município.

Nosso projeto foi construído com ferramentas acessíveis e de baixo custo, provando que a tecnologia cívica é viável.

Fase 1: Arquitetura de Dados

Este é o alicerce do projeto. A IA só pode responder sobre o que ela conhece. Nosso primeiro passo é "alimentar" a IA com os documentos públicos corretos.

1.1. Identifique as Fontes

Comece mapeando os portais da sua prefeitura. Os alvos mais comuns são:

  • Portal da Transparência: Onde estão os relatórios de receitas, despesas, licitações, contratos e gastos com pessoal.
  • Diário Oficial do Município: Onde são publicadas leis, decretos, nomeações e portarias.
  • Site da Câmara Municipal: Onde você encontra a Lei Orgânica do Município e o Regimento Interno.

1.2. Coleta de Dados

Esta é a parte de "mineração". Você precisa baixar esses documentos. Para o nosso projeto, focamos em arquivos .pdf e .csv.

  • Manual: Para documentos fixos (como a Lei Orgânica), o download manual é suficiente.
  • Automatizado (Scraping): Para dados que mudam diariamente (como o Diário Oficial ou relatórios do portal), o ideal é criar um pequeno *script* (em Python, por exemplo) para baixar novos arquivos automaticamente.

1.3. Limpeza e Preparação

A IA da OpenAI consegue ler PDFs, mas ela funciona muito melhor com texto puro. Recomendamos fortemente converter seus arquivos .pdf para .txt.

Você pode usar ferramentas gratuitas de linha de comando (como pdftotext) ou bibliotecas (como PyPDF2 em Python) para extrair o texto de dentro dos PDFs. Organize tudo em pastas (ex: `/leis`, `/diario_oficial`, `/orcamento`).

Fase 2: O Cérebro (Criação do Assistente)

Com os dados em mãos, vamos criar o assistente de IA. Nós usamos a API de Assistentes da OpenAI por ser poderosa e fácil de configurar, permitindo que a IA use os *seus* arquivos como base de conhecimento (técnica conhecida como RAG).

2.1. Conta e Chave API

Você precisará de uma conta na plataforma da OpenAI. Após se cadastrar, gere uma Chave de API (API Key) e guarde-a em local seguro. (Nota: o uso da API tem custos, embora sejam baixos para projetos de baixo tráfego).

2.2. Criando o Assistente

Dentro da plataforma da OpenAI, vá até a seção "Assistants" no menu esquerdo e clique em "Create":

  • Name: Dê um nome (ex: "Cida - Assistente de Ribeirão Preto").
  • Instructions (Prompt): Este é o passo mais importante. É aqui que você define a "personalidade" da IA. Use um prompt claro, como o nosso:
    "Você é 'Cida', uma assistente de IA especializada em documentos públicos da cidade de Ribeirão Preto. Sua missão é responder às perguntas dos cidadãos de forma clara, objetiva e imparcial, usando como base de conhecimento *apenas* os arquivos que foram fornecidos. Se a resposta não estiver nos arquivos, diga que você não possui essa informação. Não invente dados. Seja educada e foque em transparência."
  • Model: Escolha um modelo (ex: gpt-4o ou gpt-4-turbo).
  • Tools (Ferramentas): Ative a ferramenta "File Search" (ou "Retrieval"). É isso que permite à IA ler seus arquivos.

2.3. Upload dos Arquivos (Conhecimento)

Na mesma tela, na seção "File Search" (ou "Vector Stores"), faça o upload de todos os arquivos .pdf ou .txt que você preparou na Fase 1. Quanto mais documentos, mais inteligente será sua IA sobre a cidade.

2.4. Anote o Assistant ID

Após salvar, a OpenAI lhe dará um ID de Assistente (algo como asst_...). Copie e guarde este ID. Ele é a "chave" que seu site usará para chamar este assistente específico.

Fase 3: O Site (Front-end, Back-end e Hospedagem)

Agora, precisamos de um site para o público conversar com o assistente que criamos.

3.1. O Front-end (HTML, CSS, JS)

O front-end é a interface que o usuário vê. Você pode criar um do zero ou usar nosso design.html [cite: design.html] como base. O importante é ter:

  • Uma janela de chat (chat-window).
  • Uma caixa de texto (message-input).
  • Um botão de enviar (send-btn).

O JavaScript do front-end (como no nosso design.html) [cite: design.html] tem a função de:

  1. Pegar a mensagem do usuário.
  2. Enviar essa mensagem para o seu Back-end (fetch('chat_api.php', ...)).
  3. Receber a resposta do Back-end e exibi-la na tela.

3.2. O Back-end (API em PHP)

Por que um Back-end? Você NUNCA deve colocar sua API Key da OpenAI diretamente no JavaScript ou HTML. Isso a tornaria pública, e qualquer um poderia usá-la e gerar custos na sua conta.

O Back-end (em PHP, Node.js, Python, etc.) funciona como uma "sala-cofre". O front-end fala com ele, e só ele tem permissão para falar com a OpenAI.

Nós usamos PHP por ser simples e estar disponível em quase toda hospedagem (como a Hostinger). O código do nosso chat_api.php [cite: chat_api.php] é o coração do projeto. Você pode usá-lo como base:

<?php
session_start();
header('Content-Type: application/json; charset=utf-8');

// --- CONFIGURAÇÕES ---
// 🔑 SUA CHAVE SECRETA DA OPENAI
$apiKey = "sk-...."; 

// 🆔 O ID DO ASSISTENTE QUE VOCÊ CRIOU NA FASE 2
$assistantId = "asst_...."; 

// Biblioteca para converter Markdown em HTML
require_once __DIR__ . '/lib/Parsedown.php';

// --- RECEBIMENTO E VALIDAÇÃO DA MENSAGEM ---
$input = file_get_contents("php://input"); //
$data = json_decode($input, true); //

if (!isset($data['message']) || trim($data['message']) === '') { //
    http_response_code(400); // Bad Request //
    echo json_encode(["success" => false, "reply" => "Erro: Nenhuma mensagem foi enviada."]); //
    exit; //
}
$userMessage = trim($data['message']); //

// --- FUNÇÃO PARA FAZER CHAMADAS À API DA OPENAI (cURL) ---
function callOpenAI($method, $url, $payload = null) { //
    global $apiKey; //
    $ch = curl_init("https://api.openai.com/v1/$url"); //
    curl_setopt_array($ch, [ //
        CURLOPT_RETURNTRANSFER => true, //
        CURLOPT_HTTPHEADER => [ //
            "Authorization: Bearer $apiKey", //
            "Content-Type: application/json", //
            "OpenAI-Beta: assistants=v2" // Header obrigatório para a API de Assistentes //
        ],
        CURLOPT_CUSTOMREQUEST => $method, //
        CURLOPT_POSTFIELDS => $payload ? json_encode($payload) : null, //
        CURLOPT_TIMEOUT => 90 // Aumenta o tempo de espera para a resposta da IA //
    ]);
    $response = curl_exec($ch); //
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); //
    curl_close($ch); //
    $decodedResponse = json_decode($response, true); //

    // Tratamento de erros da API
    if ($http_code >= 400) { //
        $errorMessage = $decodedResponse['error']['message'] ?? 'Ocorreu um erro desconhecido na API.'; //
        throw new Exception("Erro na API OpenAI (HTTP $http_code): $errorMessage"); //
    }
    return $decodedResponse; //
}

// --- FLUXO PRINCIPAL DE INTERAÇÃO COM O ASSISTENTE ---
try {
    // 1. Verifica se o usuário já tem uma conversa (thread) na sessão.
    // Usamos uma session key DIFERENTE para não misturar com o chat do "portal".
    $threadId = $_SESSION['cidade_thread_id'] ?? null; //

    // Se não tiver, cria uma nova e salva o ID na sessão.
    if (empty($threadId)) {
        $thread = callOpenAI("POST", "threads"); //
        $threadId = $thread['id']; //
        $_SESSION['cidade_thread_id'] = $threadId; //
    }

    // 2. Adiciona a mensagem do usuário à conversa.
    callOpenAI("POST", "threads/$threadId/messages", [ //
        "role" => "user", //
        "content" => $userMessage //
    ]);

    // 3. Pede para o assistente processar a conversa (cria uma "Run").
    $run = callOpenAI("POST", "threads/$threadId/runs", [ //
        "assistant_id" => $assistantId //
    ]);
    $runId = $run['id']; //

    // 4. Aguarda o processamento ser concluído.
    $status = ''; //
    for ($i = 0; $i < 15; $i++) { // Tenta por até ~30 segundos //
        sleep(2); // Pausa para não sobrecarregar a API com verificações //
        $checkRun = callOpenAI("GET", "threads/$threadId/runs/$runId"); //
        $status = $checkRun['status']; //
        if ($status === 'completed') break; // Sucesso! //
        if (in_array($status, ['failed', 'cancelled', 'expired'])) { //
            throw new Exception("O processamento da mensagem falhou (status: $status)."); //
        }
    }

    if ($status !== 'completed') { //
        throw new Exception("O tempo para obter a resposta da IA esgotou."); //
    }

    // 5. Busca a última mensagem da conversa, que será a resposta do assistente.
    $messagesResponse = callOpenAI("GET", "threads/$threadId/messages?limit=1&order=desc"); //
    $raw_reply = "Desculpe, não consegui formular uma resposta no momento."; //
    if (!empty($messagesResponse['data']) && $messagesResponse['data'][0]['role'] === 'assistant') { //
        $raw_reply = $messagesResponse['data'][0]['content'][0]['text']['value']; //
    }

    // 6. [IMPORTANTE] Formata a resposta de Markdown para HTML
    $Parsedown = new Parsedown(); //
    $Parsedown->setSafeMode(true); // Essencial para segurança (evita ataques XSS) //
    $html_reply = $Parsedown->text($raw_reply); //

    // 7. Envia a resposta final formatada para o front-end.
    echo json_encode(["success" => true, "html_reply" => $html_reply]); //

} catch (Exception $e) {
    http_response_code(500); // Erro Interno do Servidor //
    echo json_encode(["success" => false, "reply" => "Ocorreu um erro no servidor: " . $e->getMessage()]); //
}
?>

Note que você precisará da biblioteca Parsedown.php (você pode baixá-la no GitHub) e colocá-la em uma pasta lib/ para que o PHP possa formatar as respostas da IA corretamente [cite: chat_api.php].

3.3. Hospedagem e Domínio

Finalmente, você precisa colocar seu site no ar. Na Hostinger, o processo é:

  1. Contratar: Contrate um plano de hospedagem (planos PHP básicos funcionam).
  2. Domínio: Registre um nome de domínio (ex: facilitaminhacidade.com.br).
  3. Upload: Use o "Gerenciador de Arquivos" da Hostinger para enviar seus arquivos para a pasta public_html:
    • index.html
    • docs.html (esta página)
    • portal.html (seu chat)
    • cidade.html (seu outro chat)
    • chat_api.php (e portal_api.php, cidade_api.php)
    • A pasta lib/ contendo Parsedown.php.
    • Sua pasta downloads/ com os PDFs para baixar.
  4. Verificação: Certifique-se de que a extensão curl do PHP está ativada na sua hospedagem (normalmente já vem ativada).

E pronto! Você terá seu próprio "Movimento Facilita" rodando e ajudando sua comunidade.