# Gemini (Integração com IA do Google Gemini) — Resumo Executivo

> **Versão analisada:** `v5` (o módulo de *geração de conteúdo* existe **apenas na v5**; a v6 reteve apenas a engrenagem de *mascaramento LGPD*)
> **Slug do módulo:** `gemini` — **não existe** na tabela `modulos` (que só existe na v6)
> **Natureza:** CMS (painel administrativo) + Portal (público) — **híbrido**
> **Estado:** **parcialmente removido na v6** — ver `08-GAPS-E-DIVIDAS.md`

---

## 1. Objetivo

A v5 usa a API do Google Gemini em **dois papéis distintos e independentes**, que
compartilham apenas a credencial (a chave `gemini_api_key`):

1. **Geração de conteúdo no CMS** — o operador de *Notícias* e *Publicações* escreve um
   prompt em linguagem natural e a IA devolve **título + texto corrido**, prontos para
   publication no portal. Implementado em `v5/app/Http/Controllers/Prefecture/GeminiController.php`.
2. **Mascaramento LGPD de dados pessoais** — o texto livre de pedidos do e-SIC e da
   Ouvidoria passa por um anonimizador determinístico e, em seguida, por um refinamento
   feito por IA. Implementado em `v5/app/Http/Traits/DataMaskTrait.php` (`maskTextWithAi`).

Serve ao servidor público municipal (comunicação oficial mais rápida e mascaramento
automático de dados sensíveis em pedidos Citizens).

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Recebe conteúdo institucional mais rápido; pedidos de e-SIC/Ouvidoria têm CPF, endereço, saúde e politically sensitive data mascarados automaticamente antes da publicação |
| Prefeitura (CMS) | Reduz o tempo de redação de notícias/publicações; centraliza a credencial da IA em uma única tela de Configurações |
| Transparência e legalidade | Suporta a LGPD (mascaramento de dados pessoais/sensíveis) nos relatórios estatísticos públicos |
| Operação técnica | Custo externo variável (API paga por token), dependência de rede externa no fluxo de atendimento ao cidadão e risco de exposição da chave da API |

## 3. Comportamento

- A rota `gemini.ia` (`POST /preencher-formulario`) é **pública** (grupo de middleware
  `check.site.manutention`, **sem** `check.logged`), aceita JSON `{ "prompt": "..." }` e
  responde `{ "title": "...", "text": "..." }`.
- O `prompt` é validado por `v5/app/Http/Requests/GeminiPromptRequest.php`:
  `required|string|min:4|max:5000`. `authorize()` retorna `true` — **não há autorização**.
