absiitr commited on
Commit
0b7eeb1
Β·
verified Β·
1 Parent(s): 6994cf7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -63
app.py CHANGED
@@ -1,31 +1,42 @@
1
  import streamlit as st
2
  import requests
3
- # Backend URL - handle both local and Hugging Face deployment
4
- # For Hugging Face Spaces
5
  import os
6
 
7
- # Check if running on Hugging Face
8
- HF_SPACE = os.environ.get("SPACE_ID") is not None
 
9
 
10
- if HF_SPACE:
11
- # On Hugging Face, backend runs on same container but different port
12
- BACKEND_URL = "http://localhost:8000"
13
- # OR use the public URL of your space
14
- # space_name = os.environ.get("SPACE_ID")
15
- # BACKEND_URL = f"https://{space_name}.hf.space"
16
- else:
17
- # Local development
18
- BACKEND_URL = "http://localhost:8000"
 
 
 
19
 
20
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
21
 
 
 
 
 
 
 
 
 
 
 
22
  # ---------------- CSS (Dark Theme) ----------------
23
- # FIX: Added CSS for the footer
24
  st.markdown("""
25
  <style>
26
  /* Streamlit standard setup for dark theme adherence */
27
  :root {
28
- --primary-color: #1e3a8a; /* Blue for highlights */
29
  --background-color: #0e1117;
30
  --secondary-background-color: #1a1d29;
31
  --text-color: #f0f2f6;
@@ -33,22 +44,22 @@ st.markdown("""
33
 
34
  /* Custom Chat Bubbles */
35
  .chat-user {
36
- background: #2d3748; /* Dark gray */
37
  padding: 12px;
38
- border-radius: 10px 10px 2px 10px; /* Rounded corners for chat bubble */
39
  margin: 6px 0 6px auto;
40
  max-width: 85%;
41
  text-align: right;
42
  color: var(--text-color);
43
  }
44
  .chat-bot {
45
- background: var(--primary-color); /* Primary blue */
46
  padding: 12px;
47
  border-radius: 10px 10px 10px 2px;
48
  margin: 6px auto 6px 0;
49
  max-width: 85%;
50
  text-align: left;
51
- color: #ffffff; /* White text for contrast */
52
  }
53
 
54
  /* Sources section styling */
@@ -81,6 +92,13 @@ st.markdown("""
81
  .footer a:hover {
82
  text-decoration: underline;
83
  }
 
 
 
 
 
 
 
84
  </style>
85
  """, unsafe_allow_html=True)
86
 
@@ -91,32 +109,27 @@ if "chat" not in st.session_state:
91
  if "uploaded_file_name" not in st.session_state:
92
  st.session_state.uploaded_file_name = None
93
 
94
- # Add a key to the file uploader to allow it to be reset.
95
  if "uploader_key" not in st.session_state:
96
  st.session_state.uploader_key = 0
97
 
98
- # FIX 1: Change application name
99
- st.title("πŸ“˜ PDF Assistant")
100
-
101
 
102
  # ---------------- FUNCTIONS ----------------
103
  def clear_chat_history():
104
- """Clears the chat history in the session state."""
105
  st.session_state.chat = []
106
 
107
-
108
  def clear_memory():
109
- """Calls the backend endpoint to clear loaded PDF data and resets UI state."""
110
- res = requests.post(f"{BACKEND_URL}/clear")
111
- if res.status_code == 200:
112
- st.session_state.uploaded_file_name = None
113
- # Increment the key of the file uploader to clear its value
114
- st.session_state.uploader_key += 1
115
- st.success("Memory cleared. Please upload a new PDF.")
116
- else:
117
- st.error(f"Failed to clear memory: {res.json().get('detail', 'Unknown error')}")
118
- # Removed st.rerun() to prevent "no-op" warning
119
-
120
 
121
  # ---------------- SIDEBAR CONTROLS ----------------
122
  with st.sidebar:
@@ -130,18 +143,19 @@ with st.sidebar:
130
  else:
131
  st.warning("⬆️ Upload a PDF to start chatting!")
132
 
 
 
 
133
  # ---------------- UPLOAD PDF ----------------
134
- # Use the dynamic key for the file uploader.
135
  uploaded = st.file_uploader(
136
  "Upload your PDF",
137
  type=["pdf"],
138
- key=st.session_state.uploader_key # Use the dynamic key
139
  )
140
 
141
- # Only process if a file is uploaded AND it's a NEW file
142
  if uploaded and uploaded.name != st.session_state.uploaded_file_name:
143
- st.session_state.uploaded_file_name = None # Clear status while processing
144
- st.session_state.chat = [] # Clear chat for a new document
145
 
146
  with st.spinner(f"Processing '{uploaded.name}'..."):
147
  try:
@@ -150,25 +164,24 @@ if uploaded and uploaded.name != st.session_state.uploaded_file_name:
150
 
151
  if res.status_code == 200:
152
  chunks = res.json().get("chunks", 0)
153
- st.success(f"PDF processed successfully! {chunks} chunks created.")
154
  st.session_state.uploaded_file_name = uploaded.name
 
155
  else:
156
- error_msg = res.json().get("detail", "Unknown error during processing.")
157
- st.error(f"Upload failed: {error_msg}")
158
  st.session_state.uploaded_file_name = None
159
 
160
  except requests.exceptions.ConnectionError:
161
- st.error(f"Could not connect to the backend server at {BACKEND_URL}. Ensure it is running.")
162
  st.session_state.uploaded_file_name = None
163
  except Exception as e:
164
- st.error(f"An unexpected error occurred: {e}")
165
  st.session_state.uploaded_file_name = None
166
 
167
- # Rerun the app to update the UI status immediately
168
  st.rerun()
169
 
170
  # ---------------- CHAT INPUT ----------------
171
- # Disable input field if no PDF is loaded
172
  disabled_input = st.session_state.uploaded_file_name is None
173
  question = st.text_input(
174
  "Ask a question about the loaded PDF:",
@@ -177,10 +190,8 @@ question = st.text_input(
177
  )
178
 
179
  if st.button("Send", disabled=disabled_input) and question:
180
- # 1. Add user query to chat history
181
  st.session_state.chat.append(("user", question))
182
 
183
- # 2. Call backend
184
  with st.spinner("Thinking..."):
185
  try:
186
  res = requests.post(f"{BACKEND_URL}/ask", json={"question": question})
@@ -190,40 +201,33 @@ if st.button("Send", disabled=disabled_input) and question:
190
  answer = data.get("answer", "No answer provided.")
191
  sources = data.get("sources", 0)
192
 
193
- # Format the bot's response to include source count
194
  bot_message = f"{answer}<div class='sources'>Context Chunks Used: {sources}</div>"
195
  st.session_state.chat.append(("bot", bot_message))
 
196
 
197
  else:
198
- error_detail = res.json().get("detail", "Error while generating answer.")
199
  st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** {error_detail}"))
200
 
201
  except requests.exceptions.ConnectionError:
202
- st.session_state.chat.append(("bot",
203
- f"πŸ”΄ **Error:** Could not connect to the backend server at {BACKEND_URL}. Ensure it is running."))
204
  except Exception as e:
205
- st.session_state.chat.append(("bot", f"πŸ”΄ **An unexpected error occurred:** {e}"))
206
 
207
- # Rerun to display the updated chat history
208
  st.rerun()
209
 
210
  # ---------------- SHOW CHAT HISTORY ----------------
211
  st.markdown("## Chat History")
212
- # Reverse the list to show the latest messages at the bottom
213
  for role, msg in st.session_state.chat:
214
  if role == "user":
215
  st.markdown(f"<div class='chat-user'>{msg}</div>", unsafe_allow_html=True)
216
  else:
217
- # Bot message includes the source count, so use the HTML content
218
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
219
 
220
- # ---------------- FOOTER (Creator Credit) ----------------
221
- # FIX 2: Add creator credit with LinkedIn link
222
  footer_html = """
223
  <div class="footer">
224
  Created by <a href="https://www.linkedin.com/in/abhishek-iitr/" target="_blank">Abhishek Saxena</a>
225
  </div>
226
  """
227
- st.markdown(footer_html, unsafe_allow_html=True)
228
-
229
- # ---------------- END ----------------
 
1
  import streamlit as st
2
  import requests
 
 
3
  import os
4
 
5
+ # ============== BACKEND URL CONFIGURATION ==============
6
+ # For Hugging Face deployment
7
+ import socket
8
 
9
+ def get_backend_url():
10
+ """Determine backend URL based on environment."""
11
+ # Check if we're on Hugging Face
12
+ if os.environ.get("SPACE_ID"):
13
+ # On Hugging Face, backend is on localhost:8000
14
+ return "http://localhost:8000"
15
+ else:
16
+ # Local development
17
+ return "http://localhost:8000"
18
+
19
+ BACKEND_URL = get_backend_url()
20
+ # ======================================================
21
 
22
  st.set_page_config(page_title="PDF Assistant", page_icon="πŸ“˜", layout="wide")
23
 
24
+ # Test backend connection on startup
25
+ try:
26
+ health_check = requests.get(f"{BACKEND_URL}/health", timeout=2)
27
+ if health_check.status_code == 200:
28
+ st.sidebar.success("βœ… Backend connected")
29
+ else:
30
+ st.sidebar.warning(f"⚠️ Backend status: {health_check.status_code}")
31
+ except:
32
+ st.sidebar.error("❌ Cannot connect to backend")
33
+
34
  # ---------------- CSS (Dark Theme) ----------------
 
35
  st.markdown("""
36
  <style>
37
  /* Streamlit standard setup for dark theme adherence */
38
  :root {
39
+ --primary-color: #1e3a8a;
40
  --background-color: #0e1117;
41
  --secondary-background-color: #1a1d29;
42
  --text-color: #f0f2f6;
 
44
 
45
  /* Custom Chat Bubbles */
46
  .chat-user {
47
+ background: #2d3748;
48
  padding: 12px;
49
+ border-radius: 10px 10px 2px 10px;
50
  margin: 6px 0 6px auto;
51
  max-width: 85%;
52
  text-align: right;
53
  color: var(--text-color);
54
  }
55
  .chat-bot {
56
+ background: var(--primary-color);
57
  padding: 12px;
58
  border-radius: 10px 10px 10px 2px;
59
  margin: 6px auto 6px 0;
60
  max-width: 85%;
61
  text-align: left;
62
+ color: #ffffff;
63
  }
64
 
65
  /* Sources section styling */
 
92
  .footer a:hover {
93
  text-decoration: underline;
94
  }
95
+
96
+ /* Debug info */
97
+ .debug-info {
98
+ font-size: 0.7em;
99
+ color: #888;
100
+ margin-top: 5px;
101
+ }
102
  </style>
103
  """, unsafe_allow_html=True)
104
 
 
109
  if "uploaded_file_name" not in st.session_state:
110
  st.session_state.uploaded_file_name = None
111
 
 
112
  if "uploader_key" not in st.session_state:
113
  st.session_state.uploader_key = 0
114
 
115
+ # Show backend URL for debugging
116
+ st.sidebar.markdown(f"**Backend URL:** `{BACKEND_URL}`", unsafe_allow_html=True)
 
117
 
118
  # ---------------- FUNCTIONS ----------------
119
  def clear_chat_history():
 
120
  st.session_state.chat = []
121
 
 
122
  def clear_memory():
123
+ try:
124
+ res = requests.post(f"{BACKEND_URL}/clear")
125
+ if res.status_code == 200:
126
+ st.session_state.uploaded_file_name = None
127
+ st.session_state.uploader_key += 1
128
+ st.success("Memory cleared. Please upload a new PDF.")
129
+ else:
130
+ st.error(f"Failed to clear memory: {res.json().get('detail', 'Unknown error')}")
131
+ except Exception as e:
132
+ st.error(f"Error clearing memory: {str(e)}")
 
133
 
134
  # ---------------- SIDEBAR CONTROLS ----------------
135
  with st.sidebar:
 
143
  else:
144
  st.warning("⬆️ Upload a PDF to start chatting!")
145
 
146
+ # ---------------- MAIN APP ----------------
147
+ st.title("πŸ“˜ PDF Assistant")
148
+
149
  # ---------------- UPLOAD PDF ----------------
 
150
  uploaded = st.file_uploader(
151
  "Upload your PDF",
152
  type=["pdf"],
153
+ key=st.session_state.uploader_key
154
  )
155
 
 
156
  if uploaded and uploaded.name != st.session_state.uploaded_file_name:
157
+ st.session_state.uploaded_file_name = None
158
+ st.session_state.chat = []
159
 
160
  with st.spinner(f"Processing '{uploaded.name}'..."):
161
  try:
 
164
 
165
  if res.status_code == 200:
166
  chunks = res.json().get("chunks", 0)
167
+ st.success(f"βœ… PDF processed successfully! {chunks} chunks created.")
168
  st.session_state.uploaded_file_name = uploaded.name
169
+ st.markdown(f'<div class="debug-info">Backend: {BACKEND_URL}, Status: {res.status_code}</div>', unsafe_allow_html=True)
170
  else:
171
+ error_msg = res.json().get("detail", f"HTTP {res.status_code}")
172
+ st.error(f"❌ Upload failed: {error_msg}")
173
  st.session_state.uploaded_file_name = None
174
 
175
  except requests.exceptions.ConnectionError:
176
+ st.error(f"πŸ”Œ Could not connect to backend at {BACKEND_URL}")
177
  st.session_state.uploaded_file_name = None
178
  except Exception as e:
179
+ st.error(f"⚠️ Unexpected error: {str(e)}")
180
  st.session_state.uploaded_file_name = None
181
 
 
182
  st.rerun()
183
 
184
  # ---------------- CHAT INPUT ----------------
 
185
  disabled_input = st.session_state.uploaded_file_name is None
186
  question = st.text_input(
187
  "Ask a question about the loaded PDF:",
 
190
  )
191
 
192
  if st.button("Send", disabled=disabled_input) and question:
 
193
  st.session_state.chat.append(("user", question))
194
 
 
195
  with st.spinner("Thinking..."):
196
  try:
197
  res = requests.post(f"{BACKEND_URL}/ask", json={"question": question})
 
201
  answer = data.get("answer", "No answer provided.")
202
  sources = data.get("sources", 0)
203
 
 
204
  bot_message = f"{answer}<div class='sources'>Context Chunks Used: {sources}</div>"
205
  st.session_state.chat.append(("bot", bot_message))
206
+ st.markdown(f'<div class="debug-info">Backend: {BACKEND_URL}, Status: {res.status_code}</div>', unsafe_allow_html=True)
207
 
208
  else:
209
+ error_detail = res.json().get("detail", f"HTTP {res.status_code}")
210
  st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** {error_detail}"))
211
 
212
  except requests.exceptions.ConnectionError:
213
+ st.session_state.chat.append(("bot", f"πŸ”΄ **Error:** Could not connect to backend at {BACKEND_URL}"))
 
214
  except Exception as e:
215
+ st.session_state.chat.append(("bot", f"πŸ”΄ **Unexpected error:** {str(e)}"))
216
 
 
217
  st.rerun()
218
 
219
  # ---------------- SHOW CHAT HISTORY ----------------
220
  st.markdown("## Chat History")
 
221
  for role, msg in st.session_state.chat:
222
  if role == "user":
223
  st.markdown(f"<div class='chat-user'>{msg}</div>", unsafe_allow_html=True)
224
  else:
 
225
  st.markdown(f"<div class='chat-bot'>{msg}</div>", unsafe_allow_html=True)
226
 
227
+ # ---------------- FOOTER ----------------
 
228
  footer_html = """
229
  <div class="footer">
230
  Created by <a href="https://www.linkedin.com/in/abhishek-iitr/" target="_blank">Abhishek Saxena</a>
231
  </div>
232
  """
233
+ st.markdown(footer_html, unsafe_allow_html=True)