0) { $c = $pdo->prepare('SELECT COUNT(*) FROM departments WHERE id = ? AND is_active = 1'); $c->execute([$dept]); if (!(int) $c->fetchColumn()) $dept = 0; } if ($prio > 0) { $c = $pdo->prepare('SELECT COUNT(*) FROM priorities WHERE id = ?'); $c->execute([$prio]); if (!(int) $c->fetchColumn()) $prio = 0; } set_setting('assistant_enabled', !empty($_POST['assistant_enabled']) ? '1' : '0'); set_setting('assistant_mode', $mode); set_setting('assistant_name', mb_substr(trim(strip_tags((string) ($_POST['assistant_name'] ?? ''))), 0, 60)); set_setting('assistant_greeting', mb_substr(trim(strip_tags((string) ($_POST['assistant_greeting'] ?? ''))), 0, 500)); set_setting('assistant_no_answer', mb_substr(trim(strip_tags((string) ($_POST['assistant_no_answer'] ?? ''))), 0, 500)); set_setting('assistant_department_id', (string) $dept); set_setting('assistant_priority_id', (string) $prio); set_setting('assistant_log_days', (string) max(0, min(3650, (int) ($_POST['assistant_log_days'] ?? 90)))); audit_log($admin['id'], 'Einstellungen des digitalen Assistenten geändert'); flash('success', 'Einstellungen gespeichert.'); redirect('/staff/assistant.php'); } if ($action === 'save_answer') { $id = (int) ($_POST['id'] ?? 0); $title = trim(mb_substr((string) ($_POST['title'] ?? ''), 0, 255)); $keywords = trim(mb_substr((string) ($_POST['keywords'] ?? ''), 0, 1000)); $answer = trim(mb_substr((string) ($_POST['answer'] ?? ''), 0, 4000)); $active = !empty($_POST['is_active']) ? 1 : 0; if ($title === '' || $answer === '') { $errors[] = 'Bitte eine Frage (Titel) und die Antwort angeben.'; } else { $now = db_now(); if ($id > 0) { $pdo->prepare('UPDATE assistant_answers SET title=?, keywords=?, answer=?, is_active=?, updated_at=? WHERE id=?')->execute([$title, $keywords ?: null, $answer, $active, $now, $id]); audit_log($admin['id'], "Antwort des digitalen Assistenten geändert: {$title}"); flash('success', 'Antwort gespeichert.'); } else { $pdo->prepare('INSERT INTO assistant_answers (title, keywords, answer, is_active, created_at, updated_at) VALUES (?,?,?,?,?,?)')->execute([$title, $keywords ?: null, $answer, $active, $now, $now]); audit_log($admin['id'], "Antwort des digitalen Assistenten angelegt: {$title}"); flash('success', 'Antwort angelegt.'); } redirect('/staff/assistant.php?tab=answers'); } } if ($action === 'delete_answer') { $id = (int) ($_POST['id'] ?? 0); $t = $pdo->prepare('SELECT title FROM assistant_answers WHERE id = ?'); $t->execute([$id]); $title = $t->fetchColumn(); if ($title !== false) { $pdo->prepare('DELETE FROM assistant_answers WHERE id = ?')->execute([$id]); audit_log($admin['id'], "Antwort des digitalen Assistenten gelöscht: {$title}"); flash('success', 'Antwort gelöscht.'); } redirect('/staff/assistant.php?tab=answers'); } if ($action === 'save_synonyms') { $text = mb_substr(trim(strip_tags((string) ($_POST['assistant_synonyms'] ?? ''))), 0, 5000); set_setting('assistant_synonyms', $text); audit_log($admin['id'], 'Gleichbedeutende Wörter des digitalen Assistenten geändert'); flash('success', 'Gleichbedeutende Wörter gespeichert (' . count(assistant_custom_synonyms($text)) . ' Gruppen).'); redirect('/staff/assistant.php'); } if ($action === 'clear_log') { try { $n = $pdo->exec('DELETE FROM assistant_log'); audit_log($admin['id'], 'Fragen-Log des digitalen Assistenten geleert'); flash('success', 'Fragen-Log geleert (' . (int) $n . ' Einträge).'); } catch (Throwable $e) { flash('error', 'Das Log konnte nicht geleert werden. Bitte die Datenbank aktualisieren.'); } redirect('/staff/assistant.php?tab=log'); } if ($action === 'test') { $testQuestion = trim(mb_substr((string) ($_POST['question'] ?? ''), 0, 300)); $testResult = $testQuestion !== '' ? (assistant_search($pdo, $testQuestion, false) ?: false) : null; } } $answers = []; $dbOutdated = false; try { $answers = $pdo->query('SELECT * FROM assistant_answers ORDER BY title')->fetchAll(); } catch (Throwable $e) { $dbOutdated = true; } $edit = null; if (!empty($_GET['edit'])) { foreach ($answers as $a) if ((int) $a['id'] === (int) $_GET['edit']) $edit = $a; } $showForm = isset($_GET['new']) || $edit || $errors; $tab = in_array($_GET['tab'] ?? '', ['settings', 'answers', 'log'], true) ? $_GET['tab'] : 'settings'; if (isset($_GET['edit']) || isset($_GET['new']) || $errors || ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_answer')) $tab = 'answers'; if (isset($_GET['lr']) || isset($_GET['lp']) || isset($_GET['lq']) || isset($_GET['lpage'])) $tab = 'log'; $prefillTitle = (!$edit && empty($_POST) && isset($_GET['title'])) ? mb_substr(trim((string) $_GET['title']), 0, 255) : ''; $logFilter = [ 'result' => (string) ($_GET['lr'] ?? ''), 'period' => in_array($_GET['lp'] ?? '', ['today', '7', '30', 'all'], true) ? $_GET['lp'] : '30', 'q' => trim((string) ($_GET['lq'] ?? '')), ]; $logResults = assistant_log_filters(); $logPage = ['rows' => [], 'total' => 0, 'pages' => 1, 'page' => 1]; $logStats = array_fill_keys(array_keys($logResults), 0); $logTop = []; $logOutdated = false; try { $logPage = assistant_log_list($pdo, $logFilter, (int) ($_GET['lpage'] ?? 1)); $logStats = assistant_log_stats($pdo, $logFilter['period']); $logTop = assistant_log_unanswered($pdo, $logFilter['period']); } catch (Throwable $e) { $logOutdated = true; } $logQuery = static fn(array $over = []) => '/staff/assistant.php?' . http_build_query(array_filter(array_merge(['tab' => 'log', 'lr' => $logFilter['result'], 'lp' => $logFilter['period'], 'lq' => $logFilter['q']], $over), static fn($v) => $v !== '' && $v !== null)); $departments = $pdo->query('SELECT id, name FROM departments WHERE is_active = 1 ORDER BY name')->fetchAll(); $priorities = $pdo->query('SELECT id, name FROM priorities ORDER BY sort_order')->fetchAll(); $texts = assistant_texts(); $enabled = assistant_enabled(); $activeNow = assistant_active($pdo); $liveChatOn = get_setting('live_chat_enabled', '0') === '1'; $kbOn = get_setting('kb_enabled', '1') === '1'; $pageTitle = 'Digitaler Assistent'; $activePage = 'assistant'; require __DIR__ . '/_header.php'; ?>
Der Assistent beantwortet Fragen von Kunden aus der Wissensdatenbank und aus den Antworten unten. Findet er nichts, fragt er, ob er ein Ticket erstellen soll, und erfragt dafür alles Nötige. Es wird kein externer KI-Dienst verwendet, Fragen bleiben auf diesem Server.
Zustand jetzt: ausgeschaltet aktiv (Kunden sehen den Assistenten) bereit, aber gerade nicht sichtbar (Live-Chat ist besetzt= get_setting('helpdesk_status', 'online') === 'offline' ? ' bzw. das Supportcenter ist im Wartungsmodus' : '' ?>)
Zeigt, was der Assistent auf eine Kundenfrage antworten würde (ohne Zähler und ohne Ticket).
Wörter, die Kunden und Artikel unterschiedlich nennen, aber dasselbe meinen. Eine Gruppe je Zeile, durch Komma getrennt, zum Beispiel Zugang, Einladung, beitreten. Der Assistent behandelt sie dann gleich. Einige Gruppen sind schon eingebaut, deine ergänzen oder überschreiben sie.
Diese Antworten gelten zusätzlich zur Wissensdatenbank und haben Vorrang. Der Assistent findet sie über die Wörter in der Frage und in den Stichwörtern.
Noch keine zusätzlichen Antworten.
| Frage / Thema | Stichwörter | Genutzt | Status | |
|---|---|---|---|---|
| = e($a['title']) ?> = e(mb_strimwidth((string) $a['answer'], 0, 90, '…')) ?> |
= e((string) ($a['keywords'] ?? '')) ?> | = (int) $a['hits'] ?>× | = $a['is_active'] ? 'Aktiv' : 'Aus' ?> | Bearbeiten · |
Das Log ist noch nicht verfügbar. Bitte unter System-Update auf „Datenbank aktualisieren“ klicken.
Hier siehst du, was Kunden den Assistenten gefragt haben und ob er eine Antwort gefunden hat. Es werden nur Frage und Ergebnis gespeichert (kein Name, keine E-Mail-Adresse). Fragen ohne Antwort zeigen, was du noch hinterlegen solltest.
Keine Fragen für diese Auswahl.
| Zeit | Frage | Ergebnis | Antwort / Ticket | |
|---|---|---|---|---|
| = e(date('d.m.Y H:i', strtotime((string) $r['created_at']))) ?> | = e($r['question']) ?> | = e($logResults[$r['result']] ?? $r['result']) ?>= $r['helpful'] === null ? '' : ($r['helpful'] ? ' 👍' : ' 👎') ?> | = $r['ticket_number'] ? e('#' . $r['ticket_number']) : e((string) ($r['matched_title'] ?? '')) ?> | Antwort anlegen |