AI Hub

Broker BYOK (traga sua própria chave) para o Moodle — documentação completa.

English | Português

View on GitHub Download .zip

Moodle Plugin CI Moodle License Status

A Central de IA é um pequeno intermediário BYOK (traga sua própria chave) para o Moodle. Ela permite que os plugins da própria instituição gerem texto através de chaves de API de IA compartilhadas, sem que cada plugin reimplemente o transporte HTTP, o guard de SSRF, a escada de provedores ou um armazenamento de chaves.

Use a barra lateral para pular direto a qualquer seção desta página.

Código-fonte: github.com/jeanlucio/moodle-local_aihub


✨ Funcionalidades

🧩 Como os consumidores usam

Um plugin irmão consome o hub através de um guard em runtime e mantém o próprio fallback para core_ai:

// Disponibilidade: chaves do hub primeiro, depois o fallback core_ai do consumidor.
public static function has_ai(): bool {
    if (class_exists(\local_aihub\ai::class) && \local_aihub\ai::is_available()) {
        return true;                       // BYOK via hub
    }
    return self::has_core_ai();            // funciona sem o hub
}

// Geração.
$result = \local_aihub\ai::generate_text(
    '',                    // prompt de sistema (opcional)
    $prompt,               // prompt do usuário
    false,                 // modo JSON
    'your_frankenstyle',   // 4º arg: componente chamador, para o log de uso
    'Rótulo curto'         // 5º arg: o que está sendo gerado, exibido no relatório de admin
);
if ($result['success']) {
    // $result['data'] é texto CRU e não-confiável — valide e passe por format_text().
}

O texto devolvido é cru e não-confiável: valide sua estrutura e passe por format_text() antes de exibir ou persistir.

🔗 Resolução de chave (escada BYOK)

O hub resolve a chave tier por tier e para no primeiro tier que tiver uma chave:

Tier Fonte
1 Chave pessoal — a chave do próprio usuário, quando as chaves pessoais estão habilitadas e o usuário tem local/aihub:usepersonalkey
2 Chave de site — a chave de admin definida nas configurações do hub

Dentro do tier escolhido, os provedores são tentados na ordem Gemini → Groq → DeepSeek → compatível com OpenAI (a primeira chave encontrada é usada; se a chamada falhar, o próximo provedor do mesmo tier é tentado). Quando nenhum tier tem chave, generate_text() retorna success = false — o hub nunca cai para o core_ai; essa decisão é do consumidor.

📦 Requisitos

Componente Versão
Moodle 4.5+
PHP 8.1+

Nenhuma biblioteca de terceiros empacotada. Os provedores de IA são serviços externos, declarados no Privacy provider — não em thirdpartylibs.xml.

🛠️ Instalação e Configuração

  1. Baixe o arquivo .zip ou clone este repositório.
  2. Extraia a pasta para o diretório local/ do seu Moodle.
  3. Renomeie a pasta para aihub (se necessário). Caminho final: seu-moodle/local/aihub/
  4. Acesse Administração do site → Notificações para concluir a instalação.

Configurar uma chave de provedor é opcional — o plugin instala e funciona sem nenhuma. Veja Como Usar logo abaixo para definir chaves de site e habilitar chaves pessoais.

📖 Como Usar

  1. Configurar chaves de site (admin): Administração do site → Plugins → Plugins locais → Central de IA → Configurações. Defina qualquer uma das chaves Gemini, Groq, DeepSeek ou compatível com OpenAI e, opcionalmente, habilite as chaves de API pessoais.
  2. Adicionar uma chave pessoal (usuário): usuários com a capability local/aihub:usepersonalkey ganham uma entrada Minhas chaves de IA nas preferências, onde guardam a própria chave (write-only) e veem o uso recente.
  3. Revisar o uso das chaves de site (admin): o Relatório de uso de IA do site (sob a categoria Central de IA, capability local/aihub:viewusage) lista todas as requisições atendidas pelas chaves do site, de todos os usuários, com download CSV e Excel.
  4. Consumir de um plugin (desenvolvedor): chame \local_aihub\ai::generate_text() atrás de um guard class_exists(), mantendo o próprio fallback para core_ai (ver Como os consumidores usam).

🧪 Testes Automatizados

O hub vem com uma suíte PHPUnit e Behat; todo push de CI roda contra a matriz (Moodle 4.5 → 5.x, PostgreSQL & MariaDB).

PHPUnit — Testes Unitários e de Integração

