aankitdas commited on
Commit
1489d3a
Β·
1 Parent(s): 3f422d6

fix: double upload prompt

Browse files
Files changed (2) hide show
  1. frontend/index.html +288 -114
  2. src/main.py +1 -1
frontend/index.html CHANGED
@@ -6,104 +6,158 @@
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
  <title>Document Intelligence RAG</title>
8
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  * {
10
  margin: 0;
11
  padding: 0;
12
  box-sizing: border-box;
13
  }
14
 
 
 
 
15
  body {
16
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
17
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
18
  min-height: 100vh;
19
- padding: 20px;
 
20
  }
21
 
 
 
 
22
  .container {
23
- max-width: 1000px;
24
  margin: 0 auto;
25
  }
26
 
 
 
 
27
  header {
28
  text-align: center;
29
- color: white;
30
- margin-bottom: 40px;
31
  }
32
 
33
  header h1 {
34
- font-size: 2.5em;
35
- margin-bottom: 10px;
36
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
 
37
  }
38
 
39
  header p {
40
- font-size: 1.1em;
41
- opacity: 0.9;
42
  }
43
 
 
 
 
44
  .main-grid {
45
  display: grid;
46
  grid-template-columns: 1fr 1fr;
47
- gap: 20px;
48
- margin-bottom: 20px;
49
  }
50
 
 
 
 
51
  .card {
52
- background: white;
53
- border-radius: 12px;
54
- padding: 25px;
55
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
 
56
  }
57
 
58
  .card h2 {
59
- color: #333;
60
- margin-bottom: 15px;
61
- font-size: 1.3em;
62
  }
63
 
 
 
 
64
  .upload-area {
65
- border: 2px dashed #667eea;
66
- border-radius: 8px;
67
- padding: 30px;
68
  text-align: center;
69
  cursor: pointer;
70
- transition: all 0.3s;
 
71
  }
72
 
73
  .upload-area:hover {
74
- border-color: #764ba2;
75
- background: #f8f9ff;
76
  }
77
 
78
  .upload-area.dragover {
79
- border-color: #764ba2;
80
- background: #f0f2ff;
81
  }
82
 
83
- .upload-area input {
84
- display: none;
 
85
  }
86
 
87
- .upload-area p {
88
- color: #666;
89
- margin-bottom: 10px;
90
  }
91
 
 
 
 
92
  .btn {
93
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
94
  color: white;
95
  border: none;
96
- padding: 12px 24px;
97
- border-radius: 8px;
 
 
98
  cursor: pointer;
99
- font-size: 1em;
100
- font-weight: 600;
101
- transition: transform 0.2s, box-shadow 0.2s;
102
  }
103
 
104
  .btn:hover {
105
- transform: translateY(-2px);
106
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
 
107
  }
108
 
109
  .btn:active {
@@ -111,177 +165,219 @@
111
  }
112
 
113
  .btn-secondary {
114
- background: #f0f0f0;
115
- color: #333;
116
  }
117
 
118
  .btn-secondary:hover {
119
- background: #e0e0e0;
120
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
121
  }
122
 
 
 
 
123
  .query-input {
124
  display: flex;
125
- gap: 10px;
126
  margin-bottom: 20px;
127
  }
128
 
129
  .query-input input {
130
  flex: 1;
131
- padding: 12px;
132
- border: 2px solid #e0e0e0;
133
- border-radius: 8px;
134
- font-size: 1em;
135
- transition: border-color 0.3s;
136
  }
137
 
138
  .query-input input:focus {
139
  outline: none;
140
- border-color: #667eea;
 
141
  }
142
 
 
 
 
143
  .status {
144
- padding: 15px;
145
- border-radius: 8px;
146
- margin-bottom: 15px;
147
- font-size: 0.95em;
148
  }
149
 
150
  .status.success {
151
- background: #d4edda;
152
- color: #155724;
153
- border-left: 4px solid #28a745;
154
  }
155
 
