Qsearch / Templates /agentic_dashboard.html
flyfir248's picture
Commit : Updated header.html and routes.py
aa928dd
{% extends "base.html" %}
{% block content %}
<div class="min-h-screen bg-slate-50">
<!-- Header -->
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 text-white py-12">
<div class="max-w-7xl mx-auto px-8">
<div class="flex items-center justify-between">
<div>
<h1 class="text-4xl font-black uppercase italic mb-2">
<i class="fas fa-robot mr-3"></i>Agentic AI Dashboard
</h1>
<p class="text-indigo-100 font-medium">Autonomous Intelligence for Research Discovery</p>
</div>
<div class="text-right">
<div class="text-5xl font-black">{{ total_profiles }}</div>
<div class="text-sm text-indigo-200 uppercase tracking-wider">Indexed Profiles</div>
</div>
</div>
</div>
</div>
<div class="max-w-7xl mx-auto px-8 py-8">
<!-- Control Panel -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
<!-- Discovery Control -->
<div class="bg-white rounded-2xl p-6 shadow-sm border border-slate-200">
<div class="flex items-center justify-between mb-4">
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest">Autonomous Discovery</h3>
<span class="w-3 h-3 rounded-full bg-green-500 animate-pulse"></span>
</div>
<form id="discoveryForm" class="space-y-4">
<div>
<label class="block text-xs font-bold text-slate-600 mb-2">Research Domain</label>
<input type="text" id="discoveryQuery"
placeholder="e.g., quantum computing"
class="w-full px-4 py-3 border-2 border-slate-200 rounded-xl focus:border-indigo-500 outline-none text-sm">
</div>
<div>
<label class="block text-xs font-bold text-slate-600 mb-2">Max Profiles: <span id="maxProfilesValue">20</span></label>
<input type="range" id="maxProfiles" min="5" max="50" value="20"
class="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer"
oninput="document.getElementById('maxProfilesValue').textContent = this.value">
</div>
<button type="submit"
class="w-full bg-indigo-600 text-white py-3 rounded-xl font-bold hover:bg-indigo-700 transition-all active:scale-95">
<i class="fas fa-rocket mr-2"></i>Launch Discovery
</button>
</form>
<div id="discoveryStatus" class="mt-4 p-3 bg-slate-50 rounded-lg text-xs hidden">
<div class="flex items-center">
<i class="fas fa-spinner fa-spin text-indigo-600 mr-2"></i>
<span class="font-medium text-slate-700">Discovering...</span>
</div>
</div>
</div>
<!-- Search Control -->
<div class="bg-white rounded-2xl p-6 shadow-sm border border-slate-200">
<div class="flex items-center justify-between mb-4">
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest">Semantic Search</h3>
<i class="fas fa-search text-indigo-400"></i>
</div>
<form id="searchForm" class="space-y-4">
<div>
<label class="block text-xs font-bold text-slate-600 mb-2">Search Query</label>
<input type="text" id="searchQuery"
placeholder="e.g., neural networks experts"
class="w-full px-4 py-3 border-2 border-slate-200 rounded-xl focus:border-indigo-500 outline-none text-sm">
</div>
<button type="submit"
class="w-full bg-purple-600 text-white py-3 rounded-xl font-bold hover:bg-purple-700 transition-all active:scale-95">
<i class="fas fa-search mr-2"></i>Search Profiles
</button>
</form>
<div id="searchResults" class="mt-4 space-y-2 max-h-32 overflow-y-auto hidden">
<!-- Results will be inserted here -->
</div>
</div>
<!-- Stats -->
<div class="bg-white rounded-2xl p-6 shadow-sm border border-slate-200">
<div class="flex items-center justify-between mb-4">
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest">System Status</h3>
<i class="fas fa-chart-line text-green-400"></i>
</div>
<div class="space-y-4">
<div class="flex items-center justify-between py-3 border-b border-slate-100">
<span class="text-xs font-bold text-slate-600">Vector Store</span>
<span class="text-xs font-black text-indigo-600">{{ rag_stats.vector_store_type or 'InMemory' }}</span>
</div>
<div class="flex items-center justify-between py-3 border-b border-slate-100">
<span class="text-xs font-bold text-slate-600">Embedding Model</span>
<span class="text-[10px] font-medium text-slate-500">MiniLM-L6</span>
</div>
<div class="flex items-center justify-between py-3 border-b border-slate-100">
<span class="text-xs font-bold text-slate-600">LLM Model</span>
<span class="text-[10px] font-medium text-slate-500">Llama-3-8B</span>
</div>
<div class="flex items-center justify-between py-3">
<span class="text-xs font-bold text-slate-600">Status</span>
<span class="text-xs font-black text-green-600">
<i class="fas fa-check-circle mr-1"></i>Active
</span>
</div>
</div>
</div>
</div>
<!-- Indexed Profiles -->
<div class="bg-white rounded-2xl p-8 shadow-sm border border-slate-200">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-black text-slate-900 uppercase italic">
<i class="fas fa-database text-indigo-600 mr-3"></i>Indexed Profiles
</h2>
<div class="flex items-center gap-4">
<input type="text" id="filterProfiles"
placeholder="Filter by name..."
class="px-4 py-2 border-2 border-slate-200 rounded-xl text-sm outline-none focus:border-indigo-500">
<button onclick="refreshProfiles()"
class="px-4 py-2 bg-slate-100 rounded-xl text-xs font-bold hover:bg-slate-200 transition-colors">
<i class="fas fa-sync-alt mr-1"></i>Refresh
</button>
</div>
</div>
{% if profiles %}
<div class="overflow-x-auto">
<table class="w-full" id="profilesTable">
<thead>
<tr class="border-b-2 border-slate-200">
<th class="text-left py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Researcher</th>
<th class="text-left py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Affiliation</th>
<th class="text-center py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">H-Index</th>
<th class="text-center py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Citations</th>
<th class="text-center py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Papers</th>
<th class="text-left py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Interests</th>
<th class="text-center py-4 px-4 text-xs font-black text-slate-400 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody>
{% for profile in profiles %}
<tr class="border-b border-slate-100 hover:bg-slate-50 transition-colors">
<td class="py-4 px-4">
<div class="font-bold text-slate-900">{{ profile.name }}</div>
<div class="text-[10px] text-slate-400 uppercase">{{ profile.source }}</div>
</td>
<td class="py-4 px-4 text-sm text-slate-600">{{ profile.affiliation }}</td>
<td class="py-4 px-4 text-center">
<span class="inline-block bg-indigo-100 text-indigo-700 px-3 py-1 rounded-full text-xs font-bold">
{{ profile.h_index }}
</span>
</td>
<td class="py-4 px-4 text-center text-sm font-bold text-slate-700">
{{ "{:,}".format(profile.total_citations) }}
</td>
<td class="py-4 px-4 text-center text-sm font-bold text-slate-700">
{{ profile.total_papers }}
</td>
<td class="py-4 px-4">
<div class="flex flex-wrap gap-1">
{% for interest in profile.interests[:3] %}
<span class="inline-block bg-slate-100 text-slate-600 px-2 py-1 rounded text-[10px] font-medium">
{{ interest }}
</span>
{% endfor %}
</div>
</td>
<td class="py-4 px-4 text-center">
<a href="{{ profile.profile_url }}" target="_blank"
class="inline-block bg-indigo-600 text-white px-3 py-2 rounded-lg text-xs font-bold hover:bg-indigo-700 transition-colors">
<i class="fas fa-external-link-alt mr-1"></i>View
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-20">
<div class="w-20 h-20 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-inbox text-3xl text-slate-300"></i>
</div>
<h3 class="text-xl font-bold text-slate-800 mb-2">No Profiles Indexed</h3>
<p class="text-slate-500 text-sm mb-6">Launch autonomous discovery to start collecting researcher profiles</p>
<button onclick="document.getElementById('discoveryQuery').focus()"
class="bg-indigo-600 text-white px-6 py-3 rounded-xl font-bold hover:bg-indigo-700 transition-all">
Start Discovery
</button>
</div>
{% endif %}
</div>
</div>
</div>
<script>
// Discovery Form Handler
document.getElementById('discoveryForm').addEventListener('submit', async (e) => {
e.preventDefault();
const query = document.getElementById('discoveryQuery').value;
const maxProfiles = document.getElementById('maxProfiles').value;
const statusDiv = document.getElementById('discoveryStatus');
if (!query) {
alert('Please enter a research domain');
return;
}
statusDiv.classList.remove('hidden');
try {
const response = await fetch('/api/agentic/discover', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: query,
max_profiles: parseInt(maxProfiles)
})
});
const result = await response.json();
if (result.success) {
statusDiv.innerHTML = `
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fas fa-check-circle text-green-600 mr-2"></i>
<span class="font-medium text-slate-700">Discovery complete!</span>
</div>
<span class="font-black text-indigo-600">${result.profiles_collected} profiles</span>
</div>
`;
// Refresh the page after 2 seconds
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
throw new Error(result.message || 'Discovery failed');
}
} catch (error) {
statusDiv.innerHTML = `
<div class="flex items-center">
<i class="fas fa-exclamation-circle text-red-600 mr-2"></i>
<span class="font-medium text-red-700">Error: ${error.message}</span>
</div>
`;
}
});
// Search Form Handler
document.getElementById('searchForm').addEventListener('submit', async (e) => {
e.preventDefault();
const query = document.getElementById('searchQuery').value;
const resultsDiv = document.getElementById('searchResults');
if (!query) {
alert('Please enter a search query');
return;
}
resultsDiv.innerHTML = '<div class="text-xs text-slate-500">Searching...</div>';
resultsDiv.classList.remove('hidden');
try {
const response = await fetch(`/api/agentic/search?q=${encodeURIComponent(query)}&k=5`);
const result = await response.json();
if (result.error) {
throw new Error(result.error);
}
if (result.results && result.results.length > 0) {
resultsDiv.innerHTML = result.results.map((profile, i) => `
<div class="p-3 bg-slate-50 rounded-lg">
<div class="text-xs font-bold text-slate-900">${i + 1}. ${profile.name}</div>
<div class="text-[10px] text-slate-500">${profile.affiliation}</div>
</div>
`).join('');
} else {
resultsDiv.innerHTML = '<div class="text-xs text-slate-500">No results found</div>';
}
} catch (error) {
resultsDiv.innerHTML = `<div class="text-xs text-red-600">Error: ${error.message}</div>`;
}
});
// Filter Profiles
document.getElementById('filterProfiles')?.addEventListener('input', (e) => {
const filter = e.target.value.toLowerCase();
const rows = document.querySelectorAll('#profilesTable tbody tr');
rows.forEach(row => {
const name = row.cells[0].textContent.toLowerCase();
if (name.includes(filter)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
// Refresh Profiles
function refreshProfiles() {
window.location.reload();
}
</script>
{% endblock %}