feat: per-category greeting menu in bot config
Add a "Por Categoría" tab in the bot config UI where each permission category (1, 2, 3) can be assigned its own greeting button menu. When a user writes without an active context, the bot shows the menu configured for their category instead of falling through to the global greeting text. NormalBot.process() now checks per_type[X].greeting_menu first, which directly references a menu key and serves as both greeting and fallback for that category. Fully backward-compatible with existing greeting_flow. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
0b851208ea
commit
32e2a2a82e
@@ -2372,6 +2372,34 @@ HTML;
|
||||
$flows = $config['flows'] ?? [];
|
||||
$aiProviderOpenai = $aiProviderVal === 'openai' ? ' selected' : '';
|
||||
$aiProviderMock = $aiProviderVal === 'mock' ? ' selected' : '';
|
||||
|
||||
// Per-category config HTML
|
||||
$perTypeConfig = $config['per_type'] ?? [];
|
||||
$menuKeysList = array_keys($menus);
|
||||
$catLabels = ['1' => 'Categoría 1 — Solo recibe info', '2' => 'Categoría 2 — Solo descarga informes', '3' => 'Categoría 3 — Reporta y recibe'];
|
||||
$categoryTabHtml = '';
|
||||
foreach ([1, 2, 3] as $cat) {
|
||||
$catCfg = $perTypeConfig[(string)$cat] ?? [];
|
||||
$selMenu = $catCfg['greeting_menu'] ?? '';
|
||||
$opts = '<option value="">— Usa configuración global —</option>';
|
||||
foreach ($menuKeysList as $mk) {
|
||||
$s = $selMenu === $mk ? ' selected' : '';
|
||||
$opts .= '<option value="' . self::h($mk) . '"' . $s . '>' . self::h($mk) . '</option>';
|
||||
}
|
||||
$label = $catLabels[(string)$cat];
|
||||
$categoryTabHtml .= <<<CATHTML
|
||||
<div style="background:#f8f9fd;border:1px solid #eef1f5;border-radius:10px;padding:18px;margin-bottom:16px">
|
||||
<div style="font-weight:700;font-size:13px;color:#0b3d91;margin-bottom:12px">{$label}</div>
|
||||
<div class="form-group" style="margin-bottom:0">
|
||||
<label>Menú de bienvenida (greeting menu)</label>
|
||||
<select name="per_type_menu[{$cat}]" style="width:100%;padding:9px 12px;border:1px solid #e2e5ea;border-radius:8px;font-size:13px">
|
||||
{$opts}
|
||||
</select>
|
||||
<div style="font-size:11px;color:#7a8291;margin-top:4px">Menú en botones que se muestra cuando el usuario escribe por primera vez o sin contexto activo</div>
|
||||
</div>
|
||||
</div>
|
||||
CATHTML;
|
||||
}
|
||||
$aiModelMini = $aiModelVal === 'gpt-4o-mini' ? ' selected' : '';
|
||||
$aiModel4o = $aiModelVal === 'gpt-4o' ? ' selected' : '';
|
||||
$aiModel35 = $aiModelVal === 'gpt-3.5-turbo' ? ' selected' : '';
|
||||
@@ -2384,6 +2412,7 @@ HTML;
|
||||
<button type="button" class="tab-btn active" onclick="switchTab('commands',this)">📋 Comandos</button>
|
||||
<button type="button" class="tab-btn" onclick="switchTab('menus',this)">📑 Menús</button>
|
||||
<button type="button" class="tab-btn" onclick="switchTab('flows',this)">🔀 Flujos</button>
|
||||
<button type="button" class="tab-btn" onclick="switchTab('categories',this)">👥 Por Categoría</button>
|
||||
<button type="button" class="tab-btn" onclick="switchTab('ai',this)">🤖 IA</button>
|
||||
<button type="button" class="tab-btn" onclick="switchTab('general',this)">⚙️ General</button>
|
||||
</div>
|
||||
@@ -2551,6 +2580,13 @@ HTML;
|
||||
<button type="button" class="add-btn" onclick="addFlow()">+ Agregar flujo</button>
|
||||
</div>
|
||||
|
||||
<!-- ─── POR CATEGORÍA ────────────────────────────────────────────────── -->
|
||||
<div class="tab-content" id="tab-categories">
|
||||
<div class="card-h">👥 Configuración por Categoría</div>
|
||||
<p style="font-size:12px;color:#7a8291;margin-bottom:16px">Define qué menú de bienvenida ve cada categoría de usuario cuando escribe por primera vez o sin contexto activo. El menú debe ser de tipo <strong>botón</strong>.</p>
|
||||
{$categoryTabHtml}
|
||||
</div>
|
||||
|
||||
<!-- ─── AI ───────────────────────────────────────────────────────────── -->
|
||||
<div class="tab-content" id="tab-ai">
|
||||
<div class="card-h">🤖 Inteligencia Artificial</div>
|
||||
|
||||
@@ -410,6 +410,21 @@ $routes = [
|
||||
$aiProvider = trim($_POST['ai_provider'] ?? '');
|
||||
if ($aiProvider !== '') $config['ai_provider'] = $aiProvider;
|
||||
|
||||
// Per-category menus
|
||||
$perTypeMenus = $_POST['per_type_menu'] ?? [];
|
||||
$perType = [];
|
||||
foreach ([1, 2, 3] as $cat) {
|
||||
$mk = trim($perTypeMenus[$cat] ?? '');
|
||||
if ($mk !== '') {
|
||||
$perType[(string)$cat] = [
|
||||
'greeting_menu' => $mk,
|
||||
'greeting' => '',
|
||||
'fallback' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
if (!empty($perType)) $config['per_type'] = $perType;
|
||||
|
||||
// General
|
||||
$greeting = trim($_POST['greeting'] ?? '');
|
||||
if ($greeting !== '') $config['greeting'] = $greeting;
|
||||
|
||||
@@ -46,6 +46,13 @@ class NormalBot
|
||||
return null;
|
||||
}
|
||||
|
||||
// Per-type greeting_menu: direct menu for this category (greeting + fallback in one)
|
||||
$greetingMenuKey = $perType['greeting_menu'] ?? null;
|
||||
if ($greetingMenuKey !== null && $currentNode === null && isset($menus[$greetingMenuKey])) {
|
||||
ConversationContext::updateNode($ctxId, null);
|
||||
return self::buildMenuResponse($menus[$greetingMenuKey], $context['from'], $company);
|
||||
}
|
||||
|
||||
$greeting = $perType['greeting'] ?? $config['greeting'] ?? null;
|
||||
if ($greeting !== null && $currentNode === null) {
|
||||
$greetingFlowId = $perType['greeting_flow'] ?? 'greeting';
|
||||
@@ -65,6 +72,12 @@ class NormalBot
|
||||
return self::handleFlow($flows[$fallbackFlowId], $context, $company, $ctxId, $menus);
|
||||
}
|
||||
|
||||
// greeting_menu also serves as fallback when nothing else matched
|
||||
if ($greetingMenuKey !== null && isset($menus[$greetingMenuKey])) {
|
||||
ConversationContext::updateNode($ctxId, null);
|
||||
return self::buildMenuResponse($menus[$greetingMenuKey], $context['from'], $company);
|
||||
}
|
||||
|
||||
$fallback = $perType['fallback'] ?? $config['fallback'] ?? null;
|
||||
if ($fallback !== null) {
|
||||
ConversationContext::updateNode($ctxId, null);
|
||||
|
||||
Reference in New Issue
Block a user