NAITIVEAIAGENCY commited on
Commit
ef239fa
·
verified ·
1 Parent(s): 0f9f1a9

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1016 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Ocr
3
- emoji: 🐨
4
- colorFrom: green
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: ocr
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1016 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Advanced OCR Processing System</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .split-view {
11
+ display: flex;
12
+ height: calc(100vh - 200px);
13
+ }
14
+ .split-pane {
15
+ flex: 1;
16
+ overflow: auto;
17
+ padding: 1rem;
18
+ border: 1px solid #e2e8f0;
19
+ }
20
+ .resize-handle {
21
+ width: 8px;
22
+ background: #e2e8f0;
23
+ cursor: col-resize;
24
+ }
25
+ .dropzone {
26
+ border: 2px dashed #cbd5e0;
27
+ border-radius: 0.5rem;
28
+ transition: all 0.3s ease;
29
+ }
30
+ .dropzone.active {
31
+ border-color: #4299e1;
32
+ background-color: #ebf8ff;
33
+ }
34
+ .markdown-table {
35
+ width: 100%;
36
+ border-collapse: collapse;
37
+ }
38
+ .markdown-table th, .markdown-table td {
39
+ border: 1px solid #e2e8f0;
40
+ padding: 0.5rem;
41
+ }
42
+ .markdown-table th {
43
+ background-color: #f7fafc;
44
+ }
45
+ .progress-bar {
46
+ height: 6px;
47
+ background-color: #e2e8f0;
48
+ border-radius: 3px;
49
+ overflow: hidden;
50
+ }
51
+ .progress-fill {
52
+ height: 100%;
53
+ background-color: #4299e1;
54
+ transition: width 0.3s ease;
55
+ }
56
+ .status-badge {
57
+ padding: 0.25rem 0.5rem;
58
+ border-radius: 9999px;
59
+ font-size: 0.75rem;
60
+ font-weight: 600;
61
+ }
62
+ .status-approved {
63
+ background-color: #f0fff4;
64
+ color: #38a169;
65
+ }
66
+ .status-rejected {
67
+ background-color: #fff5f5;
68
+ color: #e53e3e;
69
+ }
70
+ .status-pending {
71
+ background-color: #fffaf0;
72
+ color: #dd6b20;
73
+ }
74
+ .status-escalated {
75
+ background-color: #ebf8ff;
76
+ color: #3182ce;
77
+ }
78
+ .pdf-viewer {
79
+ height: 100%;
80
+ width: 100%;
81
+ border: 1px solid #e2e8f0;
82
+ border-radius: 0.5rem;
83
+ }
84
+ .ws-status {
85
+ width: 10px;
86
+ height: 10px;
87
+ border-radius: 50%;
88
+ display: inline-block;
89
+ margin-right: 5px;
90
+ }
91
+ .ws-connected {
92
+ background-color: #48bb78;
93
+ }
94
+ .ws-disconnected {
95
+ background-color: #f56565;
96
+ }
97
+ .ws-connecting {
98
+ background-color: #ed8936;
99
+ }
100
+ </style>
101
+ </head>
102
+ <body class="bg-gray-50">
103
+ <div class="min-h-screen">
104
+ <!-- Header -->
105
+ <header class="bg-white shadow-sm">
106
+ <div class="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8 flex justify-between items-center">
107
+ <div class="flex items-center">
108
+ <i class="fas fa-file-alt text-blue-500 text-2xl mr-3"></i>
109
+ <h1 class="text-xl font-bold text-gray-900">Advanced OCR Processing System</h1>
110
+ </div>
111
+ <div class="flex items-center space-x-4">
112
+ <div class="flex items-center">
113
+ <span class="ws-status ws-connected" id="ws-status"></span>
114
+ <span class="text-sm text-gray-500" id="ws-status-text">Connected</span>
115
+ </div>
116
+ <div class="relative">
117
+ <button class="flex items-center text-gray-500 hover:text-gray-700 focus:outline-none">
118
+ <i class="fas fa-bell"></i>
119
+ <span class="absolute -top-1 -right-1 h-4 w-4 rounded-full bg-red-500 text-white text-xs flex items-center justify-center">3</span>
120
+ </button>
121
+ </div>
122
+ <div class="flex items-center">
123
+ <img class="h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
124
+ <span class="ml-2 text-sm font-medium text-gray-700">Admin User</span>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </header>
129
+
130
+ <!-- Main Content -->
131
+ <main class="max-w-7xl mx-auto px-4 py-6 sm:px-6 lg:px-8">
132
+ <!-- Tabs Navigation -->
133
+ <div class="border-b border-gray-200">
134
+ <nav class="-mb-px flex space-x-8">
135
+ <button id="upload-tab" class="border-blue-500 text-blue-600 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">Upload Documents</button>
136
+ <button id="processing-tab" class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">Processing Queue</button>
137
+ <button id="review-tab" class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">Human Review</button>
138
+ <button id="analytics-tab" class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">Analytics Dashboard</button>
139
+ </nav>
140
+ </div>
141
+
142
+ <!-- Tab Content -->
143
+ <div class="mt-6">
144
+ <!-- Upload Documents Tab -->
145
+ <div id="upload-content" class="tab-content">
146
+ <div class="bg-white shadow rounded-lg p-6">
147
+ <h2 class="text-lg font-medium text-gray-900 mb-4">Upload Documents for OCR Processing</h2>
148
+
149
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
150
+ <!-- File Upload Section -->
151
+ <div>
152
+ <div id="dropzone" class="dropzone p-8 text-center cursor-pointer">
153
+ <input type="file" id="file-upload" class="hidden" multiple accept=".pdf,.jpg,.jpeg,.png,.tiff">
154
+ <div class="flex flex-col items-center justify-center">
155
+ <i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-3"></i>
156
+ <p class="text-sm text-gray-600 mb-1">Drag & drop files here or click to browse</p>
157
+ <p class="text-xs text-gray-500">Supports PDF, JPG, JPEG, PNG, TIFF (Max 100MB each)</p>
158
+ </div>
159
+ </div>
160
+
161
+ <div id="file-list" class="mt-4 space-y-2 max-h-60 overflow-y-auto"></div>
162
+
163
+ <div class="mt-4">
164
+ <label class="block text-sm font-medium text-gray-700 mb-1">Processing Engine</label>
165
+ <select id="engine-select" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md">
166
+ <option value="auto">Auto-select (Best for document type)</option>
167
+ <option value="gemini">Gemini 2.5 Flash (Fastest)</option>
168
+ <option value="gpt4">GPT-4o (Most accurate)</option>
169
+ <option value="mistral">Mistral Pixtral-12B (Balanced)</option>
170
+ </select>
171
+ </div>
172
+
173
+ <div class="mt-4">
174
+ <label class="block text-sm font-medium text-gray-700 mb-1">Extraction Options</label>
175
+ <div class="space-y-2">
176
+ <div class="flex items-center">
177
+ <input id="include-marginalia" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
178
+ <label for="include-marginalia" class="ml-2 block text-sm text-gray-700">Include marginalia</label>
179
+ </div>
180
+ <div class="flex items-center">
181
+ <input id="include-metadata" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
182
+ <label for="include-metadata" class="ml-2 block text-sm text-gray-700">Include metadata in markdown</label>
183
+ </div>
184
+ </div>
185
+ </div>
186
+
187
+ <div class="mt-4">
188
+ <label class="block text-sm font-medium text-gray-700 mb-1">Fields Schema (JSON)</label>
189
+ <textarea id="fields-schema" rows="5" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" placeholder='{"type": "object", "properties": {"field1": {"type": "string"}, "field2": {"type": "string"}}, "required": ["field1", "field2"]}'>{"type": "object", "properties": {"field1": {"type": "string"}, "field2": {"type": "string"}}, "required": ["field1", "field2"]}</textarea>
190
+ </div>
191
+
192
+ <button id="start-processing" class="mt-6 w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
193
+ Start Processing
194
+ </button>
195
+ </div>
196
+
197
+ <!-- Batch Processing Instructions -->
198
+ <div>
199
+ <div class="bg-blue-50 border-l-4 border-blue-400 p-4 mb-6">
200
+ <div class="flex">
201
+ <div class="flex-shrink-0">
202
+ <i class="fas fa-info-circle text-blue-400"></i>
203
+ </div>
204
+ <div class="ml-3">
205
+ <p class="text-sm text-blue-700">
206
+ For batch processing, upload multiple files at once. The system will automatically parallelize processing for optimal performance.
207
+ </p>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <h3 class="text-md font-medium text-gray-900 mb-3">Processing Guidelines</h3>
213
+ <ul class="space-y-3 text-sm text-gray-600">
214
+ <li class="flex items-start">
215
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
216
+ <span>For best results with handwritten documents, use the GPT-4o engine</span>
217
+ </li>
218
+ <li class="flex items-start">
219
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
220
+ <span>Table-heavy documents work well with Mistral Pixtral-12B</span>
221
+ </li>
222
+ <li class="flex items-start">
223
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
224
+ <span>Include marginalia for documents with side notes or annotations</span>
225
+ </li>
226
+ <li class="flex items-start">
227
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
228
+ <span>Define your fields schema carefully to ensure accurate extraction</span>
229
+ </li>
230
+ </ul>
231
+
232
+ <div class="mt-6 p-4 bg-gray-50 rounded-lg">
233
+ <h4 class="text-sm font-medium text-gray-900 mb-2">Sample Fields Schema</h4>
234
+ <pre class="text-xs bg-white p-2 rounded overflow-x-auto">{
235
+ "type": "object",
236
+ "properties": {
237
+ "invoice_number": {"type": "string"},
238
+ "date": {"type": "string"},
239
+ "total_amount": {"type": "number"},
240
+ "vendor_name": {"type": "string"}
241
+ },
242
+ "required": ["invoice_number", "date", "total_amount"]
243
+ }</pre>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </div>
249
+
250
+ <!-- Processing Queue Tab -->
251
+ <div id="processing-content" class="tab-content hidden">
252
+ <div class="bg-white shadow rounded-lg overflow-hidden">
253
+ <div class="px-6 py-4 border-b border-gray-200">
254
+ <h2 class="text-lg font-medium text-gray-900">Processing Queue</h2>
255
+ <p class="mt-1 text-sm text-gray-500">Real-time status of all OCR processing jobs</p>
256
+ </div>
257
+
258
+ <div class="overflow-x-auto">
259
+ <table class="min-w-full divide-y divide-gray-200">
260
+ <thead class="bg-gray-50">
261
+ <tr>
262
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Job ID</th>
263
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Filename</th>
264
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Engine</th>
265
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
266
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Progress</th>
267
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Pages</th>
268
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
269
+ </tr>
270
+ </thead>
271
+ <tbody id="processing-jobs" class="bg-white divide-y divide-gray-200">
272
+ <!-- Jobs will be added here dynamically -->
273
+ </tbody>
274
+ </table>
275
+ </div>
276
+
277
+ <div class="px-6 py-4 border-t border-gray-200 bg-gray-50 text-right">
278
+ <button id="refresh-jobs" class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
279
+ <i class="fas fa-sync-alt mr-2"></i> Refresh
280
+ </button>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- Human Review Tab -->
286
+ <div id="review-content" class="tab-content hidden">
287
+ <div class="bg-white shadow rounded-lg overflow-hidden">
288
+ <div class="px-6 py-4 border-b border-gray-200">
289
+ <div class="flex justify-between items-center">
290
+ <div>
291
+ <h2 class="text-lg font-medium text-gray-900">Human Review</h2>
292
+ <p class="mt-1 text-sm text-gray-500">Review and validate extracted data</p>
293
+ </div>
294
+ <div class="flex space-x-3">
295
+ <select id="review-filter" class="mt-1 block pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md">
296
+ <option value="all">All Documents</option>
297
+ <option value="pending">Pending Review</option>
298
+ <option value="approved">Approved</option>
299
+ <option value="rejected">Rejected</option>
300
+ <option value="escalated">Escalated</option>
301
+ </select>
302
+ <button id="export-reviewed" class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
303
+ <i class="fas fa-download mr-2"></i> Export
304
+ </button>
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="split-view">
310
+ <div class="split-pane">
311
+ <div class="overflow-y-auto h-full">
312
+ <table class="min-w-full divide-y divide-gray-200">
313
+ <thead class="bg-gray-50 sticky top-0">
314
+ <tr>
315
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Document</th>
316
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
317
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Reviewer</th>
318
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Updated</th>
319
+ </tr>
320
+ </thead>
321
+ <tbody id="review-documents" class="bg-white divide-y divide-gray-200">
322
+ <!-- Documents will be added here dynamically -->
323
+ </tbody>
324
+ </table>
325
+ </div>
326
+ </div>
327
+ <div class="resize-handle"></div>
328
+ <div class="split-pane">
329
+ <div id="review-detail" class="h-full flex flex-col">
330
+ <div class="flex justify-between items-center mb-4">
331
+ <h3 class="text-md font-medium text-gray-900">Document Details</h3>
332
+ <div class="flex space-x-2">
333
+ <button id="approve-doc" class="inline-flex items-center px-3 py-1 border border-transparent text-xs font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
334
+ Approve
335
+ </button>
336
+ <button id="reject-doc" class="inline-flex items-center px-3 py-1 border border-transparent text-xs font-medium rounded-md shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
337
+ Reject
338
+ </button>
339
+ <button id="escalate-doc" class="inline-flex items-center px-3 py-1 border border-transparent text-xs font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
340
+ Escalate
341
+ </button>
342
+ </div>
343
+ </div>
344
+
345
+ <div class="flex-1 grid grid-cols-1 md:grid-cols-2 gap-4 overflow-hidden">
346
+ <div class="border rounded-lg overflow-hidden">
347
+ <div class="bg-gray-50 px-4 py-2 border-b">
348
+ <h4 class="text-sm font-medium text-gray-900">Original Document</h4>
349
+ </div>
350
+ <div class="pdf-viewer">
351
+ <iframe id="pdf-preview" class="w-full h-full" src="about:blank"></iframe>
352
+ </div>
353
+ </div>
354
+ <div class="border rounded-lg overflow-hidden">
355
+ <div class="bg-gray-50 px-4 py-2 border-b">
356
+ <h4 class="text-sm font-medium text-gray-900">Extracted Data</h4>
357
+ </div>
358
+ <div class="p-4 overflow-y-auto h-full">
359
+ <div id="extracted-data" class="prose max-w-none">
360
+ <!-- Extracted data will be displayed here -->
361
+ <p class="text-gray-500 italic">Select a document to view extracted data</p>
362
+ </div>
363
+ </div>
364
+ </div>
365
+ </div>
366
+
367
+ <div class="mt-4">
368
+ <label for="review-notes" class="block text-sm font-medium text-gray-700">Review Notes</label>
369
+ <textarea id="review-notes" rows="3" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"></textarea>
370
+ </div>
371
+ </div>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ </div>
376
+
377
+ <!-- Analytics Dashboard Tab -->
378
+ <div id="analytics-content" class="tab-content hidden">
379
+ <div class="bg-white shadow rounded-lg p-6">
380
+ <h2 class="text-lg font-medium text-gray-900 mb-4">OCR Processing Analytics</h2>
381
+
382
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
383
+ <div class="bg-blue-50 rounded-lg p-4">
384
+ <div class="flex items-center justify-between">
385
+ <div>
386
+ <p class="text-sm font-medium text-blue-800">Documents Processed</p>
387
+ <p class="text-2xl font-semibold text-blue-900 mt-1">1,248</p>
388
+ </div>
389
+ <div class="bg-blue-100 p-3 rounded-full">
390
+ <i class="fas fa-file-alt text-blue-600"></i>
391
+ </div>
392
+ </div>
393
+ <div class="mt-2">
394
+ <span class="text-xs font-medium text-blue-700">+12% from last week</span>
395
+ </div>
396
+ </div>
397
+
398
+ <div class="bg-green-50 rounded-lg p-4">
399
+ <div class="flex items-center justify-between">
400
+ <div>
401
+ <p class="text-sm font-medium text-green-800">Accuracy Rate</p>
402
+ <p class="text-2xl font-semibold text-green-900 mt-1">94.7%</p>
403
+ </div>
404
+ <div class="bg-green-100 p-3 rounded-full">
405
+ <i class="fas fa-check-circle text-green-600"></i>
406
+ </div>
407
+ </div>
408
+ <div class="mt-2">
409
+ <span class="text-xs font-medium text-green-700">+2.3% from last week</span>
410
+ </div>
411
+ </div>
412
+
413
+ <div class="bg-purple-50 rounded-lg p-4">
414
+ <div class="flex items-center justify-between">
415
+ <div>
416
+ <p class="text-sm font-medium text-purple-800">Avg Processing Time</p>
417
+ <p class="text-2xl font-semibold text-purple-900 mt-1">3.2s</p>
418
+ </div>
419
+ <div class="bg-purple-100 p-3 rounded-full">
420
+ <i class="fas fa-clock text-purple-600"></i>
421
+ </div>
422
+ </div>
423
+ <div class="mt-2">
424
+ <span class="text-xs font-medium text-purple-700">-0.8s from last week</span>
425
+ </div>
426
+ </div>
427
+ </div>
428
+
429
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
430
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
431
+ <h3 class="text-md font-medium text-gray-900 mb-4">Processing Volume by Day</h3>
432
+ <div class="h-64">
433
+ <canvas id="volume-chart"></canvas>
434
+ </div>
435
+ </div>
436
+
437
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
438
+ <h3 class="text-md font-medium text-gray-900 mb-4">Engine Performance</h3>
439
+ <div class="h-64">
440
+ <canvas id="engine-chart"></canvas>
441
+ </div>
442
+ </div>
443
+
444
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
445
+ <h3 class="text-md font-medium text-gray-900 mb-4">Document Types</h3>
446
+ <div class="h-64">
447
+ <canvas id="type-chart"></canvas>
448
+ </div>
449
+ </div>
450
+
451
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
452
+ <h3 class="text-md font-medium text-gray-900 mb-4">Review Status</h3>
453
+ <div class="h-64">
454
+ <canvas id="review-chart"></canvas>
455
+ </div>
456
+ </div>
457
+ </div>
458
+ </div>
459
+ </div>
460
+ </div>
461
+ </main>
462
+ </div>
463
+
464
+ <!-- Scripts -->
465
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
466
+ <script>
467
+ // Tab switching functionality
468
+ document.addEventListener('DOMContentLoaded', function() {
469
+ const tabs = {
470
+ 'upload-tab': 'upload-content',
471
+ 'processing-tab': 'processing-content',
472
+ 'review-tab': 'review-content',
473
+ 'analytics-tab': 'analytics-content'
474
+ };
475
+
476
+ // Initialize first tab as active
477
+ document.getElementById('upload-tab').classList.add('border-blue-500', 'text-blue-600');
478
+ document.getElementById('upload-content').classList.remove('hidden');
479
+
480
+ // Add click event listeners to all tabs
481
+ Object.keys(tabs).forEach(tabId => {
482
+ document.getElementById(tabId).addEventListener('click', function() {
483
+ // Remove active classes from all tabs and hide all content
484
+ Object.keys(tabs).forEach(id => {
485
+ document.getElementById(id).classList.remove('border-blue-500', 'text-blue-600');
486
+ document.getElementById(id).classList.add('border-transparent', 'text-gray-500');
487
+ document.getElementById(tabs[id]).classList.add('hidden');
488
+ });
489
+
490
+ // Add active classes to clicked tab and show its content
491
+ this.classList.remove('border-transparent', 'text-gray-500');
492
+ this.classList.add('border-blue-500', 'text-blue-600');
493
+ document.getElementById(tabs[tabId]).classList.remove('hidden');
494
+
495
+ // Initialize charts when analytics tab is shown
496
+ if (tabId === 'analytics-tab') {
497
+ initCharts();
498
+ }
499
+ });
500
+ });
501
+
502
+ // File upload functionality
503
+ const dropzone = document.getElementById('dropzone');
504
+ const fileInput = document.getElementById('file-upload');
505
+ const fileList = document.getElementById('file-list');
506
+
507
+ dropzone.addEventListener('click', () => fileInput.click());
508
+
509
+ fileInput.addEventListener('change', handleFiles);
510
+
511
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
512
+ dropzone.addEventListener(eventName, preventDefaults, false);
513
+ });
514
+
515
+ function preventDefaults(e) {
516
+ e.preventDefault();
517
+ e.stopPropagation();
518
+ }
519
+
520
+ ['dragenter', 'dragover'].forEach(eventName => {
521
+ dropzone.addEventListener(eventName, highlight, false);
522
+ });
523
+
524
+ ['dragleave', 'drop'].forEach(eventName => {
525
+ dropzone.addEventListener(eventName, unhighlight, false);
526
+ });
527
+
528
+ function highlight() {
529
+ dropzone.classList.add('active');
530
+ }
531
+
532
+ function unhighlight() {
533
+ dropzone.classList.remove('active');
534
+ }
535
+
536
+ dropzone.addEventListener('drop', handleDrop, false);
537
+
538
+ function handleDrop(e) {
539
+ const dt = e.dataTransfer;
540
+ const files = dt.files;
541
+ handleFiles({ target: { files } });
542
+ }
543
+
544
+ function handleFiles(e) {
545
+ const files = e.target.files;
546
+ if (files.length === 0) return;
547
+
548
+ fileList.innerHTML = '';
549
+
550
+ for (let i = 0; i < files.length; i++) {
551
+ const file = files[i];
552
+ const fileItem = document.createElement('div');
553
+ fileItem.className = 'flex items-center justify-between p-2 bg-gray-50 rounded';
554
+
555
+ fileItem.innerHTML = `
556
+ <div class="flex items-center truncate">
557
+ <i class="fas fa-file-alt text-gray-400 mr-2"></i>
558
+ <span class="text-sm truncate">${file.name}</span>
559
+ </div>
560
+ <div class="flex items-center">
561
+ <span class="text-xs text-gray-500 mr-2">${formatFileSize(file.size)}</span>
562
+ <button class="text-red-400 hover:text-red-600" data-file="${file.name}">
563
+ <i class="fas fa-times"></i>
564
+ </button>
565
+ </div>
566
+ `;
567
+
568
+ fileList.appendChild(fileItem);
569
+ }
570
+
571
+ // Add event listeners to remove buttons
572
+ document.querySelectorAll('#file-list button').forEach(button => {
573
+ button.addEventListener('click', function() {
574
+ const fileName = this.getAttribute('data-file');
575
+ // In a real app, we would remove the file from the FileList
576
+ this.parentNode.parentNode.remove();
577
+ });
578
+ });
579
+ }
580
+
581
+ function formatFileSize(bytes) {
582
+ if (bytes === 0) return '0 Bytes';
583
+ const k = 1024;
584
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
585
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
586
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
587
+ }
588
+
589
+ // Start processing button
590
+ document.getElementById('start-processing').addEventListener('click', function() {
591
+ const files = fileInput.files;
592
+ if (files.length === 0) {
593
+ alert('Please select at least one file to process');
594
+ return;
595
+ }
596
+
597
+ const engine = document.getElementById('engine-select').value;
598
+ const includeMarginalia = document.getElementById('include-marginalia').checked;
599
+ const includeMetadata = document.getElementById('include-metadata').checked;
600
+ const fieldsSchema = document.getElementById('fields-schema').value;
601
+
602
+ try {
603
+ JSON.parse(fieldsSchema); // Validate JSON
604
+ } catch (e) {
605
+ alert('Invalid JSON in Fields Schema');
606
+ return;
607
+ }
608
+
609
+ // In a real app, we would send this to the server for processing
610
+ console.log('Starting processing with:', {
611
+ files: Array.from(files).map(f => f.name),
612
+ engine,
613
+ includeMarginalia,
614
+ includeMetadata,
615
+ fieldsSchema: JSON.parse(fieldsSchema)
616
+ });
617
+
618
+ // Simulate adding to processing queue
619
+ addProcessingJob(files[0].name, engine);
620
+
621
+ // Switch to processing tab
622
+ document.getElementById('processing-tab').click();
623
+ });
624
+
625
+ // Add sample processing jobs
626
+ function addProcessingJob(filename, engine) {
627
+ const jobsTable = document.getElementById('processing-jobs');
628
+ const jobId = 'job-' + Math.random().toString(36).substr(2, 8);
629
+
630
+ const row = document.createElement('tr');
631
+ row.innerHTML = `
632
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${jobId}</td>
633
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${filename}</td>
634
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${engine}</td>
635
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Processing</td>
636
+ <td class="px-6 py-4 whitespace-nowrap">
637
+ <div class="progress-bar">
638
+ <div class="progress-fill" style="width: 30%"></div>
639
+ </div>
640
+ </td>
641
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${Math.floor(Math.random() * 10) + 1}</td>
642
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
643
+ <button class="text-red-600 hover:text-red-900">Cancel</button>
644
+ </td>
645
+ `;
646
+
647
+ jobsTable.appendChild(row);
648
+
649
+ // Simulate progress
650
+ const progressFill = row.querySelector('.progress-fill');
651
+ let progress = 30;
652
+ const interval = setInterval(() => {
653
+ progress += Math.random() * 10;
654
+ if (progress >= 100) {
655
+ progress = 100;
656
+ clearInterval(interval);
657
+ row.querySelector('td:nth-child(4)').textContent = 'Completed';
658
+ row.querySelector('td:nth-child(4)').classList.add('text-green-600');
659
+ row.querySelector('td:nth-child(7) button').textContent = 'View';
660
+
661
+ // Add to review queue when complete
662
+ addReviewDocument(filename, jobId);
663
+ }
664
+ progressFill.style.width = `${progress}%`;
665
+ }, 1000);
666
+ }
667
+
668
+ // Add sample review documents
669
+ function addReviewDocument(filename, jobId) {
670
+ const statuses = ['pending', 'approved', 'rejected', 'escalated'];
671
+ const status = statuses[Math.floor(Math.random() * statuses.length)];
672
+ const reviewers = ['John Doe', 'Jane Smith', 'Mike Johnson', 'Sarah Williams'];
673
+ const reviewer = status === 'pending' ? '-' : reviewers[Math.floor(Math.random() * reviewers.length)];
674
+
675
+ const documentsTable = document.getElementById('review-documents');
676
+ const row = document.createElement('tr');
677
+ row.className = 'cursor-pointer hover:bg-gray-50';
678
+ row.dataset.filename = filename;
679
+ row.dataset.jobId = jobId;
680
+ row.dataset.status = status;
681
+
682
+ row.innerHTML = `
683
+ <td class="px-6 py-4 whitespace-nowrap">
684
+ <div class="flex items-center">
685
+ <i class="fas fa-file-alt text-gray-400 mr-2"></i>
686
+ <div class="text-sm font-medium text-gray-900">${filename}</div>
687
+ </div>
688
+ </td>
689
+ <td class="px-6 py-4 whitespace-nowrap">
690
+ <span class="status-badge status-${status}">${status.charAt(0).toUpperCase() + status.slice(1)}</span>
691
+ </td>
692
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${reviewer}</td>
693
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${new Date().toLocaleString()}</td>
694
+ `;
695
+
696
+ documentsTable.appendChild(row);
697
+
698
+ // Add click handler to show document details
699
+ row.addEventListener('click', function() {
700
+ showDocumentDetails(filename, jobId, status);
701
+ });
702
+ }
703
+
704
+ // Show document details in review panel
705
+ function showDocumentDetails(filename, jobId, status) {
706
+ // Highlight selected row
707
+ document.querySelectorAll('#review-documents tr').forEach(row => {
708
+ row.classList.remove('bg-blue-50');
709
+ });
710
+ event.currentTarget.classList.add('bg-blue-50');
711
+
712
+ // Update buttons based on status
713
+ document.getElementById('approve-doc').disabled = status !== 'pending';
714
+ document.getElementById('reject-doc').disabled = status !== 'pending';
715
+ document.getElementById('escalate-doc').disabled = status !== 'pending';
716
+
717
+ // Simulate loading PDF preview
718
+ document.getElementById('pdf-preview').src = 'about:blank';
719
+
720
+ // Simulate extracted data
721
+ const extractedData = document.getElementById('extracted-data');
722
+ extractedData.innerHTML = `
723
+ <h3>${filename}</h3>
724
+ <p class="text-sm text-gray-500">Job ID: ${jobId}</p>
725
+
726
+ <table class="markdown-table">
727
+ <thead>
728
+ <tr>
729
+ <th>Field</th>
730
+ <th>Extracted Value</th>
731
+ <th>Confidence</th>
732
+ </tr>
733
+ </thead>
734
+ <tbody>
735
+ <tr>
736
+ <td>Invoice Number</td>
737
+ <td contenteditable="true">INV-${Math.floor(Math.random() * 10000)}</td>
738
+ <td>${(Math.random() * 30 + 70).toFixed(1)}%</td>
739
+ </tr>
740
+ <tr>
741
+ <td>Date</td>
742
+ <td contenteditable="true">${new Date().toLocaleDateString()}</td>
743
+ <td>${(Math.random() * 30 + 70).toFixed(1)}%</td>
744
+ </tr>
745
+ <tr>
746
+ <td>Total Amount</td>
747
+ <td contenteditable="true">$${(Math.random() * 1000).toFixed(2)}</td>
748
+ <td>${(Math.random() * 30 + 70).toFixed(1)}%</td>
749
+ </tr>
750
+ <tr>
751
+ <td>Vendor Name</td>
752
+ <td contenteditable="true">Vendor ${Math.floor(Math.random() * 10) + 1}</td>
753
+ <td>${(Math.random() * 30 + 70).toFixed(1)}%</td>
754
+ </tr>
755
+ </tbody>
756
+ </table>
757
+
758
+ <div class="mt-4 p-3 bg-yellow-50 border-l-4 border-yellow-400">
759
+ <div class="flex">
760
+ <div class="flex-shrink-0">
761
+ <i class="fas fa-exclamation-triangle text-yellow-400"></i>
762
+ </div>
763
+ <div class="ml-3">
764
+ <p class="text-sm text-yellow-700">
765
+ Low confidence detected on field "Total Amount". Please verify.
766
+ </p>
767
+ </div>
768
+ </div>
769
+ </div>
770
+ `;
771
+ }
772
+
773
+ // Review action buttons
774
+ document.getElementById('approve-doc').addEventListener('click', function() {
775
+ updateDocumentStatus('approved');
776
+ });
777
+
778
+ document.getElementById('reject-doc').addEventListener('click', function() {
779
+ updateDocumentStatus('rejected');
780
+ });
781
+
782
+ document.getElementById('escalate-doc').addEventListener('click', function() {
783
+ updateDocumentStatus('escalated');
784
+ });
785
+
786
+ function updateDocumentStatus(newStatus) {
787
+ const selectedRow = document.querySelector('#review-documents tr.bg-blue-50');
788
+ if (!selectedRow) return;
789
+
790
+ const statusBadge = selectedRow.querySelector('.status-badge');
791
+ statusBadge.className = `status-badge status-${newStatus}`;
792
+ statusBadge.textContent = newStatus.charAt(0).toUpperCase() + newStatus.slice(1);
793
+
794
+ // Update reviewer and timestamp
795
+ const reviewers = ['John Doe', 'Jane Smith', 'Mike Johnson', 'Sarah Williams'];
796
+ selectedRow.cells[2].textContent = reviewers[Math.floor(Math.random() * reviewers.length)];
797
+ selectedRow.cells[3].textContent = new Date().toLocaleString();
798
+
799
+ // Disable buttons after status change
800
+ document.getElementById('approve-doc').disabled = true;
801
+ document.getElementById('reject-doc').disabled = true;
802
+ document.getElementById('escalate-doc').disabled = true;
803
+
804
+ // Save notes
805
+ const notes = document.getElementById('review-notes').value;
806
+ console.log(`Document ${selectedRow.dataset.filename} marked as ${newStatus} with notes: ${notes}`);
807
+ }
808
+
809
+ // Refresh jobs button
810
+ document.getElementById('refresh-jobs').addEventListener('click', function() {
811
+ // In a real app, this would fetch updated job statuses from the server
812
+ console.log('Refreshing job statuses...');
813
+ });
814
+
815
+ // Export reviewed documents
816
+ document.getElementById('export-reviewed').addEventListener('click', function() {
817
+ const format = prompt('Select export format (CSV, Excel, JSON, Markdown):', 'CSV');
818
+ if (format) {
819
+ alert(`Exporting reviewed documents in ${format} format...`);
820
+ }
821
+ });
822
+
823
+ // Filter review documents
824
+ document.getElementById('review-filter').addEventListener('change', function() {
825
+ const filter = this.value;
826
+ document.querySelectorAll('#review-documents tr').forEach(row => {
827
+ if (filter === 'all' || row.dataset.status === filter) {
828
+ row.style.display = '';
829
+ } else {
830
+ row.style.display = 'none';
831
+ }
832
+ });
833
+ });
834
+
835
+ // Initialize charts for analytics tab
836
+ function initCharts() {
837
+ // Volume chart
838
+ const volumeCtx = document.getElementById('volume-chart').getContext('2d');
839
+ new Chart(volumeCtx, {
840
+ type: 'line',
841
+ data: {
842
+ labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
843
+ datasets: [{
844
+ label: 'Documents Processed',
845
+ data: [45, 78, 62, 93, 105, 52, 30],
846
+ backgroundColor: 'rgba(66, 153, 225, 0.2)',
847
+ borderColor: 'rgba(66, 153, 225, 1)',
848
+ borderWidth: 2,
849
+ tension: 0.3
850
+ }]
851
+ },
852
+ options: {
853
+ responsive: true,
854
+ maintainAspectRatio: false,
855
+ scales: {
856
+ y: {
857
+ beginAtZero: true
858
+ }
859
+ }
860
+ }
861
+ });
862
+
863
+ // Engine performance chart
864
+ const engineCtx = document.getElementById('engine-chart').getContext('2d');
865
+ new Chart(engineCtx, {
866
+ type: 'bar',
867
+ data: {
868
+ labels: ['Gemini 2.5 Flash', 'GPT-4o', 'Mistral Pixtral-12B'],
869
+ datasets: [{
870
+ label: 'Accuracy (%)',
871
+ data: [89.2, 96.5, 92.8],
872
+ backgroundColor: [
873
+ 'rgba(102, 126, 234, 0.7)',
874
+ 'rgba(237, 137, 54, 0.7)',
875
+ 'rgba(72, 187, 120, 0.7)'
876
+ ],
877
+ borderColor: [
878
+ 'rgba(102, 126, 234, 1)',
879
+ 'rgba(237, 137, 54, 1)',
880
+ 'rgba(72, 187, 120, 1)'
881
+ ],
882
+ borderWidth: 1
883
+ }, {
884
+ label: 'Speed (pages/sec)',
885
+ data: [12.4, 7.8, 9.6],
886
+ backgroundColor: [
887
+ 'rgba(102, 126, 234, 0.4)',
888
+ 'rgba(237, 137, 54, 0.4)',
889
+ 'rgba(72, 187, 120, 0.4)'
890
+ ],
891
+ borderColor: [
892
+ 'rgba(102, 126, 234, 1)',
893
+ 'rgba(237, 137, 54, 1)',
894
+ 'rgba(72, 187, 120, 1)'
895
+ ],
896
+ borderWidth: 1,
897
+ type: 'line',
898
+ yAxisID: 'y1'
899
+ }]
900
+ },
901
+ options: {
902
+ responsive: true,
903
+ maintainAspectRatio: false,
904
+ scales: {
905
+ y: {
906
+ beginAtZero: true,
907
+ title: {
908
+ display: true,
909
+ text: 'Accuracy (%)'
910
+ }
911
+ },
912
+ y1: {
913
+ position: 'right',
914
+ beginAtZero: true,
915
+ title: {
916
+ display: true,
917
+ text: 'Speed (pages/sec)'
918
+ },
919
+ grid: {
920
+ drawOnChartArea: false
921
+ }
922
+ }
923
+ }
924
+ }
925
+ });
926
+
927
+ // Document types chart
928
+ const typeCtx = document.getElementById('type-chart').getContext('2d');
929
+ new Chart(typeCtx, {
930
+ type: 'doughnut',
931
+ data: {
932
+ labels: ['Invoices', 'Receipts', 'Forms', 'Contracts', 'Other'],
933
+ datasets: [{
934
+ data: [35, 25, 20, 15, 5],
935
+ backgroundColor: [
936
+ 'rgba(66, 153, 225, 0.7)',
937
+ 'rgba(102, 126, 234, 0.7)',
938
+ 'rgba(237, 137, 54, 0.7)',
939
+ 'rgba(72, 187, 120, 0.7)',
940
+ 'rgba(224, 102, 102, 0.7)'
941
+ ],
942
+ borderWidth: 1
943
+ }]
944
+ },
945
+ options: {
946
+ responsive: true,
947
+ maintainAspectRatio: false
948
+ }
949
+ });
950
+
951
+ // Review status chart
952
+ const reviewCtx = document.getElementById('review-chart').getContext('2d');
953
+ new Chart(reviewCtx, {
954
+ type: 'polarArea',
955
+ data: {
956
+ labels: ['Approved', 'Rejected', 'Pending', 'Escalated'],
957
+ datasets: [{
958
+ data: [65, 10, 15, 10],
959
+ backgroundColor: [
960
+ 'rgba(72, 187, 120, 0.7)',
961
+ 'rgba(224, 102, 102, 0.7)',
962
+ 'rgba(237, 137, 54, 0.7)',
963
+ 'rgba(66, 153, 225, 0.7)'
964
+ ],
965
+ borderWidth: 1
966
+ }]
967
+ },
968
+ options: {
969
+ responsive: true,
970
+ maintainAspectRatio: false
971
+ }
972
+ });
973
+ }
974
+
975
+ // Simulate WebSocket connection
976
+ function simulateWebSocket() {
977
+ const statusElement = document.getElementById('ws-status');
978
+ const statusText = document.getElementById('ws-status-text');
979
+
980
+ // Start with connected
981
+ statusElement.className = 'ws-status ws-connected';
982
+ statusText.textContent = 'Connected';
983
+
984
+ // Randomly change status to simulate real-world conditions
985
+ setInterval(() => {
986
+ const states = [
987
+ { class: 'ws-connected', text: 'Connected' },
988
+ { class: 'ws-disconnected', text: 'Disconnected' },
989
+ { class: 'ws-connecting', text: 'Connecting' }
990
+ ];
991
+
992
+ const randomState = states[Math.floor(Math.random() * states.length)];
993
+ statusElement.className = 'ws-status ' + randomState.class;
994
+ statusText.textContent = randomState.text;
995
+ }, 10000);
996
+ }
997
+
998
+ simulateWebSocket();
999
+
1000
+ // Add some sample data on load
1001
+ for (let i = 0; i < 5; i++) {
1002
+ const engines = ['Gemini 2.5 Flash', 'GPT-4o', 'Mistral Pixtral-12B'];
1003
+ const engine = engines[Math.floor(Math.random() * engines.length)];
1004
+ addProcessingJob(`document_${i+1}.pdf`, engine);
1005
+ }
1006
+
1007
+ for (let i = 0; i < 8; i++) {
1008
+ const engines = ['Gemini 2.5 Flash', 'GPT-4o', 'Mistral Pixtral-12B'];
1009
+ const engine = engines[Math.floor(Math.random() * engines.length)];
1010
+ const jobId = 'job-' + Math.random().toString(36).substr(2, 8);
1011
+ addReviewDocument(`review_doc_${i+1}.pdf`, jobId);
1012
+ }
1013
+ });
1014
+ </script>
1015
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=NAITIVEAIAGENCY/ocr" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1016
+ </html>