Protokoll #18137
| ID | 18137 |
|---|---|
| Zeitstempel | 2025-12-26 20:18:25.962247 |
| Client | root |
| IP | Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 12,053 (Input: 0, Output: 0) |
| Dauer | 90 ms |
| Request-Zeit | Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18 |
| Response-Zeit | - |
Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22
Request
{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/View\/chat\/index.php",
"content": "<?php\n\/**\n * Chat - Redesign\n * Clean, minimalist, professional\n *\/\n$currentModel = $session['model'] ?? $defaultModel ?? 'claude-opus-4-5-20251101';\n$selected = json_decode($session['collections'] ?? '[\"documents\"]', true) ?: ['documents'];\n$currentLimit = (int) ($session['context_limit'] ?? 5);\n$currentProfileId = (int) ($session['author_profile_id'] ?? 0);\n$currentPromptId = (int) ($session['system_prompt_id'] ?? 1);\n$currentTemperature = (float) ($session['temperature'] ?? 0.5);\n$currentMaxTokens = (int) ($session['max_tokens'] ?? 4096);\n?>\n<!DOCTYPE html>\n<html lang=\"de\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?> - Campus<\/title>\n <link rel=\"icon\" type=\"image\/png\" href=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\">\n <link rel=\"stylesheet\" href=\"\/css\/chat-redesign.css\">\n <script src=\"\/js\/htmx.min.js\"><\/script>\n<\/head>\n<body>\n<div class=\"chat-layout\">\n <!-- Sidebar -->\n <aside class=\"chat-sidebar\" id=\"sidebar\">\n <div class=\"chat-sidebar__header\">\n <a href=\"\/chat\" class=\"chat-sidebar__new\">+ Neuer Chat<\/a>\n <button class=\"chat-sidebar__delete-all\" hx-delete=\"\/chat\" hx-confirm=\"Alle <?= count($sessions ?? []) ?> Chats löschen?\" title=\"Alle löschen\">× Alle<\/button>\n <\/div>\n <div class=\"chat-sidebar__list\" id=\"session-list\">\n <?php foreach ($sessions ?? [] as $s):\n $totalTokens = (int) ($s['total_input_tokens'] ?? 0) + (int) ($s['total_output_tokens'] ?? 0);\n $totalCost = ((int) ($s['total_input_tokens'] ?? 0) * 0.000015) + ((int) ($s['total_output_tokens'] ?? 0) * 0.000075);\n $isOllama = str_starts_with($s['model'] ?? '', 'ollama:');\n ?>\n <a href=\"\/chat\/<?= $s['uuid'] ?>\"\n class=\"chat-session <?= ($session['uuid'] ?? '') === $s['uuid'] ? 'chat-session--active' : '' ?>\"\n data-uuid=\"<?= $s['uuid'] ?>\">\n <div class=\"chat-session__title\" id=\"title-<?= $s['uuid'] ?>\"><?= htmlspecialchars($s['title'] ?? 'Neuer Chat') ?><\/div>\n <div class=\"chat-session__meta\">\n <span><?= $isOllama ? 'Lokal' : 'Claude' ?><\/span>\n <span><?= $s['message_count'] ?? 0 ?> Nachr.<\/span>\n <?php if (!$isOllama && $totalTokens > 0): ?>\n <span title=\"<?= number_format((int) $s['total_input_tokens']) ?> in \/ <?= number_format((int) $s['total_output_tokens']) ?> out\"><?= number_format($totalTokens) ?> Tok.<\/span>\n <span class=\"chat-session__cost\">~$<?= number_format($totalCost, 2) ?><\/span>\n <?php elseif ($isOllama): ?>\n <span class=\"chat-session__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <div class=\"chat-session__actions\">\n <button class=\"chat-session__edit\" onclick=\"event.preventDefault(); event.stopPropagation(); editTitle('<?= $s['uuid'] ?>');\" title=\"Bearbeiten\">✎<\/button>\n <button class=\"chat-session__delete\" hx-delete=\"\/chat\/<?= $s['uuid'] ?>\" hx-confirm=\"Session löschen?\" onclick=\"event.preventDefault(); event.stopPropagation();\">×<\/button>\n <\/div>\n <\/a>\n <?php endforeach; ?>\n <?php if (empty($sessions)): ?>\n <div class=\"chat-session chat-session--empty\">Keine Sessions<\/div>\n <?php endif; ?>\n <\/div>\n <\/aside>\n\n <div class=\"chat-overlay\" id=\"overlay\"><\/div>\n\n <!-- Main -->\n <main class=\"chat-main\">\n <!-- Header -->\n <header class=\"chat-header\">\n <button class=\"chat-toggle\" id=\"toggle\" title=\"Sidebar\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12h18M3 6h18M3 18h18\"\/><\/svg>\n <\/button>\n <a href=\"\/\" class=\"chat-header__logo\" title=\"Zur Startseite\">\n <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus\">\n <\/a>\n <div class=\"chat-header__title\">\n <h1 id=\"page-title\"><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?><\/h1>\n <\/div>\n <\/header>\n\n <!-- Messages -->\n <div class=\"chat-messages\" id=\"messages\">\n <div class=\"chat-messages__inner\">\n <?php if (empty($messages)): ?>\n <div class=\"chat-welcome\">\n <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus am See\" class=\"chat-welcome__logo\">\n <h2>Campus am See KI Assistent<\/h2>\n <\/div>\n <?php endif; ?>\n\n <?php foreach ($messages ?? [] as $msg): ?>\n <div class=\"chat-msg chat-msg--<?= $msg['role'] ?>\">\n <div class=\"chat-msg__content\">\n <?php if ($msg['role'] === 'user'): ?>\n <?= htmlspecialchars($msg['content']) ?>\n <?php else: ?>\n <?= nl2br(htmlspecialchars($msg['content'])) ?>\n\n <?php if (!empty($msg['sources'])): ?>\n <?php $sources = json_decode($msg['sources'], true) ?: []; ?>\n <?php if (!empty($sources)): ?>\n <div class=\"chat-sources\" id=\"sources-<?= $msg['id'] ?>\">\n <button type=\"button\" class=\"chat-sources__toggle\" onclick=\"this.parentElement.classList.toggle('chat-sources--open')\">\n <?= count($sources) ?> Quelle<?= count($sources) > 1 ? 'n' : '' ?> ▾\n <\/button>\n <div class=\"chat-sources__list\">\n <?php foreach ($sources as $source): ?>\n <div class=\"chat-source\">\n <div class=\"chat-source__header\">\n <?php if (!empty($source['collection'])): ?>\n <span class=\"chat-source__collection\">[<?= htmlspecialchars($source['collection']) ?>]<\/span>\n <?php endif; ?>\n <span class=\"chat-source__title\"><?= htmlspecialchars($source['title'] ?? 'Unbekannt') ?><\/span>\n <span class=\"chat-source__score\"><?= round(($source['score'] ?? 0) * 100) ?>%<\/span>\n <\/div>\n <?php if (!empty($source['content'])): ?>\n <div class=\"chat-source__content\">\"<?= htmlspecialchars(mb_substr($source['content'], 0, 200)) ?><?= mb_strlen($source['content']) > 200 ? '...' : '' ?>\"<\/div>\n <?php endif; ?>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n <?php endif; ?>\n <?php endif; ?>\n\n <?php\n $inputTokens = (int) ($msg['tokens_input'] ?? 0);\n $outputTokens = (int) ($msg['tokens_output'] ?? 0);\n $msgCost = ($inputTokens * 0.000015) + ($outputTokens * 0.000075);\n $msgModel = $msg['model'] ?? 'claude-opus-4-5-20251101';\n $msgIsOllama = str_starts_with($msgModel, 'ollama:');\n ?>\n <div class=\"chat-msg__meta\">\n <span><?= $msgIsOllama ? substr($msgModel, 7) : $msgModel ?><\/span>\n <?php if (!$msgIsOllama && ($inputTokens > 0 || $outputTokens > 0)): ?>\n <span class=\"chat-msg__tokens\">↓<?= number_format($inputTokens) ?> ↑<?= number_format($outputTokens) ?><\/span>\n <span class=\"chat-msg__cost\">~$<?= number_format($msgCost, 4) ?><\/span>\n <?php elseif ($msgIsOllama): ?>\n <span class=\"chat-msg__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <?php endif; ?>\n <\/div>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n\n <!-- Input Area -->\n <div class=\"chat-input-area\">\n <div class=\"chat-input-wrapper\">\n <form class=\"chat-form\" id=\"chatForm\"\n hx-post=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/message\"\n hx-target=\"#messages .chat-messages__inner\"\n hx-swap=\"beforeend\">\n\n <div class=\"chat-input-row\">\n <input type=\"text\" name=\"message\" class=\"chat-input\" placeholder=\"Nachricht eingeben...\" autocomplete=\"off\" required>\n <button type=\"submit\" class=\"chat-send\" id=\"sendBtn\">\n <span class=\"chat-send__text\">Senden<\/span>\n <span class=\"chat-send__loading\"><span><\/span><span><\/span><span><\/span><\/span>\n <\/button>\n <\/div>\n\n <!-- Settings Row 1 -->\n <div class=\"chat-settings\" id=\"settings\">\n <select name=\"model\" class=\"chat-select\">\n <optgroup label=\"Anthropic\">\n <?php foreach ($models ?? [] as $modelId => $modelLabel): ?>\n <?php if (!str_starts_with($modelId, 'ollam... [TRUNCATED-4d5dc7da7e8d3775]"
}
}
Response
{
"tool_response": {
"type": "update",
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/View\/chat\/index.php",
"content": "<?php\n\/**\n * Chat - Redesign\n * Clean, minimalist, professional\n *\/\n$currentModel = $session['model'] ?? $defaultModel ?? 'claude-opus-4-5-20251101';\n$selected = json_decode($session['collections'] ?? '[\"documents\"]', true) ?: ['documents'];\n$currentLimit = (int) ($session['context_limit'] ?? 5);\n$currentProfileId = (int) ($session['author_profile_id'] ?? 0);\n$currentPromptId = (int) ($session['system_prompt_id'] ?? 1);\n$currentTemperature = (float) ($session['temperature'] ?? 0.5);\n$currentMaxTokens = (int) ($session['max_tokens'] ?? 4096);\n?>\n<!DOCTYPE html>\n<html lang=\"de\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?> - Campus<\/title>\n <link rel=\"icon\" type=\"image\/png\" href=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\">\n <link rel=\"stylesheet\" href=\"\/css\/chat-redesign.css\">\n <script src=\"\/js\/htmx.min.js\"><\/script>\n<\/head>\n<body>\n<div class=\"chat-layout\">\n <!-- Sidebar -->\n <aside class=\"chat-sidebar\" id=\"sidebar\">\n <div class=\"chat-sidebar__header\">\n <a href=\"\/chat\" class=\"chat-sidebar__new\">+ Neuer Chat<\/a>\n <button class=\"chat-sidebar__delete-all\" hx-delete=\"\/chat\" hx-confirm=\"Alle <?= count($sessions ?? []) ?> Chats löschen?\" title=\"Alle löschen\">× Alle<\/button>\n <\/div>\n <div class=\"chat-sidebar__list\" id=\"session-list\">\n <?php foreach ($sessions ?? [] as $s):\n $totalTokens = (int) ($s['total_input_tokens'] ?? 0) + (int) ($s['total_output_tokens'] ?? 0);\n $totalCost = ((int) ($s['total_input_tokens'] ?? 0) * 0.000015) + ((int) ($s['total_output_tokens'] ?? 0) * 0.000075);\n $isOllama = str_starts_with($s['model'] ?? '', 'ollama:');\n ?>\n <a href=\"\/chat\/<?= $s['uuid'] ?>\"\n class=\"chat-session <?= ($session['uuid'] ?? '') === $s['uuid'] ? 'chat-session--active' : '' ?>\"\n data-uuid=\"<?= $s['uuid'] ?>\">\n <div class=\"chat-session__title\" id=\"title-<?= $s['uuid'] ?>\"><?= htmlspecialchars($s['title'] ?? 'Neuer Chat') ?><\/div>\n <div class=\"chat-session__meta\">\n <span><?= $isOllama ? 'Lokal' : 'Claude' ?><\/span>\n <span><?= $s['message_count'] ?? 0 ?> Nachr.<\/span>\n <?php if (!$isOllama && $totalTokens > 0): ?>\n <span title=\"<?= number_format((int) $s['total_input_tokens']) ?> in \/ <?= number_format((int) $s['total_output_tokens']) ?> out\"><?= number_format($totalTokens) ?> Tok.<\/span>\n <span class=\"chat-session__cost\">~$<?= number_format($totalCost, 2) ?><\/span>\n <?php elseif ($isOllama): ?>\n <span class=\"chat-session__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <div class=\"chat-session__actions\">\n <button class=\"chat-session__edit\" onclick=\"event.preventDefault(); event.stopPropagation(); editTitle('<?= $s['uuid'] ?>');\" title=\"Bearbeiten\">✎<\/button>\n <button class=\"chat-session__delete\" hx-delete=\"\/chat\/<?= $s['uuid'] ?>\" hx-confirm=\"Session löschen?\" onclick=\"event.preventDefault(); event.stopPropagation();\">×<\/button>\n <\/div>\n <\/a>\n <?php endforeach; ?>\n <?php if (empty($sessions)): ?>\n <div class=\"chat-session chat-session--empty\">Keine Sessions<\/div>\n <?php endif; ?>\n <\/div>\n <\/aside>\n\n <div class=\"chat-overlay\" id=\"overlay\"><\/div>\n\n <!-- Main -->\n <main class=\"chat-main\">\n <!-- Header -->\n <header class=\"chat-header\">\n <button class=\"chat-toggle\" id=\"toggle\" title=\"Sidebar\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12h18M3 6h18M3 18h18\"\/><\/svg>\n <\/button>\n <a href=\"\/\" class=\"chat-header__logo\" title=\"Zur Startseite\">\n <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus\">\n <\/a>\n <div class=\"chat-header__title\">\n <h1 id=\"page-title\"><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?><\/h1>\n <\/div>\n <\/header>\n\n <!-- Messages -->\n <div class=\"chat-messages\" id=\"messages\">\n <div class=\"chat-messages__inner\">\n <?php if (empty($messages)): ?>\n <div class=\"chat-welcome\">\n <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus am See\" class=\"chat-welcome__logo\">\n <h2>Campus am See KI Assistent<\/h2>\n <\/div>\n <?php endif; ?>\n\n <?php foreach ($messages ?? [] as $msg): ?>\n <div class=\"chat-msg chat-msg--<?= $msg['role'] ?>\">\n <div class=\"chat-msg__content\">\n <?php if ($msg['role'] === 'user'): ?>\n <?= htmlspecialchars($msg['content']) ?>\n <?php else: ?>\n <?= nl2br(htmlspecialchars($msg['content'])) ?>\n\n <?php if (!empty($msg['sources'])): ?>\n <?php $sources = json_decode($msg['sources'], true) ?: []; ?>\n <?php if (!empty($sources)): ?>\n <div class=\"chat-sources\" id=\"sources-<?= $msg['id'] ?>\">\n <button type=\"button\" class=\"chat-sources__toggle\" onclick=\"this.parentElement.classList.toggle('chat-sources--open')\">\n <?= count($sources) ?> Quelle<?= count($sources) > 1 ? 'n' : '' ?> ▾\n <\/button>\n <div class=\"chat-sources__list\">\n <?php foreach ($sources as $source): ?>\n <div class=\"chat-source\">\n <div class=\"chat-source__header\">\n <?php if (!empty($source['collection'])): ?>\n <span class=\"chat-source__collection\">[<?= htmlspecialchars($source['collection']) ?>]<\/span>\n <?php endif; ?>\n <span class=\"chat-source__title\"><?= htmlspecialchars($source['title'] ?? 'Unbekannt') ?><\/span>\n <span class=\"chat-source__score\"><?= round(($source['score'] ?? 0) * 100) ?>%<\/span>\n <\/div>\n <?php if (!empty($source['content'])): ?>\n <div class=\"chat-source__content\">\"<?= htmlspecialchars(mb_substr($source['content'], 0, 200)) ?><?= mb_strlen($source['content']) > 200 ? '...' : '' ?>\"<\/div>\n <?php endif; ?>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n <?php endif; ?>\n <?php endif; ?>\n\n <?php\n $inputTokens = (int) ($msg['tokens_input'] ?? 0);\n $outputTokens = (int) ($msg['tokens_output'] ?? 0);\n $msgCost = ($inputTokens * 0.000015) + ($outputTokens * 0.000075);\n $msgModel = $msg['model'] ?? 'claude-opus-4-5-20251101';\n $msgIsOllama = str_starts_with($msgModel, 'ollama:');\n ?>\n <div class=\"chat-msg__meta\">\n <span><?= $msgIsOllama ? substr($msgModel, 7) : $msgModel ?><\/span>\n <?php if (!$msgIsOllama && ($inputTokens > 0 || $outputTokens > 0)): ?>\n <span class=\"chat-msg__tokens\">↓<?= number_format($inputTokens) ?> ↑<?= number_format($outputTokens) ?><\/span>\n <span class=\"chat-msg__cost\">~$<?= number_format($msgCost, 4) ?><\/span>\n <?php elseif ($msgIsOllama): ?>\n <span class=\"chat-msg__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <?php endif; ?>\n <\/div>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n\n <!-- Input Area -->\n <div class=\"chat-input-area\">\n <div class=\"chat-input-wrapper\">\n <form class=\"chat-form\" id=\"chatForm\"\n hx-post=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/message\"\n hx-target=\"#messages .chat-messages__inner\"\n hx-swap=\"beforeend\">\n\n <div class=\"chat-input-row\">\n <input type=\"text\" name=\"message\" class=\"chat-input\" placeholder=\"Nachricht eingeben...\" autocomplete=\"off\" required>\n <button type=\"submit\" class=\"chat-send\" id=\"sendBtn\">\n <span class=\"chat-send__text\">Senden<\/span>\n <span class=\"chat-send__loading\"><span><\/span><span><\/span><span><\/span><\/span>\n <\/button>\n <\/div>\n\n <!-- Settings Row 1 -->\n <div class=\"chat-settings\" id=\"settings\">\n <select name=\"model\" class=\"chat-select\">\n <optgroup label=\"Anthropic\">\n <?php foreach ($models ?? [] as $modelId => $modelLabel): ?>\n <?php if (!str_starts_with($modelId, 'ollam... [TRUNCATED-4d5dc7da7e8d3775]",
"structuredPatch": [
{
"oldStart": 1,
"oldLines": 7,
"newStart": 1,
"newLines": 7,
"lines": [
" <?php",
" \/**",
"- * Chat - Redesign (ChatGPT-Stil)",
"- * Alle Features aus dem Original erhalten",
"+ * Chat - Redesign",
"+ * Clean, minimalist, professional",
" *\/",
" $currentModel = $session['model'] ?? $defaultModel ?? 'claude-opus-4-5-20251101';",
" $selected = json_decode($session['collections'] ?? '[\"documents\"]', true) ?: ['documents'];"
]
},
{
"oldStart": 34,
"oldLines": 7,
"newStart": 34,
"newLines": 7,
"lines": [
" $totalTokens = (int) ($s['total_input_tokens'] ?? 0) + (int) ($s['total_output_tokens'] ?? 0);",
" $totalCost = ((int) ($s['total_input_tokens'] ?? 0) * 0.000015) + ((int) ($s['total_output_tokens'] ?? 0) * 0.000075);",
" $isOllama = str_starts_with($s['model'] ?? '', 'ollama:');",
"- ?>",
"+ ?>",
" <a href=\"\/chat\/<?= $s['uuid'] ?>\"",
" class=\"chat-session <?= ($session['uuid'] ?? '') === $s['uuid'] ? 'chat-session--active' : '' ?>\"",
" data-uuid=\"<?= $s['uuid'] ?>\">"
]
},
{
"oldStart": 70,
"oldLines": 21,
"newStart": 70,
"newLines": 12,
"lines": [
" <button class=\"chat-toggle\" id=\"toggle\" title=\"Sidebar\">",
" <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12h18M3 6h18M3 18h18\"\/><\/svg>",
" <\/button>",
"+ <a href=\"\/\" class=\"chat-header__logo\" title=\"Zur Startseite\">",
"+ <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus\">",
"+ <\/a>",
" <div class=\"chat-header__title\">",
" <h1 id=\"page-title\"><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?><\/h1>",
" <\/div>",
"- <div class=\"chat-header__actions\">",
"- <div class=\"chat-dropdown\" id=\"exportDropdown\">",
"- <button class=\"chat-btn chat-btn--ghost\" id=\"exportBtn\">Export<\/button>",
"- <div class=\"chat-dropdown__menu\">",
"- <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=markdown\" class=\"chat-dropdown__item\">Markdown (.md)<\/a>",
"- <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=json\" class=\"chat-dropdown__item\">JSON (.json)<\/a>",
"- <\/div>",
"- <\/div>",
"- <button class=\"chat-btn chat-btn--icon\" id=\"themeToggle\" title=\"Theme\">",
"- <span id=\"themeIcon\">☾<\/span>",
"- <\/button>",
"- <\/div>",
" <\/header>",
" ",
" <!-- Messages -->"
]
},
{
"oldStart": 133,
"oldLines": 12,
"newStart": 124,
"newLines": 12,
"lines": [
" <?php endif; ?>",
" ",
" <?php",
"- $inputTokens = (int) ($msg['tokens_input'] ?? 0);",
"- $outputTokens = (int) ($msg['tokens_output'] ?? 0);",
"- $msgCost = ($inputTokens * 0.000015) + ($outputTokens * 0.000075);",
"- $msgModel = $msg['model'] ?? 'claude-opus-4-5-20251101';",
"- $msgIsOllama = str_starts_with($msgModel, 'ollama:');",
"- ?>",
"+ $inputTokens = (int) ($msg['tokens_input'] ?? 0);",
"+ $outputTokens = (int) ($msg['tokens_output'] ?? 0);",
"+ $msgCost = ($inputTokens * 0.000015) + ($outputTokens * 0.000075);",
"+ $msgModel = $msg['model'] ?? 'claude-opus-4-5-20251101';",
"+ $msgIsOllama = str_starts_with($msgModel, 'ollama:');",
"+ ?>",
" <div class=\"chat-msg__meta\">",
" <span><?= $msgIsOllama ? substr($msgModel, 7) : $msgModel ?><\/span>",
" <?php if (!$msgIsOllama && ($inputTokens > 0 || $outputTokens > 0)): ?>"
]
},
{
"oldStart": 197,
"oldLines": 6,
"newStart": 188,
"newLines": 22,
"lines": [
" <option value=\"15\" <?= $currentLimit === 15 ? 'selected' : '' ?>>15 Quellen<\/option>",
" <\/select>",
" ",
"+ <!-- Collections Multi-Select -->",
"+ <select name=\"collections[]\" class=\"chat-select chat-select--multi\" id=\"collectionsSelect\" multiple size=\"1\">",
"+ <?php foreach ($collections ?? [] as $col):",
"+ $colId = $col['collection_id'];",
"+ $isSelected = in_array($colId, $selected, true);",
"+ $points = (int) ($col['points_count'] ?? 0);",
"+ ?>",
"+ <option value=\"<?= htmlspecialchars($colId) ?>\" <?= $isSelected ? 'selected' : '' ?>><?= htmlspecialchars($col['display_name']) ?> (<?= number_format($points) ?>)<\/option>",
"+ <?php endforeach; ?>",
"+ <\/select>",
"+",
"+ <button type=\"button\" class=\"chat-settings-toggle\" id=\"settingsToggle\">Mehr<\/button>",
"+ <\/div>",
"+",
"+ <!-- Settings Row 2 (Advanced) - Hidden by default -->",
"+ <div class=\"chat-settings chat-settings--advanced chat-settings--hidden\" id=\"settingsAdvanced\">",
" <select name=\"author_profile_id\" class=\"chat-select\">",
" <option value=\"0\" <?= $currentProfileId === 0 ? 'selected' : '' ?>>Kein Profil<\/option>",
" <?php foreach ($authorProfiles ?? [] as $profile): ?>"
]
},
{
"oldStart": 217,
"oldLines": 25,
"newStart": 224,
"newLines": 6,
"lines": [
" <?php endforeach; ?>",
" <\/select>",
" ",
"- <button type=\"button\" class=\"chat-settings-toggle\" id=\"settingsToggle\">Mehr<\/button>",
"- <\/div>",
"-",
"- <!-- Settings Row 2 (Advanced) -->",
"- <div class=\"chat-settings chat-settings--advanced\" id=\"settingsAdvanced\">",
"- <!-- Collections -->",
"- <div class=\"chat-collections\">",
"- <?php foreach ($collections ?? [] as $col):",
"- $colId = $col['collection_id'];",
"- $isSelected = in_array($colId, $selected, true);",
"- $points = (int) ($col['points_count'] ?? 0);",
"- ?>",
"- <label class=\"chat-checkbox\" title=\"<?= number_format($points) ?> Dokumente\">",
"- <input type=\"checkbox\" name=\"collections[]\" value=\"<?= htmlspecialchars($colId) ?>\" <?= $isSelected ? 'checked' : '' ?>>",
"- <?= htmlspecialchars($col['display_name']) ?> <span class=\"chat-checkbox__count\">(<?= number_format($points) ?>)<\/span>",
"- <\/label>",
"- <?php endforeach; ?>",
"- <\/div>",
"-",
" <!-- Temperature -->",
" <div class=\"chat-temp\">",
" <label>Temp: <span id=\"tempValue\"><?= number_format($currentTemperature, 1) ?><\/span><\/label>"
]
},
{
"oldStart": 252,
"oldLines": 9,
"newStart": 240,
"newLines": 9,
"lines": [
" ",
" <!-- Presets -->",
" <div class=\"chat-presets\">",
"- <button type=\"button\" class=\"chat-preset\" data-temp=\"0.3\" data-tokens=\"2048\">Präzise<\/button>",
"- <button type=\"button\" class=\"chat-preset chat-preset--active\" data-temp=\"0.5\" data-tokens=\"4096\">Ausgewogen<\/button>",
"- <button type=\"button\" class=\"chat-preset\" data-temp=\"0.9\" data-tokens=\"4096\">Kreativ<\/button>",
"+ <button type=\"button\" class=\"chat-preset<?= $currentTemperature == 0.3 ? ' chat-preset--active' : '' ?>\" data-temp=\"0.3\" data-tokens=\"2048\">Präzise<\/button>",
"+ <button type=\"button\" class=\"chat-preset<?= $currentTemperature == 0.5 ? ' chat-preset--active' : '' ?>\" data-temp=\"0.5\" data-tokens=\"4096\">Ausgewogen<\/button>",
"+ <button type=\"button\" class=\"chat-preset<?= $currentTemperature == 0.9 ? ' chat-preset--active' : '' ?>\" data-temp=\"0.9\" data-tokens=\"4096\">Kreativ<\/button>",
" <\/div>",
" ",
" <!-- Quality Check -->"
]
},
{
"oldStart": 262,
"oldLines": 6,
"newStart": 250,
"newLines": 20,
"lines": [
" <input type=\"checkbox\" name=\"quality_check\" value=\"1\">",
" Qualitätsprüfung",
" <\/label>",
"+",
"+ <!-- Export -->",
"+ <div class=\"chat-dropdown\" id=\"exportDropdown\">",
"+ <button type=\"button\" class=\"chat-btn chat-btn--ghost\" id=\"exportBtn\">Export<\/button>",
"+ <div class=\"chat-dropdown__menu\">",
"+ <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=markdown\" class=\"chat-dropdown__item\">Markdown (.md)<\/a>",
"+ <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=json\" class=\"chat-dropdown__item\">JSON (.json)<\/a>",
"+ <\/div>",
"+ <\/div>",
"+",
"+ <!-- Theme Toggle -->",
"+ <button type=\"button\" class=\"chat-btn chat-btn--icon\" id=\"themeToggle\" title=\"Dark\/Light Mode\">",
"+ <span id=\"themeIcon\">☾<\/span>",
"+ <\/button>",
" <\/div>",
" <\/form>",
" <\/div>"
]
},
{
"oldStart": 276,
"oldLines": 7,
"newStart": 278,
"newLines": 6,
"lines": [
" const messages = document.getElementById('messages');",
" const form = document.getElementById('chatForm');",
" const sendBtn = document.getElementById('sendBtn');",
"-const settings = document.getElementById('settings');",
" const settingsAdvanced = document.getElementById('settingsAdvanced');",
" const settingsToggle = document.getElementById('settingsToggle');",
" const themeToggle = document.getElementById('themeToggle');"
]
},
{
"oldStart": 284,
"oldLines": 6,
"newStart": 285,
"newLines": 7,
"lines": [
" const html = document.documentElement;",
" const exportDropdown = document.getElementById('exportDropdown');",
" const exportBtn = document.getElementById('exportBtn');",
"+const collectionsSelect = document.getElementById('collectionsSelect');",
" ",
" \/\/ Theme",
" const savedTheme = localStorage.getItem('chat-theme') || 'light';"
]
},
{
"oldStart": 298,
"oldLines": 12,
"newStart": 300,
"newLines": 16,
"lines": [
" themeIcon.textContent = next === 'dark' ? '☀' : '☽';",
" });",
" ",
"-\/\/ Sidebar",
"-toggle.addEventListener('click', () => {",
"+\/\/ Sidebar Toggle",
"+toggle.addEventListener('click', (e) => {",
"+ e.stopPropagation();",
" sidebar.classList.toggle('chat-sidebar--open');",
"+ overlay.classList.toggle('chat-overlay--visible');",
" });",
"+",
" overlay.addEventListener('click', () => {",
" sidebar.classList.remove('chat-sidebar--open');",
"+ overlay.classList.remove('chat-overlay--visible');",
" });",
" ",
" \/\/ Export Dropdown"
]
},
{
"oldStart": 311,
"oldLines": 6,
"newStart": 317,
"newLines": 7,
"lines": [
" e.stopPropagation();",
" exportDropdown.classList.toggle('chat-dropdown--open');",
" });",
"+",
" document.addEventListener('click', (e) => {",
" if (!exportDropdown.contains(e.target)) {",
" exportDropdown.classList.remove('chat-dropdown--open');"
]
},
{
"oldStart": 328,
"oldLines": 18,
"newStart": 335,
"newLines": 28,
"lines": [
" const tempValue = document.getElementById('tempValue');",
" tempSlider.addEventListener('input', () => {",
" tempValue.textContent = parseFloat(tempSlider.value).toFixed(1);",
"+ updatePresetHighlight();",
" });",
" ",
"+\/\/ Update preset highlight based on current temp",
"+function updatePresetHighlight() {",
"+ const currentTemp = parseFloat(tempSlider.value);",
"+ document.querySelectorAll('.chat-preset').forEach(btn => {",
"+ const btnTemp = parseFloat(btn.dataset.temp);",
"+ btn.classList.toggle('chat-preset--active', Math.abs(btnTemp - currentTemp) < 0.05);",
"+ });",
"+}",
"+",
" \/\/ Presets",
" document.querySelectorAll('.chat-preset').forEach(btn => {",
" btn.addEventListener('click', () => {",
"- tempSlider.value = btn.dataset.temp;",
"- tempValue.textContent = parseFloat(btn.dataset.temp).toFixed(1);",
"- document.querySelector('select[name=\"max_tokens\"]').value = btn.dataset.tokens;",
"+ const temp = btn.dataset.temp;",
"+ const tokens = btn.dataset.tokens;",
"+ tempSlider.value = temp;",
"+ tempValue.textContent = parseFloat(temp).toFixed(1);",
"+ document.querySelector('select[name=\"max_tokens\"]').value = tokens;",
" document.querySelectorAll('.chat-preset').forEach(b => b.classList.remove('chat-preset--active'));",
" btn.classList.add('chat-preset--active');",
"- localStorage.setItem('chat_temperature', btn.dataset.temp);",
"- localStorage.setItem('chat_max_tokens', btn.dataset.tokens);",
" });",
" });",
" "
]
},
{
"oldStart": 358,
"oldLines": 7,
"newStart": 375,
"newLines": 6,
"lines": [
" sendBtn.disabled = false;",
" sendBtn.classList.remove('chat-send--loading');",
" messages.scrollTop = messages.scrollHeight;",
"- \/\/ Refresh session list",
" htmx.ajax('GET', '\/chat\/sessions?current=<?= $session['uuid'] ?? '' ?>', '#session-list');",
" }",
" });"
]
},
{
"oldStart": 372,
"oldLines": 54,
"newStart": 388,
"newLines": 14,
"lines": [
" \/\/ Scroll to bottom on load",
" messages.scrollTop = messages.scrollHeight;",
" ",
"-\/\/ Mobile: Start with sidebar hidden",
"-if (window.innerWidth <= 768) {",
"- sidebar.classList.remove('chat-sidebar--open');",
"-}",
"-",
" \/\/ Close sidebar on mobile when clicking main",
"-document.querySelector('.chat-main').addEventListener('click', () => {",
"- if (window.innerWidth <= 768) {",
"+document.querySelector('.chat-main').addEventListener('click', (e) => {",
"+ if (window.innerWidth <= 768 && !e.target.closest('.chat-toggle')) {",
" sidebar.classList.remove('chat-sidebar--open');",
"+ overlay.classList.remove('chat-overlay--visible');",
" }",
" });",
" ",
"-\/\/ LocalStorage persistence",
"-const dropdowns = ['model', 'context_limit', 'author_profile_id', 'system_prompt_id', 'max_tokens'];",
"-dropdowns.forEach(name => {",
"- const saved = localStorage.getItem('chat_' + name);",
"- const select = document.querySelector(`select[name=\"${name}\"]`);",
"- if (saved && select) select.value = saved;",
"- if (select) {",
"- select.addEventListener('change', () => localStorage.setItem('chat_' + name, select.value));",
"- }",
"-});",
"-",
"-\/\/ Temperature",
"-const savedTemp = localStorage.getItem('chat_temperature');",
"-if (savedTemp) {",
"- tempSlider.value = savedTemp;",
"- tempValue.textContent = parseFloat(savedTemp).toFixed(1);",
"-}",
"-tempSlider.addEventListener('change', () => localStorage.setItem('chat_temperature', tempSlider.value));",
"-",
"-\/\/ Collections",
"-const savedCollections = localStorage.getItem('chat_collections');",
"-if (savedCollections) {",
"- try {",
"- const arr = JSON.parse(savedCollections);",
"- document.querySelectorAll('input[name=\"collections[]\"]').forEach(cb => {",
"- cb.checked = arr.includes(cb.value);",
"- });",
"- } catch (e) {}",
"-}",
"-document.querySelectorAll('input[name=\"collections[]\"]').forEach(cb => {",
"- cb.addEventListener('change', () => {",
"- const selected = Array.from(document.querySelectorAll('input[name=\"collections[]\"]:checked')).map(c => c.value);",
"- localStorage.setItem('chat_collections', JSON.stringify(selected));",
"- });",
"-});",
"-",
" \/\/ Inline Title Edit",
" function editTitle(uuid) {",
" const titleEl = document.getElementById('title-' + uuid);"
]
}
],
"originalFile": "<?php\n\/**\n * Chat - Redesign (ChatGPT-Stil)\n * Alle Features aus dem Original erhalten\n *\/\n$currentModel = $session['model'] ?? $defaultModel ?? 'claude-opus-4-5-20251101';\n$selected = json_decode($session['collections'] ?? '[\"documents\"]', true) ?: ['documents'];\n$currentLimit = (int) ($session['context_limit'] ?? 5);\n$currentProfileId = (int) ($session['author_profile_id'] ?? 0);\n$currentPromptId = (int) ($session['system_prompt_id'] ?? 1);\n$currentTemperature = (float) ($session['temperature'] ?? 0.5);\n$currentMaxTokens = (int) ($session['max_tokens'] ?? 4096);\n?>\n<!DOCTYPE html>\n<html lang=\"de\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?> - Campus<\/title>\n <link rel=\"icon\" type=\"image\/png\" href=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\">\n <link rel=\"stylesheet\" href=\"\/css\/chat-redesign.css\">\n <script src=\"\/js\/htmx.min.js\"><\/script>\n<\/head>\n<body>\n<div class=\"chat-layout\">\n <!-- Sidebar -->\n <aside class=\"chat-sidebar\" id=\"sidebar\">\n <div class=\"chat-sidebar__header\">\n <a href=\"\/chat\" class=\"chat-sidebar__new\">+ Neuer Chat<\/a>\n <button class=\"chat-sidebar__delete-all\" hx-delete=\"\/chat\" hx-confirm=\"Alle <?= count($sessions ?? []) ?> Chats löschen?\" title=\"Alle löschen\">× Alle<\/button>\n <\/div>\n <div class=\"chat-sidebar__list\" id=\"session-list\">\n <?php foreach ($sessions ?? [] as $s):\n $totalTokens = (int) ($s['total_input_tokens'] ?? 0) + (int) ($s['total_output_tokens'] ?? 0);\n $totalCost = ((int) ($s['total_input_tokens'] ?? 0) * 0.000015) + ((int) ($s['total_output_tokens'] ?? 0) * 0.000075);\n $isOllama = str_starts_with($s['model'] ?? '', 'ollama:');\n ?>\n <a href=\"\/chat\/<?= $s['uuid'] ?>\"\n class=\"chat-session <?= ($session['uuid'] ?? '') === $s['uuid'] ? 'chat-session--active' : '' ?>\"\n data-uuid=\"<?= $s['uuid'] ?>\">\n <div class=\"chat-session__title\" id=\"title-<?= $s['uuid'] ?>\"><?= htmlspecialchars($s['title'] ?? 'Neuer Chat') ?><\/div>\n <div class=\"chat-session__meta\">\n <span><?= $isOllama ? 'Lokal' : 'Claude' ?><\/span>\n <span><?= $s['message_count'] ?? 0 ?> Nachr.<\/span>\n <?php if (!$isOllama && $totalTokens > 0): ?>\n <span title=\"<?= number_format((int) $s['total_input_tokens']) ?> in \/ <?= number_format((int) $s['total_output_tokens']) ?> out\"><?= number_format($totalTokens) ?> Tok.<\/span>\n <span class=\"chat-session__cost\">~$<?= number_format($totalCost, 2) ?><\/span>\n <?php elseif ($isOllama): ?>\n <span class=\"chat-session__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <div class=\"chat-session__actions\">\n <button class=\"chat-session__edit\" onclick=\"event.preventDefault(); event.stopPropagation(); editTitle('<?= $s['uuid'] ?>');\" title=\"Bearbeiten\">✎<\/button>\n <button class=\"chat-session__delete\" hx-delete=\"\/chat\/<?= $s['uuid'] ?>\" hx-confirm=\"Session löschen?\" onclick=\"event.preventDefault(); event.stopPropagation();\">×<\/button>\n <\/div>\n <\/a>\n <?php endforeach; ?>\n <?php if (empty($sessions)): ?>\n <div class=\"chat-session chat-session--empty\">Keine Sessions<\/div>\n <?php endif; ?>\n <\/div>\n <\/aside>\n\n <div class=\"chat-overlay\" id=\"overlay\"><\/div>\n\n <!-- Main -->\n <main class=\"chat-main\">\n <!-- Header -->\n <header class=\"chat-header\">\n <button class=\"chat-toggle\" id=\"toggle\" title=\"Sidebar\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12h18M3 6h18M3 18h18\"\/><\/svg>\n <\/button>\n <div class=\"chat-header__title\">\n <h1 id=\"page-title\"><?= htmlspecialchars($session['title'] ?? 'KI-Chat') ?><\/h1>\n <\/div>\n <div class=\"chat-header__actions\">\n <div class=\"chat-dropdown\" id=\"exportDropdown\">\n <button class=\"chat-btn chat-btn--ghost\" id=\"exportBtn\">Export<\/button>\n <div class=\"chat-dropdown__menu\">\n <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=markdown\" class=\"chat-dropdown__item\">Markdown (.md)<\/a>\n <a href=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/export?format=json\" class=\"chat-dropdown__item\">JSON (.json)<\/a>\n <\/div>\n <\/div>\n <button class=\"chat-btn chat-btn--icon\" id=\"themeToggle\" title=\"Theme\">\n <span id=\"themeIcon\">☾<\/span>\n <\/button>\n <\/div>\n <\/header>\n\n <!-- Messages -->\n <div class=\"chat-messages\" id=\"messages\">\n <div class=\"chat-messages__inner\">\n <?php if (empty($messages)): ?>\n <div class=\"chat-welcome\">\n <img src=\"https:\/\/campus-am-see.de\/wp-content\/uploads\/menu-logo.png\" alt=\"Campus am See\" class=\"chat-welcome__logo\">\n <h2>Campus am See KI Assistent<\/h2>\n <\/div>\n <?php endif; ?>\n\n <?php foreach ($messages ?? [] as $msg): ?>\n <div class=\"chat-msg chat-msg--<?= $msg['role'] ?>\">\n <div class=\"chat-msg__content\">\n <?php if ($msg['role'] === 'user'): ?>\n <?= htmlspecialchars($msg['content']) ?>\n <?php else: ?>\n <?= nl2br(htmlspecialchars($msg['content'])) ?>\n\n <?php if (!empty($msg['sources'])): ?>\n <?php $sources = json_decode($msg['sources'], true) ?: []; ?>\n <?php if (!empty($sources)): ?>\n <div class=\"chat-sources\" id=\"sources-<?= $msg['id'] ?>\">\n <button type=\"button\" class=\"chat-sources__toggle\" onclick=\"this.parentElement.classList.toggle('chat-sources--open')\">\n <?= count($sources) ?> Quelle<?= count($sources) > 1 ? 'n' : '' ?> ▾\n <\/button>\n <div class=\"chat-sources__list\">\n <?php foreach ($sources as $source): ?>\n <div class=\"chat-source\">\n <div class=\"chat-source__header\">\n <?php if (!empty($source['collection'])): ?>\n <span class=\"chat-source__collection\">[<?= htmlspecialchars($source['collection']) ?>]<\/span>\n <?php endif; ?>\n <span class=\"chat-source__title\"><?= htmlspecialchars($source['title'] ?? 'Unbekannt') ?><\/span>\n <span class=\"chat-source__score\"><?= round(($source['score'] ?? 0) * 100) ?>%<\/span>\n <\/div>\n <?php if (!empty($source['content'])): ?>\n <div class=\"chat-source__content\">\"<?= htmlspecialchars(mb_substr($source['content'], 0, 200)) ?><?= mb_strlen($source['content']) > 200 ? '...' : '' ?>\"<\/div>\n <?php endif; ?>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n <?php endif; ?>\n <?php endif; ?>\n\n <?php\n $inputTokens = (int) ($msg['tokens_input'] ?? 0);\n $outputTokens = (int) ($msg['tokens_output'] ?? 0);\n $msgCost = ($inputTokens * 0.000015) + ($outputTokens * 0.000075);\n $msgModel = $msg['model'] ?? 'claude-opus-4-5-20251101';\n $msgIsOllama = str_starts_with($msgModel, 'ollama:');\n ?>\n <div class=\"chat-msg__meta\">\n <span><?= $msgIsOllama ? substr($msgModel, 7) : $msgModel ?><\/span>\n <?php if (!$msgIsOllama && ($inputTokens > 0 || $outputTokens > 0)): ?>\n <span class=\"chat-msg__tokens\">↓<?= number_format($inputTokens) ?> ↑<?= number_format($outputTokens) ?><\/span>\n <span class=\"chat-msg__cost\">~$<?= number_format($msgCost, 4) ?><\/span>\n <?php elseif ($msgIsOllama): ?>\n <span class=\"chat-msg__local\">lokal<\/span>\n <?php endif; ?>\n <\/div>\n <?php endif; ?>\n <\/div>\n <\/div>\n <?php endforeach; ?>\n <\/div>\n <\/div>\n\n <!-- Input Area -->\n <div class=\"chat-input-area\">\n <div class=\"chat-input-wrapper\">\n <form class=\"chat-form\" id=\"chatForm\"\n hx-post=\"\/chat\/<?= $session['uuid'] ?? '' ?>\/message\"\n hx-target=\"#messages .chat-messages__inner\"\n hx-swap=\"beforeend\">\n\n <div class=\"chat-input-row\">\n <input type=\"text\" name=\"message\" class=\"chat-input\" placeholder=\"Nachricht eingeben...\" autocomplete=\"off\" required>\n <button type=\"submit\" class=\"chat-send\" id=\"sendBtn\">\n <span class=\"chat-send__text\">Senden<\/sp... [TRUNCATED-f187369f66da68df]"
}
}