156
  .status.error {
157
- background: #f8d7da;
158
- color: #721c24;
159
- border-left: 4px solid #f5c6cb;
160
  }
161
 
162
  .status.loading {
163
- background: #e7f3ff;
164
- color: #004085;
165
- border-left: 4px solid #0c5ff4;
166
  }
167
 
 
 
 
168
  .answer-box {
169
- background: #f8f9fa;
170
- border-left: 4px solid #667eea;
171
- padding: 15px;
172
- border-radius: 8px;
173
  margin-bottom: 20px;
174
  }
175
 
176
  .answer-box h3 {
177
- color: #333;
178
- margin-bottom: 10px;
 
179
  }
180
 
181
  .answer-box p {
182
- color: #555;
183
  line-height: 1.6;
184
- margin-bottom: 15px;
185
  }
186
 
 
 
 
 
 
 
 
 
187
  .sources {
188
- background: white;
189
- border-radius: 8px;
190
- padding: 15px;
191
- margin-bottom: 15px;
192
  }
193
 
194
  .sources h4 {
195
- color: #333;
196
  margin-bottom: 12px;
197
- font-size: 0.95em;
198
  }
199
 
200
  .source-item {
201
- padding: 10px;
202
- background: #f8f9fa;
203
- border-radius: 6px;
204
- margin-bottom: 8px;
205
- border-left: 3px solid #667eea;
206
- font-size: 0.9em;
207
  }
208
 
209
  .source-item .relevance {
210
- color: #667eea;
211
  font-weight: 600;
212
- margin-bottom: 5px;
 
213
  }
214
 
215
  .source-item .text {
216
- color: #555;
 
217
  font-style: italic;
218
  }
219
 
 
 
 
220
  .stats {
221
  display: grid;
222
  grid-template-columns: repeat(2, 1fr);
223
- gap: 10px;
224
  margin-bottom: 20px;
225
  }
226
 
227
  .stat-box {
228
- background: #f8f9fa;
229
- padding: 12px;
230
- border-radius: 6px;
231
  text-align: center;
 
232
  }
233
 
234
  .stat-box .number {
235
- font-size: 1.5em;
236
- font-weight: bold;
237
- color: #667eea;
238
  }
239
 
240
  .stat-box .label {
241
- font-size: 0.85em;
242
- color: #666;
243
- margin-top: 5px;
244
  }
245
 
 
 
 
246
  .status-grid {
247
  display: grid;
248
  grid-template-columns: repeat(4, 1fr);
249
- gap: 10px;
250
  }
251
 
 
 
 
252
  .loading-spinner {
253
  display: inline-block;
254
- width: 20px;
255
- height: 20px;
256
- border: 3px solid #f3f3f3;
257
- border-top: 3px solid #667eea;
258
  border-radius: 50%;
259
  animation: spin 1s linear infinite;
260
- margin-right: 10px;
261
  vertical-align: middle;
262
  }
263
 
264
  @keyframes spin {
265
- 0% {
266
- transform: rotate(0deg);
267
- }
268
-
269
- 100% {
270
  transform: rotate(360deg);
271
  }
272
  }
273
 
 
 
 
274
  .full-width {
275
  grid-column: 1 / -1;
276
  }
277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  @media (max-width: 768px) {
279
  .main-grid {
280
  grid-template-columns: 1fr;
281
  }
282
 
283
  header h1 {
284
- font-size: 1.8em;
285
  }
286
 
287
  .stats {
@@ -293,10 +389,39 @@
293
  }
294
  }
295
 
296
- .hidden {
297
- display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  }
299
  </style>
 
300
  </head>
301
 
302
  <body>
@@ -304,6 +429,21 @@
304
  <header>
305
  <h1>πŸ“š Document Intelligence RAG</h1>
306
  <p>Ask questions about your research papers</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  </header>
308
 
309
  <div class="main-grid">
@@ -351,7 +491,7 @@
351
  <h2>❓ Ask Questions</h2>
