Hoghoghi / app /static /index.html
Really-amin's picture
Upload index.html
48b1974 verified
raw
history blame
13.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>πŸ›οΈ Legal Dashboard - OCR System</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
color: white;
padding: 40px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.2em;
opacity: 0.9;
}
.main-content {
padding: 40px;
}
.status-section {
background: #f8f9fa;
border-radius: 15px;
padding: 30px;
margin-bottom: 30px;
border-left: 5px solid #4CAF50;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-top: 20px;
}
.status-item {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
text-align: center;
}
.status-indicator {
width: 20px;
height: 20px;
border-radius: 50%;
display: inline-block;
margin-right: 10px;
}
.status-healthy { background: #4CAF50; }
.status-loading { background: #FF9800; }
.status-error { background: #f44336; }
.upload-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 30px;
}
.upload-card {
background: #f8f9fa;
border-radius: 15px;
padding: 30px;
text-align: center;
border: 2px dashed #ddd;
transition: all 0.3s ease;
}
.upload-card:hover {
border-color: #4CAF50;
background: #f0f8f0;
}
.upload-card h3 {
color: #333;
margin-bottom: 15px;
font-size: 1.5em;
}
.file-input {
margin: 20px 0;
}
.file-input input[type="file"] {
width: 100%;
padding: 15px;
border: 1px solid #ddd;
border-radius: 10px;
font-size: 16px;
}
.upload-btn {
background: #4CAF50;
color: white;
border: none;
padding: 15px 30px;
border-radius: 10px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s ease;
width: 100%;
}
.upload-btn:hover {
background: #45a049;
}
.upload-btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.result-section {
background: #f8f9fa;
border-radius: 15px;
padding: 30px;
margin-top: 30px;
display: none;
}
.result-text {
background: white;
border: 1px solid #ddd;
border-radius: 10px;
padding: 20px;
max-height: 400px;
overflow-y: auto;
font-family: 'Courier New', monospace;
white-space: pre-wrap;
margin-top: 15px;
}
.nav-links {
display: flex;
gap: 15px;
justify-content: center;
flex-wrap: wrap;
margin-top: 30px;
}
.nav-link {
background: #2196F3;
color: white;
text-decoration: none;
padding: 12px 25px;
border-radius: 25px;
transition: all 0.3s ease;
font-weight: 500;
}
.nav-link:hover {
background: #1976D2;
transform: translateY(-2px);
}
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #4CAF50;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (max-width: 768px) {
.upload-section {
grid-template-columns: 1fr;
}
.nav-links {
flex-direction: column;
align-items: center;
}
.header h1 {
font-size: 2em;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>πŸ›οΈ Legal Dashboard</h1>
<p>Advanced OCR & Document Processing System</p>
</div>
<div class="main-content">
<div class="status-section">
<h2>πŸ“Š System Status</h2>
<div class="status-grid">
<div class="status-item">
<div id="api-status">
<span class="status-indicator status-loading"></span>
<strong>API Server</strong><br>
<span id="api-text">Checking...</span>
</div>
</div>
<div class="status-item">
<div id="pdf-status">
<span class="status-indicator status-loading"></span>
<strong>PDF Processing</strong><br>
<span id="pdf-text">Checking...</span>
</div>
</div>
<div class="status-item">
<div id="ocr-status">
<span class="status-indicator status-loading"></span>
<strong>OCR Models</strong><br>
<span id="ocr-text">Loading...</span>
</div>
</div>
</div>
</div>
<div class="upload-section">
<div class="upload-card">
<h3>πŸ“„ PDF Document</h3>
<p>Upload a PDF file to extract text using advanced OCR</p>
<div class="file-input">
<input type="file" id="pdfFile" accept=".pdf">
</div>
<button class="upload-btn" onclick="uploadPDF()" id="pdfBtn">
Extract Text from PDF
</button>
</div>
<div class="upload-card">
<h3>πŸ–ΌοΈ Image Document</h3>
<p>Upload an image to extract text using TrOCR AI</p>
<div class="file-input">
<input type="file" id="imageFile" accept=".jpg,.jpeg,.png,.bmp,.tiff">
</div>
<button class="upload-btn" onclick="uploadImage()" id="imageBtn">
Extract Text from Image
</button>
</div>
</div>
<div class="result-section" id="resultSection">
<h3>πŸ“ Extraction Results</h3>
<div id="resultInfo"></div>
<div class="result-text" id="resultText"></div>
</div>
<div class="nav-links">
<a href="/api/docs" class="nav-link">πŸ“š API Documentation</a>
<a href="/health" class="nav-link">❀️ Health Check</a>
<a href="/system/status" class="nav-link">πŸ“Š System Status</a>
</div>
</div>
</div>
<script>
// Check system status on load
async function checkSystemStatus() {
try {
const response = await fetch('/health');
const data = await response.json();
// Update API status
updateStatus('api', 'healthy', 'Running');
// Update PDF status
updateStatus('pdf', data.services.pdf_processing ? 'healthy' : 'error',
data.services.pdf_processing ? 'Available' : 'Not Available');
// Update OCR status
updateStatus('ocr', data.services.ocr_model_loaded ? 'healthy' : 'loading',
data.services.ocr_model_loaded ? 'Ready' : 'Loading...');
} catch (error) {
updateStatus('api', 'error', 'Offline');
updateStatus('pdf', 'error', 'Unknown');
updateStatus('ocr', 'error', 'Unknown');
}
}
function updateStatus(service, status, text) {
const indicator = document.querySelector(`#${service}-status .status-indicator`);
const textElement = document.getElementById(`${service}-text`);
indicator.className = `status-indicator status-${status}`;
textElement.textContent = text;
}
async function uploadPDF() {
const fileInput = document.getElementById('pdfFile');
const btn = document.getElementById('pdfBtn');
if (!fileInput.files[0]) {
alert('Please select a PDF file');
return;
}
const formData = new FormData();
formData.append('file', fileInput.files[0]);
btn.disabled = true;
btn.innerHTML = '<span class="loading"></span> Processing PDF...';
try {
const response = await fetch('/api/ocr/extract-pdf', {
method: 'POST',
body: formData
});
const result = await response.json();
showResult(result);
} catch (error) {
alert('Error processing PDF: ' + error.message);
} finally {
btn.disabled = false;
btn.innerHTML = 'Extract Text from PDF';
}
}
async function uploadImage() {
const fileInput = document.getElementById('imageFile');
const btn = document.getElementById('imageBtn');
if (!fileInput.files[0]) {
alert('Please select an image file');
return;
}
const formData = new FormData();
formData.append('file', fileInput.files[0]);
btn.disabled = true;
btn.innerHTML = '<span class="loading"></span> Processing Image...';
try {
const response = await fetch('/api/ocr/extract-image', {
method: 'POST',
body: formData
});
const result = await response.json();
showResult(result);
} catch (error) {
alert('Error processing image: ' + error.message);
} finally {
btn.disabled = false;
btn.innerHTML = 'Extract Text from Image';
}
}
function showResult(result) {
const resultSection = document.getElementById('resultSection');
const resultInfo = document.getElementById('resultInfo');
const resultText = document.getElementById('resultText');
resultSection.style.display = 'block';
if (result.success) {
resultInfo.innerHTML = `
<p><strong>βœ… Success!</strong> Method: ${result.method}</p>
<p><strong>Metadata:</strong> ${JSON.stringify(result.metadata, null, 2)}</p>
`;
resultText.textContent = result.text || 'No text extracted';
} else {
resultInfo.innerHTML = `<p><strong>❌ Error:</strong> ${result.metadata.error}</p>`;
resultText.textContent = 'Processing failed';
}
resultSection.scrollIntoView({ behavior: 'smooth' });
}
// Initialize
checkSystemStatus();
// Refresh status every 30 seconds
setInterval(checkSystemStatus, 30000);
</script>
</body>
</html>