hantech's picture
Update index.html
4761772 verified
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGPU RAG - Debug Mode</title>
<script src="coi-serviceworker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';</script>
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>
<style>
body { font-family: monospace; max-width: 900px; margin: 0 auto; padding: 20px; background: #f0f0f0; }
.container { display: flex; gap: 20px; }
.main-panel { flex: 1; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
/* Debug Console Style */
#debug-console {
flex: 1;
background: #1e1e1e;
color: #00ff00;
padding: 15px;
height: 500px;
overflow-y: scroll;
border-radius: 8px;
font-size: 12px;
font-family: 'Consolas', monospace;
border: 1px solid #333;
}
.log-time { color: #888; margin-right: 5px; }
.log-info { color: #4caf50; }
.log-warn { color: #ff9800; }
.log-error { color: #f44336; font-weight: bold; }
.log-system { color: #2196f3; font-weight: bold; }
#chat-box { border: 1px solid #eee; height: 300px; overflow-y: auto; margin-bottom: 10px; padding: 10px; background: #fff; }
.ai-msg { background: #e3f2fd; padding: 8px; border-radius: 5px; margin: 5px 0; }
.user-msg { background: #f5f5f5; padding: 8px; border-radius: 5px; margin: 5px 0; text-align: right; }
</style>
</head>
<body>
<h2>🛠️ WebGPU RAG System Monitor</h2>
<div class="container">
<div class="main-panel">
<h3>1. Input Data</h3>
<input type="file" id="pdf-upload" accept="application/pdf">
<p id="status-text">Trạng thái: Đang chờ...</p>
<hr>
<h3>2. Chat (Granite 4.0)</h3>
<div id="chat-box"></div>
<input type="text" id="user-input" placeholder="Nhập câu hỏi..." style="width: 70%;">
<button onclick="sendMessage()">Gửi</button>
</div>
<div id="debug-console">
<div>[LOG] Hệ thống khởi động...</div>
</div>
</div>
<script type="module">
// --- HỆ THỐNG LOGGING ---
const debugConsole = document.getElementById('debug-console');
function logger(msg, type = 'info') {
const now = new Date();
const timeStr = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`;
const div = document.createElement('div');
// Ghi vào giao diện
div.innerHTML = `<span class="log-time">[${timeStr}]</span> <span class="log-${type}">${msg}</span>`;
debugConsole.appendChild(div);
debugConsole.scrollTop = debugConsole.scrollHeight;
// Ghi song song vào F12 Console để tiện check object
console.log(`[${type.toUpperCase()}]`, msg);
}
logger("Kiểm tra môi trường: " + (window.crossOriginIsolated ? "✅ Secure Context (WebGPU OK)" : "❌ Insecure Context (WebGPU sẽ lỗi)"), window.crossOriginIsolated ? 'system' : 'error');
// --- KHỞI TẠO WORKER ---
let worker;
try {
logger("Đang khởi tạo Web Worker...", 'system');
worker = new Worker('worker.js', { type: 'module' });
} catch (e) {
logger("Lỗi tạo Worker: " + e.message, 'error');
}
let isModelReady = false; // Biến kiểm tra
// Lắng nghe logs từ Worker gửi về
worker.onmessage = function(e) {
const { type, payload } = e.data;
switch (type) {
case 'log': // Log thông thường từ worker
logger(`[Worker] ${payload}`, 'info');
break;
case 'status': // Trạng thái tải model
logger(`[Model Status] ${payload}`, 'warn');
document.getElementById('status-text').textContent = payload;
break;
case 'download_progress': // Tiến độ tải
// Chỉ log mỗi 10% để đỡ spam
if (payload.progress % 10 < 1) {
logger(`[Download] ${payload.file}: ${Math.round(payload.progress)}%`, 'system');
}
break;
case 'init_complete':
logger("✅ TẤT CẢ MODEL ĐÃ SẴN SÀNG!", 'system');
document.getElementById('status-text').textContent = "Hệ thống Online.";
isModelReady = true; // <--- BẬT CỜ LÊN
break;
case 'answer':
logger("Nhận câu trả lời từ LLM.", 'system');
appendChat("AI: " + payload, 'ai-msg');
break;
case 'error':
logger(`❌ LỖI WORKER: ${payload}`, 'error');
break;
}
};
// --- XỬ LÝ OCR (CÓ LOG CHI TIẾT) ---
document.getElementById('pdf-upload').addEventListener('change', async (e) => {
// THÊM ĐOẠN KIỂM TRA NÀY VÀO ĐẦU
if (!isModelReady) {
alert("⚠️ Vui lòng chờ AI tải xong mô hình (Xem logs bên phải)!");
e.target.value = ''; // Reset input
return;
}
const file = e.target.files[0];
if (!file) return;
logger(`Bắt đầu xử lý file: ${file.name} (${(file.size/1024/1024).toFixed(2)} MB)`, 'info');
try {
const buffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument(buffer).promise;
logger(`PDF đã tải: ${pdf.numPages} trang.`, 'info');
let fullText = "";
const workerOcr = await Tesseract.createWorker('vie', 1, {
logger: m => {
// Log tiến độ Tesseract (chỉ log status chính)
if (m.status === 'recognizing text' && (m.progress * 100) % 20 === 0) {
logger(`[OCR-Internal] ${Math.round(m.progress * 100)}%`, 'warn');
}
}
});
for (let i = 1; i <= pdf.numPages; i++) {
logger(`Đang render trang ${i}/${pdf.numPages} ra Canvas...`, 'info');
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale: 1.5 });
const canvas = document.createElement('canvas');
canvas.width = viewport.width;
canvas.height = viewport.height;
await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise;
logger(`Đang OCR trang ${i}...`, 'info');
const { data: { text } } = await workerOcr.recognize(canvas);
logger(`-> Trang ${i}: Trích xuất được ${text.length} ký tự.`, 'system');
fullText += text + "\n";
}
await workerOcr.terminate();
logger(`OCR Hoàn tất. Tổng ký tự: ${fullText.length}. Gửi sang Worker để Indexing...`, 'system');
worker.postMessage({ type: 'ingest_text', payload: fullText });
} catch (err) {
logger("Lỗi xử lý file: " + err.message, 'error');
}
});
// --- CHAT FUNC ---
window.sendMessage = () => {
const input = document.getElementById('user-input');
const text = input.value;
if(!text) return;
appendChat("Bạn: " + text, 'user-msg');
logger(`Gửi câu hỏi: "${text}"`, 'info');
worker.postMessage({ type: 'query', payload: text });
input.value = '';
}
function appendChat(text, cls) {
const div = document.createElement('div');
div.className = cls;
div.textContent = text;
document.getElementById('chat-box').appendChild(div);
}
</script>
</body>
</html>