[FEAT] ARIA allineata all'Help contestuale della pagina + pageId canonico (Fase A)

Lamentela: "AI non allineata con help online e contesto". Causa: ARIA e Help
erano due fonti separate (Help=help.js, ARIA=KB) → divergevano.
Fix (fonte unica = help.js, zero duplicazione):
- help.js: getContextText(pageId) (testo piano dell'help della pagina) + detectPageId().
- common.js: invia page_id (canonico) + page_help (stesso testo del pannello "?") a /api/ai/ask.
- AiController: passa page_id/page_help in userContext.
- AIService::askWithRag: inietta "GUIDA CONTESTUALE DELLA PAGINA" nel system prompt
  (ARIA si allinea all'help mostrato all'utente, non lo contraddice) + usa page_id
  per il trigger relevanceGrid (più robusto del title).
Smoke: ARIA cita "registro dei rischi" dall'help + "Gestione > Rischi". Cache-buster
common.js/help.js -> 20260624e (39 pagine).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-24 08:30:10 +02:00
co-authored by Claude Opus 4.8
parent 3b9f30a890
commit bafc305503
43 changed files with 138 additions and 74 deletions
+5
View File
@@ -42,11 +42,16 @@ class AiController extends BaseController
// Pagina corrente (facoltativa) inviata dal frontend, per dare ad ARIA
// contesto sulla schermata da cui l'utente sta scrivendo (ticket #424).
$page = mb_substr(trim((string) $this->getParam('page', '')), 0, 120);
// pageId canonico + testo dell'help "?" della pagina (allineamento ARIA↔Help).
$pageId = mb_substr(trim((string) $this->getParam('page_id', '')), 0, 40);
$pageHelp = mb_substr(trim((string) $this->getParam('page_help', '')), 0, 2500);
$userContext = [
'user_id' => $userId,
'organization_id' => $this->getCurrentOrgId(), // può essere null
'consulting_firm_id' => $user['consulting_firm_id'] ?? null,
'page' => $page,
'page_id' => $pageId,
'page_help' => $pageHelp,
];
try {
+16 -4
View File
@@ -759,18 +759,30 @@ PROMPT;
// Pagina corrente dell'utente (se inviata dal frontend): aiuta ARIA a
// dare indicazioni contestuali invece di rimandare a moduli a caso.
$page = trim((string) ($userContext['page'] ?? ''));
if ($page !== '') {
$page = trim((string) ($userContext['page'] ?? ''));
$pageId = trim((string) ($userContext['page_id'] ?? ''));
if ($page !== '' || $pageId !== '') {
$systemPrompt .= "\n## CONTESTO UTENTE\n"
. "L'utente si trova attualmente nella pagina: \"" . $page . "\". "
. "L'utente si trova attualmente nella pagina: \"" . ($page !== '' ? $page : $pageId) . "\""
. ($pageId !== '' ? " (id: {$pageId})" : '') . ". "
. "Tieni conto di dove si trova quando dai indicazioni di navigazione.\n";
}
// ALLINEAMENTO ARIA ↔ HELP: inietta il testo dell'help contestuale "?" della
// pagina corrente (stessa fonte help.js che l'utente vede) così le risposte
// sono coerenti con la guida e non divergono. Fonte autorevole per la pagina.
$pageHelp = trim((string) ($userContext['page_help'] ?? ''));
if ($pageHelp !== '') {
$systemPrompt .= "\n## GUIDA CONTESTUALE DELLA PAGINA (stesso testo dell'help «?» che l'utente vede ora)\n"
. "Allinea le tue risposte a questa guida: è la fonte ufficiale per la pagina corrente; non contraddirla.\n"
. $pageHelp . "\n";
}
// Se l'utente e' nell'Inventario o la domanda riguarda la valutazione di
// rilevanza NIS2, inietta la griglia ESATTA delle combo (fonte di verita'
// AssetScoringService::GRID) per evitare risposte non corrispondenti alla
// finestra reale (ticket #429).
$onInventory = stripos($page, 'asset') !== false || stripos($page, 'inventario') !== false;
$onInventory = $pageId === 'assets' || stripos($page, 'asset') !== false || stripos($page, 'inventario') !== false;
if ($onInventory || preg_match('/rilevanz|combo|criticit|punteggio|scoring|valutazione|gv\.?oc/iu', $question)) {
$systemPrompt .= $this->relevanceGridBlock();
}