php-llm-agent-www/index.html
2025-09-17 18:02:04 +00:00

111 lines
4.4 KiB
HTML

<?php // index.php — Simple ChatGPT-like UI in a single PHP file (Bootstrap 5)
require_once __DIR__."/backend.php"; ?>
<!doctype html>
<html lang="en" data-theme="<?= $theme ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FMF GPT</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/main.css" rel="stylesheet">
</head>
<body>
<div class="container py-4 chat-wrap">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark rounded mb-3 px-3">
<a class="navbar-brand" href="#">FMF GPT</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#topNav" aria-controls="topNav"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="topNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" href="#chat">Chat</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#systemAcc">System</a>
</li>
</ul>
<div class="d-flex">
<button id="resetBtn" class="btn btn-sm btn-outline-light me-2">Reset</button>
<button id="themeToggle" class="btn btn-sm btn-outline-light" aria-pressed="false">
Toggle Theme
</button>
</div>
</div>
</nav>
<div class="accordion mb-3" id="systemAcc">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
System prompt (optional)
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#systemAcc">
<div class="accordion-body">
<textarea id="systemInput" class="form-control" rows="3" placeholder="You are a concise assistant that..."><?= $systemPrefill ?></textarea>
<div class="form-text">Saved in the session and applied to each message until changed.</div>
</div>
</div>
</div>
</div>
<div id="chat" class="chat-box p-3 mb-3 text-white">
<?php if (!$history): ?>
<div class="text-secondary">Start the conversation below…</div>
<?php else: ?>
<?php foreach ($history as $m): ?>
<?php
$role = htmlspecialchars($m['role'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$ts = (int)($m['ts'] ?? time());
?>
<div class="msg <?= $role ?>">
<div class="content">
<?php if ($role === 'assistant' && !empty($m['content_html'])): ?>
<!-- Assistant: already sanitized HTML -->
<?= $m['content_html'] ?>
<?php else: ?>
<!-- User (or legacy items): escape + preserve newlines -->
<?= nl2br(htmlspecialchars($m['content'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), false) ?>
<?php endif; ?>
</div>
<div class="time"><?= date('H:i', $ts) ?></div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<form id="chatForm" class="card shadow-sm">
<div class="card-body">
<div class="mb-2">
<textarea id="messageInput" class="form-control" rows="3" placeholder="Ask something… (Shift+Enter for newline)" required></textarea>
</div>
<div class="d-flex gap-2">
<button id="sendBtn" type="submit" class="btn btn-primary">Send</button>
<button id="saveSysBtn" type="button" class="btn btn-outline-secondary">Save System Prompt</button>
</div>
</div>
</form>
</div>
<script>
// Expose CSRF + theme to main.js
window.__APP__ = {
csrf: "<?= $csrf ?>",
theme: "<?= $theme ?>",
};
</script>
<!-- Optional client-side second layer sanitation (defense-in-depth) -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.6/dist/purify.min.js" integrity="" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="/main.js"></script>
</body>
</html>