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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -101
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 (ChatGPT/DeepSeek style) ----------------
36
  st.markdown("""
37
  <style>
38
  :root {
@@ -42,41 +42,78 @@ st.markdown("""
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 {
@@ -111,48 +148,27 @@ h1 {
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;
@@ -162,11 +178,11 @@ h1 {
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;
@@ -181,12 +197,12 @@ h1 {
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
  }
@@ -195,33 +211,34 @@ h1 {
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
 
@@ -242,6 +259,13 @@ section[data-testid="stSidebar"] {
242
  ::-webkit-scrollbar-thumb:hover {
243
  background: rgba(255, 255, 255, 0.3);
244
  }
 
 
 
 
 
 
 
245
  </style>
246
  """, unsafe_allow_html=True)
247
 
@@ -370,17 +394,31 @@ FINAL ANSWER:
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"],
@@ -397,7 +435,7 @@ with st.sidebar:
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")
@@ -406,16 +444,19 @@ with st.sidebar:
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)
@@ -428,27 +469,17 @@ 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:
@@ -469,12 +500,11 @@ with st.form(key="chat_form", clear_on_submit=True):
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:
479
  # Add user query to chat history
480
  st.session_state.chat.append(("user", question))
@@ -493,7 +523,7 @@ if submit_button and question:
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
 
@@ -501,10 +531,9 @@ if len(st.session_state.chat) > st.session_state.last_message_count:
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>
@@ -516,9 +545,9 @@ else:
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
  });
 
32
  # ---------------- STREAMLIT UI SETUP ----------------
33
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
34
 
35
+ # ---------------- CSS (ChatGPT/DeepSeek style with fixes) ----------------
36
  st.markdown("""
37
  <style>
38
  :root {
 
42
  --text-color: #f0f2f6;
43
  }
44
 
45
+ /* Fix Streamlit default layout */
46
  .stApp {
47
  padding-top: 0 !important;
48
  }
49
 
50
+ /* FIXED LEFT PANEL - always visible */
51
+ section[data-testid="stSidebar"] {
52
+ position: fixed !important;
53
+ height: 100vh !important;
54
+ overflow-y: auto !important;
55
+ padding-top: 1rem !important;
56
  }
57
 
58
+ /* Main content area - takes full width minus sidebar */
59
+ .main {
60
+ margin-left: 300px !important;
61
+ }
62
+
63
+ @media (max-width: 768px) {
64
+ section[data-testid="stSidebar"] {
65
+ position: relative !important;
66
+ height: auto !important;
67
+ }
68
+ .main {
69
+ margin-left: 0 !important;
70
+ }
71
+ }
72
+
73
+ /* Fixed input area at bottom */
74
+ .fixed-input-container {
75
+ position: fixed !important;
76
+ bottom: 0 !important;
77
+ left: 300px !important;
78
+ right: 0 !important;
79
+ background: var(--background-color) !important;
80
+ padding: 1.5rem 2rem !important;
81
+ border-top: 1px solid rgba(255, 255, 255, 0.15) !important;
82
+ z-index: 1000 !important;
83
+ backdrop-filter: blur(10px) !important;
84
+ box-shadow: 0 -5px 20px rgba(0, 0, 0, 0.3) !important;
85
+ }
86
+
87
+ @media (max-width: 768px) {
88
+ .fixed-input-container {
89
+ left: 0 !important;
90
+ }
91
+ }
92
+
93
+ /* Scrollable chat area above fixed input */
94
+ .chat-scroll-area {
95
+ position: fixed !important;
96
+ top: 0 !important;
97
+ left: 300px !important;
98
+ right: 0 !important;
99
+ bottom: 120px !important; /* Space for fixed input */
100
+ overflow-y: auto !important;
101
+ padding: 1rem 2rem !important;
102
  }
103
 
 
104
  @media (max-width: 768px) {
105
+ .chat-scroll-area {
106
+ left: 0 !important;
107
+ position: relative !important;
108
+ height: calc(100vh - 180px) !important;
109
  }
110
  }
111
 
112
+ /* Chat messages styling */
113
  .chat-messages {
 
114
  max-width: 800px;
115
  margin: 0 auto;
116
+ padding-bottom: 2rem;
117
  }
118
 
119
  .chat-user {
 
148
  padding-top: 8px;
149
  }
150
 
151
+ /* Input styling */
152
+ .input-wrapper {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  max-width: 800px;
154
  margin: 0 auto;
 
155
  }
156
 
157
+ .input-box {
158
  background: var(--secondary-background-color);
159
  border: 1px solid rgba(255, 255, 255, 0.2);
160
  border-radius: 24px;
161
  padding: 4px;
162
  display: flex;
163
  align-items: center;
 
164
  }
165
 
166
+ .input-box:focus-within {
167
  border-color: var(--primary-color);
168
  box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.3);
169
  }
170
 
171
+ .chat-input-field {
172
  flex: 1;
173
  background: transparent;
174
  border: none;
 
178
  outline: none;
179
  }
180
 
181
+ .chat-input-field::placeholder {
182
  color: rgba(255, 255, 255, 0.5);
183
  }
184
 
185
+ .send-btn {
186
  background: var(--primary-color);
187
  color: white;
188
  border: none;
 
197
  transition: all 0.2s ease;
198
  }
199
 
200
+ .send-btn:hover:not(:disabled) {
201
  background: #2d4bb5;
202
  transform: scale(1.05);
203
  }
204
 
205
+ .send-btn:disabled {
206
  opacity: 0.5;
207
  cursor: not-allowed;
208
  }
 
211
  .empty-state {
212
  text-align: center;
213
  color: #888;
214
+ padding: 60px 20px;
215
  font-style: italic;
216
+ font-size: 1.1em;
217
+ margin-top: 40px;
218
  }
219
 
220
+ /* Creator info in sidebar */
221
+ .creator-info {
 
 
 
 
 
222
  margin-top: 2rem;
223
+ padding-top: 1rem;
224
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
225
  text-align: center;
226
+ }
227
+
228
+ .creator-name {
229
+ font-size: 0.9em;
230
  color: var(--text-color);
231
+ opacity: 0.8;
232
+ margin-bottom: 5px;
233
  }
234
 
235
+ .creator-link {
236
+ font-size: 0.85em;
237
+ color: var(--primary-color) !important;
238
  text-decoration: none;
 
239
  }
240
 
241
+ .creator-link:hover {
242
  text-decoration: underline;
243
  }
244
 
 
259
  ::-webkit-scrollbar-thumb:hover {
260
  background: rgba(255, 255, 255, 0.3);
261
  }
262
+
263
+ /* Make sidebar content scrollable */
264
+ .sidebar-content {
265
+ height: calc(100vh - 150px);
266
+ overflow-y: auto;
267
+ padding-right: 10px;
268
+ }
269
  </style>
270
  """, unsafe_allow_html=True)
271
 
 
394
  except Exception as e:
395
  return None, 0, f"General error: {str(e)}"
396
 
397
+ # ==================== LAYOUT ====================
398
 
399
+ # ==================== LEFT PANEL (FIXED) ====================
400
  with st.sidebar:
401
+ # Title and creator info
402
+ st.markdown("""
403
+ <h1 style='text-align: center; margin-bottom: 0.5rem;'>πŸ“˜ PDF Assistant</h1>
404
+ <div class='creator-info'>
405
+ <div class='creator-name'>Created by</div>
406
+ <a href='https://www.linkedin.com/in/abhishek-iitr/' target='_blank' class='creator-link'>Abhishek Saxena</a>
407
+ </div>
408
+ """, unsafe_allow_html=True)
409
+
410
  st.markdown("---")
411
+
412
+ # Controls section
413
+ st.subheader("Controls")
414
  st.button("πŸ—‘οΈ Clear Chat History", on_click=clear_chat_history, use_container_width=True)
415
  st.button("πŸ”₯ Clear PDF Memory", on_click=clear_memory, use_container_width=True)
416
 
417
  st.markdown("---")
418
+
419
+ # PDF Upload section
420
+ st.subheader("Upload PDF")
421
+
422
  uploaded = st.file_uploader(
423
  "Choose a PDF file",
424
  type=["pdf"],
 
435
  chunks_count = process_pdf(uploaded)
436
 
437
  if chunks_count is not None:
438
+ st.success(f"βœ… PDF processed successfully! {chunks_count} chunks created.")
439
  st.session_state.uploaded_file_name = uploaded.name
440
  else:
441
  st.error("❌ Failed to process PDF")
 
444
  st.rerun()
445
 
446
  st.markdown("---")
447
+
448
+ # Status section
449
+ st.subheader("Status")
450
  if st.session_state.uploaded_file_name:
451
  st.success(f"**Active PDF:**\n`{st.session_state.uploaded_file_name}`")
452
  else:
453
  st.info("⬆️ Upload a PDF to start chatting!")
454
 
455
+ # ==================== RIGHT PANEL - SCROLLABLE CHAT AREA ====================
456
+ st.markdown('<div class="chat-scroll-area" id="chat-scroll-area">', unsafe_allow_html=True)
457
 
458
+ # Chat messages container
459
+ st.markdown('<div class="chat-messages">', unsafe_allow_html=True)
460
 
461
  if not st.session_state.chat:
462
  st.markdown('<div class="empty-state">Ask a question about your PDF to start the conversation!</div>', unsafe_allow_html=True)
 
469
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
470
 
471
  st.markdown('</div>', unsafe_allow_html=True) # Close chat-messages
472
+ st.markdown('</div>', unsafe_allow_html=True) # Close chat-scroll-area
473
 
474
+ # ==================== FIXED INPUT AT BOTTOM ====================
 
 
 
 
 
 
 
 
 
475
  st.markdown("""
476
+ <div class="fixed-input-container">
477
+ <div class="input-wrapper">
 
478
  """, unsafe_allow_html=True)
479
 
480
+ # Chat Input - fixed at bottom
481
  disabled_input = st.session_state.uploaded_file_name is None or client is None
482
 
 
483
  with st.form(key="chat_form", clear_on_submit=True):
484
  col1, col2 = st.columns([10, 1])
485
  with col1:
 
500
  )
501
 
502
  st.markdown("""
 
503
  </div>
504
  </div>
505
  """, unsafe_allow_html=True)
506
 
507
+ # ==================== FORM SUBMISSION HANDLING ====================
508
  if submit_button and question:
509
  # Add user query to chat history
510
  st.session_state.chat.append(("user", question))
 
523
  st.session_state.last_message_count = len(st.session_state.chat)
524
  st.rerun()
525
 
526
+ # ==================== AUTO-SCROLL JAVASCRIPT ====================
527
  if len(st.session_state.chat) > st.session_state.last_message_count:
528
  st.session_state.last_message_count = len(st.session_state.chat)
529
 
 
531
  <script>
532
  // Scroll to bottom when new messages are added
533
  setTimeout(() => {
534
+ const chatArea = document.getElementById('chat-scroll-area');
535
+ if (chatArea) {
536
+ chatArea.scrollTop = chatArea.scrollHeight;
 
537
  }
538
  }, 100);
539
  </script>
 
545
  // Initial scroll to bottom
546
  document.addEventListener('DOMContentLoaded', function() {
547
  setTimeout(() => {
548
+ const chatArea = document.getElementById('chat-scroll-area');
549
+ if (chatArea) {
550
+ chatArea.scrollTop = chatArea.scrollHeight;
551
  }
552
  }, 300);
553
  });