Qsearch / Templates /rag.html
flyfir248's picture
Commit : Updated rag.html and the routes.py for the purposes of working with TheBloke/LLaMA-Pro-8B-Instruct-GGUF
8befb33
{% extends "base.html" %}
{% block content %}
<div class="min-h-screen bg-[#f8fafc] p-8 font-sans">
<div class="max-w-7xl mx-auto">
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 p-2 mb-10">
<form action="/rag" method="POST" enctype="multipart/form-data" onsubmit="return showLoading()" class="flex items-center gap-2">
<label class="flex items-center justify-center px-6 py-4 border-r border-slate-100 cursor-pointer hover:bg-slate-50 transition-colors">
<i class="fas fa-paperclip text-slate-400 mr-2"></i>
<span id="file-name" class="text-sm font-semibold text-slate-500 truncate max-w-[120px]">Upload PDF</span>
<input type="file" name="pdf_file" id="pdf_file" accept=".pdf" class="hidden" onchange="updateFileName(this)" required />
</label>
<input type="text" name="q" id="query-input" placeholder="Ask anything about your document..."
class="flex-1 px-6 py-4 text-slate-700 outline-none placeholder:text-slate-400" required>
<button type="submit" id="submit-btn" class="bg-blue-600 text-white px-8 py-4 rounded-2xl font-bold hover:bg-blue-700 transition-all flex items-center gap-3 mr-2">
<span id="btn-text">Analyze</span>
<div id="loading-spinner" class="hidden animate-spin h-4 w-4 border-2 border-white border-t-transparent rounded-full"></div>
</button>
</form>
</div>
{% if answer %}
<div id="results-area" class="grid grid-cols-1 lg:grid-cols-12 gap-8 animate-fade-in">
<div class="lg:col-span-8">
<div class="bg-white p-10 rounded-[2rem] border border-slate-200 shadow-sm min-h-[400px]">
<div class="flex items-center justify-between mb-8">
<h3 class="text-[11px] font-black text-indigo-500 uppercase tracking-[0.2em]">Generated Answer</h3>
<button onclick="copyAnswer()" class="flex items-center gap-2 text-xs font-bold text-slate-400 hover:text-slate-600 bg-slate-50 px-3 py-1.5 rounded-md transition-all">
<i class="fas fa-copy"></i> Copy
</button>
</div>
<div id="answer-content" class="text-[#334155] text-lg leading-relaxed prose prose-slate max-w-none">
{{ answer | safe }}
</div>
</div>
</div>
<div class="lg:col-span-4 space-y-6">
<div class="flex items-center justify-between px-2">
<h3 class="text-[11px] font-black text-slate-400 uppercase tracking-[0.2em]">Supporting Context</h3>
{% if sources %}
<span class="text-[10px] bg-indigo-50 text-indigo-600 px-2.5 py-1 rounded-full font-bold">
{{ sources|length }} snippets
</span>
{% endif %}
</div>
<div class="space-y-4">
{% if sources %}
{% for source in sources %}
<div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-all group relative">
<div class="flex items-center justify-between mb-4">
<span class="text-[10px] font-black text-slate-300 uppercase tracking-widest">Chunk {{ loop.index }}</span>
<button onclick="copySnippet({{ loop.index - 1 }})" class="text-slate-300 hover:text-indigo-500 transition-colors">
<i class="fas fa-copy text-xs"></i>
</button>
</div>
<p class="text-[13px] text-slate-500 leading-relaxed snippet-text italic" data-full-text="{{ source }}">
"{{ source[:220] }}{% if source|length > 220 %}...{% endif %}"
</p>
{% if source|length > 220 %}
<button onclick="toggleSnippet({{ loop.index - 1 }})" class="text-[10px] text-indigo-500 font-bold mt-3 uppercase tracking-wider hover:underline">
Show More
</button>
{% endif %}
</div>
{% endfor %}
{% else %}
<div class="text-center py-10">
<i class="fas fa-quote-right text-slate-200 text-3xl mb-3"></i>
<p class="text-sm text-slate-400 italic">No snippets found.</p>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
</div>
<script>
function updateFileName(input) {
const fileName = document.getElementById('file-name');
if (input.files && input.files[0]) {
fileName.textContent = input.files[0].name;
fileName.classList.remove('text-slate-500');
fileName.classList.add('text-blue-600');
}
}
function showLoading() {
const btnText = document.getElementById('btn-text');
const spinner = document.getElementById('loading-spinner');
const btn = document.getElementById('submit-btn');
btn.disabled = true;
btn.classList.add('opacity-80');
btnText.textContent = 'Analyzing...';
spinner.classList.remove('hidden');
return true;
}
function copyAnswer() {
const text = document.getElementById('answer-content').innerText;
navigator.clipboard.writeText(text);
alert('Answer copied!');
}
function toggleSnippet(index) {
const snippets = document.querySelectorAll('.snippet-text');
const buttons = document.querySelectorAll('.snippet-text + button');
const snippet = snippets[index];
const button = buttons[index];
const fullText = snippet.getAttribute('data-full-text');
if (snippet.classList.contains('expanded')) {
snippet.textContent = `"${fullText.substring(0, 220)}..."`;
snippet.classList.remove('expanded');
button.textContent = 'Show More';
} else {
snippet.textContent = `"${fullText}"`;
snippet.classList.add('expanded');
button.textContent = 'Show Less';
}
}
</script>
<style>
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fade-in { animation: fade-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
body { background-color: #f8fafc; }
.prose p { margin-bottom: 1.5rem; }
</style>
{% endblock %}