Agentic-Chat-bot / app /assets /html /agenticcore_frontend.html
JerameeUC
5th commit More cleanup
aa2c39f
<!-- /app/assets/html/agenticcore_frontend.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AgenticCore Chatbot Frontend</title>
<style>
:root {
--bg: #0b0d12;
--panel: #0f172a;
--panel-2: #111827;
--text: #e5e7eb;
--muted: #9ca3af;
--accent: #60a5fa;
--border: #1f2940;
--danger: #ef4444;
--success: #22c55e;
}
* { box-sizing: border-box; }
body { margin: 0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; background: var(--bg); color: var(--text); }
.wrap { max-width: 920px; margin: 32px auto; padding: 0 16px; }
header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; gap: 16px; }
header h1 { font-size: 18px; margin: 0; letter-spacing: .3px; }
header .badge { font-size: 12px; opacity: .85; padding: 4px 8px; border:1px solid var(--border); border-radius: 999px; background: rgba(255,255,255,0.03); }
.card { background: var(--panel); border: 1px solid var(--border); border-radius: 16px; padding: 16px; }
.row { display: flex; gap: 10px; align-items: center; }
.stack { display: grid; gap: 12px; }
label { font-size: 12px; color: var(--muted); }
input[type=text] { flex: 1; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--panel-2); color: var(--text); outline: none; }
input[type=text]::placeholder { color: #6b7280; }
button { padding: 10px 14px; border-radius: 12px; border: 1px solid var(--border); background: #1f2937; color: var(--text); cursor: pointer; transition: transform .02s ease, background .2s; }
button:hover { background: #273449; }
button:active { transform: translateY(1px); }
.btn-primary { background: #1f2937; border-color: #31405a; }
.btn-ghost { background: transparent; border-color: var(--border); }
.grid { display: grid; gap: 12px; }
.grid-2 { grid-template-columns: 1fr 1fr; }
.log { margin-top: 16px; display: grid; gap: 10px; }
.bubble { max-width: 80%; padding: 12px 14px; border-radius: 14px; line-height: 1.35; }
.user { background: #1e293b; border:1px solid #2b3b55; margin-left: auto; border-bottom-right-radius: 4px; }
.bot { background: #0d1b2a; border:1px solid #223049; margin-right: auto; border-bottom-left-radius: 4px; }
.meta { font-size: 12px; color: var(--muted); margin-top: 4px; }
pre { margin: 0; white-space: pre-wrap; word-break: break-word; }
.status { display:flex; align-items:center; gap:8px; font-size: 12px; color: var(--muted); }
.dot { width:8px; height:8px; border-radius:999px; background: #64748b; display:inline-block; }
.dot.ok { background: var(--success); }
.dot.bad { background: var(--danger); }
footer { margin: 24px 0; text-align:center; color: var(--muted); font-size: 12px; }
.small { font-size: 12px; }
@media (max-width: 700px) { .grid-2 { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="wrap">
<header>
<h1>AgenticCore Chatbot Frontend</h1>
<div class="badge">Frontend → FastAPI → providers_unified</div>
</header>
<section class="card stack">
<div class="grid grid-2">
<div class="stack">
<label for="backend">Backend URL</label>
<div class="row">
<input id="backend" type="text" placeholder="http://127.0.0.1:8000" />
<button id="save" class="btn-ghost">Save</button>
</div>
<div class="status" id="status"><span class="dot"></span><span>Not checked</span></div>
</div>
<div class="stack">
<label for="message">Message</label>
<div class="row">
<input id="message" type="text" placeholder="Type a message…" />
<button id="send" class="btn-primary">Send</button>
</div>
<div class="row">
<button id="cap" class="btn-ghost small">Capabilities</button>
<button id="health" class="btn-ghost small">Health</button>
<button id="clear" class="btn-ghost small">Clear</button>
</div>
</div>
</div>
<div class="log" id="log"></div>
</section>
<footer>
Use with your FastAPI backend at <code>/chatbot/message</code>. Configure CORS if you serve this file from a different origin.
</footer>
</div>
<script>
const $ = (sel) => document.querySelector(sel);
const backendInput = $('#backend');
const sendBtn = $('#send');
const saveBtn = $('#save');
const msgInput = $('#message');
const capBtn = $('#cap');
const healthBtn = $('#health');
const clearBtn = $('#clear');
const log = $('#log');
const status = $('#status');
const dot = status.querySelector('.dot');
const statusText = status.querySelector('span:last-child');
function getBackendUrl() {
return localStorage.getItem('BACKEND_URL') || 'http://127.0.0.1:8000';
}
function setBackendUrl(v) {
localStorage.setItem('BACKEND_URL', v);
}
function cardUser(text) {
const div = document.createElement('div');
div.className = 'bubble user';
div.textContent = text;
log.appendChild(div);
log.scrollTop = log.scrollHeight;
}
function cardBot(obj) {
const wrap = document.createElement('div');
wrap.className = 'bubble bot';
const pre = document.createElement('pre');
pre.textContent = typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2);
wrap.appendChild(pre);
log.appendChild(wrap);
log.scrollTop = log.scrollHeight;
}
function setStatus(ok, text) {
dot.classList.toggle('ok', !!ok);
dot.classList.toggle('bad', ok === false);
statusText.textContent = text || (ok ? 'OK' : 'Error');
}
async function api(path, init) {
const base = backendInput.value.trim().replace(/\/$/, '');
const url = base + path;
const resp = await fetch(url, init);
if (!resp.ok) {
let t = await resp.text().catch(() => '');
throw new Error(`HTTP ${resp.status} ${resp.statusText}${t}`);
}
const contentType = resp.headers.get('content-type') || '';
if (contentType.includes('application/json')) return resp.json();
return resp.text();
}
async function checkHealth() {
try {
const h = await api('/health', { method: 'GET' });
setStatus(true, 'Healthy');
cardBot({ health: h });
} catch (e) {
setStatus(false, String(e.message || e));
cardBot({ error: String(e.message || e) });
}
}
async function sendMessage() {
const text = msgInput.value.trim();
if (!text) return;
cardUser(text);
msgInput.value = '';
try {
const data = await api('/chatbot/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text })
});
cardBot(data);
} catch (e) {
cardBot({ error: String(e.message || e) });
}
}
async function showCapabilities() {
try {
// Prefer API if available; if 404, fall back to library-like prompt.
const data = await api('/chatbot/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'help' })
});
cardBot(data);
} catch (e) {
cardBot({ capabilities: ['text-input','sentiment-analysis','help'], note: 'API help failed, showing defaults', error: String(e.message || e) });
}
}
// Wire up
backendInput.value = getBackendUrl();
saveBtn.onclick = () => { setBackendUrl(backendInput.value.trim()); setStatus(null, 'Saved'); };
sendBtn.onclick = sendMessage;
msgInput.addEventListener('keydown', (ev) => { if (ev.key === 'Enter') sendMessage(); });
capBtn.onclick = showCapabilities;
healthBtn.onclick = checkHealth;
clearBtn.onclick = () => { log.innerHTML = ''; setStatus(null, 'Idle'); };
// Initial health ping
checkHealth();
</script>
</body>
</html>