absiitr commited on
Commit
bf8b348
Β·
verified Β·
1 Parent(s): 5424384

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -47
app.py CHANGED
@@ -1,102 +1,217 @@
1
  import streamlit as st
2
  import requests
 
3
 
4
- # βœ… HF-safe same-origin routing
5
- BACKEND_URL = ""
6
 
7
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
8
 
9
- # ---------------- CSS ----------------
 
10
  st.markdown("""
11
  <style>
 
 
 
 
 
 
 
 
 
12
  .chat-user {
13
- background: #2d3748;
14
  padding: 12px;
15
- border-radius: 10px;
 
 
16
  text-align: right;
 
17
  }
18
  .chat-bot {
19
- background: #1e3a8a;
20
  padding: 12px;
21
- border-radius: 10px;
22
- color: white;
 
 
 
23
  }
 
 
24
  .sources {
25
  font-size: 0.8em;
26
  opacity: 0.7;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
  </style>
29
  """, unsafe_allow_html=True)
30
 
31
- # ---------------- STATE ----------------
32
  if "chat" not in st.session_state:
33
  st.session_state.chat = []
34
- if "pdf" not in st.session_state:
35
- st.session_state.pdf = None
 
 
 
36
  if "uploader_key" not in st.session_state:
37
  st.session_state.uploader_key = 0
38
 
 
39
  st.title("πŸ“˜ PDF Assistant")
40
 
 
41
  # ---------------- FUNCTIONS ----------------
42
- def clear_memory():
43
- requests.post(f"{BACKEND_URL}/api/clear")
44
  st.session_state.chat = []
45
- st.session_state.pdf = None
46
- st.session_state.uploader_key += 1
47
- st.success("Memory cleared")
48
 
49
 
50
- # ---------------- SIDEBAR ----------------
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  with st.sidebar:
52
- st.button("πŸ”₯ Clear PDF Memory", on_click=clear_memory)
 
 
 
 
 
 
 
 
53
 
54
- # ---------------- UPLOAD ----------------
 
55
  uploaded = st.file_uploader(
56
- "Upload PDF",
57
  type=["pdf"],
58
- key=st.session_state.uploader_key
59
  )
60
 
61
- if uploaded and uploaded.name != st.session_state.pdf:
62
- with st.spinner("Processing PDF..."):
63
- files = {"file": (uploaded.name, uploaded.getvalue(), "application/pdf")}
64
- res = requests.post(f"{BACKEND_URL}/api/upload", files=files)
65
-
66
- if res.status_code == 200:
67
- st.session_state.pdf = uploaded.name
68
- st.success("PDF processed")
69
- else:
70
- st.error(res.text)
71
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  st.rerun()
73
 
74
- # ---------------- CHAT ----------------
 
 
75
  question = st.text_input(
76
- "Ask a question",
77
- disabled=st.session_state.pdf is None
 
78
  )
79
 
80
- if st.button("Send") and question:
 
81
  st.session_state.chat.append(("user", question))
82
 
83
- res = requests.post(
84
- f"{BACKEND_URL}/api/ask",
85
- json={"question": question}
86
- )
87
 
88
- if res.status_code == 200:
89
- data = res.json()
90
- msg = f"{data['answer']}<div class='sources'>Chunks used: {data['sources']}</div>"
91
- st.session_state.chat.append(("bot", msg))
92
- else:
93
- st.session_state.chat.append(("bot", "Error"))
 
 
 
 
 
 
94
 
 
 
 
 
 
 
 
95
  st.rerun()
96
 
97
- # ---------------- CHAT HISTORY ----------------
 
 
98
  for role, msg in st.session_state.chat:
99
  if role == "user":
100
  st.markdown(f"<div class='chat-user'>{msg}</div>", unsafe_allow_html=True)
101
  else:
 
102
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import requests
3
+ import os
4
 
5
+ # Backend URL (change if deployed)
6
+ BACKEND_URL = "http://localhost:8000"
7
 
8
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
9
 