Arquivo de teste Casos O que cobre
tests/local/keys_test.php 6 Defaults de URL/modelo OpenAI; roundtrip get/save/clear da chave pessoal; roundtrip da URL/modelo pessoal compatível com OpenAI; personal_keys_allowed respeitando o toggle e a capability; resolução pessoal → site; has_any_key entre chaves pessoal/site
tests/local/client_test.php 9 Casos de SSRF do is_safe_url (http, loopback, faixa privada, IP público); branch de DNS rebinding simulado via dns_stub_client — IP resolvido privado é bloqueado, IP resolvido público passa, sem registros passa; resolve_openai_url anexa /chat/completions; tier pessoal vence o de site; fall-through de provedor dentro de um tier (Gemini → Groq, e Gemini/Groq → DeepSeek); sem chave → success=false (sem HTTP real)
tests/local/usage_log_test.php 3 Inserção do registro (com keysource, modelo vazio nulado); leitores por chave de site excluindo linhas pessoais/sem tag; filtragem recente por usuário
tests/local/export_test.php 2 Export do uso pessoal (todas as linhas, todas as colunas); export do relatório de chaves de site incluindo a coluna de usuário e excluindo o uso pessoal
tests/ai_test.php 4 Estados de is_available; uma geração bem-sucedida registra o componente chamador, a descrição e o tier da chave; uma geração com falha não registra nada; report_usage() grava uma linha de log para um consumidor que resolveu a própria chave
tests/privacy_provider_test.php 4 Declaração de metadata; descoberta de contexto/usuário; export_user_data (linhas do log + valor da chave redigido); deleção por usuário com isolamento
tests/output/mykeys_test.php 2 Status de chave pessoal por provedor (definida/não definida), sem nunca colocar o valor da chave no contexto do template; linhas de uso recente com o ícone de provedor correto, incluindo o fallback pra provedor não reconhecido
tests/output/report_test.php 2 Linhas do relatório de chaves de site com o nome do usuário solicitante e o ícone de provedor correto, excluindo linhas de chave pessoal; estado vazio quando não há uso de chaves de site
tests/task/purge_old_logs_test.php 2 Linhas mais antigas que a retenção configurada são apagadas, linhas mais recentes são mantidas; retenção 0 mantém todas as linhas indefinidamente
Total 34  
vendor/bin/phpunit --testsuite local_aihub

Cobertura de linhas por classe (PHPUnit + Xdebug):

Classe Cobertura de linhas
ai 85%
local\client 36%
local\export 83%
local\keys 92%
local\usage_log 85%
output\mykeys 100%
output\renderer 0%
output\report 100%
privacy\provider 86%
task\purge_old_logs 86%
Total 73%

Duas classes não são testadas por unidade por completo, ambas pelo mesmo motivo — as linhas não cobertas são chamadas de rede reais, não lógica de negócio:

Behat — Testes de Aceitação

Arquivo de feature Cenários O que cobre
tests/behat/mykeys.feature 2 Um provedor começa não configurado; salvar uma chave pessoal marca-a como configurada sem revelar o valor guardado
Total 2  
php admin/tool/behat/cli/init.php
vendor/bin/behat --tags=@local_aihub --profile=chrome

🔐 Segurança e Conformidade

🔎 Divulgação de Serviço de Terceiros

O hub transmite o texto do prompt a um provedor de IA de terceiros apenas quando uma chave está configurada e uma geração é solicitada.

Uma chave de API é obrigatória?

Não. O plugin instala e funciona sem nenhuma chave — apenas informa que não há fonte disponível, e os consumidores caem para a própria integração com core_ai. Nenhuma requisição externa é feita até que uma chave de site ou pessoal seja definida.

Provedores suportados

Esses serviços operam sob seus próprios termos de serviço e políticas de privacidade.

Escolha do modelo Groq

O slot da Groq chama um único modelo fixo, openai/gpt-oss-120b. A Groq descontinua periodicamente IDs de modelo específicos (ex.: llama-3.3-70b-versatile, descomissionado em 16/08/2026) e espera migração para um substituto nomeado. Entre as opções gratuitas recomendadas pela Groq para essa migração, o openai/gpt-oss-120b foi escolhido em vez do qwen/qwen3.6-27b por seguir instruções melhor e ser mais confiável em modo JSON entre os prompts variados enviados pelos diferentes plugins consumidores.

Como obter uma chave de API

As chaves de API são criadas diretamente no site oficial do provedor. Gemini, Groq e DeepSeek atualmente oferecem camadas de uso gratuitas ou créditos de teste (as políticas de preço podem mudar). O hub não fornece chaves de API.

Onde as chaves são configuradas

  1. Chave pessoal — definida por cada usuário em Minhas chaves de IA (preferências), quando as chaves pessoais estão habilitadas e o usuário tem a capability.
  2. Chave de site — definida pelo admin em Administração do site → Plugins → Plugins locais → Central de IA.

Transmissão de Dados

Quando uma chave é resolvida para um provedor, o texto do prompt é transmitido à API desse provedor para gerar a resposta:

O hub guarda um log de uso (quem solicitou, qual componente, um rótulo curto do que foi gerado, provedor, modelo, tier da chave e horário), mas não guarda prompts nem respostas da IA. Todos os destinos externos estão declarados no Privacy provider do plugin.

Credenciais de demonstração

Não aplicável — nenhuma credencial é exigida para instalar ou usar o hub. Todo recurso de IA fica inerte até que uma chave de site ou pessoal seja configurada.

📄 Licença

Este projeto está licenciado sob a GNU General Public License v3 (GPLv3).

Copyright: 2026 Jean Lúcio