v1.8.3: admin — rename Settings to LLM, merge Claude AI into LLM page, hide Claude nav

This commit is contained in:
2026-05-28 19:33:25 +00:00
parent f721ebaf4d
commit 21610345bd
15 changed files with 148 additions and 11 deletions
+72 -11
View File
@@ -326,14 +326,14 @@ a[role=button]:active {
<button class="nav-btn w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('api',this)">
<span class="msym text-lg">key</span><span>API</span>
</button>
<button class="nav-btn w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('claude',this)">
<!-- REMOVED claude nav --><button class="nav-btn w-full hidden flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('claude',this)">
<span class="msym text-lg">neurology</span><span>Claude AI</span>
</button>
<button class="nav-btn w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('tracking',this)">
<span class="msym text-lg">troubleshoot</span><span>Tracking</span>
</button>
<button class="nav-btn w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('settings',this)">
<span class="msym text-lg">settings</span><span>Settings</span>
<span class="msym text-lg">smart_toy</span><span>LLM</span>
</button>
<button class="nav-btn w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all" onclick="showPage('pages',this)">
<span class="msym text-lg">description</span><span>Pages</span>
@@ -577,8 +577,8 @@ curl -X POST https://rag.afaqzaid.com/ingest-url \
<!-- SETTINGS -->
<section id="page-settings" class="page hidden">
<div class="flex items-center justify-between mb-6">
<div><h2 class="text-2xl font-bold">Settings</h2><p class="text-on-surface-variant text-sm mt-1">AI & system configuration</p></div>
<button onclick="loadSettings()" class="glass glass-hover px-4 py-2 rounded-xl text-sm flex items-center gap-2">
<div><h2 class="text-2xl font-bold">LLM</h2><p class="text-on-surface-variant text-sm mt-1">AI provider, keys & system configuration</p></div>
<button onclick="loadSettings();loadClaude();" class="glass glass-hover px-4 py-2 rounded-xl text-sm flex items-center gap-2">
<span class="msym text-base">refresh</span> Refresh
</button>
</div>
@@ -588,10 +588,48 @@ curl -X POST https://rag.afaqzaid.com/ingest-url \
</div>
<div id="settings-llm" class="glass rounded-2xl p-6 mt-6"></div>
<div id="settings-r2" class="glass rounded-2xl p-6 mt-6"></div>
<!-- ── Claude AI Section (moved from Claude page) ──────────────────── -->
<div class="glass rounded-2xl p-6 mt-6">
<h3 class="text-primary text-xs font-bold uppercase tracking-widest mb-5 flex items-center gap-2">
<span class="msym text-base">smart_toy</span> Claude AI
</h3>
<!-- Key input -->
<div class="glass rounded-2xl p-6 mb-6">
<h3 class="text-primary text-xs font-bold uppercase tracking-widest mb-5 flex items-center gap-2"><span class="msym text-base">key</span>API Key</h3>
<div class="flex gap-3 mb-3">
<input type="password" id="claude-key-input" placeholder="sk-ant-..."
class="flex-1 bg-surface-high border border-outline-variant rounded-xl px-4 py-3 text-sm text-on-surface outline-none focus:border-primary transition-colors font-mono"/>
<button onclick="toggleClaudeKey()" id="claude-key-toggle" class="glass glass-hover px-4 py-2 rounded-xl text-xs text-on-surface-variant">Show</button>
</div>
<div class="flex items-center gap-3 mb-4">
<div id="claude-status" class="flex items-center gap-2 text-xs text-on-surface-variant">
<span class="w-2 h-2 rounded-full bg-outline-variant inline-block"></span> Not configured
</div>
</div>
<button onclick="saveClaudeKey()" class="bg-primary text-surface font-bold px-6 py-2.5 rounded-xl text-sm hover:shadow-[0_0_20px_rgba(78,222,163,0.4)] transition-all flex items-center gap-2">
<span class="msym text-base">save</span> Save Key
</button>
<p class="text-on-surface-variant text-xs mt-3">Key is stored securely in the database and loaded at runtime. Get yours at <span class="text-primary">console.anthropic.com</span></p>
</div>
<!-- Usage stats -->
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6" id="claude-stats"></div>
<!-- Daily usage chart -->
<div class="glass rounded-2xl p-6 mb-6">
<h3 class="text-primary text-xs font-bold uppercase tracking-widest mb-4 flex items-center gap-2"><span class="msym text-base">bar_chart</span>Daily Usage</h3>
<div id="claude-daily-chart"></div>
</div>
<!-- Recent calls -->
<div class="glass rounded-2xl p-6">
<h3 class="text-primary text-xs font-bold uppercase tracking-widest mb-4 flex items-center gap-2"><span class="msym text-base">history</span>Recent Calls</h3>
<div id="claude-usage-list" class="space-y-2"></div>
</div>
</section>
</div>
</section>
<!-- CLAUDE -->
<section id="page-claude" class="page hidden">
<section id="page-claude" class="page hidden" style="display:none!important">
<div class="flex items-center justify-between mb-6">
<div><h2 class="text-2xl font-bold">Claude AI</h2><p class="text-on-surface-variant text-sm mt-1">API key & usage tracking</p></div>
<button onclick="loadClaude()" class="glass glass-hover px-4 py-2 rounded-xl text-sm flex items-center gap-2">
@@ -941,7 +979,7 @@ function showPage(name, btn) {
if (btn) { btn.classList.add('active','bg-primary/10','text-primary'); btn.classList.remove('text-on-surface-variant'); }
closeSidebar();
const loaders = {overview:loadOverview, books:loadBooks, users:loadUsers,
conversations:loadConversations, resources:loadResources, settings:loadSettings,
conversations:loadConversations, resources:loadResources, settings:()=>{loadSettings();loadClaude();},
branding:loadBranding, members:loadMembers, claude:loadClaude, tracking:loadTracking};
if (loaders[name]) loaders[name]();
}
@@ -1001,19 +1039,26 @@ async function loadLibraryHealth() {
<div class="text-xs text-on-surface-variant mt-1">Missing Chunks</div>
</div>
<div class="bg-surface-high rounded-xl p-3 text-center">
<div class="text-xl font-bold text-blue-400">${d.vectors?.toLocaleString()}</div>
<div class="text-xl font-bold text-blue-400">${(d.vector_count||d.total_chunks||0).toLocaleString()}</div>
<div class="text-xs text-on-surface-variant mt-1">Vectors</div>
</div>
</div>`;
// Books with no chunks
if (d.no_chunks?.length > 0) {
if (d.missing_books?.length > 0) {
html += `<div class="mb-4">
<div class="text-xs font-bold text-red-400 uppercase tracking-widest mb-2 flex items-center gap-1">
<span class="msym text-sm">warning</span> Books with no chunks (${d.no_chunks.length})
<span class="msym text-sm">warning</span> Not Indexed (${d.missing_books.length})
</div>
<div class="space-y-1 max-h-40 overflow-y-auto">
${d.no_chunks.map(b => `<div class="bg-red-900/20 border border-red-900/30 rounded-lg px-3 py-2 text-xs text-on-surface-variant">${b.title || b.filename}</div>`).join('')}
<div class="space-y-1 max-h-60 overflow-y-auto">
${d.missing_books.map(b => `
<div class="bg-red-900/20 border border-red-900/30 rounded-lg px-3 py-2 text-xs flex items-center justify-between gap-2">
<span class="text-on-surface-variant truncate">${b.title || b.filename}</span>
<button onclick="ingestBook(${b.id}, '${b.filename.replace(/'/g,"\'")}', this)"
class="shrink-0 glass glass-hover px-2 py-1 rounded-lg text-xs font-bold text-emerald-400 flex items-center gap-1">
<span class="msym text-sm">sync</span> Ingest Now
</button>
</div>`).join('')}
</div>
</div>`;
}
@@ -1081,6 +1126,22 @@ async function clearCache() {
btn.disabled = false; btn.innerHTML = '<span class="msym text-sm">delete_sweep</span> Clear Cache';
}
async function ingestBook(bookId, filename, btn) {
btn.disabled = true;
btn.innerHTML = '<span class="msym text-sm animate-spin">sync</span> Ingesting...';
try {
const r = await api(`/admin/ingest-book/${bookId}`, {method:'POST'});
btn.innerHTML = '<span class="msym text-sm">check_circle</span> Done';
btn.classList.replace('text-emerald-400','text-primary');
toast('Ingested: ' + filename.substring(0,40));
setTimeout(loadLibraryHealth, 2000);
} catch(e) {
btn.innerHTML = '<span class="msym text-sm">error</span> Failed';
btn.classList.replace('text-emerald-400','text-red-400');
toast('Error: ' + e.message);
}
}
async function reingestMissing() {
const btn = document.getElementById('btn-reingest');
btn.disabled = true; btn.innerHTML = '<span class="msym text-sm">sync</span> Queuing...';