absiitr commited on
Commit
eaf959e
Β·
verified Β·
1 Parent(s): 0eb63e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +241 -115
app.py CHANGED
@@ -32,7 +32,7 @@ else:
32
  # ---------------- STREAMLIT UI SETUP ----------------
33
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
34
 
35
- # ---------------- CSS (Updated with scroll container) ----------------
36
  st.markdown("""
37
  <style>
38
  :root {
@@ -42,92 +42,205 @@ st.markdown("""
42
  --text-color: #f0f2f6;
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  .chat-user {
46
  background: #2d3748;
47
- padding: 12px;
48
- border-radius: 10px 10px 2px 10px;
49
- margin: 10px 0 10px auto;
50
  max-width: 85%;
51
  text-align: left;
52
  color: var(--text-color);
53
  word-wrap: break-word;
 
54
  }
 
55
  .chat-bot {
56
  background: var(--primary-color);
57
- padding: 12px;
58
- border-radius: 10px 10px 10px 2px;
59
- margin: 10px auto 10px 0;
60
  max-width: 85%;
61
  text-align: left;
62
  color: #ffffff;
63
  word-wrap: break-word;
 
64
  }
65
 
66
  .sources {
67
  font-size: 0.8em;
68
  opacity: 0.7;
69
- margin-top: 10px;
70
  border-top: 1px solid rgba(255, 255, 255, 0.1);
71
- padding-top: 5px;
72
  }
73
 
74
- .footer {
75
- margin-top: 30px;
76
- padding: 15px;
77
- background-color: var(--secondary-background-color);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  color: var(--text-color);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  text-align: center;
 
80
  font-size: 0.85em;
81
- border-top: 1px solid rgba(255, 255, 255, 0.1);
82
  }
 
83
  .footer a {
84
  color: var(--primary-color);
85
  text-decoration: none;
86
  font-weight: bold;
87
  }
 
88
  .footer a:hover {
89
  text-decoration: underline;
90
  }
91
 
92
- /* Main container to control layout */
93
- .main-container {
94
- display: flex;
95
- flex-direction: column;
96
- height: 100vh;
97
  }
98
 
99
- /* Chat container that grows and scrolls */
100
- .chat-container {
101
- flex: 1;
102
- overflow-y: auto;
103
- padding: 15px;
104
- margin-bottom: 20px;
105
- border: 1px solid rgba(255, 255, 255, 0.1);
106
- border-radius: 8px;
107
- background-color: rgba(30, 30, 30, 0.05);
108
  }
109
 
110
- /* Input area stays at bottom */
111
- .input-container {
112
- position: sticky;
113
- bottom: 0;
114
- background: var(--background-color);
115
- padding: 15px 0;
116
- border-top: 1px solid rgba(255, 255, 255, 0.1);
117
- z-index: 100;
118
  }
119
 
120
- /* Empty state styling */
121
- .empty-state {
122
- text-align: center;
123
- color: #888;
124
- padding: 60px 20px;
125
- font-style: italic;
126
- }
127
-
128
- /* Smooth scrolling */
129
- .chat-container {
130
- scroll-behavior: smooth;
131
  }
132
  </style>
133
  """, unsafe_allow_html=True)
@@ -257,54 +370,55 @@ FINAL ANSWER:
257
  except Exception as e:
258
  return None, 0, f"General error: {str(e)}"
259
 
260
- # ---------------- UI COMPONENTS ----------------
261
- st.title("πŸ“˜ PDF Assistant")
262
 
263
- # Sidebar Controls
264
  with st.sidebar:
265
- st.header("Controls")
 
266
  st.button("πŸ—‘οΈ Clear Chat History", on_click=clear_chat_history, use_container_width=True)
267
  st.button("πŸ”₯ Clear PDF Memory", on_click=clear_memory, use_container_width=True)
268
 
269
  st.markdown("---")
270
- if st.session_state.uploaded_file_name:
271
- st.success(f"βœ… **Active PDF:**\n `{st.session_state.uploaded_file_name}`")
272
- else:
273
- st.warning("⬆️ Upload a PDF to start chatting!")
274
-
275
- # File Upload
276
- uploaded = st.file_uploader(
277
- "Upload your PDF",
278
- type=["pdf"],
279
- key=st.session_state.uploader_key
280
- )
281
-
282
- if uploaded and uploaded.name != st.session_state.uploaded_file_name:
283
- st.session_state.uploaded_file_name = None
284
- st.session_state.chat = []
285
- st.session_state.last_message_count = 0
286
 
287
- with st.spinner(f"Processing '{uploaded.name}'..."):
288
- chunks_count = process_pdf(uploaded)
 
 
289
 
290
- if chunks_count is not None:
291
- st.success(f"βœ… PDF processed successfully! {chunks_count} chunks created.")
292
- st.session_state.uploaded_file_name = uploaded.name
293
- else:
294
- st.error("❌ Failed to process PDF")
295
- st.session_state.uploaded_file_name = None
 
 
 
 
 
296
 
297
- st.rerun()
 
 
 
 
298
 
299
- # Main chat interface
300
- st.markdown('<div class="main-container">', unsafe_allow_html=True)
301
 
302
- # Chat History Display
303
- st.markdown("## Chat History")
304
- st.markdown('<div class="chat-container" id="chat-container">', unsafe_allow_html=True)
305
 
306
  if not st.session_state.chat:
307
- st.markdown('<div class="empty-state">No messages yet. Ask a question to start chatting!</div>', unsafe_allow_html=True)
308
  else:
309
  # Display all messages
310
  for i, (role, msg) in enumerate(st.session_state.chat):
@@ -313,31 +427,52 @@ else:
313
  else:
314
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
315
 
316
- st.markdown('</div>', unsafe_allow_html=True)
317
 
318
- # Input area at bottom (like ChatGPT)
319
- st.markdown('<div class="input-container">', unsafe_allow_html=True)
 
 
 
 
 
 
320
 
321
- # Chat Input with form for better control
 
 
 
 
 
 
 
322
  disabled_input = st.session_state.uploaded_file_name is None or client is None
323
 
324
- # Create a form for chat input
325
  with st.form(key="chat_form", clear_on_submit=True):
326
- col1, col2 = st.columns([6, 1])
327
  with col1:
328
  question = st.text_input(
329
- "Ask a question about the loaded PDF:",
330
  key="question_input",
331
  disabled=disabled_input,
332
  label_visibility="collapsed",
333
- placeholder="Type your question here...",
334
- help="Press Enter or click Send to ask"
335
  )
336
  with col2:
337
- submit_button = st.form_submit_button("➀", disabled=disabled_input, use_container_width=True, help="Send message")
 
 
 
 
 
338
 
339
- st.markdown('</div>', unsafe_allow_html=True) # Close input-container
340
- st.markdown('</div>', unsafe_allow_html=True) # Close main-container
 
 
 
341
 
342
  # Handle form submission
343
  if submit_button and question:
@@ -354,45 +489,36 @@ if submit_button and question:
354
  else:
355
  st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** {error}"))
356
 
357
- # Update message count
358
  st.session_state.last_message_count = len(st.session_state.chat)
359
  st.rerun()
360
 
361
- # Footer
362
- footer_html = """
363
- <div class="footer">
364
- Created by <a href="https://www.linkedin.com/in/abhishek-iitr/" target="_blank">Abhishek Saxena</a>
365
- </div>
366
- """
367
- st.markdown(footer_html, unsafe_allow_html=True)
368
-
369
- # AUTOSCROLL FIX: Check if new messages were added and trigger scroll
370
  if len(st.session_state.chat) > st.session_state.last_message_count:
371
- # Update the counter
372
  st.session_state.last_message_count = len(st.session_state.chat)
373
 
374
- # Inject JavaScript to scroll to bottom
375
  st.markdown("""
376
  <script>
377
- // Wait a tiny bit for DOM to update, then scroll
378
  setTimeout(() => {
379
- const chatContainer = document.getElementById('chat-container');
380
- if (chatContainer) {
381
- chatContainer.scrollTop = chatContainer.scrollHeight;
 
382
  }
383
  }, 100);
384
  </script>
385
  """, unsafe_allow_html=True)
386
  else:
387
- # Initial scroll on load
388
  st.markdown("""
389
  <script>
390
- // Initial scroll to bottom on page load
391
  document.addEventListener('DOMContentLoaded', function() {
392
  setTimeout(() => {
393
- const chatContainer = document.getElementById('chat-container');
394
- if (chatContainer) {
395
- chatContainer.scrollTop = chatContainer.scrollHeight;
396
  }
397
  }, 300);
398
  });
 
32
  # ---------------- STREAMLIT UI SETUP ----------------
33
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
34
 
35
+ # ---------------- CSS (ChatGPT/DeepSeek style) ----------------
36
  st.markdown("""
37
  <style>
38
  :root {
 
42
  --text-color: #f0f2f6;
43
  }
44
 
45
+ /* Reset Streamlit default padding */
46
+ .stApp {
47
+ padding-top: 0 !important;
48
+ }
49
+
50
+ /* Title at very top */
51
+ h1 {
52
+ margin-top: 0.5rem !important;
53
+ margin-bottom: 1rem !important;
54
+ padding-top: 0 !important;
55
+ }
56
+
57
+ /* Main container - everything above the fixed input */
58
+ .main-content {
59
+ position: fixed;
60
+ top: 0;
61
+ left: 300px; /* Account for sidebar width */
62
+ right: 0;
63
+ bottom: 120px; /* Leave space for fixed input */
64
+ overflow-y: auto;
65
+ padding: 0 2rem;
66
+ }
67
+
68
+ /* Adjust for when sidebar is collapsed */
69
+ @media (max-width: 768px) {
70
+ .main-content {
71
+ left: 0;
72
+ }
73
+ }
74
+
75
+ /* Chat messages container */
76
+ .chat-messages {
77
+ padding-bottom: 2rem;
78
+ max-width: 800px;
79
+ margin: 0 auto;
80
+ }
81
+
82
  .chat-user {
83
  background: #2d3748;
84
+ padding: 14px 18px;
85
+ border-radius: 18px 18px 4px 18px;
86
+ margin: 16px 0 16px auto;
87
  max-width: 85%;
88
  text-align: left;
89
  color: var(--text-color);
90
  word-wrap: break-word;
91
+ line-height: 1.5;
92
  }
93
+
94
  .chat-bot {
95
  background: var(--primary-color);
96
+ padding: 14px 18px;
97
+ border-radius: 18px 18px 18px 4px;
98
+ margin: 16px auto 16px 0;
99
  max-width: 85%;
100
  text-align: left;
101
  color: #ffffff;
102
  word-wrap: break-word;
103
+ line-height: 1.5;
104
  }
105
 
106
  .sources {
107
  font-size: 0.8em;
108
  opacity: 0.7;
109
+ margin-top: 12px;
110
  border-top: 1px solid rgba(255, 255, 255, 0.1);
111
+ padding-top: 8px;
112
  }
113
 
114
+ /* FIXED INPUT AREA AT BOTTOM - LIKE CHATGPT */
115
+ .fixed-input-area {
116
+ position: fixed;
117
+ bottom: 0;
118
+ left: 300px;
119
+ right: 0;
120
+ background: var(--background-color);
121
+ padding: 1.5rem 2rem;
122
+ border-top: 1px solid rgba(255, 255, 255, 0.15);
123
+ z-index: 1000;
124
+ backdrop-filter: blur(10px);
125
+ box-shadow: 0 -5px 20px rgba(0, 0, 0, 0.3);
126
+ }
127
+
128
+ @media (max-width: 768px) {
129
+ .fixed-input-area {
130
+ left: 0;
131
+ }
132
+ }
133
+
134
+ .input-container {
135
+ max-width: 800px;
136
+ margin: 0 auto;
137
+ position: relative;
138
+ }
139
+
140
+ .input-wrapper {
141
+ background: var(--secondary-background-color);
142
+ border: 1px solid rgba(255, 255, 255, 0.2);
143
+ border-radius: 24px;
144
+ padding: 4px;
145
+ display: flex;
146
+ align-items: center;
147
+ transition: all 0.3s ease;
148
+ }
149
+
150
+ .input-wrapper:focus-within {
151
+ border-color: var(--primary-color);
152
+ box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.3);
153
+ }
154
+
155
+ .chat-input {
156
+ flex: 1;
157
+ background: transparent;
158
+ border: none;
159
  color: var(--text-color);
160
+ padding: 12px 16px;
161
+ font-size: 1rem;
162
+ outline: none;
163
+ }
164
+
165
+ .chat-input::placeholder {
166
+ color: rgba(255, 255, 255, 0.5);
167
+ }
168
+
169
+ .send-button {
170
+ background: var(--primary-color);
171
+ color: white;
172
+ border: none;
173
+ border-radius: 50%;
174
+ width: 40px;
175
+ height: 40px;
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ cursor: pointer;
180
+ margin-right: 4px;
181
+ transition: all 0.2s ease;
182
+ }
183
+
184
+ .send-button:hover:not(:disabled) {
185
+ background: #2d4bb5;
186
+ transform: scale(1.05);
187
+ }
188
+
189
+ .send-button:disabled {
190
+ opacity: 0.5;
191
+ cursor: not-allowed;
192
+ }
193
+
194
+ /* Empty state */
195
+ .empty-state {
196
+ text-align: center;
197
+ color: #888;
198
+ padding: 100px 20px;
199
+ font-style: italic;
200
+ font-size: 1.2em;
201
+ }
202
+
203
+ /* Sidebar adjustments */
204
+ section[data-testid="stSidebar"] {
205
+ padding-top: 2rem;
206
+ }
207
+
208
+ /* Footer - positioned above input */
209
+ .footer {
210
+ margin-top: 2rem;
211
+ padding: 1rem;
212
  text-align: center;
213
+ color: var(--text-color);
214
  font-size: 0.85em;
215
+ opacity: 0.7;
216
  }
217
+
218
  .footer a {
219
  color: var(--primary-color);
220
  text-decoration: none;
221
  font-weight: bold;
222
  }
223
+
224
  .footer a:hover {
225
  text-decoration: underline;
226
  }
227
 
228
+ /* Scrollbar styling */
229
+ ::-webkit-scrollbar {
230
+ width: 8px;
 
 
231
  }
232
 
233
+ ::-webkit-scrollbar-track {
234
+ background: transparent;
 
 
 
 
 
 
 
235
  }
236
 
237
+ ::-webkit-scrollbar-thumb {
238
+ background: rgba(255, 255, 255, 0.2);
239
+ border-radius: 4px;
 
 
 
 
 
240
  }
241
 
242
+ ::-webkit-scrollbar-thumb:hover {
243
+ background: rgba(255, 255, 255, 0.3);
 
 
 
 
 
 
 
 
 
244
  }
245
  </style>
246
  """, unsafe_allow_html=True)
 
370
  except Exception as e:
371
  return None, 0, f"General error: {str(e)}"
372
 
373
+ # ---------------- MAIN LAYOUT ----------------
 
374
 
375
+ # Sidebar Controls - FIRST, so it appears on left
376
  with st.sidebar:
377
+ st.header("πŸ“˜ PDF Assistant")
378
+ st.markdown("---")
379
  st.button("πŸ—‘οΈ Clear Chat History", on_click=clear_chat_history, use_container_width=True)
380
  st.button("πŸ”₯ Clear PDF Memory", on_click=clear_memory, use_container_width=True)
381
 
382
  st.markdown("---")
383
+ st.subheader("PDF Upload")
384
+ uploaded = st.file_uploader(
385
+ "Choose a PDF file",
386
+ type=["pdf"],
387
+ key=st.session_state.uploader_key,
388
+ label_visibility="collapsed"
389
+ )
 
 
 
 
 
 
 
 
 
390
 
391
+ if uploaded and uploaded.name != st.session_state.uploaded_file_name:
392
+ st.session_state.uploaded_file_name = None
393
+ st.session_state.chat = []
394
+ st.session_state.last_message_count = 0
395
 
396
+ with st.spinner(f"Processing '{uploaded.name}'..."):
397
+ chunks_count = process_pdf(uploaded)
398
+
399
+ if chunks_count is not None:
400
+ st.success(f"βœ… PDF processed! {chunks_count} chunks created.")
401
+ st.session_state.uploaded_file_name = uploaded.name
402
+ else:
403
+ st.error("❌ Failed to process PDF")
404
+ st.session_state.uploaded_file_name = None
405
+
406
+ st.rerun()
407
 
408
+ st.markdown("---")
409
+ if st.session_state.uploaded_file_name:
410
+ st.success(f"**Active PDF:**\n`{st.session_state.uploaded_file_name}`")
411
+ else:
412
+ st.info("⬆️ Upload a PDF to start chatting!")
413
 
414
+ # Main content area (chat messages)
415
+ st.markdown('<div class="main-content">', unsafe_allow_html=True)
416
 
417
+ # Chat messages
418
+ st.markdown('<div class="chat-messages" id="chat-messages">', unsafe_allow_html=True)
 
419
 
420
  if not st.session_state.chat:
421
+ st.markdown('<div class="empty-state">Ask a question about your PDF to start the conversation!</div>', unsafe_allow_html=True)
422
  else:
423
  # Display all messages
424
  for i, (role, msg) in enumerate(st.session_state.chat):
 
427
  else:
428
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
429
 
430
+ st.markdown('</div>', unsafe_allow_html=True) # Close chat-messages
431
 
432
+ # Footer above input
433
+ st.markdown("""
434
+ <div class="footer">
435
+ Created by <a href="https://www.linkedin.com/in/abhishek-iitr/" target="_blank">Abhishek Saxena</a>
436
+ </div>
437
+ """, unsafe_allow_html=True)
438
+
439
+ st.markdown('</div>', unsafe_allow_html=True) # Close main-content
440
 
441
+ # FIXED INPUT AREA AT BOTTOM - LIKE CHATGPT/DEEPSEEK
442
+ st.markdown("""
443
+ <div class="fixed-input-area">
444
+ <div class="input-container">
445
+ <div class="input-wrapper">
446
+ """, unsafe_allow_html=True)
447
+
448
+ # Chat Input - this is now inside the fixed area
449
  disabled_input = st.session_state.uploaded_file_name is None or client is None
450
 
451
+ # Create a form for the input
452
  with st.form(key="chat_form", clear_on_submit=True):
453
+ col1, col2 = st.columns([10, 1])
454
  with col1:
455
  question = st.text_input(
456
+ "Type your question",
457
  key="question_input",
458
  disabled=disabled_input,
459
  label_visibility="collapsed",
460
+ placeholder="Ask anything about your PDF document...",
461
+ help="Press Enter to send"
462
  )
463
  with col2:
464
+ submit_button = st.form_submit_button(
465
+ "➀",
466
+ disabled=disabled_input,
467
+ use_container_width=True,
468
+ help="Send message"
469
+ )
470
 
471
+ st.markdown("""
472
+ </div>
473
+ </div>
474
+ </div>
475
+ """, unsafe_allow_html=True)
476
 
477
  # Handle form submission
478
  if submit_button and question:
 
489
  else:
490
  st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** {error}"))
491
 
492
+ # Update message count for scroll detection
493
  st.session_state.last_message_count = len(st.session_state.chat)
494
  st.rerun()
495
 
496
+ # AUTOSCROLL - Scroll to bottom when new messages are added
 
 
 
 
 
 
 
 
497
  if len(st.session_state.chat) > st.session_state.last_message_count:
 
498
  st.session_state.last_message_count = len(st.session_state.chat)
499
 
 
500
  st.markdown("""
501
  <script>
502
+ // Scroll to bottom when new messages are added
503
  setTimeout(() => {
504
+ // Scroll the entire main content area
505
+ const mainContent = document.querySelector('.main-content');
506
+ if (mainContent) {
507
+ mainContent.scrollTop = mainContent.scrollHeight;
508
  }
509
  }, 100);
510
  </script>
511
  """, unsafe_allow_html=True)
512
  else:
513
+ # Initial scroll to bottom on page load
514
  st.markdown("""
515
  <script>
516
+ // Initial scroll to bottom
517
  document.addEventListener('DOMContentLoaded', function() {
518
  setTimeout(() => {
519
+ const mainContent = document.querySelector('.main-content');
520
+ if (mainContent) {
521
+ mainContent.scrollTop = mainContent.scrollHeight;
522
  }
523
  }, 300);
524
  });