AI Assistant commited on
Commit
37a1755
·
1 Parent(s): 2b8c32b

Update Bitcheck Document Service and test.html

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .env.example +0 -0
  2. .gitattributes +35 -35
  3. .gitignore +0 -0
  4. Dockerfile +0 -0
  5. README.md +0 -0
  6. app/__init__.py +0 -0
  7. app/config.py +0 -0
  8. app/routes/__init__.py +0 -0
  9. app/routes/verify_document.py +0 -0
  10. app/schemas/__init__.py +0 -0
  11. app/schemas/document_verification.py +0 -0
  12. app/services/__init__.py +0 -0
  13. app/services/content_risk_analyzer.py +0 -0
  14. app/services/deepseek_llm.py +0 -0
  15. app/services/document_context.py +0 -0
  16. app/services/field_extractor.py +0 -0
  17. app/services/file_validator.py +0 -0
  18. app/services/forensic_analyzer.py +0 -0
  19. app/services/image_processor.py +0 -0
  20. app/services/live_qr_verifier.py +0 -0
  21. app/services/metadata_analyzer.py +0 -0
  22. app/services/ocr_service.py +0 -0
  23. app/services/pdf_processor.py +0 -0
  24. app/services/prompt_builder.py +0 -0
  25. app/services/qr_code_analyzer.py +0 -0
  26. app/services/report_builder.py +0 -0
  27. app/services/source_url_analyzer.py +0 -0
  28. app/services/text_consistency.py +0 -0
  29. app/services/trust_scorer.py +0 -0
  30. app/utils/__init__.py +0 -0
  31. app/utils/file_utils.py +0 -0
  32. app/utils/image_utils.py +0 -0
  33. app/utils/text_utils.py +0 -0
  34. main.py +0 -0
  35. outputs/.gitkeep +0 -0
  36. requirements.txt +0 -0
  37. test.html +571 -0
  38. tests/__init__.py +0 -0
  39. tests/test_api_smoke.py +0 -0
  40. tests/test_content_risk_analyzer.py +0 -0
  41. tests/test_deepseek_llm.py +0 -0
  42. tests/test_field_extractor.py +0 -0
  43. tests/test_file_validator.py +0 -0
  44. tests/test_forensic_analyzer.py +0 -0
  45. tests/test_live_qr_verifier.py +0 -0
  46. tests/test_metadata_analyzer.py +0 -0
  47. tests/test_processors.py +0 -0
  48. tests/test_source_url_analyzer.py +0 -0
  49. tests/test_text_consistency.py +0 -0
  50. tests/test_trust_scorer.py +0 -0