- O controller **concatena** o prompt do usuário com uma instrução fixa ("texto corrido,
  sem Markdown, título ≤ 150 caracteres") e envia `contents[0].parts[0].text` ao endpoint
  `generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent`.
- A resposta é **partida em título e corpo** por heurística: 1ª linha em branco (`\n\n`) →
  título/corpo; senão, primeiro ponto antes de 150 caracteres; senão, corte em 150 **bytes**.
- **Caminho A (mascaramento, `DataMaskTrait::maskTextWithAi`)** usa o modelo
  `gemini-2.5-flash`, **timeout de 10 s** e **fallback silencioso** para a máscara
  determinística local em qualquer falha (sem chave, HTTP ≠ 200, JSON inesperado, exceção).
- **Caminho B (geração, `GeminiController@preencher`)** usa o modelo `gemini-2.0-flash`,
  **sem timeout** configurado e **sem fallback**: devolve HTTP 500 ao operador.
- A chave é lida de `configurations` (`key = 'gemini_api_key'`). Só o caminho A tem
  fallback para `env('GEMINI_API_KEY')`.

## 4. Como o Usuário Interage

**Operador (CMS).** Em *Notícias* (criar/editar) e *Publicações* (criar) há o botão
**"Preencher com IA"**, que abre o modal `#modal-banner` com um `textarea` de prompt.
Ao clicar em **"Gerar conteúdo"**, o JS `ia-modal.js` faz `POST` na rota `gemini.ia` com
o token CSRF; em sucesso, `#title` recebe o título e `#text` (Summernote) recebe o corpo;
o modal fecha e o prompt é limpo. Em erro, um `alert-danger` é exibido dentro do modal.

**Visitante (Portal).** Não há interface pública de IA. O cidadão é apenas **sujeito
passivo**: seu texto de pedido é mascarado antes de ser exibido nos relatórios.

## 5. Detalhes e Particularidades Técnicas

- **Duas integrações distintas**, com modelos, timeouts, fallback e resolução de chave
  diferentes — não compartilham nenhuma classe além do model `Configuration`.
- **Chave da API em texto claro** no banco (`configurations.value`) e **hardcoded no
  repositório** (`v5/database/seeds/AddToConfigurationsGeminiApiKeyValue.php`).
- A chave viaja na **query string** (`?key=...`) → fica em log de acesso/proxy.
- O `DataMaskTrait` loga o corpo bruto da resposta da IA (`Log::error`/`Log::warning`),
  podendo registrar conteúdo derivado de dado pessoal.
- `env('GEMINI_API_URL')` e `env('GEMINI_API_MODEL')` são lidos em runtime, mas
  **não existem** em `v5/.env` nem em `v5/.env.example`; e `GEMINI_API_MODEL` é lido e
  **nunca usado** (a URL é fixa).
- Dependência externa: `guzzlehttp/guzzle` **5.3.4** (`v5/composer.json`).

## 6. Estrutura de Dados

| Item | Descrição |
|---|---|
| Tabela | `configurations` (genérica, compartilhada por todo o CMS) |
| Chave usada | `gemini_api_key` — linha `id = 77` na v5 (`order = 70`, `type = text`, `max_input = 255`, `value` vazia na base local) |
| Colunas relevantes | `id, title, description, small_description, placeholder, key, value, type, order, max_input, min_input, category_configurations_id, notnull, status_create, created_at, updated_at, deleted_at` |
| FK | `category_configurations_id → category_configurations(id)` |
| Tabelas próprias | **nenhuma** |
| Seeds | `v5/database/seeds/UpdateConfigurationSeeder.php`, `v5/database/seeds/ConfigurationOrderSeeder.php`, `v5/database/seeds/AddToConfigurationsGeminiApiKeyValue.php`, orquestrados por `v5/database/seeds/ExtrasSeeder.php` |

## 7. Como Testar

- **Geração (CMS):** abrir *Notícias → Cadastrar*, clicar "Preencher com IA", enviar um
  prompt ≥ 4 caracteres; conferir `title`/`text` no retorno e o preenchimento do Summernote.
- **Erro de credencial:** limpar `configurations.value` de `gemini_api_key` → a rota deve
  responder **500** com `title = "Erro de Configuração"`.
- **Validação:** prompt com 3 caracteres → **422**; prompt com 5001 caracteres → **422**.
- **Mascaramento (Portal):** registrar um pedido no e-SIC com CPF, endereço e dado de saúde;
  conferir `informations_requests.mask_request` e o relatório estatístico público.
- **Fallback:** desligar a rede / apontar `GEMINI_API_URL` para host inválido → o
  `mask_request` deve continuar sendo preenchido pela máscara determinística.

## 8. Migração para Laravel Moderno

Mover a credencial para `.env`/vault (nunca para `configurations`), criar um
`GeminiService` único com `Http::timeout()` e `Http::retry()`, proteger a rota de
geração com `auth` + `throttle`, mover o mascaramento para **fila** (job) para não
bloquear o atendimento ao cidadão, e trocar o parser de título/corpo por uma resposta
estruturada (`responseMimeType: application/json` + schema). Detalhes em
`06-MIGRACAO-MODERNA.md`.

## 9. Resumo Geral

A v5 integrou o Google Gemini em dois lugares sem ligação entre si: um recurso de
**redação assistida** no CMS de notícias/publicações (`GeminiController@preencher`,
rota pública `gemini.ia`, modelo `gemini-2.0-flash`) e um **anonimizador LGPD** no
fluxo de pedidos do cidadão (`DataMaskTrait::maskTextWithAi`, modelo `gemini-2.5-flash`,
com fallback local determinístico). A credencial vive em `configurations.gemini_api_key`,
em texto claro, e há uma cópia literal dela versionada no seeder
`AddToConfigurationsGeminiApiKeyValue`. O principal risco do módulo não é funcional, é
**operacional e de segurança**: a rota de geração é pública, sem *throttle* e sem
autenticação, expondo uma chave paga a qualquer visitante; e a chave trafega em query
string e é gravada em log de atividades em claro. Na v6 o bloco de **geração de
conteúdo foi removido por completo** (sem controller, sem request, sem rota, sem
componente Blade e sem JS), enquanto o bloco de **mascaramento foi mantido e copiado
quase byte a byte** — inclusive a mesma leitura de `env()` e o mesmo fallback. Para a
v7, a recomendação é unificar as duas integrações em um serviço único, credencial em
vault, e fila para o mascaramento.

---

## Índice do dossiê

| Arquivo | Conteúdo |
|---|---|
| `00-RESUMO.md` | Este documento |
| `01-ARQUITETURA.md` | Camadas, classes e o diagrama de fluxo |
| `02-MODELAGEM.md` | Estrutura de dados detalhada |
| `03-ROTAS-E-CONTROLADORES.md` | Rotas, controllers, requests, recursos |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `05-REGRAS-E-PORTABILIDADE.md` | Particularidades e armadilhas |
| `06-MIGRACAO-MODERNA.md` | Plano de reconstrução em Laravel moderno |
| `07-TESTES.md` | Estratégia e casos de teste |
| `08-GAPS-E-DIVIDAS.md` | Pendências, riscos, comparativo v5 vs v6 |