10
+ # ---------------- CSS (Dark Theme) ----------------
11
+ # FIX: Added CSS for the footer
12
  st.markdown("""
13
  <style>
14
+ /* Streamlit standard setup for dark theme adherence */
15
+ :root {
16
+ --primary-color: #1e3a8a; /* Blue for highlights */
17
+ --background-color: #0e1117;
18
+ --secondary-background-color: #1a1d29;
19
+ --text-color: #f0f2f6;
20
+ }
21
+
22
+ /* Custom Chat Bubbles */
23
  .chat-user {
24
+ background: #2d3748; /* Dark gray */
25
  padding: 12px;
26
+ border-radius: 10px 10px 2px 10px; /* Rounded corners for chat bubble */
27
+ margin: 6px 0 6px auto;
28
+ max-width: 85%;
29
  text-align: right;
30
+ color: var(--text-color);
31
  }
32
  .chat-bot {
33
+ background: var(--primary-color); /* Primary blue */
34
  padding: 12px;
35
+ border-radius: 10px 10px 10px 2px;
36
+ margin: 6px auto 6px 0;
37
+ max-width: 85%;
38
+ text-align: left;
39
+ color: #ffffff; /* White text for contrast */
40
  }
41
+
42
+ /* Sources section styling */
43
  .sources {
44
  font-size: 0.8em;
45
  opacity: 0.7;
46
+ margin-top: 10px;
47
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
48
+ padding-top: 5px;
49
+ }
50
+
51
+ /* Footer styling */
52
+ .footer {
53
+ position: fixed;
54
+ left: 0;
55
+ bottom: 0;
56
+ width: 100%;
57
+ background-color: var(--secondary-background-color);
58
+ color: var(--text-color);
59
+ text-align: center;
60
+ padding: 10px;
61
+ font-size: 0.85em;
62
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
63
+ }
64
+ .footer a {
65
+ color: var(--primary-color);
66
+ text-decoration: none;
67
+ font-weight: bold;
68
+ }
69
+ .footer a:hover {
70
+ text-decoration: underline;
71
  }
72
  </style>
73
  """, unsafe_allow_html=True)
74
 
75
+ # ---------------- SESSION STATE ----------------
76
  if "chat" not in st.session_state:
77
  st.session_state.chat = []
78
+
79
+ if "uploaded_file_name" not in st.session_state:
80
+ st.session_state.uploaded_file_name = None
81
+
82
+ # Add a key to the file uploader to allow it to be reset.
83
  if "uploader_key" not in st.session_state:
84
  st.session_state.uploader_key = 0
85
 
86
+ # FIX 1: Change application name
87
  st.title("πŸ“˜ PDF Assistant")
88
 
89
+
90
  # ---------------- FUNCTIONS ----------------
91
+ def clear_chat_history():
92
+ """Clears the chat history in the session state."""
93
  st.session_state.chat = []
 
 
 
94
 
95
 
96
+ def clear_memory():
97
+ """Calls the backend endpoint to clear loaded PDF data and resets UI state."""
98
+ res = requests.post(f"{BACKEND_URL}/clear")
99
+ if res.status_code == 200:
100
+ st.session_state.uploaded_file_name = None
101
+ # Increment the key of the file uploader to clear its value
102
+ st.session_state.uploader_key += 1
103
+ st.success("Memory cleared. Please upload a new PDF.")
104
+ else:
105
+ st.error(f"Failed to clear memory: {res.json().get('detail', 'Unknown error')}")
106
+ # Removed st.rerun() to prevent "no-op" warning
107
+
108
+
109
+ # ---------------- SIDEBAR CONTROLS ----------------
110
  with st.sidebar:
111
+ st.header("Controls")
112
+ st.button("πŸ—‘οΈ Clear Chat History", on_click=clear_chat_history, use_container_width=True)
113
+ st.button("πŸ”₯ Clear PDF Memory", on_click=clear_memory, use_container_width=True)
114
+
115
+ st.markdown("---")
116
+ if st.session_state.uploaded_file_name:
117
+ st.success(f"βœ… **Active PDF:**\n `{st.session_state.uploaded_file_name}`")
118
+ else:
119
+ st.warning("⬆️ Upload a PDF to start chatting!")
120
 
121
+ # ---------------- UPLOAD PDF ----------------
122
+ # Use the dynamic key for the file uploader.
123
  uploaded = st.file_uploader(
124
+ "Upload your PDF",
125
  type=["pdf"],
126
+ key=st.session_state.uploader_key # Use the dynamic key
127
  )
128
 
129
+ # Only process if a file is uploaded AND it's a NEW file
130
+ if uploaded and uploaded.name != st.session_state.uploaded_file_name:
131
+ st.session_state.uploaded_file_name = None # Clear status while processing
132
+ st.session_state.chat = [] # Clear chat for a new document
133
+
134
+ with st.spinner(f"Processing '{uploaded.name}'..."):
135
+ try:
136
+ files = {"file": (uploaded.name, uploaded.getvalue(), "application/pdf")}
137
+ res = requests.post(f"{BACKEND_URL}/upload", files=files)
138
+
139
+ if res.status_code == 200:
140
+ chunks = res.json().get("chunks", 0)
141
+ st.success(f"PDF processed successfully! {chunks} chunks created.")
142
+ st.session_state.uploaded_file_name = uploaded.name
143
+ else:
144
+ error_msg = res.json().get("detail", "Unknown error during processing.")
145
+ st.error(f"Upload failed: {error_msg}")
146
+ st.session_state.uploaded_file_name = None
147
+
148
+ except requests.exceptions.ConnectionError:
149
+ st.error(f"Could not connect to the backend server at {BACKEND_URL}. Ensure it is running.")
150
+ st.session_state.uploaded_file_name = None
151
+ except Exception as e:
152
+ st.error(f"An unexpected error occurred: {e}")
153
+ st.session_state.uploaded_file_name = None
154
+
155
+ # Rerun the app to update the UI status immediately
156
  st.rerun()
157
 
158
+ # ---------------- CHAT INPUT ----------------
159
+ # Disable input field if no PDF is loaded
160
+ disabled_input = st.session_state.uploaded_file_name is None
161
  question = st.text_input(
162
+ "Ask a question about the loaded PDF:",
163
+ key="question_input",
164
+ disabled=disabled_input
165
  )
166
 
167
+ if st.button("Send", disabled=disabled_input) and question:
168
+ # 1. Add user query to chat history
169
  st.session_state.chat.append(("user", question))
170
 
171
+ # 2. Call backend
172
+ with st.spinner("Thinking..."):
173
+ try:
174
+ res = requests.post(f"{BACKEND_URL}/ask", json={"question": question})
175
 
176
+ if res.status_code == 200:
177
+ data = res.json()
178
+ answer = data.get("answer", "No answer provided.")
179
+ sources = data.get("sources", 0)
180
+
181
+ # Format the bot's response to include source count
182
+ bot_message = f"{answer}<div class='sources'>Context Chunks Used: {sources}</div>"
183
+ st.session_state.chat.append(("bot", bot_message))
184
+
185
+ else:
186
+ error_detail = res.json().get("detail", "Error while generating answer.")
187
+ st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** {error_detail}"))
188
 
189
+ except requests.exceptions.ConnectionError:
190
+ st.session_state.chat.append(("bot",
191
+ f"πŸ”΄ **Error:** Could not connect to the backend server at {BACKEND_URL}. Ensure it is running."))
192
+ except Exception as e:
193
+ st.session_state.chat.append(("bot", f"πŸ”΄ **An unexpected error occurred:** {e}"))
194
+
195
+ # Rerun to display the updated chat history
196
  st.rerun()
197
 
198
+ # ---------------- SHOW CHAT HISTORY ----------------
199
+ st.markdown("## Chat History")
200
+ # Reverse the list to show the latest messages at the bottom
201
  for role, msg in st.session_state.chat:
202
  if role == "user":
203
  st.markdown(f"<div class='chat-user'>{msg}</div>", unsafe_allow_html=True)
204
  else:
205
+ # Bot message includes the source count, so use the HTML content
206
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
207
+
208
+ # ---------------- FOOTER (Creator Credit) ----------------
209
+ # FIX 2: Add creator credit with LinkedIn link
210
+ footer_html = """
211
+ <div class="footer">
212
+ Created by <a href="https://www.linkedin.com/in/abhishek-iitr/" target="_blank">Abhishek Saxena</a>
213
+ </div>
214
+ """
215
+ st.markdown(footer_html, unsafe_allow_html=True)
216
+
217
+ # ---------------- END ----------------