.env.example CHANGED
File without changes
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
File without changes
Dockerfile CHANGED
File without changes
README.md CHANGED
File without changes
app/__init__.py CHANGED
File without changes
app/config.py CHANGED
File without changes
app/routes/__init__.py CHANGED
File without changes
app/routes/verify_document.py CHANGED
File without changes
app/schemas/__init__.py CHANGED
File without changes
app/schemas/document_verification.py CHANGED
File without changes
app/services/__init__.py CHANGED
File without changes
app/services/content_risk_analyzer.py CHANGED
File without changes
app/services/deepseek_llm.py CHANGED
File without changes
app/services/document_context.py CHANGED
File without changes
app/services/field_extractor.py CHANGED
File without changes
app/services/file_validator.py CHANGED
File without changes
app/services/forensic_analyzer.py CHANGED
File without changes
app/services/image_processor.py CHANGED
File without changes
app/services/live_qr_verifier.py CHANGED
File without changes
app/services/metadata_analyzer.py CHANGED
File without changes
app/services/ocr_service.py CHANGED
File without changes
app/services/pdf_processor.py CHANGED
File without changes
app/services/prompt_builder.py CHANGED
File without changes
app/services/qr_code_analyzer.py CHANGED
File without changes
app/services/report_builder.py CHANGED
File without changes
app/services/source_url_analyzer.py CHANGED
File without changes
app/services/text_consistency.py CHANGED
File without changes
app/services/trust_scorer.py CHANGED
File without changes
app/utils/__init__.py CHANGED
File without changes
app/utils/file_utils.py CHANGED
File without changes
app/utils/image_utils.py CHANGED
File without changes
app/utils/text_utils.py CHANGED
File without changes
main.py CHANGED
File without changes
outputs/.gitkeep CHANGED
File without changes
requirements.txt CHANGED
File without changes
test.html ADDED
@@ -0,0 +1,571 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>BitCheck Document API Tester</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --bg-color: #0f172a;
11
+ --surface: #1e293b;
12
+ --surface-hover: #334155;
13
+ --primary: #3b82f6;
14
+ --primary-hover: #2563eb;
15
+ --text-main: #f8fafc;
16
+ --text-muted: #94a3b8;
17
+ --border: #334155;
18
+ --success: #10b981;
19
+ --danger: #ef4444;
20
+ --warning: #f59e0b;
21
+ }
22
+
23
+ body {
24
+ font-family: 'Inter', sans-serif;
25
+ background-color: var(--bg-color);
26
+ color: var(--text-main);
27
+ margin: 0;
28
+ padding: 2rem;
29
+ min-height: 100vh;
30
+ display: flex;
31
+ flex-direction: column;
32
+ align-items: center;
33
+ }
34
+
35
+ .header {
36
+ margin-bottom: 2rem;
37
+ text-align: center;
38
+ }
39
+
40
+ h1 {
41
+ font-weight: 700;
42
+ margin-bottom: 0.5rem;
43
+ font-size: 2.5rem;
44
+ background: linear-gradient(135deg, #60a5fa, #a78bfa);
45
+ -webkit-background-clip: text;
46
+ -webkit-text-fill-color: transparent;
47
+ }
48
+
49
+ .subtitle {
50
+ color: var(--text-muted);
51
+ font-size: 1.1rem;
52
+ }
53
+
54
+ .container {
55
+ max-width: 1100px;
56
+ width: 100%;
57
+ display: grid;
58
+ grid-template-columns: 1fr 1fr;
59
+ gap: 2rem;
60
+ }
61
+
62
+ @media (max-width: 768px) {
63
+ .container {
64
+ grid-template-columns: 1fr;
65
+ }
66
+ }
67
+
68
+ .card {
69
+ background: rgba(30, 41, 59, 0.6);
70
+ backdrop-filter: blur(16px);
71
+ border: 1px solid var(--border);
72
+ border-radius: 16px;
73
+ padding: 2rem;
74
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
75
+ display: flex;
76
+ flex-direction: column;
77
+ }
78
+
79
+ .form-group {
80
+ margin-bottom: 1.2rem;
81
+ }
82
+
83
+ label {
84
+ display: block;
85
+ font-size: 0.85rem;
86
+ font-weight: 600;
87
+ margin-bottom: 0.5rem;
88
+ color: var(--text-muted);
89
+ text-transform: uppercase;
90
+ letter-spacing: 0.05em;
91
+ }
92
+
93
+ input[type="text"], input[type="number"], select {
94
+ width: 100%;
95
+ padding: 0.75rem 1rem;
96
+ background: rgba(15, 23, 42, 0.8);
97
+ border: 1px solid var(--border);
98
+ border-radius: 8px;
99
+ color: var(--text-main);
100
+ font-family: 'Inter', sans-serif;
101
+ transition: all 0.2s ease;
102
+ box-sizing: border-box;
103
+ font-size: 0.95rem;
104
+ }
105
+
106
+ input[type="text"]:focus, input[type="number"]:focus, select:focus {
107
+ outline: none;
108
+ border-color: var(--primary);
109
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
110
+ }
111
+
112
+ .grid-2 {
113
+ display: grid;
114
+ grid-template-columns: 1fr 1fr;
115
+ gap: 1rem;
116
+ }
117
+
118
+ .checkbox-container {
119
+ display: grid;
120
+ grid-template-columns: 1fr 1fr;
121
+ gap: 0.75rem;
122
+ margin-bottom: 1.5rem;
123
+ background: rgba(15, 23, 42, 0.3);
124
+ padding: 1rem;
125
+ border-radius: 8px;
126
+ border: 1px solid var(--border);
127
+ }
128
+
129
+ .checkbox-label {
130
+ display: flex;
131
+ align-items: center;
132
+ gap: 0.5rem;
133
+ cursor: pointer;
134
+ text-transform: none;
135
+ letter-spacing: normal;
136
+ font-weight: 500;
137
+ color: var(--text-main);
138
+ margin: 0;
139
+ user-select: none;
140
+ }
141
+
142
+ .checkbox-label input {
143
+ cursor: pointer;
144
+ width: 1.2rem;
145
+ height: 1.2rem;
146
+ accent-color: var(--primary);
147
+ margin: 0;
148
+ }
149
+
150
+ .file-drop {
151
+ border: 2px dashed var(--border);
152
+ border-radius: 12px;
153
+ padding: 2.5rem 2rem;
154
+ text-align: center;
155
+ cursor: pointer;
156
+ transition: all 0.3s ease;
157
+ margin-bottom: 1.5rem;
158
+ background: rgba(15, 23, 42, 0.5);
159
+ position: relative;
160
+ }
161
+
162
+ .file-drop:hover, .file-drop.dragover {
163
+ border-color: var(--primary);
164
+ background: rgba(59, 130, 246, 0.05);
165
+ }
166
+
167
+ .file-drop input[type="file"] {
168
+ position: absolute;
169
+ top: 0;
170
+ left: 0;
171
+ width: 100%;
172
+ height: 100%;
173
+ opacity: 0;
174
+ cursor: pointer;
175
+ }
176
+
177
+ .file-icon {
178
+ font-size: 2.5rem;
179
+ margin-bottom: 1rem;
180
+ color: var(--primary);
181
+ }
182
+
183
+ .file-drop p {
184
+ margin: 0;
185
+ color: var(--text-muted);
186
+ font-size: 0.95rem;
187
+ }
188
+
189
+ #fileName {
190
+ color: var(--text-main);
191
+ font-weight: 600;
192
+ margin-top: 0.75rem;
193
+ display: block;
194
+ word-break: break-all;
195
+ }
196
+
197
+ button {
198
+ width: 100%;
199
+ padding: 1rem;
200
+ background: linear-gradient(135deg, var(--primary), #8b5cf6);
201
+ color: white;
202
+ border: none;
203
+ border-radius: 8px;
204
+ font-size: 1rem;
205
+ font-weight: 600;
206
+ cursor: pointer;
207
+ transition: all 0.2s ease;
208
+ display: flex;
209
+ justify-content: center;
210
+ align-items: center;
211
+ gap: 0.75rem;
212
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
213
+ margin-top: auto;
214
+ }
215
+
216
+ button:hover {
217
+ transform: translateY(-2px);
218
+ box-shadow: 0 6px 15px rgba(59, 130, 246, 0.4);
219
+ }
220
+
221
+ button:active {
222
+ transform: translateY(0);
223
+ }
224
+
225
+ button:disabled {
226
+ background: var(--surface-hover);
227
+ box-shadow: none;
228
+ cursor: not-allowed;
229
+ color: var(--text-muted);
230
+ transform: none;
231
+ }
232
+
233
+ .spinner {
234
+ width: 1.2rem;
235
+ height: 1.2rem;
236
+ border: 3px solid rgba(255,255,255,0.3);
237
+ border-radius: 50%;
238
+ border-top-color: white;
239
+ animation: spin 1s linear infinite;
240
+ display: none;
241
+ }
242
+
243
+ @keyframes spin {
244
+ to { transform: rotate(360deg); }
245
+ }
246
+
247
+ .result-card {
248
+ display: flex;
249
+ flex-direction: column;
250
+ height: 100%;
251
+ }
252
+
253
+ .status-bar {
254
+ display: flex;
255
+ justify-content: space-between;
256
+ align-items: center;
257
+ margin-bottom: 1rem;
258
+ padding-bottom: 1rem;
259
+ border-bottom: 1px solid var(--border);
260
+ }
261
+
262
+ .status-badge {
263
+ display: inline-flex;
264
+ align-items: center;
265
+ padding: 0.35rem 0.85rem;
266
+ border-radius: 999px;
267
+ font-size: 0.8rem;
268
+ font-weight: 600;
269
+ text-transform: uppercase;
270
+ letter-spacing: 0.05em;
271
+ }
272
+
273
+ .status-idle { background: rgba(148, 163, 184, 0.1); color: #94a3b8; border: 1px solid #475569; }
274
+ .status-success { background: rgba(16, 185, 129, 0.1); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.3); }
275
+ .status-error { background: rgba(239, 68, 68, 0.1); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.3); }
276
+ .status-warning { background: rgba(245, 158, 11, 0.1); color: #fbbf24; border: 1px solid rgba(245, 158, 11, 0.3); }
277
+
278
+ .time-badge {
279
+ font-size: 0.85rem;
280
+ color: var(--text-muted);
281
+ font-family: monospace;
282
+ }
283
+
284
+ .json-viewer {
285
+ flex-grow: 1;
286
+ background: #0f172a;
287
+ border-radius: 8px;
288
+ padding: 1.5rem;
289
+ overflow-y: auto;
290
+ font-family: 'Consolas', monospace;
291
+ font-size: 0.85rem;
292
+ color: #a5b4fc;
293
+ border: 1px solid rgba(255,255,255,0.05);
294
+ white-space: pre-wrap;
295
+ max-height: 550px;
296
+ line-height: 1.5;
297
+ box-shadow: inset 0 2px 10px rgba(0,0,0,0.2);
298
+ }
299
+
300
+ .json-viewer .string { color: #86efac; }
301
+ .json-viewer .number { color: #fca5a5; }
302
+ .json-viewer .boolean { color: #fcd34d; }
303
+ .json-viewer .null { color: #94a3b8; }
304
+ .json-viewer .key { color: #93c5fd; font-weight: 600; }
305
+
306
+ .endpoint-selector {
307
+ display: flex;
308
+ gap: 0.5rem;
309
+ margin-bottom: 1.5rem;
310
+ }
311
+
312
+ .endpoint-selector button {
313
+ background: var(--surface-hover);
314
+ color: var(--text-muted);
315
+ border-radius: 6px;
316
+ padding: 0.5rem;
317
+ box-shadow: none;
318
+ font-size: 0.85rem;
319
+ margin: 0;
320
+ flex: 1;
321
+ }
322
+
323
+ .endpoint-selector button.active {
324
+ background: rgba(59, 130, 246, 0.2);
325
+ color: var(--primary);
326
+ border: 1px solid var(--primary);
327
+ }
328
+
329
+ </style>
330
+ </head>
331
+ <body>
332
+
333
+ <div class="header">
334
+ <h1>BitCheck Tester</h1>
335
+ <div class="subtitle">Evaluate Document Verification API Endpoints</div>
336
+ </div>
337
+
338
+ <div class="container">
339
+ <!-- Configuration Card -->
340
+ <div class="card">
341
+
342
+ <div class="endpoint-selector">
343
+ <button type="button" id="btn-hf" class="active" onclick="setEndpoint('hf')">Hugging Face Space</button>
344
+ <button type="button" id="btn-local" onclick="setEndpoint('local')">Local Server</button>
345
+ </div>
346
+
347
+ <div class="form-group">
348
+ <label for="apiUrl">API Endpoint URL</label>
349
+ <input type="text" id="apiUrl" value="https://jaykay73-bitcheck-document.hf.space/verify/document">
350
+ </div>
351
+
352
+ <div class="file-drop" id="dropZone">
353
+ <div class="file-icon">📄</div>
354
+ <p>Drag & drop a document here</p>
355
+ <p style="font-size: 0.8rem; margin-top: 0.5rem; opacity: 0.7;">Supports PDF, JPG, PNG, WEBP (Max 20MB)</p>
356
+ <input type="file" id="fileInput" accept=".pdf,.jpg,.jpeg,.png,.webp">
357
+ <span id="fileName">No file selected</span>
358
+ </div>
359
+
360
+ <div class="grid-2">
361
+ <div class="form-group">
362
+ <label for="docType">Document Type</label>
363
+ <select id="docType">
364
+ <option value="general">General</option>
365
+ <option value="certificate">Certificate</option>
366
+ <option value="identity_document">Identity Document</option>
367
+ <option value="academic_result">Academic Result</option>
368
+ <option value="invoice">Invoice</option>
369
+ <option value="receipt">Receipt</option>
370
+ <option value="bank_statement">Bank Statement</option>
371
+ </select>
372
+ </div>
373
+
374
+ <div class="form-group">
375
+ <label for="maxPages">Max PDF Pages</label>
376
+ <input type="number" id="maxPages" value="5" min="1" max="50">
377
+ </div>
378
+ </div>
379
+
380
+ <label style="margin-top: 0.5rem;">Analysis Modules</label>
381
+ <div class="checkbox-container">
382
+ <label class="checkbox-label">
383
+ <input type="checkbox" id="runOcr" checked> Run OCR
384
+ </label>
385
+ <label class="checkbox-label">
386
+ <input type="checkbox" id="runForensics" checked> Visual Forensics
387
+ </label>
388
+ <label class="checkbox-label">
389
+ <input type="checkbox" id="runQr" checked> QR / Barcode
390
+ </label>
391
+ <label class="checkbox-label">
392
+ <input type="checkbox" id="runLiveQr"> Live QR Check
393
+ </label>
394
+ <label class="checkbox-label">
395
+ <input type="checkbox" id="runLlm" checked> DeepSeek LLM
396
+ </label>
397
+ </div>
398
+
399
+ <button id="submitBtn" onclick="submitRequest()">
400
+ <div class="spinner" id="spinner"></div>
401
+ <span id="btnText">Analyze Document</span>
402
+ </button>
403
+ </div>
404
+
405
+ <!-- Result Card -->
406
+ <div class="card result-card">
407
+ <div class="status-bar">
408
+ <div id="statusBadge" class="status-badge status-idle">Ready</div>
409
+ <div id="timeBadge" class="time-badge">0ms</div>
410
+ </div>
411
+
412
+ <div class="json-viewer" id="jsonOutput">Waiting for submission...</div>
413
+ </div>
414
+ </div>
415
+
416
+ <script>
417
+ // Preset endpoints
418
+ const endpoints = {
419
+ 'hf': 'https://jaykay73-bitcheck-document.hf.space/verify/document',
420
+ 'local': 'http://localhost:7860/verify/document'
421
+ };
422
+
423
+ function setEndpoint(type) {
424
+ document.getElementById('apiUrl').value = endpoints[type];
425
+ document.getElementById('btn-hf').classList.toggle('active', type === 'hf');
426
+ document.getElementById('btn-local').classList.toggle('active', type === 'local');
427
+ }
428
+
429
+ // File handling
430
+ const fileInput = document.getElementById('fileInput');
431
+ const fileNameDisplay = document.getElementById('fileName');
432
+ const dropZone = document.getElementById('dropZone');
433
+
434
+ fileInput.addEventListener('change', (e) => {
435
+ if (e.target.files.length > 0) {
436
+ fileNameDisplay.textContent = e.target.files[0].name;
437
+ } else {
438
+ fileNameDisplay.textContent = 'No file selected';
439
+ }
440
+ });
441
+
442
+ // Drag and drop effects
443
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
444
+ dropZone.addEventListener(eventName, preventDefaults, false);
445
+ });
446
+
447
+ function preventDefaults(e) {
448
+ e.preventDefault();
449
+ e.stopPropagation();
450
+ }
451
+
452
+ ['dragenter', 'dragover'].forEach(eventName => {
453
+ dropZone.addEventListener(eventName, () => dropZone.classList.add('dragover'), false);
454
+ });
455
+
456
+ ['dragleave', 'drop'].forEach(eventName => {
457
+ dropZone.addEventListener(eventName, () => dropZone.classList.remove('dragover'), false);
458
+ });
459
+
460
+ dropZone.addEventListener('drop', (e) => {
461
+ let dt = e.dataTransfer;
462
+ let files = dt.files;
463
+ fileInput.files = files;
464
+ if(files.length > 0) {
465
+ fileNameDisplay.textContent = files[0].name;
466
+ }
467
+ });
468
+
469
+ // JSON syntax highlighting
470
+ function syntaxHighlight(json) {
471
+ if (typeof json != 'string') {
472
+ json = JSON.stringify(json, undefined, 2);
473
+ }
474
+ json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
475
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
476
+ var cls = 'number';
477
+ if (/^"/.test(match)) {
478
+ if (/:$/.test(match)) {
479
+ cls = 'key';
480
+ } else {
481
+ cls = 'string';
482
+ }
483
+ } else if (/true|false/.test(match)) {
484
+ cls = 'boolean';
485
+ } else if (/null/.test(match)) {
486
+ cls = 'null';
487
+ }
488
+ return '<span class="' + cls + '">' + match + '</span>';
489
+ });
490
+ }
491
+
492
+ async function submitRequest() {
493
+ const url = document.getElementById('apiUrl').value;
494
+ const file = fileInput.files[0];
495
+ const output = document.getElementById('jsonOutput');
496
+ const statusBadge = document.getElementById('statusBadge');
497
+ const timeBadge = document.getElementById('timeBadge');
498
+ const btn = document.getElementById('submitBtn');
499
+ const btnText = document.getElementById('btnText');
500
+ const spinner = document.getElementById('spinner');
501
+
502
+ if (!file) {
503
+ alert('Please select a file to upload.');
504
+ return;
505
+ }
506
+
507
+ // Setup form data
508
+ const formData = new FormData();
509
+ formData.append('file', file);
510
+ formData.append('document_type', document.getElementById('docType').value);
511
+ formData.append('max_pages', document.getElementById('maxPages').value);
512
+ formData.append('run_ocr', document.getElementById('runOcr').checked);
513
+ formData.append('run_forensics', document.getElementById('runForensics').checked);
514
+ formData.append('run_qr', document.getElementById('runQr').checked);
515
+ formData.append('run_live_qr_check', document.getElementById('runLiveQr').checked);
516
+ formData.append('run_llm_analysis', document.getElementById('runLlm').checked);
517
+
518
+ // Update UI state
519
+ btn.disabled = true;
520
+ btnText.textContent = 'Analyzing...';
521
+ spinner.style.display = 'block';
522
+ output.innerHTML = 'Sending request...';
523
+ statusBadge.className = 'status-badge status-idle';
524
+ statusBadge.textContent = 'Processing';
525
+ timeBadge.textContent = '...';
526
+
527
+ const startTime = performance.now();
528
+
529
+ try {
530
+ const response = await fetch(url, {
531
+ method: 'POST',
532
+ body: formData,
533
+ headers: {
534
+ 'Accept': 'application/json'
535
+ }
536
+ });
537
+
538
+ const data = await response.json();
539
+ const endTime = performance.now();
540
+ const duration = Math.round(endTime - startTime);
541
+
542
+ output.innerHTML = syntaxHighlight(data);
543
+ timeBadge.textContent = `${duration}ms`;
544
+
545
+ if (response.ok) {
546
+ if (data.status === 'completed_with_warnings') {
547
+ statusBadge.className = 'status-badge status-warning';
548
+ statusBadge.textContent = 'Warnings';
549
+ } else {
550
+ statusBadge.className = 'status-badge status-success';
551
+ statusBadge.textContent = 'Success';
552
+ }
553
+ } else {
554
+ statusBadge.className = 'status-badge status-error';
555
+ statusBadge.textContent = `HTTP ${response.status}`;
556
+ }
557
+ } catch (error) {
558
+ const endTime = performance.now();
559
+ timeBadge.textContent = `${Math.round(endTime - startTime)}ms`;
560
+ output.innerHTML = `<span style="color:#ef4444;">Error: ${error.message}</span>\n\nMake sure the API is running and CORS is configured if calling cross-origin.`;
561
+ statusBadge.className = 'status-badge status-error';
562
+ statusBadge.textContent = 'Failed';
563
+ } finally {
564
+ btn.disabled = false;
565
+ btnText.textContent = 'Analyze Document';
566
+ spinner.style.display = 'none';
567
+ }
568
+ }
569
+ </script>
570
+ </body>
571
+ </html>
tests/__init__.py CHANGED
File without changes
tests/test_api_smoke.py CHANGED
File without changes
tests/test_content_risk_analyzer.py CHANGED
File without changes
tests/test_deepseek_llm.py CHANGED
File without changes
tests/test_field_extractor.py CHANGED
File without changes
tests/test_file_validator.py CHANGED
File without changes
tests/test_forensic_analyzer.py CHANGED
File without changes
tests/test_live_qr_verifier.py CHANGED
File without changes
tests/test_metadata_analyzer.py CHANGED
File without changes
tests/test_processors.py CHANGED
File without changes
tests/test_source_url_analyzer.py CHANGED
File without changes
tests/test_text_consistency.py CHANGED
File without changes
tests/test_trust_scorer.py CHANGED
File without changes