352
 
353
  <div class="query-input">
354
- <input type="text" id="queryInput" placeholder="What would you like to know about your documents?"
355
  onkeypress="if(event.key==='Enter') submitQuery()">
356
  <button class="btn" onclick="submitQuery()">Search</button>
357
  </div>
@@ -386,7 +526,7 @@
386
  const uploadArea = document.getElementById('uploadArea');
387
  const fileInput = document.getElementById('fileInput');
388
 
389
- uploadArea.addEventListener('click', () => fileInput.click());
390
  uploadArea.addEventListener('dragover', (e) => {
391
  e.preventDefault();
392
  uploadArea.classList.add('dragover');
@@ -586,6 +726,40 @@
586
  loadHealth();
587
  setInterval(loadHealth, 30000); // Refresh every 30s
588
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  </script>
590
  </body>
591
 
 
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
  <title>Document Intelligence RAG</title>
8
  <style>
9
+ /* -----------------------------
10
+ Design tokens (neutral)
11
+ ------------------------------*/
12
+ :root {
13
+ --surface: #ffffff;
14
+ --surface-subtle: #fafafa;
15
+ --bg-main: #f5f7fb;
16
+ --card-bg: #ffffff;
17
+ --accent: #2563eb;
18
+ /* calm blue */
19
+ --accent-soft: #eff6ff;
20
+ --text-main: #111827;
21
+ --text-muted: #6b7280;
22
+ --border-soft: #e5e7eb;
23
+
24
+ --success: #16a34a;
25
+ --error: #dc2626;
26
+ --info: #2563eb;
27
+
28
+ --radius-sm: 6px;
29
+ --radius-md: 10px;
30
+ --radius-lg: 14px;
31
+ }
32
+
33
+ /* -----------------------------
34
+ Reset
35
+ ------------------------------*/
36
  * {
37
  margin: 0;
38
  padding: 0;
39
  box-sizing: border-box;
40
  }
41
 
42
+ /* -----------------------------
43
+ Base
44
+ ------------------------------*/
45
  body {
46
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI",
47
+ Roboto, Helvetica, Arial, sans-serif;
48
+ background: var(--bg-main);
49
  min-height: 100vh;
50
+ padding: 24px;
51
+ color: var(--text-main);
52
  }
53
 
54
+ /* -----------------------------
55
+ Container
56
+ ------------------------------*/
57
  .container {
58
+ max-width: 1040px;
59
  margin: 0 auto;
60
  }
61
 
62
+ /* -----------------------------
63
+ Header
64
+ ------------------------------*/
65
  header {
66
  text-align: center;
67
+ margin-bottom: 48px;
 
68
  }
69
 
70
  header h1 {
71
+ font-size: 2.2rem;
72
+ font-weight: 600;
73
+ letter-spacing: -0.02em;
74
+ margin-bottom: 8px;
75
  }
76
 
77
  header p {
78
+ font-size: 1rem;
79
+ color: var(--text-muted);
80
  }
81
 
82
+ /* -----------------------------
83
+ Layout
84
+ ------------------------------*/
85
  .main-grid {
86
  display: grid;
87
  grid-template-columns: 1fr 1fr;
88
+ gap: 24px;
89
+ margin-bottom: 24px;
90
  }
91
 
92
+ /* -----------------------------
93
+ Cards
94
+ ------------------------------*/
95
  .card {
96
+ background: var(--surface);
97
+ border-radius: var(--radius-lg);
98
+ padding: 28px;
99
+ border: 1px solid var(--border-soft);
100
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.05);
101
  }
102
 
103
  .card h2 {
104
+ font-size: 1.2rem;
105
+ font-weight: 600;
106
+ margin-bottom: 18px;
107
  }
108
 
109
+ /* -----------------------------
110
+ Upload area
111
+ ------------------------------*/
112
  .upload-area {
113
+ border: 2px dashed var(--border-soft);
114
+ border-radius: var(--radius-md);
115
+ padding: 40px 24px;
116
  text-align: center;
117
  cursor: pointer;
118
+ background: var(--surface-subtle);
119
+ transition: border-color 0.2s ease, background 0.2s ease;
120
  }
121
 
122
  .upload-area:hover {
123
+ border-color: var(--accent);
124
+ background: var(--accent-soft);
125
  }
126
 
127
  .upload-area.dragover {
128
+ border-color: var(--accent);
129
+ background: var(--accent-soft);
130
  }
131
 
132
+ .upload-area p {
133
+ color: var(--text-muted);
134
+ margin-bottom: 14px;
135
  }
136
 
137
+ .upload-area input {
138
+ display: none;
 
139
  }
140
 
141
+ /* -----------------------------
142
+ Buttons
143
+ ------------------------------*/
144
  .btn {
145
+ background: var(--accent);
146
  color: white;
147
  border: none;
148
+ padding: 11px 20px;
149
+ border-radius: var(--radius-md);
150
+ font-size: 0.9rem;
151
+ font-weight: 500;
152
  cursor: pointer;
153
+ transition: background 0.15s ease, transform 0.15s ease,
154
+ box-shadow 0.15s ease;
 
155
  }
156
 
157
  .btn:hover {
158
+ background: #1d4ed8;
159
+ transform: translateY(-1px);
160
+ box-shadow: 0 6px 16px rgba(37, 99, 235, 0.25);
161
  }
162
 
163
  .btn:active {
 
165
  }
166
 
167
  .btn-secondary {
168
+ background: #f3f4f6;
169
+ color: #374151;
170
  }
171
 
172
  .btn-secondary:hover {
173
+ background: #e5e7eb;
174
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
175
  }
176
 
177
+ /* -----------------------------
178
+ Query input
179
+ ------------------------------*/
180
  .query-input {
181
  display: flex;
182
+ gap: 12px;
183
  margin-bottom: 20px;
184
  }
185
 
186
  .query-input input {
187
  flex: 1;
188
+ padding: 12px 14px;
189
+ border: 1.5px solid var(--border-soft);
190
+ border-radius: var(--radius-md);
191
+ font-size: 0.9rem;
 
192
  }
193
 
194
  .query-input input:focus {
195
  outline: none;
196
+ border-color: var(--accent);
197
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
198
  }
199
 
200
+ /* -----------------------------
201
+ Status messages
202
+ ------------------------------*/
203
  .status {
204
+ padding: 14px 16px;
205
+ border-radius: var(--radius-md);
206
+ margin-bottom: 16px;
207
+ font-size: 0.9rem;
208
  }
209
 
210
  .status.success {
211
+ background: #ecfdf3;
212
+ color: var(--success);
213
+ border-left: 4px solid var(--success);
214
  }
215
 
216
  .status.error {
217
+ background: #fef2f2;
218
+ color: var(--error);
219
+ border-left: 4px solid var(--error);
220
  }
221
 
222
  .status.loading {
223
+ background: #eff6ff;
224
+ color: var(--info);
225
+ border-left: 4px solid var(--info);
226
  }
227
 
228
+ /* -----------------------------
229
+ Answer
230
+ ------------------------------*/
231
  .answer-box {
232
+ background: var(--card-bg);
233
+ border-left: 4px solid var(--accent);
234
+ padding: 18px;
235
+ border-radius: var(--radius-md);
236
  margin-bottom: 20px;
237
  }
238
 
239
  .answer-box h3 {
240
+ font-size: 1rem;
241
+ margin-bottom: 8px;
242
+ color: var(--text-main);
243
  }
244
 
245
  .answer-box p {
246
+ color: var(--text-main);
247
  line-height: 1.6;
 
248
  }
249
 
250
+ [data-theme="dark"] .answer-box {
251
+ background: #020617;
252
+ /* slightly darker than cards */
253
+ }
254
+
255
+ /* -----------------------------
256
+ Sources
257
+ ------------------------------*/
258
  .sources {
259
+ background: var(--surface);
260
+ border-radius: var(--radius-md);
261
+ padding: 16px;
262
+ border: 1px solid var(--border-soft);
263
  }
264
 
265
  .sources h4 {
266
+ font-size: 0.85rem;
267
  margin-bottom: 12px;
268
+ color: var(--text-muted);
269
  }
270
 
271
  .source-item {
272
+ background: var(--surface-subtle);
273
+ border-radius: var(--radius-sm);
274
+ padding: 12px;
275
+ margin-bottom: 10px;
276
+ border-left: 3px solid var(--accent);
 
277
  }
278
 
279
  .source-item .relevance {
280
+ font-size: 0.8rem;
281
  font-weight: 600;
282
+ color: var(--accent);
283
+ margin-bottom: 6px;
284
  }
285
 
286
  .source-item .text {
287
+ font-size: 0.85rem;
288
+ color: var(--text-muted);
289
  font-style: italic;
290
  }
291
 
292
+ /* -----------------------------
293
+ Stats
294
+ ------------------------------*/
295
  .stats {
296
  display: grid;
297
  grid-template-columns: repeat(2, 1fr);
298
+ gap: 12px;
299
  margin-bottom: 20px;
300
  }
301
 
302
  .stat-box {
303
+ background: var(--surface-subtle);
304
+ padding: 14px;
305
+ border-radius: var(--radius-md);
306
  text-align: center;
307
+ border: 1px solid var(--border-soft);
308
  }
309
 
310
  .stat-box .number {
311
+ font-size: 1.4rem;
312
+ font-weight: 600;
313
+ color: var(--accent);
314
  }
315
 
316
  .stat-box .label {
317
+ font-size: 0.75rem;
318
+ color: var(--text-muted);
319
+ margin-top: 6px;
320
  }
321
 
322
+ /* -----------------------------
323
+ System status grid
324
+ ------------------------------*/
325
  .status-grid {
326
  display: grid;
327
  grid-template-columns: repeat(4, 1fr);
328
+ gap: 12px;
329
  }
330
 
331
+ /* -----------------------------
332
+ Spinner
333
+ ------------------------------*/
334
  .loading-spinner {
335
  display: inline-block;
336
+ width: 18px;
337
+ height: 18px;
338
+ border: 3px solid #e5e7eb;
339
+ border-top: 3px solid var(--accent);
340
  border-radius: 50%;
341
  animation: spin 1s linear infinite;
342
+ margin-right: 8px;
343
  vertical-align: middle;
344
  }
345
 
346
  @keyframes spin {
347
+ to {
 
 
 
 
348
  transform: rotate(360deg);
349
  }
350
  }
351
 
352
+ /* -----------------------------
353
+ Utilities
354
+ ------------------------------*/
355
  .full-width {
356
  grid-column: 1 / -1;
357
  }
358
 
359
+ .upload-area,
360
+ .stat-box,
361
+ .sources,
362
+ .source-item,
363
+ .card {
364
+ border-color: var(--border-soft);
365
+ }
366
+
367
+ .hidden {
368
+ display: none;
369
+ }
370
+
371
+ /* -----------------------------
372
+ Responsive
373
+ ------------------------------*/
374
  @media (max-width: 768px) {
375
  .main-grid {
376
  grid-template-columns: 1fr;
377
  }
378
 
379
  header h1 {
380
+ font-size: 1.7rem;
381
  }
382
 
383
  .stats {
 
389
  }
390
  }
391
 
392
+ [data-theme="dark"] {
393
+ --bg-main: #0f172a;
394
+ --card-bg: #020617;
395
+ --accent: #60a5fa;
396
+ --accent-soft: #0b1b33;
397
+
398
+ --text-main: #e5e7eb;
399
+ --text-muted: #9ca3af;
400
+ --border-soft: #1f2937;
401
+
402
+ --success: #22c55e;
403
+ --error: #f87171;
404
+ --info: #60a5fa;
405
+ --surface: #020617;
406
+ --surface-subtle: #020617;
407
+ }
408
+
409
+ /* smoother transitions */
410
+ body,
411
+ .card,
412
+ .upload-area,
413
+ .btn,
414
+ input,
415
+ .status,
416
+ .answer-box,
417
+ .sources,
418
+ .stat-box {
419
+ transition: background-color 0.25s ease,
420
+ color 0.25s ease,
421
+ border-color 0.25s ease;
422
  }
423
  </style>
424
+
425
  </head>
426
 
427
  <body>
 
429
  <header>
430
  <h1>πŸ“š Document Intelligence RAG</h1>
431
  <p>Ask questions about your research papers</p>
432
+ <button id="themeToggle" aria-label="Toggle dark mode" style="
433
+ position: fixed;
434
+ top: 16px;
435
+ right: 20px;
436
+ background: none;
437
+ border: none;
438
+ padding: 6px;
439
+ font-size: 0.9rem;
440
+ cursor: pointer;
441
+ color: #6b7280;
442
+ ">
443
+ πŸŒ™ Dark
444
+ </button>
445
+
446
+ </button>
447
  </header>
448
 
449
  <div class="main-grid">
 
491
  <h2>❓ Ask Questions</h2>
492
 
493
  <div class="query-input">
494
+ <input type="text" id="queryInput" placeholder="Ask about your documents?"
495
  onkeypress="if(event.key==='Enter') submitQuery()">
496
  <button class="btn" onclick="submitQuery()">Search</button>
497
  </div>
 
526
  const uploadArea = document.getElementById('uploadArea');
527
  const fileInput = document.getElementById('fileInput');
528
 
529
+ // uploadArea.addEventListener('click', () => fileInput.click());
530
  uploadArea.addEventListener('dragover', (e) => {
531
  e.preventDefault();
532
  uploadArea.classList.add('dragover');
 
726
  loadHealth();
727
  setInterval(loadHealth, 30000); // Refresh every 30s
728
  });
729
+
730
+ // -----------------------------
731
+ // Dark mode toggle
732
+ // -----------------------------
733
+ const themeToggle = document.getElementById("themeToggle");
734
+ const root = document.documentElement;
735
+
736
+ // Load saved theme or system preference
737
+ const savedTheme = localStorage.getItem("theme");
738
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
739
+
740
+ if (savedTheme) {
741
+ root.setAttribute("data-theme", savedTheme);
742
+ } else if (prefersDark) {
743
+ root.setAttribute("data-theme", "dark");
744
+ }
745
+
746
+ // Update button text
747
+ function updateToggleText() {
748
+ const isDark = root.getAttribute("data-theme") === "dark";
749
+ themeToggle.textContent = isDark ? "β˜€οΈ Light mode" : "πŸŒ™ Dark mode";
750
+ }
751
+ updateToggleText();
752
+
753
+ // Toggle on click
754
+ themeToggle.addEventListener("click", () => {
755
+ const isDark = root.getAttribute("data-theme") === "dark";
756
+ const newTheme = isDark ? "light" : "dark";
757
+
758
+ root.setAttribute("data-theme", newTheme);
759
+ localStorage.setItem("theme", newTheme);
760
+ updateToggleText();
761
+ });
762
+
763
  </script>
764
  </body>
765
 
src/main.py CHANGED
@@ -329,7 +329,7 @@ async def query(request: QueryRequest):
329
  if pipeline.vector_store.size() == 0:
330
  raise HTTPException(
331
  status_code=400,
332
- detail="No documents ingested yet. Use /ingest endpoint first."
333
  )
334
 
335
  try:
 
329
  if pipeline.vector_store.size() == 0:
330
  raise HTTPException(
331
  status_code=400,
332
+ detail="No documents ingested yet. Upload documents first."
333
  )
334
 
335
  try: